How to use body_class to condition behavior in JS in WordPress

Contents

Overview

This tutorial explains how to use WordPresss body_class output to conditionally control JavaScript behavior across templates, pages, post types, taxonomies and custom conditions. Youll learn:

  • How WordPress generates body classes and how to add custom classes safely.
  • Patterns for detecting classes in JavaScript (vanilla and jQuery).
  • Advanced patterns: DOM-based routing, performance tips, conditional script loading and security considerations.
  • Complete, copy-paste-ready code examples (PHP and JavaScript) that show real-world usage.

What body_class does and why it matters for JS

WordPresss body_class() function prints a list of classes on the ltbodygt element representing the current page context: template name, page id, post type, taxonomy terms, logged-in state and more. These classes give your JavaScript an easy, semantic way to detect which behavior to run without coupling scripts tightly to specific URLs or fragile selectors.

Two main approaches to condition behavior:

  1. Enqueue and execute scripts conditionally in PHP (preferred for performance when you can determine conditions in PHP).
  2. Load a shared script and branch in JS using body classes (useful when one script handles many contexts or when behavior is best kept in client-side code).

Typical body_class entries you will see

  • home, blog
  • single, single-post, single-post-{postID}
  • page, page-id-{ID}, page-template, page-template-template-contact
  • archive, tax-{taxonomy}-{term}, category-{slug}
  • logged-in (when user is logged in)
  • post-type-archive-{post_type}

Adding custom classes to body_class from PHP

When you need a custom marker on the body for JS to pick up, use the body_class filter. Always sanitize any class you add with sanitize_html_class to avoid malformed classes and XSS vectors.

Example: Add a custom class based on a custom field or condition

Place this in your themes functions.php or a plugin file. Note the use of sanitize_html_class.


Basic JavaScript detection techniques

Once classes are present on the body you can detect them in JS in multiple ways. Prefer classList.contains for modern browsers fall back to string checks for older browsers if necessary.

Vanilla JS — modern and recommended

// Run behavior when DOM is ready (recommended)
document.addEventListener(DOMContentLoaded, function() {
  var body = document.body

  if ( body.classList.contains(home) ) {
    // Home-specific code
    initHome()
  }

  if ( body.classList.contains(page-contact) ) {
    // Contact page behavior
    initContactForm()
  }

  if ( body.classList.contains(product-featured) ) {
    // Behavior for featured products
    initFeaturedProduct()
  }
})

function initHome() {
  console.log(Home initialized)
}
function initContactForm() {
  console.log(Contact form behavior initialized)
}
function initFeaturedProduct() {
  console.log(Featured product behavior initialized)
}

jQuery — using hasClass

jQuery(function(){
  var body = (document.body)

  if ( body.hasClass(home) ) {
    initHome()
  }

  if ( body.hasClass(page-contact) ) {
    initContactForm()
  }
})

DOM-based routing pattern (Organized approach)

DOM-based routing organizes per-page JS into named modules and runs those modules based on body classes. Its especially useful for medium-to-large themes with many conditional behaviors. The pattern below maps body classes to functions and executes them in a predictable order.

/
  DOM-based routing simple implementation

  Body classes: if a class contains dashes (page-contact) its converted to an underscore-key (page_contact)
  so object property names are valid identifiers.
/

(function(window, document){
  var Router = {
    // Common code runs on all pages
    common: {
      init: function() {
        // Code fired on all pages
        console.log(Common init)
      }
    },
    // Home page module (body class: home)
    home: {
      init: function() {
        console.log(Home init)
      }
    },
    // Contact page (body class: page-contact -> key: page_contact)
    page_contact: {
      init: function() {
        console.log(Contact page init)
      }
    },
    product_featured: {
      init: function() {
        console.log(Featured Product init)
      }
    }
  }

  function fire(module, fnName) {
    var nav = Router
    fnName = fnName  init
    if ( module !==   nav[module]  typeof nav[module][fnName] === function ) {
      nav[module][fnName]()
    }
  }

  function loadEvents() {
    fire(common)

    // Run modules based on body classes
    var classes = document.body.className.replace(/-/g, _).split(/s /)
    for ( var i = 0 i < classes.length i   ) {
      fire(classes[i])
    }
  }

  document.addEventListener(DOMContentLoaded, loadEvents)

})(window, document)

Why convert dashes to underscores?

JavaScript object property names cannot be used as bare identifiers if they contain dashes (e.g., Router[page-contact] works but Router.page-contact is invalid). Converting dashes to underscores lets you use Router.page_contact style access, which is convenient for methods and better for minification/readability.

Mapping multiple body classes to a single behavior

Sometimes you want the exact same behavior to run for multiple classes (for example multiple templates should get the same JS). Use a mapping object to register handlers for several class names.

