Siren

Configuration

How get_option, update_option, and post meta translate to Siren's three-level config system.

Last updated: April 9, 2026

Configuration

WordPress stores settings with get_option / update_option (global settings) and get_post_meta / update_post_meta (per-entity settings). Siren replaces both with a unified config system that uses a three-level hierarchy: type, subtype, and key.

// WordPress: global settings
update_option('my_plugin_api_key', 'abc123');
$key = get_option('my_plugin_api_key');

// WordPress: per-entity settings
update_post_meta($post_id, '_commission_rate', '15');
$rate = get_post_meta($post_id, '_commission_rate', true);
// Siren facade: three-level config hierarchy
use Siren\Configs\Core\Facades\Configs;

// Read a config value: type, subtype, key, default
$rate = Configs::getConfigValue('program', '42', 'maxCommission', '0');

// Write a config value: type, subtype, key, value
Configs::getContainedInstance()->setConfig('program', '42', 'maxCommission', '15');
// Siren DI: inject ConfigDatastore
use Siren\Configs\Core\Datastores\Config\Interfaces\ConfigDatastore;

class CommissionService
{
    protected ConfigDatastore $config;

    public function __construct(ConfigDatastore $config)
    {
        $this->config = $config;
    }

    public function getMaxCommission(int $programId): string
    {
        return $this->config->getConfigValue(
            'program',
            (string) $programId,
            'maxCommission',
            '0'   // default if not set
        );
    }

    public function setMaxCommission(int $programId, string $value): void
    {
        $this->config->setConfig(
            'program',
            (string) $programId,
            'maxCommission',
            $value
        );
    }
}

How does the three-level hierarchy work?

Every config value is scoped by three coordinates:

  • type is the domain area. Examples: 'program', 'collaborator', 'system'.
  • subtype is the specific entity or context within that type. For entity-scoped settings, this is typically the entity’s ID as a string (e.g., '42'). For global settings within a domain, this might be a category name.
  • key is the individual setting name. Examples: 'maxCommission', 'payoutThreshold', 'notificationEmail'.

This maps cleanly to both of WordPress’s storage patterns. Global settings (get_option) correspond to a fixed type and subtype with varying keys. Per-entity settings (get_post_meta) correspond to a fixed type and key with varying subtypes (one per entity ID).

// Global setting: same type and subtype, different keys
$this->config->getConfigValue('system', 'general', 'siteName', '');
$this->config->getConfigValue('system', 'general', 'currency', 'USD');

// Per-program setting: same type and key, different subtypes (program IDs)
$this->config->getConfigValue('program', '42', 'maxCommission', '0');
$this->config->getConfigValue('program', '99', 'maxCommission', '0');

Why a single system instead of two?

WordPress’s split between wp_options and wp_postmeta creates a conceptual divide. Global settings live in one place, per-entity settings in another, and the APIs are different. Siren’s config system is one table, one API, one mental model. The scope is determined by the type/subtype/key coordinates, not by which function you call.

This also means config values are queryable the same way regardless of scope. You can fetch all config values for a given type and subtype, or all values with a given key across all subtypes.

Where can I learn more?

For the full ConfigDatastore API (querying, deleting, and batch operations), see the Configs resource reference.

For the full PHPNomad framework documentation on datastores, see Datastores Introduction.