カテゴリ構造に従って、WordPressデータベースから複雑な結果セットを取得する必要があります。
まず、私のカテゴリー構造について説明します。下のように3段構造になっています。
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
カテゴリとしてタグ付けされたすべての投稿、または次のルールで子の1つを取得する必要があります。
economy
のタグが付いた投稿を除外する必要があります。
business
またはfirst
)のいずれかにタグが付けられている場合は、結果セットに含まれているはずです。alliance
またはその子がタグ付けされた投稿は考慮しないでくださいIF 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
アプローチも検討します。私がこれを数日間苦労していたので、どんな助けも高く評価されます。
ここで声を出して考えています...
$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 );
分類用語ID 202、203などのすべての投稿を取得...
OR
分類用語ID 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 );
分類用語ID 202、203などのすべての投稿を取得...
OR
分類用語ID 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 );
分類用語ID 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
が存在するが別の分類も存在する場合、その投稿が返されます。キーは投稿IDです。
注:私のサンプル結果は、コンテンツ作成者が祖先を割り当てるのを忘れた場合の潜在的な値を示しています。すでに述べたように、それは別の質問で解決できます。
# 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
信じられないほど効率的ではありませんが、それはそれについて取り組む力のない方法です。