15%

Збережіть 15% на всі хостинг-послуги

Перевірте свої навички і отримайте Знижку на будь-який план хостингу

Використовуй код:

Skills
Почати
21.10.2024

Що таке Tax Query у WordPress? Повний посібник розробника

A tax query у WordPress — це структурований фільтр, що передається до WP_Query, який отримує публікації, що відповідають певним термінам таксономії. Замість того щоб витягувати кожну публікацію з бази даних, tax query звужує результуючий набір лише до тих записів, чиї термінові зв’язки задовольняють визначені умови — будь то один слаг категорії, комбінація термінів власної таксономії або складний шаблон виключення кількох таксономій.

На практиці: якщо вам потрібно відображати лише публікації з тегом «web-development», які також належать до власної таксономії «project-type» з терміном «client-work», tax query — це правильний та продуктивний інструмент для цього завдання. Він працює на рівні SQL через клас WP_Tax_Query WordPress, генеруючи оптимізовані клаузи JOIN та WHERE для таблиць wp_term_relationships та wp_term_taxonomy.

Як структуровані таксономії та терміни WordPress

Перш ніж написати хоч рядок коду запиту, вам потрібна чітка уявна модель базової архітектури даних.

Таксономії — це системи класифікації. WordPress постачається з двома глобальними таксономіями — category та post_tag — але функція register_taxonomy() дозволяє визначати необмежену кількість власних. Таксономія — це по суті іменований механізм групування.

