Отображение одного типа записей на двух разных шаблонах single
У меня есть клиент, который хочет отображать планы домов (custom post type) на своем сайте в двух разных разделах с разным оформлением, в зависимости от того, с какой страницы списка был осуществлен переход к записи. Я нашел это решение от @gmazzap нескольких летней давности, и оно выглядит перспективным, но у меня не получается заставить его работать: Несколько шаблонов для custom post type
Конкретно, не удается модифицировать URL на альтернативной странице списка: он просто использует slug, указанный при регистрации CPT:
'rewrite' => array( 'slug' => 'plan', 'with_front' => false ),
Это означает, что когда я кликаю на ссылку плана в шаблоне 'page_kioskoverview.php', запись отображается на стандартном шаблоне 'single-plans.php', а не на альтернативном 'single-kioskplans.php'.
Вот как выглядит мой код:
add_action('template_redirect', 'change_plans_plink');
function change_plans_plink() {
if (is_page_template('page_kioskoverview.php')) {
add_filter( 'post_link', 'plans_query_string', 10, 2 );
}
}
function plans_query_string( $url, $post ) {
if ( $post->post_type === 'plans' ) {
$url = add_query_arg( array('style'=>'alt'), $url );
}
return $url;
}
// Назначаем альтернативный single-шаблон для ссылки с параметром alt
add_action('template_include', 'kiosk_plan_single');
function kiosk_plan_single($template) {
if( is_singular('plans') ) {
$alt = filter_input(INPUT_GET, 'style', FILTER_SANITIZE_STRING);
if ( $alt === 'alt' ) $template = 'single-kioskplans.php';
}
return $template;
}
После нескольких дней изучения (и попыток различных вариаций без успеха), я не могу обнаружить проблему, но должно быть что-то упускаю.

Для отображения разных шаблонов для одного типа записи я бы создал 2 разные ссылки, проверял, на какой ссылке я нахожусь, и выбирал, какой шаблон загружать.
Рабочий пример:
/**
* Регистрация типа записи "Событие"
*
* Регистрация типа записи "Событие" добавит такую структуру постоянных ссылок: event/([^/]+)/?$
*/
function wpse_288345_register_event_post_type() {
$labels = array(
'name' => __( 'События' ),
'singular_name' => __( 'Событие' ),
'add_new' => __( 'Добавить новое' ),
'add_new_item' => __( 'Добавить новое' ),
'edit_item' => __( 'Редактировать' ),
'new_item' => __( 'Новое' ),
'view_item' => __( 'Просмотреть' ),
'search_items' => __( 'Поиск' ),
'not_found' => __( 'Не найдено' ),
'not_found_in_trash' => __( 'События не найдены в корзине' ),
'parent_item_colon' => __( 'Родительский' ),
'menu_name' => __( 'События' ),
);
$args = array(
'labels' => $labels,
'hierarchical' => false,
'supports' => array( 'title', 'page-attributes' ),
'taxonomies' => array(),
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => false,
'publicly_queryable' => true,
'exclude_from_search' => false,
'has_archive' => true,
'query_var' => true,
'can_export' => true,
'rewrite' => array('slug' => 'event'),
'capability_type' => 'post',
);
register_post_type( 'event', $args );
}
add_action( 'init', 'wpse_288345_register_event_post_type' );
/**
* Добавление пользовательских правил перезаписи для типа записи "Событие".
*
* Не забудьте сбросить правила перезаписи для применения изменений.
*/
function wpse_288345_add_event_rewrite_rules() {
/**
* Пользовательские правила перезаписи для одного типа записи.
*
* Мы будем знать, на каком URL находимся, по параметрам $_GET 'performers' и 'summary', которые мы добавим в
* публичные переменные запроса для удобного доступа.
*/
add_rewrite_rule('event/performers/([^/]+)/?$', 'index.php?post_type=event&name=$matches[1]&performers=1', 'top');
add_rewrite_rule('event/summary/([^/]+)/?$', 'index.php?post_type=event&name=$matches[1]&summary=1', 'top');
}
add_action('init', 'wpse_288345_add_event_rewrite_rules');
/**
* Добавление пользовательских переменных запроса 'performers' и 'summary' для событий.
*/
function wpse_288345_register_event_query_vars( $vars ) {
$vars[] = 'performers';
$vars[] = 'summary';
return $vars;
}
add_filter( 'query_vars', 'wpse_288345_register_event_query_vars' );
/**
* Определение, какой шаблон загружать
*/
function wpse_288345_load_performers_or_summary_template( $template ) {
// Получение публичных переменных запроса
$performers = (int) get_query_var( 'performers', 0 );
$summary = (int) get_query_var( 'summary', 0 );
// Если performer = 1, значит мы на ссылке event/performers
if( $performers === 1 ) {
$template = locate_template( array( 'single-event-performers.php' ) );
}
// Если summary = 1, значит мы на ссылке event/summary
if( $summary === 1 ) {
$template = locate_template( array( 'single-event-summary.php' ) );
}
if($template == '') {
throw new \Exception('Шаблон не найден');
}
return $template;
}
add_filter( 'template_include', 'wpse_288345_load_performers_or_summary_template' );

Вот альтернативный подход, который у меня сработал, с использованием GET-параметра и условных операторов.
На странице альтернативного списка я добавил '?template=kiosk' к постоянным ссылкам.
В шаблоне для одиночных записей (single-plans.php) я добавил следующее в начале шаблона (и, конечно, 'endif' в конце шаблона):
$kiosk = $_GET['template']; if(isset($kiosk)) :
Затем, в шаблоне я создал условные операторы в зависимости от наличия параметра, чтобы отображать контент соответствующим образом:
if(isset($kiosk)) { // показать версию для киоска } else { // показать стандартную версию }

Я тоже пробовал почти такой же код, и он не работал. Нужно внести всего одно изменение, чтобы всё заработало. Просто добавьте locate_template
в одну строку.
Замените
if ( $alt === 'alt' ) $template = 'single-kioskplans.php';
на
if ( $alt === 'alt' ) $template = locate_template('single-kioskplans.php');
Полный код будет выглядеть так:
add_action('template_redirect', 'change_plans_plink');
function change_plans_plink() {
if (is_page_template('page_kioskoverview.php')) {
add_filter( 'post_link', 'plans_query_string', 10, 2 );
}
}
function plans_query_string( $url, $post ) {
if ( $post->post_type === 'plans' ) {
$url = add_query_arg( array('style'=>'alt'), $url );
}
return $url;
}
//назначение альтернативного шаблона single для ссылки с alt
add_action('template_include', 'kiosk_plan_single');
function kiosk_plan_single($template) {
if( is_singular('plans') ) {
$alt = filter_input(INPUT_GET, 'style', FILTER_SANITIZE_STRING);
if ( $alt === 'alt' ) $template = locate_template('single-kioskplans.php');
}
return $template;
}
