Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Bulding off of this response from @kaiser about being able to filter by post types on a search page, I wanted to be able to automatically add-in all of the public post types available. So, after some help with @kaiser, I came up with:

function sw_custom_post_type_includes($query) {
    $args = array(
        'public'   => true
    ); 
    $output = 'names'; // names or objects, note names is the default
    $operator = 'and'; // 'and' or 'or'
    $post_types = get_post_types( $args, $output, $operator ); 
    if ( !is_search() && !in_array( get_post_type(), $post_types ) )
        return;

    $query->set( 'post_type', $post_types );
    return $query;
}
add_filter('pre_get_posts', 'sw_custom_post_type_includes');

Which initially seemed to work great, but I ran into an issue -> everything filtered by post type correctly EXCEPT when I tried to use &post_type=page. I was actually getting an undefined index error for post_type. I couldn't figure out why this wasn't working. So, I decided to use print_r($query->query_vars) to see if everything was being pulled in correctly. Low and behold - for all post types EXCEPT for pages, that variable was set.

I conferred with another dev on this and they verified the issue. This is what I ended up using as a workaround:

function sw_custom_post_type_includes($query) {
    if(isset($_GET['post_type']) && ((!isset($query->query_vars['post_type'])) || (isset($query->query_vars['post_type']) && $query->query_vars['post_type'] != 'nav_menu_item'))) {
        $query->set('post_type', urldecode($_GET['post_type']));
    }
}
add_action('pre_get_posts', 'sw_custom_post_type_includes');

This honestly seems like an odd workaround for something that has been baffling me for a few hours. Anyone with input on this will be rewarded with virtual high-fives.

share|improve this question
1  
I'm pretty sure, that you're simply adding the filter too early... Check in core, where this gets set up. –  kaiser Jul 31 '12 at 10:20
    
Hey @kaiser - issue here is that it's pulling all of the post types for everything else - just not pages. A little befuddled on why it works for everything else but. Thanks. –  Zach Aug 2 '12 at 15:06
    
Hey @Zach - when I comment something with "is the default", then I wanted to give you a hint: It's optional, so you can leave it out, as the function will have it, even if you don't provide it. So the only thing you need for $post_types is the $args array. –  kaiser Aug 3 '12 at 9:42
    
Do a var_dump() of the global $wp_post_types at the beginning of the function, please. –  kaiser Aug 3 '12 at 9:43
    
Bleh that's a lot :) Here's what I have pastebin.com/20AdkFZC –  Zach Aug 6 '12 at 13:07

3 Answers 3

up vote 2 down vote accepted

To clear up some confusion in previous answers, pre_get_posts isn't a filter so you don't need to return anything.

Your only problem that I see is the if:

if ( !is_search() && !in_array( get_post_type(), $post_types ) )
    return;

Basically get_post_type() is going to return false during pre_get_posts because the global $post hasn't been set yet (usually set once you start the loop).

I'm not totally sure WHEN you want all public post types and when you don't. If you just want to set all searches to include all public post types, you really just need to check is_search(). You may also want to make sure the query being modified is the main query and not a custom query that a plugin or theme file is creating. The code should look like this:

function range_search_all_public_post_types( $q ) {
    if ( is_search() && is_main_query() )
        $q->set( 'post_type', get_post_types( array( 'public' => true ) ) );
}
add_action( 'pre_get_posts', 'range_search_all_public_post_types' );

That's it. That will cause all public post types to be queried for searches.

If you want all public post types on the home page and search, use this:

function range_search_all_public_post_types( $q ) {
    if ( ( is_search() || is_home() ) && is_main_query() )
        $q->set( 'post_type', get_post_types( array( 'public' => true ) ) );
}
add_action( 'pre_get_posts', 'range_search_all_public_post_types' );

UPDATE:

The problem you are having is unique to post_types that have publicly_queryable set to false. You basically want all public types to work even if they are not publicly_queryable. To do that use this code:

function range_search_all_public_post_types( $q ) {
    if ( is_search() && is_main_query() && '' == $q->get( 'post_type' ) && ! empty( $_GET['post_type'] ) && post_type_exists( $_GET['post_type'] ) && get_post_type_object( $_GET['post_type'] )->public )
        $q->set( 'post_type', $_GET['post_type'] );
}
add_action( 'pre_get_posts', 'range_search_all_public_post_types' );

Basically, if a post_type is in URL but NOT in QP_Query, it COULD be because it's not publicly_queryable, and if so we fix it. Here is what is checked:

  • Is this a search page?
  • Is this the main query?
  • Is there no post_type specified in the query?
  • Is there a post_type specified in the URL?
  • Does the URL-specified post_type exist?
  • Is the URL-specified post_type public?

If all those are true, it sets the post_type to the one in the URL.

share|improve this answer
    
Appreciate the response - I gave what you provided a shot, but not sure if it's achieving what I'm after. Basically - it should be grabbing the post type by a URL param -- like so http://localhost/wordpress/?s=test&post_type=page but doesn't yours return all of the values in an array? This should be filtering down to a single post type based on the post_type query var. Thanks. –  Zach Aug 9 '12 at 18:17
    
I looked into it, and the default is to search all public post type, so the code above isn't needed. Additionally, if you add &post_type=something to the URL it will already only search that post type. Basically what you want is already built into WordPress. Use /?s=searchstring to search all public post types and use /?s=searchstring&post_type=myposttype to search only myposttype –  Aaron D. Campbell Aug 10 '12 at 23:33
    
Thanks for clarifying - here's the problem though. Vanilla install, create a 'test' post and 'test page' page. Perform a search, site/?s=test. ?s=test&post_type=post shows only posts but ?s=test&post_type=page shows both. So the page doesn't seem to be filtering still. –  Zach Aug 14 '12 at 18:58
    
Please see the update in my answer, which will fix your problem (which turned out to be an issue with publicly_queryable) –  Aaron D. Campbell Aug 18 '12 at 20:23
    
Awesome! Really appreciate all your efforts here. Thanks again! –  Zach Aug 23 '12 at 16:06

As I answered the question, where this one is a follow up and after commenting a lot on the questions here, I'm pretty sure, that you somewhere got another filter or conditional that is holding you back from retrieving a result for pages. 99% chance that this is your problem. You better start with a blank vanilla installation and try to run nothing than this filter to prove, that it's working. Then walk in and start removing/commenting out all that custom stuff, deactivate plugins, etc. until you know what's going on.

share|improve this answer

you wrote

if ( !is_search() && !in_array( get_post_type(), $post_types ) )
    return;

if page is not in your $post_types array there's an empty return;

Actually I don't see why you add this security, this function is called only when there's an actual need thanks to the pre_get_posts filter

You should just change the return:

function sw_custom_post_type_includes($query) {
    $args = array(
        'public'   => true
    ); 
    $output = 'names'; // names or objects, note names is the default
    $operator = 'and'; // 'and' or 'or'
    $post_types = get_post_types( $args, $output, $operator ); 
    if ( !is_search() && !in_array( get_post_type(), $post_types ) )
        return $query;  //#### keep it unchanged instead of removing everything ####

    $query->set( 'post_type', $post_types );
    return $query;
}
add_filter('pre_get_posts', 'sw_custom_post_type_includes');

It's just a thought, I didn't try

share|improve this answer
    
Appreciate the input @chriscatfr but no dice. Still doesn't recognize page as a post type - which is quite odd to me. I'm using the second one (which is an action instead of a filter), to get around a possible mistake of not returning what was already there, back. Thanks. –  Zach Jul 9 '12 at 13:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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