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.

So this may seem like a pretty menial thing, but follow me here.

I'm trying to add some logic through the pre_get_posts action. This is the entire WP_Query object given to me. (see the end)

Things I have considered using:

  • is_single() - too broad.
  • is_singular() - too early to use this, as get_queried_object() is not yet set.
  • $query->single property - again too broad.
  • $query->get('post_type') - not set, as it's using the name property.

is name really the only indicator here?

WP_Query Object
(
    [query] => Array
        (
            [page] => 
            [name] => abcs-of-mental-health
        )

    [query_vars] => Array
        (
            [page] => 
            [name] => abcs-of-mental-health
            [error] => 
            [m] => 0
            [p] => 0
            [post_parent] => 
            [subpost] => 
            [subpost_id] => 
            [attachment] => 
            [attachment_id] => 0
            [static] => 
            [pagename] => 
            [page_id] => 0
            [second] => 
            [minute] => 
            [hour] => 
            [day] => 0
            [monthnum] => 0
            [year] => 0
            [w] => 0
            [category_name] => 
            [tag] => 
            [cat] => 
            [tag_id] => 
            [author_name] => 
            [feed] => 
            [tb] => 
            [paged] => 0
            [comments_popup] => 
            [meta_key] => 
            [meta_value] => 
            [preview] => 
            [s] => 
            [sentence] => 
            [fields] => 
            [menu_order] => 
            [category__in] => Array
                (
                )

            [category__not_in] => Array
                (
                )

            [category__and] => Array
                (
                )

            [post__in] => Array
                (
                )

            [post__not_in] => Array
                (
                )

            [tag__in] => Array
                (
                )

            [tag__not_in] => Array
                (
                )

            [tag__and] => Array
                (
                )

            [tag_slug__in] => Array
                (
                )

            [tag_slug__and] => Array
                (
                )

            [post_parent__in] => Array
                (
                )

            [post_parent__not_in] => Array
                (
                )

        )

    [tax_query] => 
    [meta_query] => 
    [queried_object] => 
    [queried_object_id] => 0
    [post_count] => 0
    [current_post] => -1
    [in_the_loop] => 
    [comment_count] => 0
    [current_comment] => -1
    [found_posts] => 0
    [max_num_pages] => 0
    [max_num_comment_pages] => 0
    [is_single] => 1
    [is_preview] => 
    [is_page] => 
    [is_archive] => 
    [is_date] => 
    [is_year] => 
    [is_month] => 
    [is_day] => 
    [is_time] => 
    [is_author] => 
    [is_category] => 
    [is_tag] => 
    [is_tax] => 
    [is_search] => 
    [is_feed] => 
    [is_comment_feed] => 
    [is_trackback] => 
    [is_home] => 
    [is_404] => 
    [is_comments_popup] => 
    [is_paged] => 
    [is_admin] => 
    [is_attachment] => 
    [is_singular] => 1
    [is_robots] => 
    [is_posts_page] => 
    [is_post_type_archive] => 
    [query_vars_hash] => f473ebf7f725c2627dc5fd9a1429f626
    [query_vars_changed] => 
    [thumbnails_cached] => 
)
share|improve this question
add comment

4 Answers

up vote 4 down vote accepted

I've tried to sort this out before for my own purposes. As far as I can tell ...

  • post_type is not really set anywhere for the post post type.
  • For the page post type I only see the post type key in queried_object.
  • For CPT types there is a post_type key in query_vars and also in query.
  • Nav menus appear to behave like other CPTs in this respect.

The data is very inconsistent but if you eliminate pages and CPT's I believe you can assume the post type.

Edit: Working code from @EricHolmes:

add_action( 'pre_get_posts', 'something_for_single_posts_only' ) ; 
function something_for_single_posts_only( $query ) { 
  if( $query->is_main_query() 
    && $query->is_singular() 
    && ! $query->get( 'post_type' ) 
    && ! $query->is_page() 
    && ! $query->is_attachment() 
  ) { 
      // do something for single posts only. 
  } 
} 

We check for is_singular, no post type (CPTs have post_type in query_vars), not a page or attachment.

share|improve this answer
    
And it works inside pre_get_posts (before query run)? –  G. M. Oct 8 '13 at 20:12
    
I wonder if is_page() is set at the pre_get_posts level. If it is, and I can check against post_type not being set in query_vars, I guess that's as good as it gets? So broken. –  Eric Holmes Oct 8 '13 at 20:13
1  
is_page does seem to be set. –  s_ha_dum Oct 8 '13 at 20:18
    
