Havenlytics wires its subsystems together through a lightweight service container rather than global state. Two objects cooperate: the HvnlyNab singleton holds a small private container and exposes a public accessor surface, while Bootstrap owns the full service registry populated during boot. This guide explains how to reach each service from extension code, which accessors are public, and which services are effectively internal. It builds on the Bootstrap Process, where these services are registered.
The HvnlyNab container and __get magic
The HvnlyNab singleton keeps a private $container array. The class implements PHP’s __get magic method to lazy-load two shared objects on first access — the Helper and the DB — and __isset to report their presence. This means the objects are only constructed when something actually asks for them.
<?php
$plugin = HVNLY_NAB();
// Lazy-loaded via __get on first access:
$helper = $plugin->get_helper(); // preferred accessor
$database = $plugin->database(); // preferred accessor
Note: Prefer the named accessors (
get_helper(),database()) over relying on magic property access. The accessors are the stable, documented contract; the container is private.
Public accessors on the singleton
Everything you need in day-to-day extension work is reachable through the HVNLY_NAB() singleton. These are the public methods and globals.
| Accessor | Returns | Purpose |
|---|---|---|
HVNLY_NAB() | HvnlyNab | Global accessor for the plugin singleton. |
HVNLY_NAB_engine() | engine | Global shortcut to the property engine. |
HvnlyNab::init() | self | Returns/creates the singleton instance. |
->get_helper() | Helper | The shared helper service (lazy). |
->database() | Database | The database access layer (lazy). |
->engine() | engine | The property engine (or fallback engine). |
->clear_cache() | void | Clears plugin caches. |
->version() | string | Plugin version (3.3.1). |
->plugin_path() | string | Absolute plugin directory path. |
->assets_url( $file = '' ) | string | URL to a bundled asset. |
__get($prop) / __isset($prop) | mixed | Lazy Helper/DB access. |
The Bootstrap service registry
The Bootstrap object is the real registry. During init() it fills a services map and exposes typed getters. Because Bootstrap itself lives on the singleton’s private container, its getters are effectively internal — extensions normally use the HVNLY_NAB() accessors above, which delegate where appropriate.
| Bootstrap method | Returns |
|---|---|
get_engine() | The property engine (real or fallback). |
get_service($service) | Any registered service by key. |
get_database() | The Database service. |
get_helper() | The Helper service. |
The service keys registered during boot are: Helper, DB, rest_api, settings_manager, style_generator, cache_manager, hook_manager, admin, cache_admin, workspace (admin context), and frontend (frontend/AJAX context). Only Helper, DB, and the engine have dedicated public accessors; the rest are reachable via $bootstrap->get_service('...') but, since $bootstrap is on the private container, are effectively internal.
Warning: Do not build your integration around
get_service('settings_manager')or other internal keys. They are not part of the public contract and may change. Use singleton accessors, documented hooks, and the REST API instead.
The fallback engine
If the real \HvnlyEngine class is unavailable, Bootstrap::init_engine() creates an anonymous fallback engine so calls to engine() never fatal. The fallback implements a defined method set: clear_all_cache(), get_cache_stats(), get_performance_metrics(), clear_transients_by_pattern($pattern), update_config($config), and get_config(). Your code can safely call these on HVNLY_NAB()->engine() whether or not the real engine is present.
<?php
$engine = HVNLY_NAB()->engine();
// Available on both the real engine and the anonymous fallback:
$stats = $engine->get_cache_stats();
$metrics = $engine->get_performance_metrics();
$engine->clear_transients_by_pattern( 'hvnly_search_' );
Singleton services
Several core services are singletons in their own right, obtained via ::get_instance() and registered into the Bootstrap map. Understanding which are singletons clarifies why you must never instantiate them yourself.
| Service | Obtained via | Role |
|---|---|---|
SettingsManager | SettingsManager::get_instance() | Central settings store. |
DynamicStyleGenerator | DynamicStyleGenerator::get_instance() | Front-end CSS generation. |
CacheManager | new CacheManager() | Transient-backed cache; mostly static methods. |
HookManager | new HookManager() | Registers runtime WordPress hooks. |
EnterpriseCache | EnterpriseCache::get_instance() | Section cache for DnD builder sections. |
Note:
CacheManagerexposes static cache operations (clear_expired_cache,get_cache_stats,clear_all_cache,clear_transients_by_pattern). You do not need the container to call them, but preferHVNLY_NAB()->clear_cache()for a full clear.
Access patterns
These are the canonical, supported ways to reach Havenlytics functionality from your own plugin or theme. Use them consistently.
<?php
add_action( 'hvnly_loaded', function () {
// 1. The property engine.
$engine = HVNLY_NAB()->engine();
// 2. The shared helper.
$helper = HVNLY_NAB()->get_helper();
// 3. The database access layer.
$db = HVNLY_NAB()->database();
// 4. Clear all plugin caches (e.g. after a bulk data change).
HVNLY_NAB()->clear_cache();
// 5. Version and path metadata.
$version = HVNLY_NAB()->version(); // '3.3.1'
$path = HVNLY_NAB()->plugin_path();
$asset = HVNLY_NAB()->assets_url( 'img/marker.svg' );
} );
Tip: Wrap access in the
hvnly_loadedaction so the container is guaranteed to be populated. Calling these accessors before boot completes can return incomplete state.
Security: Reaching a service does not bypass WordPress capability and nonce checks. When you trigger privileged operations (like
clear_cache()) from a request handler, gate them with a capability check and a verified nonce, exactly as the built-in cache AJAX handlers do.
Core classes reference
A quick map of the container-related Core classes and what they do, for orientation when reading the source.
| Class | Namespace | Responsibility |
|---|---|---|
HvnlyNab | (global) | Plugin singleton; private container; public accessors. |
Bootstrap | HvnlyNab\Core | Service orchestrator and registry; engine/service getters. |
SettingsManager | HvnlyNab\Core | Central settings store (singleton). |
DynamicStyleGenerator | HvnlyNab\Core | Front-end CSS generation (singleton). |
CacheManager | HvnlyNab\Core | Transient cache operations (static). |
CacheInvalidator | HvnlyNab\Core | Clears search/query caches on property save/delete. |
EnterpriseCache | HvnlyNab\Core | DnD section cache (singleton), gated on cache enabled. |
HookManager | HvnlyNab\Core | Registers runtime WordPress hooks. |
Best practices
- Reach services only through the
HVNLY_NAB()accessors and thehvnly_loadedaction. - Treat
get_service()keys other than the documented accessors as internal. - Never call
newon singleton services; use theirget_instance()or the plugin accessors. - Call engine methods (like
get_cache_stats()) knowing the fallback engine implements the same surface.
Performance recommendations
- Rely on lazy loading: the Helper and DB are built only on first access, so touching them adds no cost until you need them.
- Use
clear_transients_by_pattern()to clear a targeted cache namespace instead of flushing everything when possible. - Prefer
HVNLY_NAB()->clear_cache()after batched writes rather than clearing on every single write.
Common mistakes
- Depending on internal service keys. Only Helper, DB, and the engine have public accessors.
- Accessing services before boot. Use
hvnly_loaded; earlier access can return incomplete state. - Instantiating singletons. This breaks the single-instance guarantee the plugin relies on.
- Skipping capability/nonce checks when invoking privileged accessors from request handlers.