Skip to main content
Skip to main content

Developers Doc

Service Container

6 mins read 5 Views 3+

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.

AccessorReturnsPurpose
HVNLY_NAB()HvnlyNabGlobal accessor for the plugin singleton.
HVNLY_NAB_engine()engineGlobal shortcut to the property engine.
HvnlyNab::init()selfReturns/creates the singleton instance.
->get_helper()HelperThe shared helper service (lazy).
->database()DatabaseThe database access layer (lazy).
->engine()engineThe property engine (or fallback engine).
->clear_cache()voidClears plugin caches.
->version()stringPlugin version (3.3.1).
->plugin_path()stringAbsolute plugin directory path.
->assets_url( $file = '' )stringURL to a bundled asset.
__get($prop) / __isset($prop)mixedLazy 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 methodReturns
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: HelperDBrest_apisettings_managerstyle_generatorcache_managerhook_manageradmincache_adminworkspace (admin context), and frontend (frontend/AJAX context). Only HelperDB, 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.

ServiceObtained viaRole
SettingsManagerSettingsManager::get_instance()Central settings store.
DynamicStyleGeneratorDynamicStyleGenerator::get_instance()Front-end CSS generation.
CacheManagernew CacheManager()Transient-backed cache; mostly static methods.
HookManagernew HookManager()Registers runtime WordPress hooks.
EnterpriseCacheEnterpriseCache::get_instance()Section cache for DnD builder sections.

Note: CacheManager exposes static cache operations (clear_expired_cacheget_cache_statsclear_all_cacheclear_transients_by_pattern). You do not need the container to call them, but prefer HVNLY_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_loaded action 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.

ClassNamespaceResponsibility
HvnlyNab(global)Plugin singleton; private container; public accessors.
BootstrapHvnlyNab\CoreService orchestrator and registry; engine/service getters.
SettingsManagerHvnlyNab\CoreCentral settings store (singleton).
DynamicStyleGeneratorHvnlyNab\CoreFront-end CSS generation (singleton).
CacheManagerHvnlyNab\CoreTransient cache operations (static).
CacheInvalidatorHvnlyNab\CoreClears search/query caches on property save/delete.
EnterpriseCacheHvnlyNab\CoreDnD section cache (singleton), gated on cache enabled.
HookManagerHvnlyNab\CoreRegisters runtime WordPress hooks.

Best practices

  • Reach services only through the HVNLY_NAB() accessors and the hvnly_loaded action.
  • Treat get_service() keys other than the documented accessors as internal.
  • Never call new on singleton services; use their get_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.

Need more help?

Can't find what you're looking for? Our team and community are here to help you ship faster.