Какво е данъчна заявка в WordPress? Пълно ръководство за разработчици
A данъчна заявка в WordPress е структуриран филтър, предаден на WP_Query, който извлича публикации, съответстващи на конкретни таксономични термини. Вместо да извлича всяка публикация от базата данни, данъчната заявка стеснява набора от резултати само до онези записи, чиито термин-връзки отговарят на зададените от вас условия — независимо дали става дума за единичен slug на категория, комбинация от персонализирани таксономични термини или сложен модел за изключване на множество таксономии.
На практика: ако трябва да показвате само публикации, маркирани с „web-development”, които също принадлежат към персонализирана таксономия, наречена „project-type”, с термина „client-work”, данъчната заявка е правилният и ефективен инструмент за задачата. Тя работи на 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 — четимият от човека етикет за показване
Термин-връзките са pivot записите в wp_term_relationships, които свързват обектния ID на публикацията с ID на термин-таксономията. Всяка данъчна заявка в крайна сметка се разрешава до търсене в тази таблица.
Разбирането на тази трислойна структура — таксономия > термин > термин-връзка — е от съществено значение за писането на ефективни заявки и диагностицирането на неочаквани набори от резултати.
Основни аргументи на параметъра tax_query
Ключът tax_query приема масив от един или повече масиви с клаузи на заявката, плюс незадължителен ключ relation на горно ниво. Всяка клауза поддържа следните аргументи:
Аргумент
Тип
Описание
Чести стойности
—
—
—
—
`taxonomy`
string
Таксономията, спрямо която се прави заявката
`category`, `post_tag`, персонализиран slug
`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' на горно ниво, което комбинира отделни клаузи. Смесването на тези две е една от най-честите грешки при данъчните заявки в продукционния WordPress код.
Основна данъчна заявка: Филтър за единична таксономия
Най-простият случай на употреба — извличане на всички публикации в категорията „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, което нарушава template таговете като the_title() и get_the_ID() за всички последващи заявки на същата страница.
Комбиниране на множество данъчни заявки с 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' и ще получите публикации, отговарящи на което и да е от условията.
Вложени данъчни заявки (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 — вложените масиви са единственият правилен подход.
Персонализирани типове публикации и персонализирани таксономии
Данъчните заявки стават особено мощни, когато се комбинират с персонализирани типове публикации, регистрирани чрез 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`
Твърдо кодирани заявки в код на тема/плъгин
Slug-овете могат да бъдат променяни от редактори в административния панел
`term_id`
Критични за производителността или програмни заявки
ID-тата се различават между средите (dev срещу production)
`name`
Четима от човека логика на слоя за показване
Чувствително към регистъра; нестабилно ако имената се редактират
`term_taxonomy_id`
Разграничаване при множество таксономии
Рядко е необходимо; използвайте само когато ID-тата на термините се сблъскват между таксономии
За продукционен код, slug е като цяло най-безопасният избор за четимост. Въпреки това, ако мигрирате бази данни между staging и live среда, имайте предвид, че стойностите на term_id ще се различават. Винаги използвайте slug за преносим код.
Съображения за производителността и чести клопки
Въздействие върху базата данни
Всяка данъчна заявка генерира минимум едно допълнително JOIN срещу wp_term_relationships. При множество клаузи това се натрупва. На сайтове с десетки хиляди публикации, лошо конструираните данъчни заявки са водеща причина за бавно зареждане на страниците и таймаути на базата данни.
Ключови оптимизации:
Използвайте fields => 'ids', когато се нуждаете само от ID-та на публикации, а не от пълни обекти на публикации. Това избягва зареждането на post meta и сериализирани данни.
Кеширайте резултатите с Transients API. Данъчните заявки на архивни страници, които рядко се променят, трябва да бъдат кеширани с set_transient() и get_transient().
Избягвайте operator => 'AND' с големи масиви от термини. Всеки допълнителен термин в AND клауза добавя подзаявка. Направете benchmark с 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 ще сочи към грешната публикация за остатъка от рендирането на страницата. Това причинява фини грешки: грешни заглавия на публикации в breadcrumbs, неправилни канонични URL адреси и счупени Open Graph тагове. Винаги нулирайте.
Заявки за термини, които не съществуват
Ако подадете стойност на terms, която не съществува в базата данни, WP_Query връща нула резултати безшумно. Няма грешка или предупреждение. Винаги валидирайте съществуването на термина с term_exists() преди конструирането на динамични данъчни заявки, базирани на потребителски вход или външни данни.
$term = term_exists( 'technology', 'category' );
if ( $term !== 0 && $term !== null ) {
// Safe to build the tax query
}
Реални случаи на употреба
Персонализирани архивни страници
Заменете archive.php или използвайте pre_get_posts, за да инжектирате данъчна заявка в основната заявка, филтрирайки архив да показва само конкретни термини без създаване на отделен обект на заявка:
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. Данъчните заявки захранват страничната лента с филтри за многопластова навигация. Персонализиран филтър за „червени лаптопи под конкретна марка” би комбинирал три отделни клаузи на таксономии с 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',
),
),
);
Това е безценно за одити на съдържанието на големи редакционни сайтове, където публикациите може да са били импортирани без правилно таксономично присвояване.
Данъчна заявка срещу Meta заявка: Избор на правилния инструмент
Едно от честите архитектурни решения при разработката на WordPress е дали да се съхраняват данни за филтриране като таксономичен термин или като post meta. Този избор има значителни последици за производителността.
Критерий
Данъчна заявка (`tax_query`)
Meta заявка (`meta_query`)
—
—
—
Таблица в базата данни
`wp_term_relationships` (индексирана)
`wp_postmeta` (по-малко оптимизирана за филтриране)
Производителност на заявките
Бърза — проектирана за търсения, базирани на множества
По-бавна при мащаб — EAV структура
Многопластово филтриране
Нативно, ефективно
Изисква заобиколни решения
Тип данни
Контролиран речник (термини)
Произволни двойки ключ-стойност
Случай на употреба
Категоризация, класификация
Атрибути, измервания, флагове
Индексиране
Автоматично чрез ID-та на термин-таксономии
Изисква ръчно настройване на индекси
Практическо правило: ако данните се използват за филтриране или навигация (цвят, категория, тип, статус), използвайте таксономия. Ако е уникален атрибут за всяка публикация (цена, тегло, времеви печат на публикуване), използвайте post meta. Смесването на тези два подхода е една от най-честите причини за бавни WordPress сайтове при мащаб.
Съображения за хостинг при WordPress сайтове, използващи сложни заявки
Данъчните заявки с множество клаузи, вложена логика или големи набори от термини генерират сложен SQL. Производителността на тези заявки зависи силно от вашата сървърна среда.
При план за VPS Хостинг имате директен контрол върху конфигурацията на MySQL — можете да настроите innodb_buffer_pool_size, да активирате кеша на заявките (MySQL 5.7 и по-ранни) и да добавите персонализирани индекси към wp_term_relationships при необходимост. Споделените среди обикновено не позволяват такова ниво на настройка на базата данни.
Ако управлявате WooCommerce магазин с голям трафик с многопластова навигация, захранвана от данъчни заявки, Dedicated сървър ви дава изолиран I/O на базата данни, което елиминира проблема с „шумния съсед”, който влошава времето за отговор на заявките в споделена инфраструктура.
За разработчици, които искат удобството на контролен панел, като същевременно поддържат достъп на ниво сървър за оптимизация на базата данни, VPS с cPanel осигурява практична средна позиция — пълен достъп до MySQL чрез phpMyAdmin заедно с познат интерфейс за управление.
Сайтовете, които разчитат в голяма степен на WordPress REST API крайни точки, подкрепени от данъчни заявки, трябва също да обмислят обектно кеширане (Redis или Memcached) на ниво сървър, което е конфигурируемо на VPS контролни панели, поддържащи персонализирани PHP и кеширащи слоеве от страна на сървъра.
Матрица за вземане на решения и техническа контролна листа
Преди внедряване на данъчна заявка в production, проверете следното:
Валидирано съществуване на термина — използвайте 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 комбинации само с плосък ключ relationSAVEQUERIES, за да инспектирате генерирания SQL преди пусканеЧесто задавани въпроси
Каква е разликата между relation => 'AND' и operator => 'AND' в данъчна заявка?
relation е ключ на горно ниво, който свързва множество клаузи на данъчни заявки помежду им — определя дали публикацията трябва да отговаря на всички клаузи (AND) или поне на една (OR). operator е ключ за всяка клауза, който определя как масивът terms се съпоставя в рамките на единична клауза — AND изисква публикацията да има всеки изброен термин присвоен едновременно.
Защо данъчната ми заявка не връща резултати, въпреки че публикациите и термините съществуват?
Най-честите причини са: подаване на стойност на terms, която не съответства на посочения тип field (напр. подаване на name, когато field е зададен на slug), заявка към таксономия, нерегистрирана за типа публикация, или използване на operator => 'AND' с термини, които нито една публикация не притежава едновременно. Активирайте SAVEQUERIES и инспектирайте суровия SQL за диагностика.
Мога ли да използвам данъчна заявка вътре в 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, когато се нуждаете от точно съпоставяне на термини и не изисквате наследяване на дъщерни термини.
Има ли ограничение за броя клаузи, които може да има данъчна заявка?
Няма твърдо кодирано ограничение в ядрото на WordPress, но практически ограничения се налагат от максималната дълбочина на свързване на MySQL и праговете за сложност на заявките. Повече от четири или пет клаузи в единична данъчна заявка е сигнал, че моделът на данните може да се нуждае от преосмисляне — или чрез денормализация, специализиран индекс за търсене (Elasticsearch, Typesense), или преструктуриране на йерархията на таксономията за намаляване на броя на клаузите.
