VaultBBDocs
phpBB ExtensionsVaultBB Core

Developer Reference

API documentation for building VaultBB premium extensions on phpBB 3.3.x.

Developer Reference

This page documents everything you need to build a VaultBB premium extension for phpBB 3.3.x. All services described here are for premium extensions only — free/standalone phpBB extensions must never depend on VaultBB Core.


Available Services

VaultBB Core registers seven Symfony DI services, all injectable via config/services.yml:

Service IDClassPurpose
vaultbb.core.registryvaultbb\core\registry\registryExtension registry — read/write
vaultbb.core.loggervaultbb\core\logger\loggerUnified audit logger
vaultbb.core.admin_uivaultbb\core\admin_ui\admin_uiACP component library
vaultbb.core.error_handlervaultbb\core\error\error_handlerProduction-safe exception management
vaultbb.core.settingsvaultbb\core\settings\settingsPer-extension key-value configuration store
vaultbb.core.notifiervaultbb\core\notification\notifierPersistent ACP notification queue
vaultbb.core.update_checkervaultbb\core\update\update_checkerRemote update manifest checker

Declaring Core as a Dependency

composer.json

"require": {
    "php": ">=7.4.0",
    "phpbb/phpbb": ">=3.3.0,<3.4.0",
    "vaultbb/core": ">=1.0.0"
}

ext.phpis_enableable()

Every VaultBB extension must block activation if Core is absent or too old:

public function is_enableable(): bool|\phpbb\extension\exception
{
    if (!$this->container->has('vaultbb.core.registry')) {
        return new \phpbb\extension\exception(
            'VAULTBB_CORE_REQUIRED',
            ['My Extension', '1.0.0']
        );
    }

    $registry = $this->container->get('vaultbb.core.registry');

    if (!$registry->meetsVersion('1.0.0')) {
        return new \phpbb\extension\exception(
            'VAULTBB_CORE_VERSION_REQUIRED',
            ['My Extension', '1.0.0']
        );
    }

    return true;
}

ext.php — Registry lifecycle

// enable_step() — after all migrations have run
$registry->register([
    'ext_name' => 'vaultbb/myextension',
    'title'    => 'My Extension',
    'version'  => '1.0.0',
    'core_min' => '1.0.0',
    'active'   => true,
    'meta'     => ['features' => ['feature_a']],
]);

// disable_step()
$registry->setActive('vaultbb/myextension', false);

// purge_step()
$registry->unregister('vaultbb/myextension');

Missing any step of the Registry lifecycle will cause the Dashboard to show stale data. All three — register on enable, setActive(false) on disable, unregister on purge — are mandatory.


Registry (vaultbb.core.registry)

Class: vaultbb\core\registry\registry

Writing

// Register a new extension (called in enable_step)
$registry->register([
    'ext_name' => 'vaultbb/myextension',
    'title'    => 'My Extension',
    'version'  => '1.0.0',
    'core_min' => '1.0.0',
    'active'   => true,
    'meta'     => [],
]);

// Mark as inactive (called in disable_step)
$registry->setActive('vaultbb/myextension', false);

// Remove entirely (called in purge_step)
$registry->unregister('vaultbb/myextension');

Reading

// Get a single extension record (returns null if not found)
$info = $registry->get('vaultbb/myextension');
// Keys: ext_name, ext_title, ext_version, core_min, ext_active,
//       ext_meta, registered_at, updated_at

// Get all registered extensions (array keyed by ext_name, cached)
$all = $registry->getAll();

// Get the version string ('0.0.0' if not found)
$version = $registry->getVersion('vaultbb/myextension');

// Check active state
$active = $registry->isActive('vaultbb/myextension'); // bool

// Check if the installed Core meets a minimum version requirement
$ok = $registry->meetsVersion('1.0.0'); // bool

Logger (vaultbb.core.logger)

Class: vaultbb\core\logger\logger

Writing logs

$this->logger->log(
    'myextension',      // source — your extension's short codename
    'item_created',     // action — see standard names below
    [                   // context — any key/value pairs useful for debugging
        'item_id' => $item_id,
        'user_id' => $user_id,
    ]
);

Use consistent action names across all VaultBB extensions:

ActionWhen to use
ext_enabledExtension enabled
ext_disabledExtension disabled
settings_updatedACP settings form submitted
item_createdA record was created
item_updatedA record was updated
item_deletedA record was deleted
feature_usedA significant user-facing feature ran
error_occurredAn exception was caught (auto-logged by ErrorHandler)
permission_deniedAn authorization check failed
cache_clearedA cache was manually busted

Reading logs

// Fetch recent logs for this extension (paginated)
$logs = $this->logger->getLogs(['source' => 'myextension'], 30, 0);

// Count total entries matching a filter (for pagination)
$total = $this->logger->countLogs(['source' => 'myextension']);

// Delete entries older than N days, returns the count of deleted rows
$deleted = $this->logger->purgeLogs(90);

AdminUI (vaultbb.core.admin_ui)

Class: vaultbb\core\admin_ui\admin_ui

All VaultBB ACP modules must use AdminUI exclusively. No bespoke admin styling is permitted.

Brand header

Call once at the top of every ACP mode. Sets S_VAULTBB_BRAND_HEADER, VAULTBB_BRAND_TITLE, and VAULTBB_BRAND_SUBTITLE in the template.