Терміни — це окремі мітки в межах таксономії. У таксономії category «Technology», «Lifestyle» та «Business» є термінами. Кожен термін має три адресовані ідентифікатори:

  • term_id — цілочисельний первинний ключ у wp_terms
  • slug — URL-безпечний рядковий ідентифікатор (наприклад, web-development)
    name — зрозуміла людині мітка для відображення
    
    Термінові зв’язки — це зведені записи в wp_term_relationships, що пов’язують ID об’єкта публікації з ID таксономії терміна. Кожен tax query зрештою зводиться до пошуку в цій таблиці.
    Розуміння цієї трирівневої структури — таксономія > термін > терміновий зв’язок — є необхідним для написання ефективних запитів та діагностики неочікуваних результуючих наборів.
    Основні аргументи параметра tax_query
    Ключ tax_query приймає масив з одного або кількох масивів клауз запиту, а також необов’язковий ключ relation верхнього рівня. Кожна клауза підтримує такі аргументи:
    
    
    
    Аргумент
    Тип
    Опис
    Поширені значення
    
    
    
    
    
    
    
    
    —
    —
    —
    —
    
    
    
    
    
    
    
    
    `taxonomy`
    string
    Таксономія для запиту
    `category`, `post_tag`, власний слаг
    
    
    
    
    
    
    
    
    `field`
    string
    Яке поле терміна зіставляти
    `slug`, `name`, `term_id`, `term_taxonomy_id`
    
    
    
    
    
    
    
    
    `terms`
    string / int / array
    Значення терміна для зіставлення
    `'technology'`, `[4, 7]`, `'web-dev'`
    
    
    
    
    
    
    
    
    `operator`
    string
    Як застосовувати зіставлення терміна
    `IN`, `NOT IN`, `AND`, `EXISTS`, `NOT EXISTS`
    
    
    
    
    
    
    
    
    `include_children`
    bool
    Чи включати дочірні терміни (лише для ієрархічних таксономій)
    `true` (за замовчуванням), `false`
    
    
    
    
    
    
    
    
    `relation`
    string
    Логічний з’єднувач верхнього рівня між кількома клаузами
    `AND`, `OR`
    
    
    
    
    
    Аргумент operator детально
    Саме тут більшість розробників припускаються помилок. Оператори поводяться таким чином:
    
    IN (за замовчуванням) — повертає публікації, призначені до *будь-якого* із зазначених термінів. Це збіг OR у межах однієї клаузи.
    NOT IN — виключає публікації, призначені до будь-якого із зазначених термінів.
    AND — повертає публікації, призначені до *всіх* зазначених термінів одночасно. Використовуйте це, коли публікація повинна мати кілька тегів одночасно.
    EXISTS — повертає публікації, що мають *будь-який* термін у зазначеній таксономії, незалежно від того, який саме. Аргумент terms ігнорується.
    NOT EXISTS — повертає публікації без призначення терміна у зазначеній таксономії. Корисно для пошуку контенту без категорій або тегів.
    
    Важливий нюанс: operator => 'AND' в межах однієї клаузи перевіряє, що одна публікація призначена до кожного терміна в масиві terms. Це відрізняється від використання relation => 'AND' на верхньому рівні, який об’єднує окремі клаузи. Змішування цих двох понять є однією з найпоширеніших помилок tax query у виробничому коді WordPress.
    Базовий Tax Query: фільтр за однією таксономією
    Найпростіший випадок використання — отримати всі публікації в категорії «Technology»:
    $args = array(
        'post_type'  => 'post',
        'tax_query'  => array(
            array(
                'taxonomy' => 'category',
                'field'    => 'slug',
                'terms'    => 'technology',
            ),
        ),
    );
    
    $query = new WP_Query( $args );
    
    if ( $query->have_posts() ) {
        while ( $query->have_posts() ) {
            $query->the_post();
            // Render post content here
        }
        wp_reset_postdata();
    }
    Завжди викликайте wp_reset_postdata() після власного циклу WP_Query. Невиконання цього пошкоджує глобальний об’єкт $post, що порушує роботу тегів шаблону, таких як the_title() та get_the_ID(), для будь-яких наступних запитів на тій самій сторінці.
    Поєднання кількох Tax Query за допомогою relation
    Ключ relation на верхньому рівні масиву tax_query контролює, як об’єднуються кілька клауз:
    $args = array(
        'post_type'  => 'post',
        'tax_query'  => array(
            'relation' => 'AND',
            array(
                'taxonomy' => 'category',
                'field'    => 'slug',
                'terms'    => 'technology',
            ),
            array(
                'taxonomy' => 'post_tag',
                'field'    => 'slug',
                'terms'    => 'web-development',
            ),
        ),
    );
    Це повертає лише публікації, які *одночасно* знаходяться в категорії «Technology» та мають тег «web-development». Змініть relation на 'OR' — і ви отримаєте публікації, що відповідають будь-якій з умов.
    Вкладені Tax Query (WordPress 4.1+)
    Для розширеної логіки фільтрації WordPress підтримує вкладені масиви tax_query, що дозволяє будувати складені булеві вирази:
    $args = array(
        'post_type'  => 'product',
        'tax_query'  => array(
            'relation' => 'AND',
            array(
                'taxonomy' => 'product_cat',
                'field'    => 'slug',
                'terms'    => array( 'laptops', 'desktops' ),
                'operator' => 'IN',
            ),
            array(
                'relation' => 'OR',
                array(
                    'taxonomy' => 'product_tag',
                    'field'    => 'slug',
                    'terms'    => 'sale',
                ),
                array(
                    'taxonomy' => 'availability',
                    'field'    => 'slug',
                    'terms'    => 'in-stock',
                ),
            ),
        ),
    );
    Це отримує продукти в категоріях «Laptops» або «Desktops», які *також* або розпродаються, або є в наявності. Такий вид вкладеної логіки неможливо чисто відтворити за допомогою плаского ключа relation — вкладені масиви є єдиним правильним підходом.
    Власні типи публікацій та власні таксономії
    Tax query стають особливо потужними в поєднанні з власними типами публікацій, зареєстрованими через register_post_type(), та власними таксономіями через register_taxonomy(). Розглянемо сайт-портфоліо, де ви реєструєте тип публікації portfolio та таксономію portfolio_type:
    // Register custom taxonomy (typically in functions.php or a plugin)
    register_taxonomy(
        'portfolio_type',
        'portfolio',
        array(
            'label'        => 'Portfolio Types',
            'hierarchical' => true,
        )
    );
    
    // Query portfolio items of type "branding"
    $args = array(
        'post_type'  => 'portfolio',
        'tax_query'  => array(
            array(
                'taxonomy' => 'portfolio_type',
                'field'    => 'slug',
                'terms'    => 'branding',
            ),
        ),
    );
    
    $query = new WP_Query( $args );
    Коли hierarchical має значення true і include_children явно не встановлено в false, запит автоматично включає всі дочірні терміни «branding». Це правильна поведінка для ієрархій типу категорій, але вона може давати неочікувані результати, якщо у вас є глибоко вкладені дерева термінів. Встановіть 'include_children' => false, коли вам потрібне зіставлення лише точного терміна.
    Використання term_id проти slug проти name як значення field
    
    
    
    Значення поля
    Використовувати коли
    Застереження
    
    
    
    
    
    
    
    
    —
    —
    —
    
    
    
    
    
    
    
    
    `slug`
    Жорстко закодовані запити в коді теми/плагіна
    Слаги можуть бути змінені редакторами в адмін-панелі
    
    
    
    
    
    
    
    
    `term_id`
    Критичні для продуктивності або програмні запити
    ID відрізняються між середовищами (розробка проти виробництва)
    
    
    
    
    
    
    
    
    `name`
    Зрозуміла людині логіка рівня відображення
    Чутливий до регістру; ненадійний, якщо назви редагуються
    
    
    
    
    
    
    
    
    `term_taxonomy_id`
    Усунення неоднозначності між кількома таксономіями
    Рідко потрібен; використовуйте лише коли ID термінів збігаються між таксономіями
    
    
    
    
    
    Для виробничого коду slug зазвичай є найбезпечнішим вибором для читабельності. Однак якщо ви переносите бази даних між тестовим та робочим середовищем, майте на увазі, що значення term_id відрізнятимуться. Завжди використовуйте slug для переносного коду.
    Міркування щодо продуктивності та поширені підводні камені
    Вплив на базу даних
    Кожен tax query генерує щонайменше один додатковий JOIN до wp_term_relationships. При наявності кількох клауз це накопичується. На сайтах з десятками тисяч публікацій погано побудовані tax query є основною причиною повільного завантаження сторінок та тайм-аутів бази даних.
    Ключові оптимізації:
    
    Використовуйте fields => 'ids', коли вам потрібні лише ID публікацій, а не повні об’єкти публікацій. Це дозволяє уникнути завантаження метаданих публікацій та серіалізованих даних.
    Кешуйте результати за допомогою Transients API. Tax query на сторінках архівів, що рідко змінюються, слід кешувати за допомогою set_transient() та get_transient().
    Уникайте operator => 'AND' з великими масивами термінів. Кожен додатковий термін у клаузі AND додає підзапит. Виконайте бенчмарк за допомогою EXPLAIN у MySQL перед розгортанням.
    Встановіть no_found_rows => true, коли вам не потрібна пагінація. Це пропускає накладні витрати SQL_CALC_FOUND_ROWS.
    
    $args = array(
        'post_type'      => 'post',
        'fields'         => 'ids',
        'no_found_rows'  => true,
        'tax_query'      => array(
            array(
                'taxonomy' => 'category',
                'field'    => 'slug',
                'terms'    => 'technology',
            ),
        ),
    );
    Пастка wp_reset_postdata()
    Якщо ви запускаєте вторинний WP_Query всередині основного циклу без скидання даних публікації, глобальна змінна $post вказуватиме на неправильну публікацію для решти рендерингу сторінки. Це спричиняє непомітні помилки: неправильні заголовки публікацій у хлібних крихтах, неправильні канонічні URL та зламані теги Open Graph. Завжди скидайте.
    Запит термінів, яких не існує
    Якщо ви передаєте значення terms, якого не існує в базі даних, WP_Query мовчки повертає нуль результатів. Жодної помилки чи попередження немає. Завжди перевіряйте існування терміна за допомогою term_exists() перед побудовою динамічних tax query на основі введення користувача або зовнішніх даних.
    $term = term_exists( 'technology', 'category' );
    if ( $term !== 0 && $term !== null ) {
        // Safe to build the tax query
    }
    Реальні випадки використання
    Власні сторінки архівів
    Перевизначте archive.php або використовуйте pre_get_posts для впровадження tax query в основний запит, фільтруючи архів для відображення лише певних термінів без створення окремого об’єкта запиту:
    add_action( 'pre_get_posts', function( $query ) {
        if ( ! is_admin() && $query->is_main_query() && is_post_type_archive( 'portfolio' ) ) {
            $query->set( 'tax_query', array(
                array(
                    'taxonomy' => 'portfolio_type',
                    'field'    => 'slug',
                    'terms'    => array( 'branding', 'web-design' ),
                    'operator' => 'IN',
                ),
            ) );
        }
    } );
    Використання pre_get_posts є ефективнішим, ніж створення вторинного WP_Query, оскільки воно модифікує основний запит до звернення до бази даних.
    Фільтрація товарів електронної комерції
    WooCommerce реєструє product_cat та product_tag як стандартні таксономії WordPress, а також таксономії атрибутів, такі як pa_color та pa_size. Tax query забезпечують роботу бічної панелі фільтра багатошарової навігації. Власний фільтр для «червоних ноутбуків певного бренду» поєднував би три окремі клаузи таксономії з relation => 'AND'.
    Редакційне виключення контенту
    Використовуйте operator => 'NOT IN' для приховування спонсорованого або рекламного контенту з редакційних стрічок:
    $args = array(
        'post_type'  => 'post',
        'tax_query'  => array(
            array(
                'taxonomy' => 'post_tag',
                'field'    => 'slug',
                'terms'    => array( 'sponsored', 'promoted' ),
                'operator' => 'NOT IN',
            ),
        ),
    );
    Пошук некласифікованого контенту
    Використовуйте operator => 'NOT EXISTS' для аудиту бібліотеки контенту на предмет публікацій, яким бракує обов’язкових призначень таксономії:
    $args = array(
        'post_type'  => 'post',
        'tax_query'  => array(
            array(
                'taxonomy' => 'category',
                'operator' => 'NOT EXISTS',
            ),
        ),
    );
    Це безцінно для аудиту контенту на великих редакційних сайтах, де публікації могли бути імпортовані без належного призначення таксономії.
    Tax Query проти Meta Query: вибір правильного інструменту
    Поширеним архітектурним рішенням у розробці WordPress є питання, чи зберігати дані фільтрації як термін таксономії або як метадані публікації. Цей вибір має значні наслідки для продуктивності.
    
    
    
    Критерій
    Tax Query (`tax_query`)
    Meta Query (`meta_query`)
    
    
    
    
    
    
    
    
    —
    —
    —
    
    
    
    
    
    
    
    
    Таблиця бази даних
    `wp_term_relationships` (індексована)
    `wp_postmeta` (менш оптимізована для фільтрації)
    
    
    
    
    
    
    
    
    Продуктивність запитів
    Швидка — розроблена для пошуку на основі множин
    Повільніша при масштабуванні — структура EAV
    
    
    
    
    
    
    
    
    Фасетна фільтрація
    Нативна, ефективна
    Потребує обхідних рішень
    
    
    
    
    
    
    
    
    Тип даних
    Контрольований словник (терміни)
    Довільні пари ключ-значення
    
    
    
    
    
    
    
    
    Випадок використання
    Категоризація, класифікація
    Атрибути, вимірювання, прапорці
    
    
    
    
    
    
    
    
    Індексування
    Автоматичне через ID таксономії термінів
    Потребує ручного налаштування індексів
    
    
    
    
    
    Практичне правило: якщо дані використовуються для фільтрації або навігації (колір, категорія, тип, статус), використовуйте таксономію. Якщо це унікальний атрибут для кожної публікації (ціна, вага, мітка часу публікації), використовуйте метадані публікації. Змішування цих підходів є однією з найпоширеніших причин повільних сайтів WordPress при масштабуванні.
    Міркування щодо хостингу для сайтів WordPress, що використовують складні запити
    Tax query з кількома клаузами, вкладеною логікою або великими наборами термінів генерують складний SQL. Продуктивність цих запитів значною мірою залежить від вашого серверного середовища.
    На плані VPS Хостинг у вас є прямий контроль над конфігурацією MySQL — ви можете налаштувати innodb_buffer_pool_size, увімкнути кеш запитів (MySQL 5.7 та раніше) та додати власні індекси до wp_term_relationships за потреби. Спільні середовища зазвичай не дозволяють такого рівня налаштування бази даних.
    Якщо ви керуєте високонавантаженим магазином WooCommerce з багатошаровою навігацією на основі tax query, Виділений сервер надає вам ізольований I/O бази даних, що усуває проблему «галасливого сусіда», яка погіршує час відповіді запитів на спільній інфраструктурі.
    Для розробників, які хочуть зручності панелі керування при збереженні доступу на рівні сервера для оптимізації бази даних, VPS з cPanel забезпечує практичний середній варіант — повний доступ до MySQL через phpMyAdmin поряд зі звичним інтерфейсом управління.
    Сайти, що значною мірою покладаються на кінцеві точки WordPress REST API, підкріплені tax query, також повинні розглянути об’єктне кешування (Redis або Memcached) на рівні сервера, яке можна налаштувати на Панелях керування VPS, що підтримують власні шари кешування PHP та на стороні сервера.
    Матриця рішень та технічний контрольний список
    Перш ніж розгортати tax query у виробництві, перевірте наступне:
    
    Існування терміна перевірено — використовуйте term_exists() для будь-яких динамічно побудованих значень термінів
    wp_reset_postdata() викликано — після кожного власного циклу WP_Query, без винятків
    include_children явно встановлено — не покладайтеся на значення за замовчуванням для ієрархічних таксономій, якщо включення дочірніх елементів не є навмисним
    fields => 'ids' використовується — скрізь, де повні об’єкти публікацій не потрібні
    no_found_rows => true встановлено — для будь-якого запиту, що не потребує пагінації
    Результати кешовано — використовуйте Transients API для запитів на сторінках архівів або цільових сторінках з високим трафіком
    pre_get_posts надається перевага — над вторинними екземплярами WP_Query для модифікацій основного запиту
    Вибір operator підтверджено — розрізняйте IN (будь-який термін), AND (всі терміни) та NOT IN (виключення) перед написанням клаузи
    Різниця між relation та operator зрозуміла — relation з’єднує клаузи; operator контролює зіставлення в межах клаузи
    Вкладені масиви використовуються для складеної логіки — не намагайтеся виражати комбінації AND/OR лише за допомогою плаского ключа relation
  • Запит до бази даних зареєстровано та перевірено — використовуйте плагін Query Monitor або SAVEQUERIES для перевірки згенерованого SQL перед запуском

