Introduction
Conditional tags answer a simple question inside your code: what kind of page is this? Are we on the front page, a single post, a category archive, a search results page, or a 404? Once you can ask that, one template or one function can behave correctly in every context.
This article explains what conditional tags are, lists the ones you will use most, and shows the real patterns where they matter, such as enqueuing a script only where it is needed or changing layout per page type.
You will learn:
- What a conditional tag is and what it returns
- The most common conditionals for posts, pages, archives, and special pages
- Where conditional tags work and the timing rule that catches everyone
- Practical patterns and the mistakes to avoid
This builds on the template tags and Loop articles. Conditional tags are how you decide which template tags to run where.
What Is a Conditional Tag?
A conditional tag is a WordPress function that returns a boolean, true or false, describing the current request. You use them in if statements to branch your logic.
<?php
if ( is_single() ) {
// Code that runs only on single posts.
}
Conditional tags read from the main query, which WordPress builds from the URL before your template loads. That is why is_single(), is_page(), and the rest already know the answer by the time your theme runs.
The Timing Rule You Must Know
Conditional tags only work after the main query is set up, which happens on the wp action. If you call a conditional too early, for example directly inside a plugin file or on a very early hook, it returns false or throws a notice because the query does not exist yet.
The safe rule: use conditional tags inside template files, or inside callbacks on template_redirect, wp, or later hooks. For enqueuing assets, the wp_enqueue_scripts hook is late enough.
<?php
// Wrong: runs too early, query not ready.
// add_action( 'init', function() { if ( is_single() ) { ... } } );
// Right: wp_enqueue_scripts runs after the query is built.
add_action( 'wp_enqueue_scripts', function() {
if ( is_page( 'contact' ) ) {
wp_enqueue_script( 'contact-map' );
}
} );
Front Page and Home Conditionals
- is_front_page() – True on the site front page, whether that is the latest posts or a static page set in the reading settings.
- is_home() – True on the main blog posts index. On a default setup this equals the front page; with a static front page, is_home() is the separate posts page.
The front page versus home distinction is the most confused pair in WordPress. Remember: is_front_page() is the site root; is_home() is the blog stream. Use is_front_page() for "the homepage", and is_home() for "the blog listing".
Single Content Conditionals
- is_single() – True on a single post (and single custom post type entries, but not pages). Pass an ID, slug, or title to narrow it.
- is_page() – True on a static page. Accepts an ID, slug, or title, for example is_page( 'about' ).
- is_singular() – True on any single content view: posts, pages, and custom post types. Use it when you mean any single item.
- is_sticky() – True if the current post is marked sticky.
- is_attachment() – True on an attachment page.
<?php
// Any single post of a specific custom post type.
if ( is_singular( 'product' ) ) {
// Product-specific markup.
}
Archive Conditionals
- is_archive() – True on any archive: category, tag, author, date, taxonomy, or post type archive.
- is_category() – True on a category archive. Accepts a category to test a specific one.
- is_tag() – True on a tag archive.
- is_tax() – True on a custom taxonomy archive. Pass the taxonomy and optionally a term.
- is_author() – True on an author archive.
- is_date() – True on any date-based archive, with is_year(), is_month(), and is_day() for finer checks.
- is_post_type_archive() – True on the archive page of a custom post type.
Special Page Conditionals
- is_search() – True on a search results page.
- is_404() – True when no content matched the request.
- is_paged() – True on page two and beyond of any paginated list.
- is_admin() – True inside the admin dashboard. Note this is not a security check; it only tells you the request targets wp-admin.
- is_user_logged_in() – True when a user is signed in. Useful for showing member-only content.
Combining Conditional Tags
Conditional tags are ordinary booleans, so you combine them with normal PHP logic.
<?php
// A sidebar everywhere except single posts and the 404 page.
if ( ! is_single() && ! is_404() ) {
get_sidebar();
}
// A promo banner only on the blog or category archives.
if ( is_home() || is_category() ) {
get_template_part( 'parts/promo' );
}
Practical Pattern: Conditionally Loading Assets
The best-known use of conditional tags is loading CSS or JavaScript only where it is needed, which keeps other pages lean.
<?php
add_action( 'wp_enqueue_scripts', function() {
// Load the gallery script only on single portfolio items.
if ( is_singular( 'portfolio' ) ) {
wp_enqueue_script(
'portfolio-gallery',
get_theme_file_uri( 'assets/js/gallery.js' ),
array(),
'1.0',
true
);
}
} );
Loading a script everywhere when only one template uses it wastes bandwidth and slows pages. A single conditional fixes that.
Practical Pattern: Adjusting the Main Query by Context
Conditional tags are essential inside pre_get_posts, where you change the main query for specific contexts only. Always guard with is_main_query() and is_admin() so you do not affect the dashboard or secondary queries.
<?php
add_action( 'pre_get_posts', function( $query ) {
if ( $query->is_main_query() && ! is_admin() && $query->is_category() ) {
$query->set( 'posts_per_page', 12 );
}
} );
Notice the conditional here is called as a method on the query object ($query->is_category()) inside pre_get_posts. That checks the query being modified rather than the global one, which is the correct approach in that hook.
When Conditionals Are Not Enough: get_queried_object()
Conditional tags tell you the type of page. When you also need the specific thing being viewed, the current category, author, or post type object, use get_queried_object(). It returns whatever the main query is currently showing.
<?php
if ( is_category() ) {
$term = get_queried_object(); // a WP_Term object
echo esc_html( $term->name );
echo esc_html( $term->count . ' posts' );
}
if ( is_author() ) {
$author = get_queried_object(); // a WP_User object
echo esc_html( $author->display_name );
}
get_queried_object() pairs naturally with conditional tags: the conditional confirms the context, and the queried object gives you the data for it. Use get_queried_object_id() when you only need the ID.
Best Practices
- Call conditional tags after the main query exists: in templates, or on wp_enqueue_scripts, template_redirect, or later.
- Use is_front_page() for the site homepage and is_home() for the blog posts index; do not mix them up.
- Prefer is_singular() and is_archive() when you mean any single or any archive, rather than listing every type.
- Inside pre_get_posts, guard with is_main_query() and ! is_admin(), and call conditionals on the query object.
- Remember is_admin() is not a permission check; use current_user_can() for capabilities.
Common Mistakes
Confusing is_home() and is_front_page()
On a static front page setup, is_home() is the blog page and is_front_page() is the static homepage. Targeting the wrong one is the most common conditional bug. Decide whether you mean the site root or the blog stream.
Calling conditionals too early
Used on init or in a plugin file body, conditional tags run before the query exists and return false. Move the logic to wp_enqueue_scripts or template_redirect.
Treating is_admin() as a security gate
is_admin() only reports that the request is for the admin area, including admin-ajax. It does not verify permissions. Use current_user_can() and nonces for security.
Forgetting is_main_query() in pre_get_posts
Without that guard, your changes hit every secondary query and the admin, causing strange, hard-to-trace behaviour. Always check is_main_query() and exclude admin.
Troubleshooting
My conditional always returns false
It is almost always a timing issue. Confirm the code runs after the query is built. In a plugin, wrap it in a hook like template_redirect rather than running it at load time.
is_page() does not match my page
Check what you pass. is_page() matches by ID, slug, or title, and the slug must be the page slug, not the menu label. Dump get_queried_object_id() to see the real ID.
A change meant for the front end also affects the dashboard
Add ! is_admin() to the condition. Hooks like pre_get_posts fire in the admin too, so front-end-only logic must exclude it.
Frequently Asked Questions
What is the difference between is_home() and is_front_page()?
is_front_page() is true on the site front page regardless of whether it shows posts or a static page. is_home() is true on the blog posts index. With a static front page they are two different pages; on a default setup they coincide.
When can I safely use conditional tags?
After the main query is built, which is the wp action. In practice that means inside template files and on hooks like wp_enqueue_scripts, template_redirect, or wp. Avoid init and earlier.
What is the difference between is_single() and is_singular()?
is_single() matches single posts and custom post type entries but not pages. is_singular() matches any single view including pages. Use is_singular() when you mean any single item.
Can I use conditional tags inside pre_get_posts?
Yes, but call them as methods on the passed query object, such as $query->is_category(), and guard with $query->is_main_query() and ! is_admin(). This targets the query being modified rather than the global one.
Is is_admin() a security check?
No. It only tells you the request is for the admin area. For access control, use capability checks with current_user_can() and verify nonces on actions.
Conclusion
Conditional tags turn a fixed template into one that adapts to every kind of page. With a handful of them, is_front_page(), is_home(), is_single(), is_page(), is_archive(), is_search(), and is_404(), you can target almost any context precisely.
Keep the timing rule and the home-versus-front-page distinction in mind, and guard your query modifications properly, and conditional tags become one of the most reliable tools in your theme. They are the decision layer that sits between the template hierarchy and your template tags.
Next, the classic template hierarchy article shows how WordPress already picks a template per context, and the pre_get_posts article shows how to reshape the main query for specific pages.