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)

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

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.

Leave a Comment