9

Not sure how to achieve this. I'm trying to mix standard posts and custom posts on a site homepage but I only want to display the custom posts if a meta value is set. Displaying the posts works fine 'post_type' => array('game', 'post') but when I add in the meta_query the regular posts are no longer displaying (which makes sense as they don't meet the meta_query condition).

So how do I limit the meta_query to only the custom post type so that the regular post will still be included?

1
  • 1
    Good question ... +1. I think you won't be able to do that with a default WP_Query. You'll need to either use pre_get_posts alter your query or a custom SQL statement. Anyway, please show your current code. – kaiser Jan 10 '14 at 6:45
4

There are different way to do the trick, 2 comes into my mind:

  1. use a complete custom $wpdb query
  2. use WP_Query with filters, using WP_Meta_Query to build the additional sql

I'll post here sample code for case #2

/**
 * Run on pre_get_posts and if on home page (look at url)
 * add posts_where, posts_join and pre_get_posts hooks
 */
function home_page_game_sql( $query ) {
  // exit if is not main query and home index
  if ( ! ( $query->is_main_query() && ! is_admin() && is_home() ) ) return;
  add_filter( 'posts_where', 'home_page_game_filter' );
  add_filter( 'posts_join', 'home_page_game_filter' );
}
add_action('pre_get_posts', 'home_page_game_sql');


/**
 * Set the SQL filtering posts_join and posts_where
 * use WP_Meta_Query to generate the additional where clause
 */
function home_page_game_filter( $sql = '' ) {
  // remove filters
  remove_filter( current_filter(), __FUNCTION__);
  static $sql_game_filters;
  if ( is_null($sql_game_filters) ) {
    // SET YOUR META QUERY ARGS HERE
    $args = array(
      array(
        'key' => 'my_custom_key',
        'value'   => 'value_your_are_looking_for',
        'compare' => '='
      )
    );
    $meta_query = new WP_Meta_Query( $args );
    $sql_game_filters = $meta_query->get_sql('post', $GLOBALS['wpdb']->posts, 'ID');
  }
  // SET YOUR CPT NAME HERE
  $cpt = 'game';
  global $wpdb;
  if ( current_filter() === 'posts_where' && isset($sql_game_filters['where']) ) {
    $where = "AND ($wpdb->posts.post_status = 'publish') ";
    $where .= "AND ( $wpdb->posts.post_type = 'post' OR ( ";
    $where .= $wpdb->prepare( "$wpdb->posts.post_type = %s", $cpt);
    $where .= $sql_game_filters['where'] . ' ) )';
    $where .= " GROUP BY $wpdb->posts.ID ";
    return $where;
  }
  if ( current_filter() === 'posts_join' && isset($sql_game_filters['join']) ) {
    return $sql .= $sql_game_filters['join'];
  }
}

See inline comments for further explaination.

Also look at WP_Meta_Query on Codex for complete docs on how to set your meta query args.


Edit

I refactored code in a reusable plugin, using a class. Available as Gist.

3
  • 1
    Worked perfectly and thank you for the inline comments. I simply copied the code into my utils.php plugin put the appropriate values into the meta query args that you provided the stubs for, refreshed the home page and there were my posts and game posts in their full glory. Thanks again. – lrm Jan 10 '14 at 22:13
  • Thank you so much, the Gist you prepared is not available anymore, Is there any way to access it? Thanks, Sara – user2811803 Jul 31 '20 at 16:32
  • @user2811803 I've updated the link to the Gist. No idea if it still works after more than 6 years. – gmazzap Aug 1 '20 at 17:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.