Пользовательская таксономия и Tax_Query
У меня возникли большие проблемы с запуском WP_Query
с использованием tax_query
для моей пользовательской таксономии.
Я на 99.9% уверен, что мой register_taxonomy
правильный, так как я могу помечать записи нужным термином, вижу его в базе данных, и правильный термин возвращается с помощью этой функции: http://pastebin.com/18Aj1ysT.
Но когда я использую tax_query
в моем WP_Query
, я не получаю никаких записей. Мой запрос:
$nextSundayTalkArgs = array(
'post_type' => 'talk',
'posts_per_page' => 1,
'tax_query' => array(
array(
'taxonomy' => 'talktype',
'field' => 'slug',
'terms' => 'sunday-talk'
)
)
);
$nextSundayTalkQuery = new WP_Query( $nextSundayTalkArgs );
Он отлично работает без 'tax_query'. Если я использую что-то вроде 'talktype' => 'sunday-talk' вместо этого, используя query_var при регистрации таксономии, он просто игнорирует эту строку, как будто её нет, и выводит любую беседу (вместо того, чтобы показать "нет записей").
Вставка <?php echo $GLOBALS['nextSundayTalkQuery']->request; ?>
дает мне следующее:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts WHERE 1=1
AND 0 = 1
AND wp_posts.post_type = 'talk'
AND (
wp_posts.post_status = 'publish'
OR wp_posts.post_author = 1
AND wp_posts.post_status = 'private'
)
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 1
Использование идентичного кода для запроса к стандартной таксономии WordPress "category" работает нормально, поэтому похоже, что проблема связана с моей пользовательской таксономией или типом записи. Чтобы сэкономить место в этом посте, мой код пользовательского типа записи находится здесь:
а мой код пользовательской таксономии здесь:
Я пробовал включать 'include_children' => false
, как было предложено, но безуспешно.
Я буду благодарен за любую помощь, так как эта проблема остается нерешенной в течение месяцев, и многие люди пытались (к сожалению, безуспешно) выяснить, в чем проблема.
Прежде всего, вы запускаете register_post_type
на хуке init
, а register_taxonomy
на after_setup_theme
, который вызывается после init
. Это означает, что ваша пользовательская таксономия не будет доступна при регистрации типа записи. Я рекомендую убрать ключевое слово taxonomies
из массива аргументов register_post_type
и просто зарегистрировать таксономию вручную позже. В вашем примере кода похоже, что связь между типом записи и таксономией создаётся дважды.
Также я не уверен насчёт 'query_var' => true,
в массиве аргументов register_taxonomy
. Документация говорит, что можно установить значение false
или строку, но не уточняет, что произойдёт при установке true
. Надеюсь, WordPress достаточно умен, чтобы подставить что-то более полезное, но раз вы явно не указываете значение, отличное от имени таксономии, просто удалите этот параметр (это означает, что будет использоваться talktype
).
Я добавил это в пустую тему, и всё работает корректно (то есть выводится SQL-запрос, включая мета-запрос). Фактическое выполнение запроса тоже работает без проблем:
functions.php
// Добавляем типы записей "Talk" и "Event"
function nc_custom_post_types() {
register_post_type( 'talk',
array(
'labels' => array(
'name' => __( 'Talks' ),
'singular_name' => __( 'Talk' )
),
'public' => true,
'has_archive' => true,
)
);
// Добавляем таксономию "talktype" для типа записи "talk"
register_taxonomy('talktype', 'talk', array(
'hierarchical' => true,
// Этот массив управляет метками в админке WordPress
'labels' => array(
'name' => _x( 'Talk Types', 'taxonomy general name' ),
'singular_name' => _x( 'Talk Type', 'taxonomy singular name' ),
'search_items' => __( 'Search Talk Types' ),
'all_items' => __( 'All Talk Types' ),
'parent_item' => __( 'Parent Talk Type' ),
'parent_item_colon' => __( 'Parent Talk Type:' ),
'edit_item' => __( 'Edit Talk Type' ),
'update_item' => __( 'Update Talk Type' ),
'add_new_item' => __( 'Add New Talk Type' ),
'new_item_name' => __( 'New Talk Type Name' ),
'menu_name' => __( 'Talk Types' ),
),
// Управление ЧПУ для таксономии
'rewrite' => array(
'slug' => 'talktype',
'with_front' => false, // Не отображать базу категории перед "/locations/"
'hierarchical' => true // Разрешить URL вида "/locations/boston/cambridge/"
),
));
}
add_action( 'init', 'nc_custom_post_types' );
/* Для тестирования
add_action('wp', 'test');
function test() {
$nextSundayTalkArgs = array(
'post_type' => 'talk',
'posts_per_page' => 1,
'tax_query' => array(
array(
'taxonomy' => 'talktype',
'field' => 'slug',
'terms' => 'sunday-talk'
)
)
);
$nextSundayTalkQuery = new WP_Query( $nextSundayTalkArgs );
var_dump($nextSundayTalkQuery->request);
die();
}
*/
function sunday_query_args() {
$nextSundayTalkArgs = array(
'post_type' => 'talk',
'posts_per_page' => 1,
'tax_query' => array(
array(
'taxonomy' => 'talktype',
'field' => 'slug',
'terms' => 'sunday-talk'
)
)
);
return $nextSundayTalkArgs;
}
index.php
<?php get_header(); ?>
<?php query_posts(sunday_query_args()); ?>
<div id="content">
<?php while ( have_posts() ) : the_post(); ?>
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
<h1 class="entry-title"><?php the_title(); ?></h1>
<div class="entry-content">
<?php the_content(); ?>
</div>
</article>
<?php endwhile; ?>
</div>
<?php get_sidebar(); ?>
<?php get_footer(); ?>
РЕДАКТИРОВАНИЕ: Только что попробовал запустить ваш исходный код без изменений, и он тоже работает. Насколько я могу судить, часть 0 = 1
в SQL генерируется, когда либо таксономия, либо термин не найдены, что означает невозможность создания INNER JOIN
. Убедитесь, что термин есть в вашей базе данных и что он отображается в интерфейсе редактирования вашего типа записи.
Я знаю, что вы уже проверяли содержимое базы данных, но если проблема сохраняется, попробуйте ещё раз локализовать её. Начните с чистой установки WordPress, добавьте только приведённый выше код, создайте запись типа talk
и назначьте ей термин sunday-talk
. У меня это работает. Также попробуйте выполнить SQL-запрос вручную — если он не сработает, это точно указывает на отсутствие связи между записью и термином. SQL-запрос должен выглядеть примерно так (не забудьте изменить значение wp_term_relationships.term_taxonomy_id
):
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (4) ) AND wp_posts.post_type = 'talk' AND (wp_posts.post_status = 'publish') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1