@s_ha_dum I removed the comment because it seems to doesn't work for CPT... –  G. M. Oct 8 '13 at 20:47
1  
Adding the working solution to your answer. –  Eric Holmes Oct 9 '13 at 13:00
add comment

I don't know if this will be useful:

function hwl_home_pagesize( $query ) {
    global $wp_query;
    if (is_main_query() && count($wp_query->posts) < 2) {

    }

}
add_action( 'pre_get_posts', 'hwl_home_pagesize', 1 );

Use $wp_query->posts (array) to check the post type.

share|improve this answer
    
Not yet. Pre get posts happens before the $wp_query->posts variable is actually populated. Thanks though! –  Eric Holmes Oct 8 '13 at 20:19
add comment

After some tests I see that unfortunately is impossible to get the post type of cpt inside pre_get_posts hook. Only is_page works but not standard post type nor cpt can be retrieved there.

If you have only page and post (no cpt) a check to is_single() with true as response means that post type is post, because it return false for pages.

If you have also CPTs I'm afraid you have to perform an additional query. The simplest I can think is just get the post_type column where post status is publish and post_name is the one required (skipping revisions):

function test( $q ) {
  if ( is_single() ) {
    global $wpdb;
    $type = $wpdb->get_var( $wpdb->prepare(
      "SELECT post_type FROM $wpdb->posts WHERE post_name = %s AND post_status = 'publish' AND post_type <> 'revision'",
      $q->query['name']
    ) );
    var_dump($type);
  }
}
add_action( 'pre_get_posts', 'test', 1); 

If you want to check a specific post type you can write a custom conditional tag that just count the rows with a given post_type and the given name:

function is_single_post_type( $type = 'post' ) {
  if ( is_single() ) {
    global $wpdb, $wp_query;
    $is = $wpdb->get_var( $wpdb->prepare(
      "SELECT count(ID) FROM $wpdb->posts WHERE post_name = %s AND post_status = 'publish' AND post_type = %s",
      $wp_query->query['name'], $type
    ) );
    return $is > 0;
  }
  return false;
}

Of course this is needed on pre_get_post, in any later hook you can use get_post_type()...

share|improve this answer
1  
This would definitely work, but look in the accepted answer, it's a much less complicated conditional, without an additional query to the database. :) –  Eric Holmes Oct 9 '13 at 12:56
    
Yes. I understand that you wanted to know exactly which post type are you showing. Not only if you are in one single post view. @EricHolmes –  G. M. Oct 9 '13 at 16:41
add comment

This is what I'm using, though it's specialized for my own directory structure.

/**
 * Function to list all templates used in a page
 * @author Imperative Ideas with thanks to Rarst
 * @uri http://wordpress.stackexchange.com/a/89005
 */

function thelist() {
    $included_files = get_included_files();
    $stylesheet_dir = str_replace( '\\', '/', get_stylesheet_directory() );
    $template_dir   = str_replace( '\\', '/', get_template_directory() );
    echo '<h3 class="debugtitle">Theme file templates used in this page</h3>';
    foreach ( $included_files as $key => $path ) {

        $path   = str_replace( '\\', '/', $path );

        if ( false === strpos( $path, $stylesheet_dir ) && false === strpos( $path, $template_dir ) )
            unset( $included_files[$key] );

        if(!strpos($path, '/wp-content/themes/') === false) { // Files IN this directory
            if(strpos($path, '/library/') === false) { // Ignore this subdir
                if(strpos($path, '/hybrid-core/') === false) { // Ignore this subdir
                    echo $key." = ". $path."</br>"; // Finally, output the list
                }
            }
        }
    }
}

Mileage may vary. The strpos bits where I check that files are in one directory but not another would need to be modified for your build and could probably be re-factored more efficiently. They exist to cut out results above and below a certain directory structure.

Running thelist() in the footer will give you a numbered list of every .php template file used to compile the current view. It's especially useful when dealing with a child theme that is rendering out a mystery component.

share|improve this answer
    
Seems overkill. Cool idea though? –  Eric Holmes Oct 9 '13 at 12:56
    
There aren't a lot of good ways to determine what templates are driving a page, other than parsing them. I guess if you're looking for something as simple as single vs page, yeah, it's overkill. Try running the function some time though, minus the extra ignore conditionals, and you'll see why I use this. There are a TON of files that go into driving a WP page and it can be really useful to know what they all are. Even this won't identify hooked functions though. –  Imperative Ideas Oct 9 '13 at 19:53
add comment

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.