web-dev-qa-db-fra.com

Ordre des publications par termes de taxonomie (coutume hiérarchique) et terme enfants

Le scénario

  • un type de message personnalisé wiki
  • une taxonomie personnalisée (hiérarchique) topics
  • un modèle de page archive-wiki.php

La situation

Les publications apparaissent et sont commandées par post_date (valeur par défaut).

La requête principale correspondante est:

SELECT SQL_CALC_FOUND_ROWS {$wpdb->prefix}posts.ID 
    FROM {$wpdb->prefix}posts WHERE 1=1 
    AND {$wpdb->prefix}posts.post_type = 'wiki' 
    AND ({$wpdb->prefix}posts.post_status = 'publish' OR {$wpdb->prefix}posts.post_status = 'private') 
ORDER BY {$wpdb->prefix}posts.post_date 
DESC 
LIMIT 0, {$setting->posts_per_page}

Oui, je suis connecté lorsque je saisis cette requête - d'où le statut + = private.

La tâche

Commandez tous les articles en fonction des termes principaux de la hiérarchie personnalisée. À l’intérieur du taxon principal, assignez les messages aux sous-termes. Ainsi, le tableau principal ne contient que les taxons principaux des taxonomies avec les articles wiki- réels affectés à leurs sous-taxons correspondants. S'ils ne sont pas attribués à un sous-taxon ou si le taxon n'a pas de taxon enfant, alors il devrait simplement être ajouté au tableau principal.

Où cela devrait-il arriver?

À l'intérieur du pre_get_posts ou du posts_pieces (et de filtres similaires). Je ne veux pas ajouter une requête supplémentaire pour cela.

Je vous remercie.

2
kaiser

Cette requête gérera deux niveaux de hiérarchie dans votre taxonomie. Plus de deux niveaux de hiérarchie et vous aurez besoin d'une auto-jointure récursive.

Cela permet de retourner les publications dans le bon enfant dans l'ordre parent. Pour créer les en-têtes de niveau parent appropriés, vous devez comparer le taxon parent de la publication actuelle avec celui de la publication précédente. Imprimez l'en-tête du taxon en haut de la page et un autre niveau à chaque point où la valeur du taxon parent change. Vous aurez besoin d'appeler une fonction sur chaque article pour obtenir le taxon de niveau parent, car je ne connais aucun moyen de transmettre la valeur de la requête à l'objet post.

 SELECT *
   from wp_posts 
  LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
    LEFT JOIN wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
    LEFT JOIN wp_terms ON (wp_term_taxonomy.term_id = wp_terms.term_id)
    LEFT JOIN wp_term_taxonomy AS parent ON (wp_term_taxonomy.parent = parent.term_taxonomy_id)
    LEFT JOIN wp_terms AS parent_terms ON (parent.term_id = parent_terms.term_id) 
  WHERE wp_posts.post_type = 'post'
  AND wp_term_taxonomy.taxonomy = 'category'
  and not exists(select 1 
                   from wp_posts AS subposts
                        LEFT JOIN wp_term_relationships as subtr ON subposts.ID = subtr.object_id
                        LEFT JOIN wp_term_taxonomy as subtt ON (subtr.term_taxonomy_id = subtt.term_taxonomy_id)
                        LEFT JOIN wp_terms as subt ON (subtt.term_id = subt.term_id)
                        LEFT JOIN wp_term_taxonomy AS subparent ON (subtt.parent = subparent.term_taxonomy_id)
                  where subtt.parent > wp_term_taxonomy.parent
                    and subposts.ID = wp_posts.ID 
                    AND subtt.taxonomy = wp_term_taxonomy.taxonomy)
  ORDER BY IFNULL(  parent_terms.slug ,  wp_terms.slug) ASC, wp_terms.slug  ASC;

Etant donné qu'il s'agit du code SQL correct pour votre page d'archive, examinons la manière de la mettre en œuvre à l'aide de filtres, tels que pre_get_posts, etc.

UPDATE La requête SQL ci-dessus a été testée et modifiée pour retourner des résultats corrects. Ce qui suit, similaire à ma requête d'origine, renvoie deux lignes pour toute publication ayant un parent.

   SELECT wp_posts.ID,  parent_terms.slug parent_slug, wp_terms.slug, wp_term_taxonomy.taxonomy, wp_term_taxonomy.parent
         , IFNULL(  parent_terms.slug ,  wp_terms.slug) sort_col2
   from wp_posts 
   LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
    LEFT JOIN wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
    LEFT JOIN wp_terms ON (wp_term_taxonomy.term_id = wp_terms.term_id)
    LEFT JOIN wp_term_taxonomy AS parent ON (wp_term_taxonomy.parent = parent.term_taxonomy_id)
    LEFT JOIN wp_terms AS parent_terms ON (parent.term_id = parent_terms.term_id) 
  WHERE wp_posts.post_type = 'post'
  AND wp_term_taxonomy.taxonomy = 'category'
  ORDER BY IFNULL(  parent_terms.slug ,  wp_terms.slug) ASC, wp_terms.slug  ASC;

