Проверка отображения страницы архива пользовательской таксономии
У меня есть пользовательский тип записи 'advert' и связанная с ним пользовательская таксономия 'advert_category', созданные сторонним плагином. В плагине я использую условие if, которое должно (как я ожидаю) установить определенный макет темы для отдельных объявлений (example.com/advert/a-single-advert.html) и для страниц архива пользовательской таксономии (example.com/advert-category/services/), но второе условие is_tax( 'advert_category' ) не работает. Что здесь не так?
Мой код:
function my_advert_single_template( ) {
global $post;
global $wpgo_global_column_layout;
if ( $post->post_type == 'advert' || is_tax( 'advert_category' ) ) {
$wpgo_global_column_layout = "2-col-l";
}
}
add_filter( 'single_template', 'my_advert_single_template' );
Вот как зарегистрированы пользовательский тип записи и пользовательская таксономия:
// регистрация типа записи и таксономии для возможности вставки данных по умолчанию
register_post_type( 'advert' );
register_taxonomy( 'advert_category', 'advert' );
$hid = wp_insert_post(array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => 'Объявления',
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_content' => "[adverts_list]"
));
$aid = wp_insert_post(array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => 'Добавить',
'post_parent' => $hid,
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_content' => "[adverts_add]"
));
$mid = wp_insert_post(array(
'post_type' => 'page',
'post_status' => 'publish',
'post_title' => 'Управление',
'post_parent' => $hid,
'comment_status' => 'closed',
'ping_status' => 'closed',
'post_content' => "[adverts_manage]"
));
wp_insert_term(
'По умолчанию',
'advert_category'
);
У вас здесь много проблем:
pre_get_posts— это неправильный хук для установки шаблонов.pre_get_postsиспользуется для изменения параметров основного запроса непосредственно перед тем, как SQL-запрос будет построен для выполнения основного запроса.Фильтр всегда должен что-то возвращать. Если этого не делать, это приведет к непредсказуемому поведению, а забывчивость может заставить вас часами искать ошибку.
Использование глобальных переменных для управления функциями темы или хранения данных — это плохая практика и небезопасный код. WordPress уже создал огромный беспорядок с глобальными переменными, особенно с их именованием. Просто посмотрите, как новички (не знающие WordPress) неосознанно используют переменные вроде
$postи$postsв качестве локальных. Это нативные глобальные переменные WordPress, и их использование в качестве локальных ломает их значения.Из-за этого что-то на странице работает неправильно, ошибок нет, и вы застреваете в бесконечном поиске проблемы, которую сами же и сломали. Глобальные переменные — это чистое зло, их следует избегать. Представьте: если вы используете переменную
$wpgo_global_column_layoutдля аргументов пользовательского запроса, вы сломаете значение шаблона, который нужно установить. Ваш шаблон не загрузится, потому что значение$wpgo_global_column_layoutне распознается как допустимое имя шаблона. Вы в тупике и не понимаете, почему ваш шаблон не загружается, хотя код на 100% должен это делать.is_tax()— неправильная проверка для определения, имеет ли запись определенный термин.is_tax()просто проверяет, находитесь ли вы на архиве таксономии. Вместо этого следует использоватьhas_term(), который как раз и проверяет, есть ли у записи определенный термин.Если вам нужно установить шаблон для страницы таксономии,
single_template— неправильный хук. Вместо него следует использовать хукtaxonomy_templateили более универсальный фильтрtemplate_include.В строке
$post->post_type == 'advert' || is_tax( 'advert_category' ), скорее всего, используется неверный оператор. Вместо||следует использоватьAND. Я не буду объяснять это здесь, так как уже делал это здесь. Обратите внимание, что при текущей настройке условие будет возвращатьtrueи срабатывать всякий раз, когда вы просматриваете запись типаadvert, независимо от того, выполняется ли второе условие (is_tax( 'advert_category' )).Если вам нужно определить термин по его положению в иерархии (родитель/потомок), достаточно проверить свойство
$parentобъекта термина. Значение0означает, что термин является родительским, любое другое значение указывает на дочерний/внучатый и т.д. термин.
Давайте избавимся от глобальных переменных и правильно установим шаблоны. Я не знаю, как именно ваша тема устанавливает шаблоны через $wpgo_global_column_layout, но следующий код должен работать с приоритетом. Я прокомментировал код, чтобы его было легче понять.
ДЛЯ ОДИНОЧНЫХ СТРАНИЦ:
add_filter( 'single_template', function ( $template )
{
// Удаляем все фильтры из текущего хука
remove_all_filters( current_filter(), PHP_INT_MAX );
/**
* Получаем текущий объект записи. Используем get_queried_object,
* так как это безопаснее, чем $post
*
* @see https://wordpress.stackexchange.com/q/167706/31545
*/
$current_post = get_queried_object();
// Проверяем, принадлежит ли текущая запись типу advert, если нет — выходим
if ( $current_post->post_type !== 'advert' )
return $template;
// Получаем термины записи
$terms = get_the_terms(
$current_post, // Объект текущей записи
'advert_category' // Название таксономии
);
// Если $terms пуст или возвращает объект WP_Error — выходим
if ( !$terms || is_wp_error( $terms ) )
return $template;
/**
* Берем первый термин и проверяем, является ли он родительским.
* Загружаем шаблон в зависимости от значения parent
*
* ПРИМЕЧАНИЕ: это работает корректно, только если у записи один термин
*/
if ( $terms[0]->parent == 0 ) {
$part = 'single-parent.php'; // Устанавливаем шаблон для родительских терминов
} else {
$part = 'single-child.php'; // Устанавливаем шаблон для дочерних терминов
}
// Проверяем, существует ли шаблон, если нет — выходим
$locate_template = locate_template( $part );
if ( !$locate_template )
return $template;
// Если дошли до этой точки — устанавливаем наш кастомный шаблон
return $template = $locate_template;
}, PHP_INT_MAX + 1 );
ДЛЯ СТРАНИЦ ТАКСОНОМИЙ:
add_filter( 'taxonomy_template', function ( $template )
{
// Удаляем все фильтры из текущего хука
remove_all_filters( current_filter(), PHP_INT_MAX );
// Получаем текущий объект термина. Используем get_queried_object
$current_term = get_queried_object();
// Если текущий термин не принадлежит таксономии advert_category — выходим
if ( $current_term->taxonomy !== 'advert_category' )
return $template;
// Проверяем, является ли термин родительским, и устанавливаем шаблон
if ( $current_term->parent == 0 ) {
$part = 'taxonomy-parent.php'; // Устанавливаем шаблон для родительских терминов
} else {
$part = 'taxonomy-child.php'; // Устанавливаем шаблон для дочерних терминов
}
// Проверяем, существует ли шаблон, если нет — выходим
$locate_template = locate_template( $part );
if ( !$locate_template )
return $template;
// Если дошли до этой точки — устанавливаем наш кастомный шаблон
return $template = $locate_template;
}, PHP_INT_MAX + 1 );
Одно замечание: весь код не тестировался, поэтому сначала протестируйте его локально с включенным режимом отладки. Также можете изменять и адаптировать код под свои нужды.
Не работает :(. Согласно FunctionReference/has term: "Проверяет, содержит ли текущая запись любые из указанных терминов", так что это будет работать только на одиночных записях?
Iurie
Это работает на одиночных страницах, в чем проблема. Не работает — это слишком общее описание
Pieter Goosen
Я имею в виду, что страница 'example.com/advert-category/services/' не меняет шаблон.
Iurie
В вашей функции есть две проблемы:
- Вы пропускаете аргумент в фильтре "single_template", поэтому фильтр не возвращает то, что должен.
- Также вы вызываете has_term() без указания таксономии, в которой пытаетесь выполнить поиск.
Вот исправленный вариант:
function my_advert_single_template( $single_template ) {
global $post;
global $wpgo_global_column_layout;
if ( $post->post_type == 'advert' || has_term( 'util-categorie', 'advert_category' ) ) {
$wpgo_global_column_layout = "2-col-l";
}
return $single_template;
}
add_filter( 'single_template', 'my_advert_single_template' );
Я исправил некоторые ошибки в своём старом коде (это был тестовый вариант, извините, видимо, я ещё не проснулся). И я протестировал вашу функцию, но она не работает для страниц пользовательских таксономий, только для одиночных записей. И я нашёл решение (см. обновление).
Iurie