Sometimes a page needs a one-off script that calls a component's methods — often injected
through the HFCM plugin (Header Footer Code Manager) rather than living in the theme.
The Globals registry exists precisely for this: it exposes
every registered component at window.LeaseLeads_Theme.components, so an outside script
can look up a class by moniker and reach a specific element's instance.
LeaseLeads_Theme.components.get('Intro').get(el).someMethod()
The catch is timing.
1. Place the script in the FOOTER
Components boot lazily and asynchronously — Deferred does the real instantiation on first interaction (WP-Rocket-delayed in production). A script in the header runs long before any instance exists. Put HFCM snippets that touch components in the footer, and even then assume the instance may not be there yet at eval time.
LeaseLeads_Theme.components.get('Intro') can return the class while
.get(el) returns undefined — the class registered, but that element's instance
hasn't been constructed yet. Never assume the instance exists the moment your script
runs.
2. Prefer the lifecycle event
The robust approach is to wait for the element to tell you it's ready. Every instance
fires an initialized lifecycle event on its element in two flavours: a generic
module.initialized and a moniker-scoped intro.initialized. Both carry the live
instance on event.detail.instance. Listen, and you get the instance exactly when it
becomes usable — no polling, no race.
<!-- HFCM: Footer -->
<script>
document.querySelectorAll('.intro').forEach(el => {
el.addEventListener('intro.initialized', event => {
const intro = event.detail.instance
// The instance is fully booted and initialized here.
intro.carousel?.go(0)
})
})
</script>
Use the moniker-scoped name (intro.initialized) when you know the component; use the
generic module.initialized when a listener is shared across module types.
The moniker is a public API contract. intro.initialized and
components.get('Intro') both depend on the string Intro staying stable — it survives
Vite's minification precisely so external scripts can rely on it. Renaming a component's
moniker is a breaking change for any HFCM snippet.
3. Or pull the instance directly
If your script runs after boot — for example behind a user click, well past the deferred init — you can skip the event and read the instance straight from the registry. Guard for the not-yet-ready case.
<!-- HFCM: Footer -->
<script>
document.querySelector('#open-intro')?.addEventListener('click', () => {
const Intro = LeaseLeads_Theme.components.get('Intro')
const el = document.querySelector('.intro')
const intro = Intro?.get(el)
if ( ! intro ) return // not booted yet — bail rather than throw
intro.carousel?.go(1)
})
</script>
components.get('Intro') resolves by moniker (or Vite's built name); .get(el) returns the
registered instance for that element, or undefined if it hasn't been constructed. Because
the click happens long after page load, the instance is reliably present — but the guard
keeps the snippet safe either way.
4. Guard against the registry not being ready
On a very fast interaction the theme's registry may not have attached yet. Globals
dispatches a leaseleads.theme.loaded event on document (and sets
window.LeaseLeads_Theme.loaded = true) once it is available, so the belt-and-braces
pattern is:
<script>
function ready(fn) {
if ( window.LeaseLeads_Theme?.loaded ) return fn()
document.addEventListener('leaseleads.theme.loaded', fn, { once: true })
}
ready(() => {
document.querySelectorAll('.intro').forEach(el => {
el.addEventListener('intro.initialized', e => e.detail.instance.carousel?.go(0))
})
})
</script>
Related
- The Globals registry — the external API, moniker lookup, and the event bus.
- The lifecycle — the
initializedevent and when instances actually exist. data-*options — configuring a component from PHP instead of scripting it.