Notez que post.id = 629 apparaît deux fois dans les résultats:

  +-----+-------------+---------------+----------+--------+-----------+
  | ID  | parent_slug | slug          | taxonomy | parent | sort_col2 |
  +-----+-------------+---------------+----------+--------+-----------+
  | 629 |             | business      | category | 0      | business  |
  | 629 | business    | press-release | category | 3      | business  |
  | 618 |             | media         | category | 0      | media     |
  | 608 |             | media         | category | 0      | media     |
  | 624 |             | startups      | category | 0      | startups  |
  | 621 |             | startups      | category | 0      | startups  |
  +-----+-------------+---------------+----------+--------+-----------+
  6 rows in set (0.00 sec)

Les lignes en double sont filtrées en ajoutant une condition NOT EXISTS(...):

  SELECT wp_posts.ID,  parent_terms.slug parent_slug, wp_terms.slug, wp_term_taxonomy.taxonomy, wp_term_taxonomy.parent
         , IFNULL(  parent_terms.slug ,  wp_terms.slug) sort_col2
   from wp_posts 
  LEFT JOIN wp_term_relationships ON wp_posts.ID = wp_term_relationships.object_id
    LEFT JOIN wp_term_taxonomy ON (wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id)
    LEFT JOIN wp_terms ON (wp_term_taxonomy.term_id = wp_terms.term_id)
    LEFT JOIN wp_term_taxonomy AS parent ON (wp_term_taxonomy.parent = parent.term_taxonomy_id)
    LEFT JOIN wp_terms AS parent_terms ON (parent.term_id = parent_terms.term_id) 
  WHERE wp_posts.post_type = 'post'
  AND wp_term_taxonomy.taxonomy = 'category'
  and not exists(select 1 
                   from wp_posts AS subposts
                        LEFT JOIN wp_term_relationships as subtr ON subposts.ID = subtr.object_id
                        LEFT JOIN wp_term_taxonomy as subtt ON (subtr.term_taxonomy_id = subtt.term_taxonomy_id)
                        LEFT JOIN wp_terms as subt ON (subtt.term_id = subt.term_id)
                        LEFT JOIN wp_term_taxonomy AS subparent ON (subtt.parent = subparent.term_taxonomy_id)
                  where subtt.parent > wp_term_taxonomy.parent
                    and subposts.ID = wp_posts.ID )
  ORDER BY IFNULL(  parent_terms.slug ,  wp_terms.slug) ASC, wp_terms.slug  ASC;

Et les résultats, les messages triés par enfant au sein du parent et aucun enregistrement en double:

  +-----+-------------+---------------+----------+--------+-----------+
  | ID  | parent_slug | slug          | taxonomy | parent | sort_col2 |
  +-----+-------------+---------------+----------+--------+-----------+
  | 629 | business    | press-release | category | 3      | business  |
  | 618 |             | media         | category | 0      | media     |
  | 608 |             | media         | category | 0      | media     |
  | 624 |             | startups      | category | 0      | startups  |
  | 621 |             | startups      | category | 0      | startups  |
  +-----+-------------+---------------+----------+--------+-----------+
  5 rows in set (0.00 sec)

UPDATE: Fonction non actuelle avec le dernier code SQL ci-dessus

function wpse69290_query( $pieces, $obj )
{
    global $wpdb;

    #$pieces['fields'] = "* ";

    $pieces['join'] .= " LEFT JOIN `$wpdb->term_relationships` AS trs ON ($wpdb->posts.ID = trs.object_id)";
    $pieces['join'] .= " LEFT JOIN `$wpdb->term_taxonomy` AS tt ON (trs.term_taxonomy_id = tt.term_taxonomy_id)";
    $pieces['join'] .= " LEFT JOIN `$wpdb->terms` AS t ON (tt.term_id = t.term_id)";
    $pieces['join'] .= " LEFT JOIN `$wpdb->term_taxonomy` AS parent ON (parent.parent = trs.term_taxonomy_id)";
    $pieces['join'] .= " LEFT JOIN `$wpdb->terms` AS parent_terms ON (parent.term_id = parent_terms.term_id)";

    $pieces['where'] .= " AND (tt.taxonomy = 'topics')";

    $pieces['orderby'] = "IFNULL(parent_terms.slug, t.slug) ASC";

    $pieces['limits'] = "LIMIT 0, 999";

    return $pieces;
}
add_filter( 'posts_clauses', 'wpse69290_query', 10, 2 );

Et oui, pas besoin d'utiliser prepare() pour les pièces de requête qui ont uniquement les noms de table par défaut.

3
marfarma