document.addEventListener(DOMContentLoaded, function(){
  var handlers = {
    single-post: function(){ initSinglePost() },
    single-portfolio: function(){ initSinglePost() }, // share same handler
    page-contact: function(){ initContactForm() }
  }

  var bodyClasses = document.body.className.split(/s /)
  bodyClasses.forEach(function(c){
    if ( handlers[c] ) handlers[c]()
  })
})

Conditional script loading using body_class (and why PHP conditional enqueuing is often better)

If you can determine the need for a script on the server side, enqueue it conditionally in PHP with is_page(), is_singular(), is_post_type_archive(), etc. That prevents unnecessary downloads. Use body_class-based checks in JS when the same script serves multiple contexts or when you cannot easily determine conditions on the server.

Example: Enqueue a shared script but activate features via body class


Then site.js contains the DOM-based routing or class checks shown earlier. This is ideal when you want one logical JS bundle to handle many page types.

Performance considerations

  • Prefer server-side conditional script enqueuing when you can (fewer bytes transferred).
  • If using a single script to handle many contexts, perform class detection once and map to functions instead of repeated DOM queries.
  • Use document.body.classList.contains (fast) instead of string indexOf where possible.
  • Debounce or throttle event handlers (scroll, resize) and only attach them on relevant pages.
  • Place scripts in the footer or use async/defer to avoid blocking rendering ensure DOMContentLoaded or DOM-ready before accessing classes.

Security and sanitization

  • Always sanitize classes you add in PHP with sanitize_html_class to avoid invalid or malicious classes.
  • Do not inject arbitrary user input into classes without sanitizing. If adding user-generated values, validate and escape.
  • When outputting data into inline scripts, use wp_localize_script or wp_add_inline_script with esc_js on dynamic values to avoid XSS.

Safe example: adding a class derived from a sanitized value


Advanced: Using body classes for feature-flags or A/B tests

body_class can be used by server code to output A/B test buckets or feature flags (e.g., bucket-A, bucket-B) so tracking and front-end behavior can respond accordingly without additional API calls. When doing this:

  • Make sure the assignment is deterministic (or set via server session/cookie) to avoid a flicker or inconsistent user experience.
  • Sanitize values as described earlier.
  • Prefer the server to enqueue only the necessary assets if bucket differences are asset-heavy.

Debugging tips

  • Open DevTools and inspect document.body.className to confirm classes are present.
  • Console log results when testing conditional branches: console.log(Running contact init) to ensure the right block ran.
  • Remember that class names may include template-file prefixes and the page template slug check exact body_class output for the theme you’re working on.
  • Use view-source or the inspector to verify that body_class() is present in your themes header.php and that the classes printed match what your PHP conditions produce.

Common pitfalls and how to avoid them

  • Relying on a body class that doesnt exist — inspect output first.
  • Using dashed class names as object keys in JS without converting or using bracket notation — either convert to underscores or use bracket lookups: Router[page-contact].
  • Adding classes without sanitizing — use sanitize_html_class.
  • Attaching heavy event handlers on every page — attach only when the class indicates its needed.

Complete mini example: Add a custom class in PHP and run a matching JS module

Step 1: Add a PHP filter to add a class for a custom condition.


Step 2: Enqueue a unified script that branches based on body class (functions.php)


Step 3: site.js uses DOM-based routing to execute features only when classes exist.

// assets/js/site.js
document.addEventListener(DOMContentLoaded, function() {
  var body = document.body

  // Common bootstrap
  (function common() {
    console.log(Common site behaviors loaded.)
  })()

  // Feature: front page banner
  if ( body.classList.contains(front-featured) ) {
    initFrontBanner()
  }

  // Feature: featured post enhancements
  if ( body.classList.contains(post-featured) ) {
    initFeaturedPost()
  }

  function initFrontBanner() {
    console.log(Initializing front page banner)
    // Example DOM manipulation
    var el = document.querySelector(.hero)
    if ( el ) {
      el.classList.add(hero--featured)
    }
  }

  function initFeaturedPost() {
    console.log(Enhancing featured post UI)
    // Example enhancement
  }
})

Summary and best-practice checklist

  • Prefer server-side conditional enqueuing when you can determine the need in PHP.
  • When using body_class for client-side branching, prefer document.body.classList.contains and run logic on DOMContentLoaded.
  • Sanitize classes in PHP using sanitize_html_class.
  • Organize code using a DOM-based routing pattern for maintainability.
  • Profile and minimize event listeners and DOM queries add behavior only for pages that need it.

Useful WordPress references

Final note

Using body classes is a robust and semantic approach for conditional JavaScript behavior. Combine careful PHP-side class assignment, sanitization, and clean JS detection patterns to make site behavior predictable, efficient and maintainable.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Leave a Reply

Your email address will not be published. Required fields are marked *