[wp-hackers] is_single() includes attachments

Bart Schouten list at xenhideout.nl
Tue Sep 2 01:38:20 UTC 2014

(I wrote this two weeks ago).

Hi all,

There seems to be a bit of a confusion all around about the "is_single()" 
template function.

>From the Codex:

"This conditional tag checks if a single post of any post type except 
attachment and page post types is being displayed. (...). To check for all 
the post types, use the is_singular() function."

However when you check the code it is clear attachments are included, not 

(Talking about 3.9.2 now)..

query.php: WP_Query::init_query_flags() initializes $this->is_single to

query.php: WP_Query::parse_query() then does:

if ( ('' != $qv['attachment']) || !empty($qv['attachment_id']) ) {
      $this->is_single = true;
      $this->is_attachment = true;

Also, further down:

} elseif ( '' != $qv['static'] || '' != $qv['pagename'] || 
!empty($qv['page_id']) ) {
      $this->is_page = true;
      $this->is_single = false;

This "is_single = false" is pointless since is_single was already false in
all conditions. But that's beside the point really. From the code you can
see that "pages" are excluded but "attachments" are included in

There is other code that depends on this:

E.g. post-template.php, get_body_class(), line 536:

if ( is_attachment() ) {

...only runs if is_single() is also true, ie. it is situated inside an if
( is_single() ) block.

But this code in query.php is meaningless now:

$this->is_singular = $this->is_single || $this->is_page ||

because is_single already includes is_attachment at this point.

It seems to me that the intent of this design was for is_single to NOT
include is_attachment.

In 3.9.2 the offending line is at query.php:1500, in trunk it is at

(There is a lot more documentation for that function (parse_query) in

There is this function in link-template.php:

function adjacent_posts_rel_link_wp_head() {
      if ( !is_singular() || is_attachment() )

That could also be written as:

function adjacent_posts_rel_link_wp_head() {
      if ( is_single() || is_page() ) {

provided that is_single would actually work as intended.

(!is_singular || is_attachment) is equivalent to !(is_singular &&
!is_attachment) which means you could also write:

function adjacent_posts_rel_link_wp_head() {
      if ( is_singular() && !is_attachment ) {

and that would currently also work.)

This code:

function get_boundary_post( $in_same_term = false, $excluded_terms = '',
$start = true, $taxonomy = 'category' ) {
      $post = get_post();
      if ( ! $post || ! is_single() || is_attachment() || ! taxonomy_exists(
$taxonomy ) )
          return null;

actually only tests for is_attachment because of the is_single() flaw.

It ought to be covered by !is_single() but that doesn't work, so an
additional test is needed.

Of course there is many more references to is_single() and you'd need to
check them all. Many templates may also have been designed around this
aberrant code. Any template that checks for is_single expecting it to only
cover single posts, would find to (its) surprise that attachments are also
covered by that code. So e.g. some sidebar code that does different things
depending on query/page type would need to test for is_attachment first or
as a form of "if (is_single && !is_attachment)".

I encountered it because I have some buggy sidebar code that bugs out on
any anomaly of this kind. Canary in the coalmine kinda thing :p.

I am not any regular contributor, nor have I ever contributed any code to
anything, but instead of writing this as a bug in TRAC I thought I would
(first) post it here.

I guess I could submit a bug and then start modifying files, make patch
files out of them, then attach them to the bug, but it is still a
modification that can affect a lot of files (potentially) so I guess I
just want to offer this just as a suggestion for now.


Bart Schouten, NL.

More information about the wp-hackers mailing list