web-dev-qa-db-fra.com

Commandes de postes par taxonomie et méta-valeur

Il est possible de commander des posts par Meta Value .

Il est possible de classer les publications par plus d'une valeur .

Et grâce au code ci-dessous, il est possible de commander par taxonomie.

Mais comment puis-je modifier le code ci-dessous pour commander par taxonomy AND meta_value ?

Ajouté à functions.php

function orderby_tax_clauses( $clauses, $wp_query ) {
global $wpdb;
$taxonomies = get_taxonomies();
foreach ($taxonomies as $taxonomy) {
    if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby']     ) {
            $clauses['join'] .=<<<SQL
LEFT OUTER JOIN {$wpdb->term_relationships} ON {$wpdb->posts}.ID={$wpdb-    >term_relationships}.object_id
LEFT OUTER JOIN {$wpdb->term_taxonomy} USING (term_taxonomy_id)
LEFT OUTER JOIN {$wpdb->terms} USING (term_id)
SQL;
            $clauses['where'] .= " AND (taxonomy = '{$taxonomy}' OR taxonomy IS NULL)";
            $clauses['groupby'] = "object_id";
            $clauses['orderby'] = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC) ";
            $clauses['orderby'] .= ( 'ASC' == strtoupper( $wp_query->get('order') ) ) ?     'ASC' : 'DESC';
        }
    }
    return $clauses;
}

    add_filter('posts_clauses', 'orderby_tax_clauses', 10, 2 );

Ajouté à index.php

<?php $args = array(
'post_type' => 'custom_post_type',
'posts_per_page' => -1,
'meta_key' => '_EventStartDate',
'orderby' => 'taxonomy_cat',
'order' => asc
);
$the_query = new WP_Query( $args );

if ( $the_query->have_posts() ) : while ( $the_query->have_posts() ) : $the_query-    >the_post(); ?>

etc. etc.

Changer cela ne fonctionne pas

'orderby' => 'taxonomy_cat meta_value',
3
Chris

Dans votre code, il y a

if ( isset( $wp_query->query['orderby'] ) && $taxonomy == $wp_query->query['orderby'] 

qui font que votre code ne fonctionne pas avec plusieurs champs de commande, car si vous définissez

'orderby' => 'taxonomy_cat meta_value'

alors $taxonomy == $wp_query->query['orderby'] n'est jamais vrai.

De plus, je trouve que boucler toute la taxonomie uniquement dans le but de trouver la taxonomie sur laquelle commander est peu performant et peu fiable.

J'ai donc modifié un peu votre code: lorsque vous souhaitez commander une taxonomie, votre argument doit ressembler à ceci:

'orderby' => 'taxonomy.taxonomy_cat'

grâce au 'taxonomy.', il est facile de reconnaître la taxonomie et il n’est pas nécessaire de parcourir toutes les taxonomies.

Après cela, WordPress permet de ne transmettre qu'un seul argument en tant qu'argument 'order'. Ainsi, lorsque vous passez plusieurs arguments 'orderby', le résultat peut ne pas être celui attendu.

J'ai donc modifié votre code pour accepter un argument supplémentaire: 'ordertax'. Bien sûr, c'est facultatif, donc si vous ne le transmettez pas, l'argument 'order' est utilisé. Il est également ignoré si 'orderby' ne contient aucun argument de taxonomie. Si vous utilisez plusieurs arguments 'orderby' sans transmettre 'ordertax', tous les arguments sont ordonnés en fonction de l'argument 'order' (ou par défaut 'DESC').

'orderby' => 'taxonomy.taxonomy_cat meta_value',
'order' => 'ASC'

signifie "ORDERBY taxonomy_cat ASC, meta_value ASC", en utilisant

'orderby' => 'taxonomy.taxonomy_cat meta_value',
'ordertax' => 'DESC'
'order' => 'ASC'

signifie "ORDERBY taxonomy_cat DESC, meta_value ASC".

Maintenant voici le code:

function orderby_tax_clauses( $clauses, $wp_query ) {
  $orderby_arg = $wp_query->get('orderby');
  if ( ! empty( $orderby_arg ) && substr_count( $orderby_arg, 'taxonomy.' ) ) {
    global $wpdb;
    $bytax = "GROUP_CONCAT({$wpdb->terms}.name ORDER BY name ASC)";
    $array = explode( ' ', $orderby_arg ); 
    if ( ! isset( $array[1] ) ) {
      $array = array( $bytax, "{$wpdb->posts}.post_date" );
      $taxonomy = str_replace( 'taxonomy.', '', $orderby_arg );
    } else {
      foreach ( $array as $i => $t ) {
        if ( substr_count( $t, 'taxonomy.' ) )  {
          $taxonomy = str_replace( 'taxonomy.', '', $t );
          $array[$i] = $bytax;
        } elseif ( $t === 'meta_value' || $t === 'meta_value_num' ) {
          $cast = ( $t === 'meta_value_num' ) ? 'SIGNED' : 'CHAR';
          $array[$i] = "CAST( {$wpdb->postmeta}.meta_value AS {$cast} )";
        } else {
          $array[$i] = "{$wpdb->posts}.{$t}";
        }
      }
    }
    $order = strtoupper( $wp_query->get('order') ) === 'ASC' ? ' ASC' : ' DESC';
    $ot = strtoupper( $wp_query->get('ordertax') );
    $ordertax = $ot === 'DESC' || $ot === 'ASC' ? " $ot" : " $order";
    $clauses['orderby'] = implode(', ',
      array_map( function($a) use ( $ordertax, $order ) {
        return ( strpos($a, 'GROUP_CONCAT') === 0 ) ? $a . $ordertax : $a . $order;
      }, $array )
    );
    $clauses['join'] .= " LEFT OUTER JOIN {$wpdb->term_relationships} ";
    $clauses['join'] .= "ON {$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id";
    $clauses['join'] .= " LEFT OUTER JOIN {$wpdb->term_taxonomy} ";
    $clauses['join'] .= "USING (term_taxonomy_id)";
    $clauses['join'] .= " LEFT OUTER JOIN {$wpdb->terms} USING (term_id)";
    $clauses['groupby'] = "object_id";
    $clauses['where'] .= " AND (taxonomy = '{$taxonomy}' OR taxonomy IS NULL)";
  }
  return $clauses;
}

Utilisez-le comme ceci:

$args = array(
  'post_type'      => 'custom_post_type',
  'posts_per_page' => -1,
  'meta_key'       => '_EventStartDate',
  'orderby'        => 'taxonomy.taxonomy_cat meta_value',
  'ordertax'       => 'ASC',
  'order'          => 'DESC'
);

add_filter( 'posts_clauses', 'orderby_tax_clauses', 10, 2 );
$the_query = new WP_Query( $args );
remove_filter( 'posts_clauses', 'orderby_tax_clauses', 10, 2 );

Notez que l'utilisation de mon code (comme le vôtre) avec un WP_Query contenant une requête de taxonomie peut casser des choses ... pour cette raison, il est important de supprimer le filtre après l'avoir utilisé.

4
gmazzap