OptionSource
BetterData\Source\OptionSource hydrates a DataObject from a single WordPress option (typically an array stored under one option key).
Method
OptionSource::hydrate(string $option, string $dtoClass, array $default = []): DataObject
- Reads
get_option($option). If missing or non-array, uses$default. - Passes the array straight to
$dtoClass::fromArray().
No system/meta split
Options are flat — there's no equivalent of post_meta. Use plain property names that match the array keys:
final readonly class SettingsDto extends DataObject {
use HasWpSources;
public function __construct(
public string $contactEmail = '',
public bool $maintenanceMode = false,
public int $cacheTtl = 300,
#[Encrypted]
public ?Secret $apiKey = null,
) {}
}
$settings = SettingsDto::fromOption('myplugin_settings');
// With explicit defaults:
$settings = SettingsDto::fromOption(
'myplugin_settings',
default: ['cacheTtl' => 600, 'maintenanceMode' => false],
);
Encrypted options
#[Encrypted] works on options too. Encrypted values are stored as bd:v1:... envelopes inside the option array; the source decrypts before coercion.
The corresponding write path is OptionSink, which calls Secret::reveal() on write (option storage already trusts the value, so revealing the plaintext to encrypt it is the only way to persist).
Common mistakes
- Storing the full DTO at the top level vs. a nested key —
OptionSourceexpects the option value to be the array of fields directly. If you storeupdate_option('foo', ['data' => [...]]), you'd hydrate from['data' => ...]not'foo' - Forgetting that
get_optionreturnsfalsewhen missing —OptionSourcedefends against this and uses$default, but custom unwrapping logic might not