FAQ

У чому різниця між relation => 'AND' та operator => 'AND' у tax query?

relation — це ключ верхнього рівня, що з’єднує кілька клауз tax query між собою — він визначає, чи повинна публікація задовольняти всі клаузи (AND) або хоча б одну (OR). operator — це ключ для кожної клаузи, що визначає, як масив terms зіставляється в межах однієї клаузи — AND вимагає, щоб публікація мала кожен перелічений термін, призначений одночасно.

Чому мій tax query повертає нуль результатів, хоча публікації та терміни існують?

Найпоширеніші причини: передача значення terms, що не відповідає зазначеному типу field (наприклад, передача назви, коли field встановлено в slug), запит таксономії, не зареєстрованої для типу публікації, або використання operator => 'AND' з термінами, яких жодна окрема публікація не має одночасно. Увімкніть SAVEQUERIES та перевірте необроблений SQL для діагностики.

Чи можна використовувати tax query всередині WordPress REST API?

Так. WP_REST_Posts_Controller REST API приймає tax_query опосередковано через зареєстровані параметри запиту. Для власних таксономій вам потрібно встановити 'show_in_rest' => true при реєстрації таксономії. Для складних багатоклаузних запитів використовуйте власну кінцеву точку REST, яка будує аргументи WP_Query на стороні сервера.

Чи впливає include_children => true на продуктивність?

Так. Коли include_children увімкнено (за замовчуванням для ієрархічних таксономій), WordPress виконує додатковий запит для отримання всіх ID дочірніх термінів перед побудовою основного запиту. На таксономіях з глибокими ієрархіями та багатьма термінами цей попередній запит додає відчутні накладні витрати. Встановіть 'include_children' => false, коли вам потрібне зіставлення точного терміна і не потрібне успадкування дочірніх термінів.

Чи є обмеження на кількість клауз у tax query?

У ядрі WordPress немає жорстко закодованого обмеження, але практичні обмеження накладаються максимальною глибиною з’єднань MySQL та порогами складності запитів. Більше чотирьох-п’яти клауз в одному tax query є сигналом того, що модель даних може потребувати перегляду — або через денормалізацію, виділений пошуковий індекс (Elasticsearch, Typesense), або реструктуризацію ієрархії таксономії для зменшення кількості клауз.

15%

Збережіть 15% на всі хостинг-послуги

Перевірте свої навички і отримайте Знижку на будь-який план хостингу

Використовуй код:

Skills
Почати