Limit number of posts in WP_query per month

WP_Query is not going to be able to perform a query of the complexity required to do this in one shot. What it would take to pick 10 from one month, ten form another, then 5 from another, then 3, then 1 like that is a number of UNIONs and WP_Query can’t do that.

You have two choices that I can see:

  1. Hand write the SQL to pull your post IDs. This is not horribly
    complicated, but but not trivial. Then pass the post IDs through
    WP_Query as post__in to convert to post objects.
  2. Run a bunch of different queries, and Loops. Certainly the easiest solution.
    WP_Query accepts year and monthnum arguments.

For the first, you could save yourself some effort by doing something like this:

$qrypattern = "SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} 
INNER JOIN {$wpdb->postmeta} ON ({$wpdb->posts}.ID = {$wpdb->postmeta}.post_id)
WHERE 1=1  
AND {$wpdb->posts}.post_type="post" 
AND ({$wpdb->posts}.post_status="publish") 
AND ({$wpdb->postmeta}.meta_key = 'your_date'
AND {$wpdb->postmeta}.meta_value BETWEEN '%s' AND '%s')
GROUP BY {$wpdb->posts}.ID 
ORDER BY {$wpdb->postmeta}.meta_value ASC LIMIT %d";

$dates = array(
  array (
    's' => 'startdate',
    'e' => 'enddate',
    'c' => 10
  ),
  array (
    's' => 'startdate',
    'e' => 'enddate',
    'c' => 5
  )
);
$union = array();
foreach ($dates as $v) {
  $union[] = '('.sprintf($qrypattern,$v['s'],$v['e'],$v['c']).')';
}
$qry = implode(' UNION ',$union );

Obviously, startdate and enddate are filler values. Those have to match your data. Hopefully that data is in some form that sorts appropriately– UNIXTIME or YYYY-MM-DD, something like that.

No promises about the details of that query. I’d have to test it with real data to be certain it works correctly. Consider it an illustration only.

You could probably do something similar with filters but in this case I don’t see the point. I think it would be more trouble than its worth.