Multiple single templates?

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();
  }

}