Issue with pre_get_posts on custom post type archive pages

Overview

  1. I am creating a theme which has 2 custom post types (as custom plugins):

    1. Articles
    2. Reviews
  2. I have also created single-articles.php and archive-articles.php templates inside the plugin. Same for Reviews CPT.

  3. BOTH the custom post types use the default WordPress Taxonomies (categories and tags)

  4. My Reading Settings are set to “A Static Page”

    1. Front page: Home ( a Custom front-page.php file I created)

    2. Posts Page: The “Site News” page (which I want to show BOTH posts AND CPT’s)

The Problem

After creating a regular post and a post based on the Articles CPT, I went to the Main Posts page (The Site News) wherein I did not see the custom post type (only the post using the standard post type).

After some searching (i’m a noob) I understood that if I wanted to display CPT’s on the main posts page, I would have to write a filter using pre_get_posts.

So, to recap: I wish to show

  1. BOTH regular posts AND Custom Post Types (CPT’s) on the Main Posts page
  2. BOTH regular posts AND Custom Post Types (CPT’s) for the Category Archives pages

Here’s What I Did

// Add custom post types to the default loop (ref: http://bit.ly/1bqeBJC)
function odigbs_add_custom_types( $query ) {
    if ( !is_admin()  && !is_preview() ) {
        if ( (is_home() || is_category() || is_tag() || is_archive()  || is_feed() ) && $query->is_main_query()  ) {
            $query->set( 'post_type', array( 'post', 'articles', 'reviews') );
            return $query;
        }
    }
}
add_filter( 'pre_get_posts', 'odigbs_add_custom_types' );

I’m sure this is not the right way to craft this filter, but I cannot find any article that explains this concept thoroughly… so i’m wingin it.

The Results

  1. If I go to: http://site.dev/the-site-news/ (the main posts page from Reading Settings), I now DO see all of my custom post types and it does use the single-{post_type}.php file inside the plugin.
  2. If I click on any of the taxonomy terms the page goes to: http://site.dev/category/{some term}/ and it does use the archive-{post_type}.php file inside the plugin.

But…

  1. If I point my browser to http://site.dev/{custom_post_type}, (i.e. not using the category) to see the archives for that CPT, the site throws all kind of errors.
  2. But if I disable the filter, then I can now go to http://starter.dev/{custom_post_type}/, but I’m right back where I started with only default posts showing on the main posts page. No custom Post types.

Questions

  1. Is (as I suspect) the problem is in the filter?
  2. If so, how should it be written?

I hope I clearly articulated the drama…

Thanks in advance

Solutions Collecting From Web of "Issue with pre_get_posts on custom post type archive pages"

If we look in source, we’ll see under what conditions is_archive is true:

if ( $this->is_post_type_archive
|| $this->is_date
|| $this->is_author
|| $this->is_category
|| $this->is_tag
|| $this->is_tax )
    $this->is_archive = true;

The issue is that is_archive is triggering your filter on your post type archive. If you want to exclude those, either make sure it’s not is_post_type_archive, or target the other archives by checking if it’s an author or date archive as well as tag and category and remove the check for is_archive.

If I understand correctly, you want your CPTs to show on regular archive pages (cateogires, main query etc) but when searching only your CPTs you get again your CPTs with all regular posts etc..

Here is what I made and for now as I have seen it is working well, but you never know where you can get any error so here, try it and see if it works well for you.

change YOURCPT for your cpt 🙂

add_action( 'pre_get_posts', 'wpstck_get_YOURCPT_into_posts' );
function wpstck_get_YOURCPT_into_posts($query){


    if ( !is_post_type_archive() && $query->is_main_query() ) {
        $query->set( 'post_type', array( 'post', 'YOURCPT' ) );
            return $query;
        }
}