WP_query : meta_key with custom rule for specific value

I’m a bit stuck with a WP_Query code. Here it is :

$args = array(
      'post_type' => 'post',
      'meta_query'=> array(
          'key' => 'karma',
          'compare' => '>=',
          'value' => 0,
          'type' => 'numeric'),
        'posts_per_page' => 9,
        'meta_key' => 'karma',
        'orderby' => 'meta_value_num', 
        'order' => 'DESC',
        'post__not_in' => $dont_show_me
    );

What I want to do :

Show all posts with karma >= 0 (it works fine with this code). BUT if there are posts with karma = 100 only show 3 of them + the rest of posts.

Examples : 9 posts with karma = 150, 133, 100, 100, 100, 100, 100, 33, 11.

I want to show: 150, 133, 100, 100, 100, 33, 11. (Only 3 posts with karma = 100 are allowed).

Do you have any idea how to achieve this?
Maybe a add_filter('posts_where'); ?

UPDATE: Okay I got it working, based on @s_ha_dum answer. It’s a bit tricky, but the result works 😉

$args = array(
       // Check for 9 last posts with karma = 100
       'post_type' => 'post',
       'meta_query'=> array(
          array(
              'key' => 'karma',
              'compare' => '=', 
              'value' => 100,
              'type' => 'numeric'
           )
        ),
       'posts_per_page' => 9,
       'meta_key' => 'karma',
       'orderby' => 'meta_value_num', 
       'order' => 'DESC',
       'post__not_in' => $dont_show_me
    );
    $karma_qry = new WP_Query($args);

    if (!empty($karma_qry->posts)) {
        $i = 0;
        foreach ($karma_qry->posts as $p) {
            $i++;
            // Check for more than 3 posts with karma = 100
            // Add them in the $dont_show_me array 
            if($i > 3){
                $dont_show_me[] = $p->ID;
            }
        }
    }

    // Setup the final query that excluded addional posts with karma = 100
    $args['meta_query'][0]['compare'] = '>=';
    $args['meta_query'][0]['value'] = 0;
    $args['post__not_in'] = $dont_show_me;

    $wp_query = new WP_Query($args);

1 Answer
1

A meta_query is an array of arrays. Look at the examples in the the Codex.

 $args = array(
   'post_type' => 'my_custom_post_type',
   'meta_key' => 'age',
   'orderby' => 'meta_value_num',
   'order' => 'ASC',
   'meta_query' => array(
       array(
           'key' => 'age',
           'value' => array(3, 4),
           'compare' => 'IN',
       )
   )
 );
 $query = new WP_Query($args);

What you have is just an array. That could be causing trouble. What you want to do is this:

$args = array(
   'post_type' => 'post',
   'meta_query'=> array(
      array(
          'key' => 'karma',
          'compare' => '>=', // limit to "karma value = 100"
          'value' => 0, // limit to "karma value = 100"
          'type' => 'numeric'
       )
    ),
   'posts_per_page' => 9,
   'meta_key' => 'karma',
   'orderby' => 'meta_value_num', 
   'order' => 'DESC',
   'post__not_in' => $dont_show_me
);

However, to get to the question itself, you can’t do logic as complicated as you need …

Show all posts with karma >= 0 (it works fine with this code). BUT if
there are posts with karma = 100 only show 3 of them + the rest of
posts.

… with a single WP_Query. That sounds like you want to pull 3, and only 3, posts with karma greater than 100, and fill in the rest with anything else. That would be tricky with pure SQL. I think it is possible in SQL but I would have to think a lot to be sure, much less to make it work.

I would suggest two queries– one to get the “greater than 100” and a second to get the rest.

$dont_show_me = array(1);
$args = array(
   'post_type' => 'post',
   'meta_query'=> array(
      array(
          'key' => 'karma',
          'compare' => '>=', 
          'value' => 100,
          'type' => 'numeric'
       )
    ),
   'posts_per_page' => 3,
   'meta_key' => 'karma',
   'orderby' => 'meta_value_num', 
   'order' => 'DESC',
   'post__not_in' => $dont_show_me
);
$karma_qry = new WP_Query($args);

if (!empty($karma_qry->posts)) {
  $args['posts_per_page'] = 9 - $karma_qry->found_posts;
  $args['meta_query'][0]['value'] = 0;
  foreach ($karma_qry->posts as $p) {
      // assuming $dont_show_me is an array
      $dont_show_me[] = $p->ID;
  }
  $args['post__not_in'] = $dont_show_me;
} else {
  $args['posts_per_page'] = 9;
  $args['meta_query'][0]['value'] = 0;
}

$the_rest_qry = new WP_Query($args);

I can’t test that as I don’t have your karma data on my server, but I am fairly sure that is correct. It ought to get you most of the way, at least.

Leave a Comment