WordPress.org

Make WordPress Core

Opened 19 months ago

Last modified 3 months ago

#22110 new enhancement

Check for current conditional

Reported by: mintindeed Owned by:
Milestone: Future Release Priority: normal
Severity: normal Version: 3.4
Component: Query Keywords: needs-patch
Focuses: Cc:

Description

More than once I've needed a programmatic way to determine what page is being displayed, for example when implementing event tracking recently:

add_action( 'wp_enqueue_scripts', function() {
	wp_enqueue_script( 'my-site', get_template_directory_uri() . '/js/mysite.js', array( 'jquery' ), '1', true );

	// Figure out what type of page we're on
	$is = '';
	foreach ( $GLOBALS['wp_query'] as $key => $value ) {
		if ( true === $value && 'is_' === substr( $key, 0, 3 ) ) {
			$is = substr( $key, 3, strlen($key) );
			break;
		}
	}
	wp_localize_script( 'my-site', 'event_tracking', array(
		'category' => $is,
	) );
} );

And then used like:

<a onclick="_gaq.push(['_trackEvent', event_tracking.category, 'more-stories', 'click']);">Action</a>

Now granted the above way to determine the current page is a little janky, and has at least one flaw (on custom post type archives because both "is_archive" and "is_post_type_archive" are set, and it will find "is_archive" first, every time). TBH this was me with a bowl of chili in one hand trying to avoid typing out "if ( is_* ) { } elseif ( is_* ) { } elseif ( is_* ) {} ...".

A saner function would probably explicitly check each conditional, which would make it a little more tedious but also more maintainable:

function where_am_i( $return = 'simple' ) {
	global $wp_query;
	
	if ( ! isset( $wp_query ) ) {
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.5' );
		return false;
	}
	
	$primary = null;
	$secondary = null;
	$tertiary = null;
	
	// Tried to maintain the hierarchy from query.php
	if ( true === $wp_query->is_robots ) {
		$primary = 'robots';
	} elseif ( true === $wp_query->is_attachment ) {
		$primary = 'attachment';
		$secondary = 'single';
		$tertiary = 'singular';
	} elseif ( true === $wp_query->is_page ) {
		$primary = 'page';
		$tertiary = 'singular';
	} elseif ( true === $wp_query->is_single ) {
		$primary = 'single';
		$secondary = 'singular';
	} elseif ( true === $wp_query->is_search ) {
		$primary = 'search';
	} elseif ( true === $wp_query->is_time ) {
		$primary = 'time';
		$secondary = 'date';
		$tertiary = 'archive';
	} elseif ( true === $wp_query->is_day ) {
		$primary = 'day';
		$secondary = 'date';
		$tertiary = 'archive';
	} elseif ( true === $wp_query->is_month ) {
		$primary = 'month';
		$secondary = 'date';
		$tertiary = 'archive';
	} elseif ( true === $wp_query->is_year ) {
		$primary = 'year';
		$secondary = 'date';
		$tertiary = 'archive';
	} elseif ( true === $wp_query->is_date ) {
		$primary = 'date';
		$secondary = 'archive';
	} elseif ( true === $wp_query->is_category ) {
		$primary = 'category';
		$secondary = 'archive';
	} elseif ( true === $wp_query->is_tag ) {
		$primary = 'tag';
		$secondary = 'archive';
	} elseif ( true === $wp_query->is_tax ) {
		$primary = 'custom_taxonomy';
		$secondary = 'archive';
	} elseif ( true === $wp_query->is_author ) {
		$primary = 'author';
		$secondary = 'archive';
	} elseif ( true === $wp_query->is_post_type_archive ) {
		$primary = 'post_type';
		$secondary = 'archive';
	} elseif ( true === $wp_query->is_feed ) {
		$primary = 'feed';
	} elseif ( true === $wp_query->is_trackback ) {
		$primary = 'trackback';
	} elseif ( true === $wp_query->is_comments_popup ) {
		$primary = 'comments_popup';
		$secondary = 'comments';
	} elseif ( true === $wp_query->is_preview ) {
		$primary = 'preview';
		$secondary = 'singular';
	} elseif ( true === $wp_query->is_admin ) {
		$primary = 'admin';
	} elseif ( true === $wp_query->is_comment_feed ) {
		$primary = 'comment_feed';
		$secondary = 'comments';
		$tertiary = 'feed';
	} elseif ( true === $wp_query->is_404 ) {
		$primary = '404';
		$secondary = 'singular';
	} elseif ( true === $wp_query->is_home ) {
		$primary = 'home';
		if ( true === $wp_query->is_posts_page ) {
			$secondary = 'posts_page';
			$tertiary = 'page';
		} else {
			$secondary = 'static_page';
		}
	}
	
	if ( 'detailed' === $return ) {
		$details = compact( $primary, $secondary, $tertiary );
		$details = array_filter( $details ); // Remove empty
		return $details;
	}
	
	// 'simple' === $return
	return $primary;
}

Should it use $wp_the_query so that it always acts on the main query?

Change History (10)

comment:1 follow-up: scribu19 months ago

Can't you just use get_body_class()?

comment:2 in reply to: ↑ 1 mintindeed19 months ago

Replying to scribu:

Can't you just use get_body_class()?

