Ignore post by meta value in the main query

I use this function to insert at the beginning of the loop two post at my convenience (with meta key and value)

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;
}

But these posts still appear in the loop, they would have to hide to not look twice.

How can I do this?

2 Answers
2

We can try the following alternative way:

  • Remove the two posts we select via our custom query from the main query via the pre_get_posts action

  • Return the two posts on top of page one via the the_posts filter

Lets look at possible code:

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 );
    }
}); 

This should replace the current code that you have posted in your question

Leave a Comment