получите сложный набор результатов в соответствии со структурой категорий
Мне нужно получить сложный набор результатов из базы данных WordPress в соответствии со структурой категорий.
Сначала я попытаюсь объяснить структуру моей категории. У меня трехуровневая структура, как показано ниже.
flight [level 1] [ID : 100]
- class [level 2] [ID : 200]
-- economy [level 3] [ID : 201]
-- business [level 3] [ID : 202]
-- first [level 3] [ID : 203]
- alliance [level 2] [ID : 210]
-- star [level 3] [ID : 211]
-- oneworld [level 3] [ID : 212]
-- skyteam [level 3] [ID : 213]
Теперь алгоритм:
Мне нужно, чтобы все сообщения были помечены как категория flight
или как дочерняя категория со следующими правилами.
Мне нужно исключить сообщения, помеченные как economy
;
- Однако он все равно должен быть в результирующий набор, если один из его братьев и сестер (
business
илиfirst
) был помечен. - Не следует рассматривать сообщения, в которых
alliance
или его дочерний элемент были помечены, ЕСЛИeconomy
также помечены в тех же сообщениях [но это правило в любом случае полностью заполняется, когда мы исключаем категориюeconomy
в целом]
Мой подход до сих пор:
Я пытался tax_query
со следующим типом аргументов
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array( 100 ),
'include_children' => 1,
),
array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array( 200 ),
'include_children' => 1,
),
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array( 201 ),
'operator' => 'NOT IN',
),
),
),
);
$query = new WP_Query( $args );
Но проблема здесь в том, что это не соответствует правилу № 1. Даже несмотря на то, что мне нужны сообщения с тегом business
и first
независимо от economy
, приведенный выше запрос просто игнорирует все сообщения, помеченные economy
.
Я бы даже рассмотрел также чистый SQL
подход.
Любая помощь была бы очень признательна, так как я боролся с этим уже пару дней.
1 answers
Размышляя здесь вслух...
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array( 202, 203 ),
'include_children' => 1,
),
array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array( 100 ),
'include_children' => false,
)
),
),
);
$query = new WP_Query( $args );
Получить все записи с идентификаторами терминов таксономии 202, 203 и т. Д.
ИЛИ
Получить все записи только в термине таксономии с идентификатором 100 (исключая детей)
На самом деле вышесказанное можно было бы просто выразить как (БЕЗ ВЛОЖЕННОГО ЗАПРОСА):
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array( 202, 203 ),
'include_children' => 1,
),
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array( 100 ),
'include_children' => false,
)
),
);
$query = new WP_Query( $args );
Получить все записи с идентификаторами терминов таксономии 202, 203 и т. Д.
ИЛИ
Получить все записи только в термине таксономии с идентификатором 100 (исключая детей)
И еще раз... в качестве альтернативы (если вы заставляете авторы, чтобы всегда устанавливать дочерние категории с помощью крючка на save_post
или аналогичного):
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => array( 202, 203 ),
'include_children' => 1,
),
),
);
$query = new WP_Query( $args );
Получить все записи с идентификаторами терминов таксономии 202, 203 и т. Д.
ОБНОВЛЕНИЕ
Это был бы мой быстрый подход:
$terms = get_terms(array(
'taxonomy' => 'category',
'exclude' => 201
));
$term_ids = array_column( $terms, 'term_id' );
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => $term_ids,
'include_children' => 1,
),
),
);
$query = new WP_Query( $args );
$post_term_ids = [];
foreach ( $query->posts as $post ) {
$post_term_ids[$post->ID] = implode( ', ', array_column(
wp_get_object_terms( $post->ID, 'category' ), 'name', 'term_id'
));
}
Мой образец возвращенного набора данных:
array (
547 => 'Alliance, Business, Class, Flights, Oneworld',
540 => 'Business, Class, Economy, Flights',
605 => 'Star',
524 => 'Alliance, Flights, Oneworld',
594 => 'Skyteam',
569 => 'Star',
551 => 'Flights, Oneworld, Star',
582 => 'Business',
528 => 'Business, Class, Economy, Flights',
565 => 'Skyteam',
)
Если бы я удалил 'exclude' => 201
при вызове get_terms
Я бы увидел результат, подобный этому:
array (
547 => 'Alliance, Business, Class, Flights, Oneworld',
540 => 'Business, Class, Economy, Flights',
605 => 'Star',
524 => 'Alliance, Flights, Oneworld',
594 => 'Skyteam',
569 => 'Star',
551 => 'Flights, Oneworld, Star',
582 => 'Business',
528 => 'Business, Class, Economy, Flights',
565 => 'Economy', // <-- WHAT WE DO NOT WANT
)
Как вы можете видеть, я возвращаю все сообщения, кроме тех, в которых есть economy
один. Где economy
присутствует, но так же и другая классификация, тогда этот пост возвращается. Ключи - это идентификаторы сообщений.
Примечание: результаты моего примера показывают, какими могут быть ваши потенциальные ценности, если авторы контента забудут назначить предков. Как уже упоминалось, это можно решить в другом вопросе.
ОБНОВЛЕНИЕ #2
# change the IDs below to match your environment
$class = 92; // ancestor
$alliance = 96; // ancestor
$economy = 93; // child
$terms_class = get_terms(array(
'taxonomy' => 'category',
'exclude' => [$alliance, $economy],
'child_of' => $class,
));
$terms_alliance = get_terms(array(
'taxonomy' => 'category',
'child_of' => $alliance,
));
$term_ids_class = array_column($terms_class, 'term_id');
$term_ids_alliance = array_column($terms_alliance, 'term_id');
$args = array(
'post_type' => 'post',
'posts_per_page' => -1,
'tax_query' => array(
'relation' => 'OR',
array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => $term_ids_class,
),
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => $term_ids_alliance,
'operator' => 'NOT IN',
),
),
array(
'relation' => 'AND',
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => $term_ids_alliance,
),
array(
'taxonomy' => 'category',
'field' => 'term_id',
'terms' => $economy,
'operator' => 'NOT IN',
),
),
),
);
$query = new WP_Query( $args );
$post_term_ids = [];
foreach ( $query->posts as $post ) {
$post_term_ids[$post->ID] = implode( ', ', array_column(
wp_get_object_terms( $post->ID, 'category' ), 'name', 'term_id'
));
}
В моем образце набора данных я получаю такой результат:
array (
547 => 'Alliance, Business, Class, Flights, Oneworld',
540 => 'Business, Class, Economy, Flights',
524 => 'Alliance, Flights, Oneworld',
594 => 'Skyteam',
569 => 'Star',
551 => 'Flights, Oneworld, Star',
582 => 'Business',
528 => 'Business, Class, Economy, Flights',
589 => 'Oneworld',
603 => 'Oneworld',
584 => 'Oneworld',
585 => 'First',
601 => 'First',
543 => 'Business, Class, Economy, Flights',
572 => 'First',
578 => 'Business',
592 => 'Alliance, Business, Class, Flights, Star',
563 => 'Star',
559 => 'Skyteam',
575 => 'Star',
549 => 'Flights, Oneworld, Skyteam',
596 => 'Star',
534 => 'Class, First, Flights',
561 => 'Star',
556 => 'Star',
587 => 'Oneworld',
)
И SQL выглядит следующим образом:
SELECT
wp_posts.*
FROM
wp_posts
LEFT JOIN wp_term_relationships ON (
wp_posts.ID = wp_term_relationships.object_id
)
LEFT JOIN wp_term_relationships AS tt1 ON (wp_posts.ID = tt1.object_id)
WHERE
1 = 1
AND (
(
wp_term_relationships.term_taxonomy_id IN (94, 95)
AND wp_posts.ID NOT IN (
SELECT
object_id
FROM
wp_term_relationships
WHERE
term_taxonomy_id IN (97, 98, 99)
)
)
OR (
tt1.term_taxonomy_id IN (97, 98, 99)
AND wp_posts.ID NOT IN (
SELECT
object_id
FROM
wp_term_relationships
WHERE
term_taxonomy_id IN (93)
)
)
)
AND wp_posts.post_type = 'post'
AND (
wp_posts.post_status = 'publish'
OR wp_posts.post_status = 'private'
)
GROUP BY
wp_posts.ID
ORDER BY
wp_posts.post_date DESC
Не невероятно эффективный, но это способ применения грубой силы это.