Your main problem is that when you list your events, you (most probably) use the the_permalink()
function to get the url of the single event.
When this url is called, WordPress show the single event, but how can WordPress know if the link was clicked in the page-events.php
or in the page-media.php
?
If you don’t say nothing to WordPress (i.e. if you don’t put information in the url) WP cannot distinguish if a link was clicked in a page or in other.
So, what I suggest you is to add an endpoint.
It means that you will have different url for your single event, e.g. if the standard link is something like http://example.com/events/one-event/
you can have also http://example.com/events/one-event/show/media
or http://example.com/events/one-event/show/whatever
.
show
is the endpoint, it means that a variable show = media
or show = whatever
is passed as query var to Wordpess and so you can make use of it to include the wanted template.
To add the endpoint use:
add_action('init', 'add_show_endpoint');
function add_show_endpoint() {
add_rewrite_endpoint( 'show', EP_PERMALINK );
}
Now when you are in the page-media.php
you should have link like http://example.com/events/one-event/show/media
and when you are in page-whatever.php
you should have links like http://example.com/events/one-event/show/whatever
.
How to accomplish this? It’s simple: add a filter on get_permalink
function.
add_action('wp_head', 'set_event_permalink_filter');
function set_event_permalink_filter() {
$single_templates = array(
// page template => endpoint to use
'page-media.php' => 'media',
'page-info.php' => 'info',
'page-whatever.php' => 'whatever'
);
foreach ( $single_templates as $page => $endpoint) {
if ( is_page_template($page) ) {
global $event_endpoint;
$event_endpoint = $endpoint;
add_filter('post_link', 'event_permalink', 99, 3);
return;
}
}
}
function event_permalink ($permalink, $post, $leavename) {
if ( $post->post_type != 'events' ) return $permalink;
global $event_endpoint;
if ( empty($event_endpoint) ) return $permalink;
return user_trailingslashit($permalink) . 'show/' . $event_endpoint . "https://wordpress.stackexchange.com/";
}
This workflow is a bit more complex than it can be, because the is_page_template()
conditional tag doesn’t work inside the loop (info), so we need to check page template before the loop start and use a global variable to pass the endpoint to the event_permalink
function that is called by filter hook inside the loop.
At this point, if you go on the page, e.g. page-media.php
all links generated for events post type end with /show/media/
and when you click on them the query variable show
is setted to media
.
So, now we can hook into template_include
filter and based on the show
variable include the right template. For the pourpose we can use locate_template
to full support child themes.
add_filter('template_include', 'single_event_template');
function single_event_template( $template ) {
if ( ! is_single('events') ) return $template;
global $wp_query;
$show = $wp_query->get('show');
if ( empty($show) ) return $template;
$file = locate_template( 'single-events-' . $show . '.php', true, false );
return $file ? : $template;
}
So when we visit the link http://example.com/events/one-event/show/media
(that is generated inside the page-media.php
) if the template file single-event-media.php
is found in parent or child theme it will be required, otherwise the standard single-event.php
will be used.
Remember that after adding all the code in this answer to a plugin or in functions.php
you have to flush the rewrite rules logging in your backend, going to Settings->Permalinks and clicking Save Changes.
Please note that code is totally untested and written here (with no syntax highlight), so it may contain typos and syntax errors: if you got some errors look in Codex (on php.net docs) for the code that trigger the error and check the right syntax.
In all the code is assumed your CPT is named ‘events’, change to fit your needs.
Also change the page templates to endpoint associations in the $single_templates
variable inside set_event_permalink_filter
function.
Plugin Code
I’ve put all above code together in a plugin that use a class (avoiding the use of the global variable.
There are 2 static variables in the class you have to change to fit your needs.
The plugin also contain a filter: 'multiple_cpt_single_templates'
that allow adding page templates to endpoint associations from theme or from another plugin. You can even completely empty (set to array()
) the default $single_templates
static variable and fill it via filter.
Being a plugin, I use the register_activation_hook to flush rewrite rules.
<?php
/**
* Plugin Name: Multiple CPT Single Templates
* Plugin URI: http://wordpress.stackexchange.com/questions/113878/multiple-single-templates
* Author: G. M.
* Author URI: http://wordpress.stackexchange.com/users/35541/
*/
add_action('after_setup_theme', 'initMultipleCptSingleTemplates');
function initMultipleCptSingleTemplates() {
MultipleCptSingleTemplates::init();
}
register_activation_hook( __FILE__, array('MultipleCptSingleTemplates', 'install') );
register_deactivation_hook( __FILE__, array('MultipleCptSingleTemplates', 'uninstall') );
class MultipleCptSingleTemplates {
/**
* CHANGES FOLLOWING TWO VARIABLES ACCORDING TO YOUR NEEDS
*/
static $cpt="events";
static $single_templates = array(
// page template => endpoint to use
'page-media.php' => 'media',
'page-info.php' => 'info',
'page-whatever.php' => 'whatever'
);
/** CONFIGIGURATION END */
static $endpoint;
static function init() {
add_action('init', array( __CLASS__, 'add_show_endpoint') );
add_filter('template_include', array( __CLASS__, 'single_event_template') );
add_action('wp_head', array( __CLASS__, 'set_event_permalink_filter') );
}
static function add_show_endpoint() {
add_rewrite_endpoint( 'show', EP_PERMALINK );
}
static function set_event_permalink_filter() {
$single_templates = apply_filter('multiple_cpt_single_templates', self::$single_templates);
if ( empty($single_templates) ) return;
foreach ( $single_templates as $page => $endpoint) {
if ( is_page_template($page) ) {
self::$endpoint = $endpoint;
add_filter('post_link', array( __CLASS__, 'event_permalink'), 99, 3);
return;
}
}
}
static function event_permalink ($permalink, $post, $leavename) {
if ( $post->post_type != self::$cpt ) return $permalink;
if ( empty(self::$endpoint) ) return $permalink;
return user_trailingslashit($permalink) . 'show/' . self::$endpoint . "https://wordpress.stackexchange.com/";
}
static function event_permalink ($permalink, $post, $leavename) {
if ( $post->post_type != self::$cpt ) return $permalink;
if ( empty(self::$endpoint) ) return $permalink;
return user_trailingslashit($permalink) . 'show/' . self::$endpoint . "https://wordpress.stackexchange.com/";
}
static function install( $template ) {
self::add_show_endpoint();
flush_rewrite_rules();
}
static function uninstall( $template ) {
flush_rewrite_rules();
}
}