Honestly I hadn't considered that, I was mostly aware of body_class() which of course just outputs a space-delimited string.

get_body_class() looks like it would mostly work, but there are some core differences:

  • rtl is the first element of the array when is_rtl() is set, so if I wanted to use this to a theme (for example) I would have to do some funky workarounds to account for rtl support — the first element of the array wouldn't always be the primary section of the site.
  • it wouldn't work if you needed to programmaticallly find "where am I" in a feed, or anywhere that's not really user-facing.
  • no clear identifier that you're on a custom taxonomy, e.g. the second element is "tax-<taxonomy name>" so when you just want to know whether you're on a custom taxonomy page you have to do some custom parsing.

You're right that get_body_class() would work better than the hacky way I currently get the current section, for the most part.

comment:3 follow-up: nacin19 months ago

Off the top of my head, I can think of four supersets of other flags: is_time, is_date, is_archive, is_singular. So, is_time is true when is_hour, is_minute, or is_second is true. is_date is true when is_day, is_month, or is_year. is_singular when is_single or is_page. (Also is_attachment, but when is_attachment is true, is_single XOR is_page is always true.) is_archive is a superset of a whole bunch of conditionals, such as is_tag, is_category, is_tax, is_post_type_archive, etc.

I would probably just code around those supersets. It can probably be much saner than a giant if/elseif/elseif/... statement.

comment:4 follow-up: scribu19 months ago

it wouldn't work if you needed to programmaticallly find "where am I" in a feed, or anywhere that's not really user-facing.

Why not?

comment:5 in reply to: ↑ 4 mintindeed19 months ago

Replying to scribu:

it wouldn't work if you needed to programmaticallly find "where am I" in a feed, or anywhere that's not really user-facing.

Why not?

Using feeds as an example, in the default feed:

var_dump(get_body_class());

array (size=0)
  empty

In a custom feed:

var_dump(get_body_class());

array (size=3)
  0 => string 'logged-in' (length=9)
  1 => string 'admin-bar' (length=9)
  2 => string 'no-customize-support' (length=20)

comment:6 in reply to: ↑ 3 mintindeed19 months ago

Replying to nacin:

Off the top of my head, I can think of four supersets of other flags: is_time, is_date, is_archive, is_singular. So, is_time is true when is_hour, is_minute, or is_second is true. is_date is true when is_day, is_month, or is_year. is_singular when is_single or is_page. (Also is_attachment, but when is_attachment is true, is_single XOR is_page is always true.) is_archive is a superset of a whole bunch of conditionals, such as is_tag, is_category, is_tax, is_post_type_archive, etc.

I would probably just code around those supersets. It can probably be much saner than a giant if/elseif/elseif/... statement.

If I weren't trying to make it "everything for everybody" it would look more like this:

function where_am_i() {
	global $wp_query;
	
	if ( ! isset( $wp_query ) ) {
		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.5' );
		return false;
	}
	
	// Tried to maintain the hierarchy from query.php
	if ( true === $wp_query->is_robots ) {
		return 'robots';
	} elseif ( true === $wp_query->is_attachment ) {
		return 'attachment';
	} elseif ( true === $wp_query->is_page ) {
		return 'page';
	} elseif ( true === $wp_query->is_single ) {
		return 'single';
	} elseif ( true === $wp_query->is_search ) {
		return 'search';
	} elseif ( true === $wp_query->is_time ) {
		return 'time';
	} elseif ( true === $wp_query->is_date ) {
		return 'date';
	} elseif ( true === $wp_query->is_category ) {
		return 'category';
	} elseif ( true === $wp_query->is_tag ) {
		return 'tag';
	} elseif ( true === $wp_query->is_tax ) {
		return 'custom_taxonomy';
	} elseif ( true === $wp_query->is_author ) {
		return 'author';
	} elseif ( true === $wp_query->is_post_type_archive ) {
		return 'post_type';
	} elseif ( true === $wp_query->is_feed ) {
		return 'feed';
	} elseif ( true === $wp_query->is_trackback ) {
		return 'trackback';
	} elseif ( true === $wp_query->is_admin ) {
		return 'admin';
	} elseif ( true === $wp_query->is_404 ) {
		return '404';
	} elseif ( true === $wp_query->is_home ) {
		return 'home';
	}
	
	return null;
}

comment:7 SergeyBiryukov19 months ago

  • Version changed from trunk to 3.4

comment:8 mintindeed19 months ago

After a bit more testing, get_blog_class() could work but:
1) It should use in-memory caching to store the resulting body class (e.g., putting it in a global and returning the global if ! empty())
2) the first two elements of the array should be reversed in some cases. Any kind of archive-type page (author, date, etc) return "archive" as the 0th element when the useful value is held in the 1st element, while non-archive pages return the desired value (single, home, etc) in the 0th element.
3) I'd kinda want to wrap it in a helper, like: function where_am_i() { return get_body_class()[0]; }

I know I'm not the only person who would find this useful, but if you all disagree then I'll happily keep using our local copy.

comment:9 nacin3 months ago

  • Component changed from General to Query

comment:10 wonderboymusic3 months ago

  • Keywords needs-patch added
  • Milestone changed from Awaiting Review to Future Release
Note: See TracTickets for help on using tickets.