$this->admin_ui->brand_header(
    $this->user->lang('ACP_MYEXTENSION'),
    $this->user->lang('ACP_MYEXTENSION_EXPLAIN')
);

Metrics

$this->admin_ui->metric('Total Items', (string) $count,  '#2f6fed');
$this->admin_ui->metric('Active Today', (string) $today, '#16a34a');
$this->admin_ui->metric('Errors',       (string) $errors,'#dc2626');

The template iterates {% for metric in vaultbb_metrics %} to render tiles.

Status rows

$this->admin_ui->status_row('Feature X', (bool) $this->config['myext_feature_x']);
$this->admin_ui->status_row('Cache',     true, 'Warm', 'Cold');

The template iterates {% for row in vaultbb_status_rows %}.

Alerts

$this->admin_ui->alert('Settings saved.', 'success');
$this->admin_ui->alert('Something looks off.', 'warning');

Available types: success · info · warning · danger

Inline badge

// Returns an HTML string — use |raw in Twig
$badge = $this->admin_ui->badge(true, 'Active', 'Inactive');

ACP template structure

Your .html templates must include the VaultBB base stylesheet and use the provided CSS class names:

<!-- INCLUDE @vaultbb_core/vaultbb_core_base.html -->

<div class="vaultbb-acp-wrap">
    {% if S_VAULTBB_BRAND_HEADER %}
    <div class="vaultbb-brand-header">
        <div class="vaultbb-brand-logo">V</div>
        <div class="vaultbb-brand-text">
            <p class="vaultbb-brand-title">{{ VAULTBB_BRAND_TITLE }}</p>
            <p class="vaultbb-brand-subtitle">{{ VAULTBB_BRAND_SUBTITLE }}</p>
        </div>
        <span class="vaultbb-brand-version">v{{ VAULTBB_CORE_VERSION }}</span>
    </div>
    {% endif %}

    <!-- your content here -->
</div>

Error Handler (vaultbb.core.error_handler)

Class: vaultbb\core\error\error_handler

Handling a caught exception

try {
    $this->doSomethingRisky();
} catch (\Throwable $e) {
    $this->error_handler->handle($e, 'myextension', 'save_item');
    // Production: exception is logged and swallowed — forum stays online
    // When vaultbb_core_enabled is off: exception is re-thrown for inspection
}

Safe callable wrapper

$result = $this->error_handler->safe(
    fn() => $this->riskyOperation(),
    'myextension',
    []   // default value returned if the callable throws
);

Settings Store (vaultbb.core.settings)

Class: vaultbb\core\settings\settings

A per-extension key-value store backed by a dedicated database table (not phpBB's phpbb_config). Use this for extension-specific values that are not global phpBB config.

// Write a value (creates or updates)
$this->settings->set('myextension', 'some_key', 'some_value');

// Read a value (returns null if not set)
$value = $this->settings->get('myextension', 'some_key');

// Delete a value
$this->settings->delete('myextension', 'some_key');

Notifier (vaultbb.core.notifier)

Class: vaultbb\core\notification\notifier

Posts persistent notifications to the VaultBB Dashboard. Useful for extension warnings that should remain visible until an admin actively dismisses them.

// Post a notification (survives page loads until dismissed)
$this->notifier->notify(
    'myextension',
    'warning',              // type: 'info' | 'warning' | 'error'
    'LANG_KEY_OR_RAW_MSG'
);

// Dismiss a notification by ID (called automatically by the Dashboard UI)
$this->notifier->dismiss($notification_id);

ACP Module Structure

All VaultBB ACP modules must live under the ACP_VAULTBB tab created by Core. Never create a separate top-level tab.

In your migration's update_data():

// Core has already created ACP_VAULTBB — add your category under it
['module.add', ['acp', 'ACP_VAULTBB', 'ACP_VAULTBB_MYEXTENSION']],
['module.add', ['acp', 'ACP_VAULTBB_MYEXTENSION', [
    'module_basename' => '\vaultbb\myextension\acp\main_module',
    'modes'           => ['overview', 'settings'],
]]],

Cross-Extension Communication

Use the Registry to safely check whether another VaultBB extension is active before interacting with it:

$registry = $this->container->get('vaultbb.core.registry');

if ($registry->isActive('vaultbb/otherextension')) {
    $other = $this->container->get('vaultbb.otherextension.some_service');
    $other->doSomething();
}

Dispatching Custom Events

Every VaultBB extension must dispatch named phpBB events at key moments so third-party code can hook into it:

$event = new \phpbb\event\data([
    'item_id'   => $item_id,
    'item_data' => $item_data,   // writable — listeners may modify this
    'user_id'   => $user_id,     // read-only — document this clearly
]);

$this->dispatcher->dispatch($event, 'vaultbb.myextension.item_created');

// Always read data back after dispatch
$item_data = $event['item_data'];

Document all dispatched events in your extension's docs/EVENTS.md.


Template Variables Provided by Core

VaultBB Core assigns the following Twig variables on every front-end and ACP page load (via core.page_header and core.adm_page_header):

VariableTypeDescription
S_VAULTBB_CORE_ACTIVEbooltrue when Core is enabled
VAULTBB_CORE_VERSIONstringInstalled Core version string

Use these in any VaultBB template to conditionally render Core-powered features:

{% if S_VAULTBB_CORE_ACTIVE %}
    {# render something that requires Core #}
{% endif %}

On this page