Пользовательская таксономия и Tax_Query

5 февр. 2013 г., 17:10:37
Просмотры: 31.1K
Голосов: 7

У меня возникли большие проблемы с запуском 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" работает нормально, поэтому похоже, что проблема связана с моей пользовательской таксономией или типом записи. Чтобы сэкономить место в этом посте, мой код пользовательского типа записи находится здесь:

http://pastebin.com/LxKt2pv5

а мой код пользовательской таксономии здесь:

http://pastebin.com/NxuuxKuG

Я пробовал включать 'include_children' => false, как было предложено, но безуспешно.

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

2
Комментарии

0=1, скорее всего, означает, что ничего не найдено, соответствующего вашей таксономии и терминам. Проверьте написание таксономии в базе данных.

Otto Otto
6 февр. 2013 г. 04:19:30

Спасибо, Отто. Как бы мне ни хотелось, чтобы это была простая ошибка вроде этой, я уже несколько раз перепроверял таксономию и термины. До сих пор в недоумении. В базе данных всё выглядит нормально - как я уже упоминал, это не работает даже когда я использую ID вместо слагов.

Pete Gale Pete Gale
6 февр. 2013 г. 12:57:51
Все ответы на вопрос 1
11

Прежде всего, вы запускаете 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
18 февр. 2013 г. 18:42:46
Комментарии

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

Pete Gale Pete Gale
18 февр. 2013 г. 20:55:55

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

Pete Gale Pete Gale
18 февр. 2013 г. 20:59:26

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

Tom Tom
18 февр. 2013 г. 21:28:00

Спасибо :) У меня выводится:

`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`

Pete Gale Pete Gale
18 февр. 2013 г. 21:37:57

Мне удалось успешно выполнить запрос с помощью 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.

Simon Simon
18 февр. 2013 г. 21:45:01

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

Pete Gale Pete Gale
18 февр. 2013 г. 22:04:37

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

Pete Gale Pete Gale
18 февр. 2013 г. 22:05:38

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

Simon Simon
18 февр. 2013 г. 22:06:50

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

Simon Simon
18 февр. 2013 г. 22:12:14

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

Pete Gale Pete Gale
18 февр. 2013 г. 22:35:27

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

Simon Simon
18 февр. 2013 г. 23:51:19
Показать остальные 6 комментариев