Mixing regular and custom post types (with meta_query) on home page

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?

Related posts

1 comment

  1. 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.

Comments are closed.