web-dev-qa-db-fra.com

Commander par méta clé optionnelle?

Je construis la fonctionnalité de tri pour un type d'article personnalisé et j'ai une méta valeur personnalisée pour les articles "En vedette". Cette valeur est définie lorsque vous cochez la case, sinon elle n'est pas définie.

L'utilisation de la valeur par défaut orderby=meta_value avec meta_key=featured fait en sorte que l'écran affiche uniquement les publications ayant la clé méta. S'ils ne le font pas, ils n'apparaissent même pas.

Je le veux donc si ce n'est pas réglé, ils apparaissent, mais ils apparaissent en dernier. Je suppose que je dois utiliser meta_query à la place, mais cela ne fonctionne pas non plus.

Comment puis-je autoriser les clés méta vides, fausses ou non existantes dans les arguments WP_Query?

Mon code est ci-dessous. C'est pour trier les colonnes dans le tableau de bord, donc il modifie les arguments par défaut WP Query.

function featured_sortable_order( $vars ) {
  if ( isset($vars['orderby']) && $vars['orderby'] == 'featured' ) {

    $vars = array_merge( $vars, array(
      'meta_key' => 'featured',
      'orderby' => 'meta_value',
      'order'     => isset($vars['order']) ? $vars['order'] : 'asc',
    ) );

  }
  return $vars;
}
add_filter( 'request', 'featured_sortable_order' );
6
Radley Sustaire

Complètement édité après la première publication

Le problème est que pour commander une méta-valeur, WordPress doit 'meta_key' dans la requête est défini sur quelque chose. Mais si vous définissez 'meta_key' sur quelque chose, WordPress ajoutera quelque chose comme:

AND ( wp_postmeta.meta_key = 'the_meta_key' )

à WHERE clause SQL; et quelque chose comme

INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )

aux clauses join. Donc, requête renvoie uniquement les publications contenant cette méta requête.

Une fois que vous travaillez sur le backend, et que vous appelez get_post_meta( $postid, 'featured', true) pour que chaque post montre la colonne, ce n’est pas un gros problème de performance que vous appelez-le deux fois grâce au cache WordPress sur get meta function.

Donc, l’idée est d’obtenir tous les articles (sans ajouter de filtre sur la clé méta), puis de filtrer les articles en utilisant 'posts_results' crochet et commander les articles en regardant la clé méta 'sélectionnée'.

Je retirerai le filtre juste après l'avoir utilisé.

add_filter( 'posts_results', 'order_by_featured', PHP_INT_MAX, 2 );

function order_by_featured ( $posts, $query ) {
  // run only on admin, on main query and only if 'orderby' is featured
  if ( is_admin() && $query->is_main_query() && $query->get('orderby') === 'featured' ) {
    // run once
    remove_filter( current_filter(), __FUNCTION__, PHP_INT_MAX, 2 );
    $nonfeatured = array();
    $featured = array();
    foreach ( $posts as $post ) {
      if ( get_post_meta( $post->ID, 'featured', TRUE ) ) {
        $featured[] = $post;
      } else {
        $nonfeatured[] = $post;
      }
    }
    $order = strtoupper( $query->get('order') ) === 'ASC' ? 'DESC' : 'ASC';
    // if order is ASC put featured at top, otherwise put featured at bottm
    $posts = ( $order === 'ASC' )
      ? array_merge( $nonfeatured, $featured )
      : array_merge( $featured, $nonfeatured );
  }
  return $posts;
}

De plus, j'ajoute un filtre sur 'pre_get_post' pour utiliser 'ASC' comme ordre par défaut si aucun ordre n'est défini dans la requête:

add_action( 'pre_get_posts', function( $query ) {
  // if no order is set set order to ASC
  if (
    is_admin() && $query->is_main_query()
    && $query->get('orderby') === 'featured' 
    && $query->get('order') === ''
  ) {
    $query->set( 'order', 'ASC' );
  }
});
6
gmazzap