web-dev-qa-db-fra.com

Ignorer la publication par méta-valeur dans la requête principale

J'utilise cette fonction pour insérer au début de la boucle deux messages à ma convenance (avec clé méta et valeur)

add_filter( 'posts_results', 'insert_post_wpse_96347', 10, 2 );
function insert_post_wpse_96347( $posts, \WP_Query $q ) {
    remove_filter( current_filter(), __FUNCTION__ );

    if ( $q->is_main_query() && $q->is_home() && 0 == get_query_var( 'paged' ) ) {

        $args = [
            'meta_key'         => 'caja', 
            'meta_value'       => ['uno','dos'], 
            'post__not_in'     => get_option( "sticky_posts" ), 
            'posts_per_page'   => '2',
            'suppress_filters' => true
        ];

        $p2insert = new WP_Query($args);
        $insert_at = 0;
        if ( !empty( $p2insert->posts ) ) {
            array_splice( $posts, $insert_at, 0, $p2insert->posts );
        }
    }
  return $posts;
}

Mais ces messages apparaissent toujours dans la boucle, ils devraient se cacher pour ne pas regarder deux fois.

Comment puis-je faire ceci?

2
nicogaldo

Nous pouvons essayer la méthode alternative suivante:

  • Supprimez les deux publications sélectionnées via notre requête personnalisée de la requête principale via l'action pre_get_posts

  • Renvoie les deux articles en haut de la première page via le filtre the_posts

Regardons le code possible:

add_action( 'pre_get_posts', function ( $q )
{
    remove_filter( current_filter(), __FUNCTION__ );

    if (    $q->is_home()       // Only target the home page     
         && $q->is_main_query() // Only target the main query
    ) {
        // Set our query args and run our query to get the required post ID's
        $args = [
            'meta_key'         => 'caja', 
            'meta_value'       => ['uno','dos'], 
            'posts_per_page'   => '2',
            'fields'           => 'ids', // Get only post ID's
        ];      
        $ids = get_posts( $args );

        // Make sure we have ID's, if not, bail
        if ( !$ids )
            return;

        // We have id's, lets remove them from the main query
        $q->set( 'post__not_in', $ids );

        // Lets add the two posts in front on page one
        if ( $q->is_paged() )
            return;

        add_filter( 'the_posts', function ( $posts, $q ) use ( $args )
        {
            if ( !$q->is_main_query() )
                return $posts;

            // Lets run our query to get the posts to add
            $args['fields'] = 'all';
            $posts_to_add   = get_posts( $args );

            $stickies = get_option( 'sticky_posts' );
            if ( $stickies ) {
                $sticky_count = count( $stickies );
                array_splice( $posts, $sticky_count, 0, $posts_to_add );

                return $posts;
            }

            // Add these two posts in front
            $posts = array_merge( $posts_to_add, $posts );

            return $posts;
        }, 10, 2 );
    }
}); 

Cela devrait remplacer le code actuel que vous avez posté dans votre question

1
Pieter Goosen

Essayez ceci à la place:

REMARQUE: veillez à ajouter toute logique conditionnelle supplémentaire dont vous avez besoin pour votre cas d'utilisation, telle qu'une vérification de is_home() et la valeur de get_query_var( 'paged' ). J'ai volontairement laissé ceux-ci pour plus de concision.

function custom_pre_get_posts_meta_query( $query ) {

    if ( is_admin() || ! $query->is_main_query() )
        return;


    $meta_key = 'caja'; //meta_key to query

    $query->set( 
        'orderby', 
        array(
            'meta_value' => 'DESC',
            'date'       => 'DESC'
        ) 
    );

    $query->set( 
        'meta_query', 
        array(
            array(
                'key'     => $meta_key,
                'value'   => 'IGNORE THIS VALUE', //this just needs to be something random
                'compare' => 'NOT EXISTS'
            )
        )
    );

    add_filter( 'posts_where', 'custom_where_meta_query' );

}   

add_action( 'pre_get_posts', 'custom_pre_get_posts_meta_query', 1 );


function custom_where_meta_query( $where = '' ){

    global $wpdb;

    $meta_key    = 'caja'; //meta_key
    $meta_values = array('uno', 'dos'); //meta_values

    $sql = "'" . implode( "', '", array_map( 'esc_sql', $meta_values ) ) . "'";

    $where .= $wpdb->prepare( 
        " OR (( {$wpdb->postmeta}.meta_key = %s AND {$wpdb->postmeta}.meta_value IN ( {$sql} ) ))", 
        $meta_key
    );

    remove_filter( 'posts_where', 'custom_where_meta_query' );

    return $where;

}

La première fonction de rappel sur pre_get_posts lancera WP_Meta_Query, qui crée le code SQL nécessaire que nous filtrons ensuite dans la deuxième fonction de rappel.

Les résultats sont d'abord classés par meta_value DESC, puis par date DESC. Cela regroupera les deux messages correspondants pour la clé méta caja en haut et les messages restants seront triés par date par la suite.

Cela vous évite d'avoir à interroger de nouveau la base de données pour deux publications spécifiques, puis de fusionner le jeu de résultats et enfin de purger le jeu de résultats des doublons.

0
userabuser