My answer is something like an application of one of the @allenericr answer points + some cache.
I suggest to implement this only if the 3 templates are different in the content and not only in the aspect, otherwise a CSS + JS solution should be the best choice.
Create a main page template 'multi-template-page.php'
that only contain the switch buttons and a get_template_part
call to include one of the 3 different template files (named e.g. my-template-1.php
, my-template-2.php
and my-template-3.php
) that you have to write for every template.
In the main template put something like:
<?php
/*
Template Name: Multi Template Page
*/
get_header(); ?>
<ul id="template_switches">
<li><a href="#template-1" data-template="1" class="active">Template 1</a></li>
<li><a href="#template-2" data-template="2">Template 2</a></li>
<li><a href="#template-2" data-template="3">Template 3</a></li>
</ul>
<div id="template-target"><?php get_template_part('my-template', '1'); ?></div>
<?php get_footer(); ?>
So, by default you’ll have first template active and displayed.
Then, in functions.php
enqueue a script for this template:
add_action('wp_enqueue_scripts', 'template_switch_script');
function template_switch_script() {
if ( is_page_template('multi-template-page.php') ) {
wp_enqueue_script('multi-template', get_template_directory_uri() . '/js/multi-template.js', array('jquery'));
$data = array(
'url' => admin_url('admin-ajax.php'),
'id' => get_queried_object()->ID
);
wp_localize_script('multi-template', 'multiTemplateData', $data );
}
}
Now you have to create the jsvascript file multi-template.js
in js subfolder of your theme:
window.multiTemplateCache = {} // prepare a cache object
jQuery().ready( function($) {
// cache the 1st template on load
window.multiTemplateCache.template_1 = $('#template-target').html();
$('#template_switches li a').click( function(e) {
e.preventDefault();
if ( $(this).hasClass('active') ) return false; // do nothing if click active link
var template = $(this).data('template');
if ( window.multiTemplateCache['template_' + template ] ) { // look in cache
// in cache, just output to page
$('#template-target').html( window.multiTemplateCache['template_' + template] );
} else { // not in cache, retrieve via ajax
// remove current template and put a loading message
$('#template-target').html( 'loading...' );
// css stuff
$('#template_switches li a').removeClass('active');
$(this).addClass('active');
$.get(
multiTemplateData.url,
{
postId: multiTemplateData.id,
action: 'multi_template_template',
which: template
},
function( data ) {
// cache the template
window.multiTemplateCache['template_' + template ] = data;
// output the template to page
$('#template-target').html( data );
}
);
} // end if
}); // end on click event
}); // on ready event
This script on click on one of the switch links, check in a cache object if the template is already loaded, and if so, output it. If not send an ajax request passing the template required.
Before putting the content to page, it is cached, so the ajax call is fired once per template. But only for templates 2 and 3 because template 1 is cached on load 🙂
So, now in your function.php
you have to to add the ajax action and the relative function.
add_action('wp_ajax_multi_template_template', 'multi_template_template');
add_action('wp_ajax_nopriv_multi_template_template', 'multi_template_template');
function multi_template_template() {
$template = isset($_REQUEST['which']) ? $_REQUEST['which'] : false;
if ( ! $template ) die('Sorry, impossible to load content');
$postid = isset($_REQUEST['postId']) ? $_REQUEST['postId'] : false;
if ( $postid ) {
global $post; // I'm setting global $post just-in-case the template make use of it
$post = get_post($postid);
}
get_template_part('my-template', $template);
die();
}
You can improve my code, adding the #
feature, i.e. when you point to an address like http://example.com/multi-template-page/#template2
the template 2 is setted as active and loaded for first…