Acquia FE Specialist (D10) study materials
Acquia FE Specialist (D10) study resources

Preprocess Order and the Vanishing Body Class

Acquia FE Specialist (D10) · Put your knowledge to work in context.

All case studies

Preprocess Order and the Vanishing Body Class

A developer adds a body class in the theme's .theme file using function mytheme_preprocess_body(&$variables) { $variables['attributes']['class'][] = 'has-promo'; }. The class appears on the homepage but not on node pages. A colleague's module also adds a body class via hook_preprocess_HOOK and that one shows everywhere. The theme also has a mytheme_preprocess_page that rebuilds $variables['page']['#attributes']. Template caching is enabled and the developer insists they cleared the cache several times. The site uses a base theme that itself implements hook_preprocess_HOOK for html and page. The team wants a reliable, cache-safe way to add the class on all pages.

1. Explain why the body class is inconsistent and identify the most likely ordering/caching cause.

Read the worked answer

Preprocess hooks run in a specific order: modules first, then the base theme, then the active theme, each sorted by weight/name. If the class is missing only on some routes, the culprit is usually not the hook name but what the hook targets.

Key reasoning:

  1. body attributes are often populated from page or html preprocess. If mytheme_preprocess_page overwrites #attributes on the page array, it can discard classes added earlier by the base theme or other preprocessors.
  2. Cache context: body classes derived from route or content must declare cache contexts/tags, otherwise cached responses (e.g., anonymous page cache) can serve a variant without the class.
  3. The hook itself is valid; the inconsistency points to a downstream overwrite or a cached render array, not a typo.

Diagnosis: inspect the order of preprocess execution and confirm whether preprocess_page reassigns rather than merges attributes. Also verify that the class is not being added conditionally based on a variable only present on the front page.

2. Propose a robust fix that survives caching and theme hierarchy.

Read the worked answer

Merge rather than overwrite, and be explicit about cacheability.

  • In preprocess_page, use $variables['page']['#attributes']['class'][] = 'has-promo'; or better, target html/body attributes through the appropriate preprocess and append, never reassign the whole #attributes array.
  • If the class depends on content or route, add the corresponding cache context (e.g., route, url.path) and cache tags so the render cache varies correctly.
  • Prefer adding the class in hook_preprocess_html for attributes on <body> when no content dependency exists, since that is the canonical place and runs reliably.
  • Clear caches and verify with the render cache enabled, testing anonymous and authenticated responses.

Reasoning: the class must be (a) appended after base theme processing, and (b) declared cacheable so the page cache does not serve a stale variant.