Best way to detect if you are in a SINGLE POST page

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)

Read More

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

Related posts

4 comments

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

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

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

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

Comments are closed.