Проверка отображения страницы архива пользовательской таксономии
У меня есть пользовательский тип записи '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: "Проверяет, содержит ли текущая запись любые из указанных терминов", так что это будет работать только на одиночных записях?

Это работает на одиночных страницах, в чем проблема. Не работает — это слишком общее описание

Я имею в виду, что страница 'example.com/advert-category/services/' не меняет шаблон.

В вашей функции есть две проблемы:
- Вы пропускаете аргумент в фильтре "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' );

Я исправил некоторые ошибки в своём старом коде (это был тестовый вариант, извините, видимо, я ещё не проснулся). И я протестировал вашу функцию, но она не работает для страниц пользовательских таксономий, только для одиночных записей. И я нашёл решение (см. обновление).
