10

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] => 
)

4 Answers 4

10

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.

5
  • And it works inside pre_get_posts (before query run)?
    – gmazzap
    Commented Oct 8, 2013 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. Commented Oct 8, 2013 at 20:13
  • 1
    is_page does seem to be set.
    – s_ha_dum
    Commented Oct 8, 2013 at 20:18
  • @s_ha_dum I removed the comment because it seems to doesn't work for CPT...
    – gmazzap
    Commented Oct 8, 2013 at 20:47
  • 2
    Adding the working solution to your answer. Commented Oct 9, 2013 at 13:00
0

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.

1
  • Not yet. Pre get posts happens before the $wp_query->posts variable is actually populated. Thanks though! Commented Oct 8, 2013 at 20:19
0

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()...

2
  • 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. :) Commented Oct 9, 2013 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
    – gmazzap
    Commented Oct 9, 2013 at 16:41
-1

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.

2
  • Seems overkill. Cool idea though? Commented Oct 9, 2013 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. Commented Oct 9, 2013 at 19:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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