Привет, Саймон, большое спасибо за помощь. Дела идут на лад - var_dump($nextSundayTalkQuery->request);
возвращает "здоровый" запрос, когда я пробую код, оформленный так, как у тебя. Это сначала наводит на мысль, что проблема была в том, как я вызывал функции register_post_type
и register_taxonomy
. Теперь, когда это работает, похоже, есть проблема с циклом записей, так как страница теперь падает на этом моменте. if ( $nextSundayTalkQuery->have_posts() ) : while ( $nextSundayTalkQuery->have_posts() ) : $nextSundayTalkQuery->the_post();
- вот что я использую.

Не уверен, что с этим не так - раньше не подозревал это как проблему, потому что без tax_query всё работает нормально.

@PeteG Когда ты говоришь "падает", ты имеешь в виду, что страница не отображается? Можешь включить http://codex.wordpress.org/WP_DEBUG и вставить сообщение об ошибке :)

Спасибо :) У меня выводится:
`Notice: Undefined variable: nextSundayTalkQuery in index.php on line 13
Fatal error: Call to a member function have_posts() on a non-object in index.php on line 13`

Мне удалось успешно выполнить запрос с помощью while ($nextSundayTalkQuery->have_posts()) { $nextSundayTalkQuery->the_post(); the_title(); }
, заменив строку с var_dump
в моём примере. Вы держите весь код в index.php
или разделили его каким-то образом? Ошибка Undefined variable: nextSundayTalkQuery
может означать только одно - что переменная $nextSundayTalkQuery не определена. Попробуйте сделать var_dump($nextSundayTalkQuery);
чтобы посмотреть что в ней содержится. Если вы выполнили $nextSundayTalkQuery = new WP_Query( $nextSundayTalkArgs );
до этого, там должен быть объект WP_Query.

Это работает в функции (если поместить код туда, где в вашем примере находится var_dump
), но по какой-то причине не работает в моём index.php
. Таксономии / типы записей / фильтры записей находятся в functions.php
, а мой цикл в index.php
. Выполнение var_dump
в моём index.php возвращает NULL
.

Я думаю, моя проблема в том, что я ещё очень новичок в WordPress, поэтому, вероятно, неправильно структурирую свою тему. functions.php
всегда просто работал, поэтому я предположил, что WordPress вызывает его автоматически, так как он нигде не вызывается в моём index.php
(но всё остальное в нём, кажется, работает).

functions.php
будет подключён автоматически, но, возможно, ваши файлы шаблонов не могут получить доступ ко всему необходимому из-за области видимости функций. Я скоро обновлю свой ответ с решением, которое должно сработать.

Я обновил свой пример, добавив функцию под названием sunday_query_args()
, которую вы можете использовать как аргумент функции для query_posts()
(или WP_Query
, если вам это нужно).

Победа :) Огромное спасибо! Теперь мне нужно разобраться: а) что было не так с изначальной структурой моего файла functions.php
, и б) что именно делают ваши изменения :) Похоже, мне не нужен "аргумент функции" для других моих WP_Query
на той же странице, не могли бы вы немного объяснить, что он делает / зачем он мне нужен?

Замечательно! query_posts будет автоматически выполняться WordPress с использованием переменных запроса из строки запроса веб-сервера. Это означает, что на index.php он получит 10 последних записей, а на page.php — конкретную страницу. Чтение документации должно помочь вам начать работу. Также посмотрите WP_Query и get_posts и попытайтесь понять их сходства и различия.
