J'ai besoin d'obtenir un ensemble de résultats complexe à partir d'une base de données WordPress selon la structure de la catégorie.
Je vais d'abord essayer d'expliquer ma structure de catégorie. J'ai une structure à trois niveaux comme ci-dessous.
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]
Maintenant l'algorithme:
J'ai besoin d'obtenir tous les messages étiquetés en tant que catégorie flight
ou son de l'enfant avec les règles suivantes.
Je dois exclure les messages marqués comme economy
;
business
ou first
) était marqué.alliance
ou son enfant ont été marqués SI economy
également marqués dans les mêmes messages [mais cette règle est de toute façon complètement remplie lorsque nous excluons le economy
catégorie en général]Mon approche jusqu'à présent:
J'essayais tax_query
avec le type d'arguments suivant
$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 );
Mais le problème ici est qu'il ne remplit pas la règle numéro 1. Même si j'ai besoin d'avoir des messages avec la balise business
et first
indépendamment de economy
, ce qui précède La requête ignore simplement toutes les publications marquées avec economy
.
Je considérerais même l'approche pure SQL
également. Toute aide serait très appréciée car je me débattais avec cela depuis quelques jours maintenant.
Penser à haute voix ici ...
$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 );
Obtenez tous les messages dans les termes de taxonomie ID 202, 203, etc ...
OR
Obtenez toutes les publications dans le terme de taxonomie ID 100 uniquement (excluez les enfants)
En fait, ce qui précède pourrait simplement être exprimé comme (AUCUNE REQUÊTE IMPRIMÉE):
$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 );
Obtenez tous les messages dans les termes de taxonomie ID 202, 203, etc ...
OR
Obtenez toutes les publications dans le terme de taxonomie ID 100 uniquement (excluez les enfants)
Et encore ... alternativement (si vous forcez les écrivains à toujours définir des catégories d'enfants par le biais d'un crochet sur save_post
ou similaire):
$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 );
Obtenez tous les messages dans les termes de taxonomie ID 202, 203, etc ...
Ce serait mon approche rapide:
$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'
));
}
Mon exemple de jeu de données retourné est:
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',
)
Si je supprimais le 'exclude' => 201
lors de l'appel get_terms
Je verrais un résultat similaire à ceci:
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
)
Comme vous pouvez le voir, je retourne tous les messages sauf ceux qui ont economy
seuls. Où economy
est présent, mais aussi une autre classification, alors ce message est retourné. Les clés sont les identifiants de poste.
Remarque: mes résultats d'exemple montrent quelles pourraient être vos valeurs potentielles si les rédacteurs de contenu oublient d'affecter des ancêtres. Comme mentionné, cela peut être résolu dans une autre question.
# 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'
));
}
Dans mon échantillon de données, j'obtiens un résultat comme celui-ci:
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',
)
Et le SQL est le suivant:
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
Pas incroyablement efficace, mais c'est une manière brutale de s'y prendre.