WHA Docs

Gotchas

Known issues, build pitfalls, caching quirks, and lessons learned from maintaining the site. Read this before touching anything unfamiliar.

Every item on this page comes from an actual incident or discovery during development. If something on this list seems overly specific, it's because it bit someone.

PostCSS Nested @apply Silently Fails

Nested child combinators with @apply do not compile and produce no error:

/* This silently fails — the rule is dropped from output */
.parent {
  > svg {
    @apply mr-1.5;
  }
}

The fix: Use plain CSS for nested child combinator rules instead of @apply:

.parent {
  > svg {
    margin-right: 0.375rem;
  }
}

This is a limitation with Tailwind's nesting plugin (tailwindcss/nesting). There's no error, no warning — the rule just disappears from the compiled CSS.

wp_kses SVG Attribute Casing

When using wp_kses() to sanitize SVG markup, the allowed attributes array must use lowercase keys — even for camelCase SVG attributes like viewBox.

// WRONG — viewBox gets silently stripped
$allowed = ['svg' => ['viewBox' => true]];

// CORRECT — wp_kses lowercases source attributes before lookup
$allowed = ['svg' => ['viewbox' => true]];

PHP array keys are case-sensitive, but wp_kses lowercases all source attribute names before checking the allowed list. Mixed-case keys cause attributes to be silently stripped with no warning.

Stale Content After PHP Changes

PHP-FPM picks up file changes immediately, but the object cache (Redis in local dev) may serve stale output. If you see stale content after editing a component or template, flush caches. See Caching for the full debugging checklist.

Provider Listing Renders Client-Side, Not Server-Side

The provider archive at /providers/ renders cards via AJAX, not server-side PHP. This means the listing requires JavaScript and search engines may not index individual provider cards from this page. Individual provider detail pages are server-rendered and indexable. See Custom Post Types > Providers for details.

Content-Hash Cache Busting Requires Production Build

In development (npm run dev), Laravel Mix doesn't generate the mix-manifest.json with version hashes. The yax_asset_version() function falls back to the theme version. For proper cache busting:

cd src/wp-content/themes/wha2025
npm run production

Always run the production build before deploying. The compiled assets in assets/dist/ are tracked in git, so they must be committed.

wp-admin Lives at /wp/wp-admin/

Because WordPress core is installed in the wp/ subdirectory, the admin is at /wp/wp-admin/, not /wp-admin/. Nginx has redirects for the bare paths, but direct links to /wp-admin/ in documentation or bookmarks should use the full path.

The 000yax-loader.php Bootstrap File Is Gitignored

The file 000yax-loader.php in mu-plugins/ is auto-generated by the entrypoint script (03-composer-install.sh). It's not tracked in git and not part of the deploy artifact — it gets created on container startup.

If yax mu-plugins aren't loading, check that this file exists. The entrypoint script creates it whenever yax-loader is installed:

# Check if it exists
ls src/wp-content/mu-plugins/000yax-loader.php

# Manually create it if needed
echo "<?php require_once __DIR__ . '/yax-loader/bootstrap.php';" > src/wp-content/mu-plugins/000yax-loader.php

Mapbox Maps Only Load on Pages That Need Them

The Mapbox GL JS and Supercluster scripts are conditionally enqueued in functions.php. They only load on:

  • Provider single pages (single-wha_providers)
  • Location single pages (single-wha_locations)
  • Provider/location archive pages
  • Any page with a find-a-provider or find-a-location ACF flexible content layout

If maps aren't showing on a page, check that the page has the correct ACF layout or that the template matches one of the conditional checks.

AccessiBe Widget Is Inline, Not a Plugin

The AccessiBe ADA compliance widget is loaded via wp_add_inline_script() in functions.php, not through the accessibe WordPress plugin. The inline script creates a <script> element dynamically. Both the plugin and the inline loader exist — the inline version is what actually runs on the frontend.

N+1 Provider Queries Are Mitigated by Caching

The provider data handler loads each provider individually — a classic N+1 pattern with ~130 providers. It's mitigated by transient caching at the API layer — the AJAX collection endpoint caches the full response, preventing repeated N+1 queries within the TTL window. If provider data appears stale, see Caching.

Theme Assets Must Be Committed

Unlike many modern setups, the compiled assets in assets/dist/ are tracked in git. The build process (npm run build) copies them into dist/ as-is. If you forget to commit updated assets after running npm run production, production will serve stale CSS/JS.

WORDPRESS_BLOCK_PLUGINS Deletes, Not Deactivates

The plugin-blocking mechanism physically removes plugin directories on every container start. Manually-installed plugins added to this list would be permanently lost. See Plugin System > Blocking Plugins.

On this page