-
Notifications
You must be signed in to change notification settings - Fork 0
Options
Options refer to the database records in the WordPress wp_options table, typically used to store settings and other
persistent information.
The SDK provides a wrapper class for options to simplify the reading and writing of values, with proper type handling.
use RebelCode\WpSdk\Wp\Option;
new Option('my_option', Option::default() true, false);The constructor accepts the following arguments:
- The name of the option.
- The type of the option.
- An optional default value.
- Whether the option is autoloaded.
Transients have a similar API to options, and can be created using a similar constructor signature:
use RebelCode\WpSdk\Wp\Transient;
new Transient('my_transient', Transient::default(), 300, 'default');The constructor accepts the following arguments:
- The name of the option.
- The type of the option.
- An optional expiry time, in seconds.
- An optional default value.
Both options and transients extend the RebelCode\WpSdk\Wp\AbstractOption class. If your code supports both, you can
use this abstract class as a type hint to accept either.
use RebelCode\WpSdk\Wp\AbstractOption;
function my_code(AbstractOption $option) {
$option->getValue();
$option->setValue('value');
$option->delete();
}Both options and transients inherit most of their functionality from this class. The remainder of this document will focus mainly on options to avoid duplication, but keep in mind that transients also support most of what is covered in this document.
WordPress options are always stored as strings in the database; scalar values are cast into strings, while arrays and objects are serialized using the PHP serialization format.
The SDK provides a simple but powerful type system for options, which allows for the automatic conversion of option values to and from strings and their desired native PHP types.
The SDK provides the following types:
-
Option::default()- The default type, which does not perform any conversion. -
Option::string()- Reads options without conversion, but ensures that written values are cast to strings. -
Option::bool()- Reads options as booleans, and writes them as1or0strings. -
Option::int()- Reads options as integers, and writes them as numeric integer strings. -
Option::float- Reads options as floats, and writes them as numeric float strings. -
Option::jsonArray()- Decodes option JSON strings as arrays, and encodes arrays into JSON strings. -
Option::jsonObject()- Decodes option JSON strings as objects, and encodes objects into JSON strings.
Options can be queried or manipulated using the methods in the Option instance itself.
Example 1: Read a value
use RebelCode\WpSdk\Wp\Option;
$option = new Option('count', Option::int(), 0, false);
$count = $option->get();Example 2: Write a value
$option->set(5);
$option->get(); // 5Example 3: Delete a value
$option->delete();
$options->get(); // 0Note that the return type of the get() method depends on the option type. In the above example, the option type is
Option::int(), which means that the get() method will return a PHP integer value.
The Option class uses the @template PHPDoc tag. If you IDE supports it, you can type hint your Option instances
to get proper type hinting for the getValue() and setValue() methods.
Example 4: Type hinting an option:
use RebelCode\WpSdk\Wp\Option;
/** @var Option<bool> $option */
$option = new Option(Option::BOOL, 'my_flag', false);
$value = $option->getValue();
The Options API is primarily designed such that the values passed to the set() method are values of the appropriate
type, and that the values that are stored in the database are written in the appropriate format. Unexpected values
may yield unexpected results. For instance:
Example 5: Invalid write value
use RebelCode\WpSdk\Wp\Option;
$option = new Option('my_option', Option::int(), 0, false);
$option->set(['a', 'b', 'c']); // This will write a "0" string to the databaseExample 6: Unexpected database value
use RebelCode\WpSdk\Wp\Option;
// |-------------------|-----------------------|
// | Option | Value |
// |-------------------|-----------------------|
// | my_option | a:1:{i:0;s:4:"test";} |
// |-------------------|-----------------------|
$option = new Option('my_option', Option::int(), 0, false);
$option->get(); // 0It is recommended not to always use the appropriate types, to avoid unexpected results.
Sometimes, you may need to access or modify multiple options at once. In such situations, it would be inconvenient to
have to pass all the necessary Option instances. It would be much simpler if you could represent your plugin's
settings using a single instance.
Option sets provide this functionality. They are simply a collection of Option instances. You can use a single set
for all of your options. Alternatively, you can create multiple sets for different groups of options.
use RebelCode\WpSdk\Wp\Option;
use RebelCode\WpSdk\Wp\OptionSet;
$greeting = new OptionSet([
'enabled' => new Option('show_greeting', Option::bool(), true),
'text' => new Option('greeting_text', Option::string(), ''),
]);
// Get a single option value
$showTutorial = $greeting->get('enabled'); // => true
// Set a single option value
$greeting->set('text', 'Welcome to my website!');
// Set multiple option values
$greeting->update([
'enabled' => false,
'greeting' => 'Welcome to my blog!',
]);
// Delete an option
$greeting->delete('enabled');Note 1: When creating an OptionSet, you must pass an associative array. The keys are used to identify the options,
and do not need to necessarily be the same as the option names. In the above example, the greeting_text option uses
the text key in the set, allowing us to use a more readable key.
Note 2: You can also use Transient instances in option sets.
You can create your own custom types by implementing the OptionType interface. This interface has two methods that
need to be implemented; one for parsing values read from the database, and another to serialize values before they are
written to the database.
For instance, here's a custom type that writes a WordPress post ID:
use RebelCode\WpSdk\Wp\Option;
use RebelCode\WpSdk\Wp\OptionType;
class MyType implements OptionType
{
public function parse($value)
{
$int = Option::int()->parse($value);
return get_post($int);
}
public function serialize($value)
{
if ($value instanceof \WP_Post) {
// If a WordPress post, write its ID
return (string) $value->ID;
} else {
// Fallback to writing an integer
return Option::int()->parseValue($value)
}
}
}You can then use your custom type simply by instantiating it and passing it to the Option constructor:
use RebelCode\WpSdk\Wp\Option;
$option = new Option('checkout_page', new MyType(), null, false);
$post = get_post(5);
$option->setValue($post);
$option->getValue(); // => WP_Post instanceIf the type is reused multiple times, you may want to create a singleton instance for the type, to avoid unnecessary memory usage. You can also declare a service for the type. The next section explains this in more detail.
Factories can be easily created for Option, Transient, and OptionSet instances:
Example 1: Creating factories
use RebelCode\WpSdk\Module;
use RebelCode\WpSdk\Wp\Option;
use RebelCode\WpSdk\Wp\OptionSet;
use RebelCode\WpSdk\Wp\Transient;
class MyModule extends Module
{
public function getFactories() : array
{
return [
'options/greeting' => Option::factory('greeting_text', Option::string(), 'Hello, world!'),
'options/show_tutorial' => Transient::factory('show_tutorial', Transient::bool(), 3600),
'options' => OptionSet::factory([
'greeting' => 'options/greeting',
'show_tutorial' => 'options/show_tutorial',
]),
];
}
}-
Note 1: The
Option::factory()method accepts similar arguments as theOptionconstructor. -
Note 2: The
Transient::factory()method accepts similar arguments as theTransientconstructor. -
Note 3: The
Option::factory()andTransient::factory()methods can be given a service ID as their type, instead of a type instance. This is useful when you want to use a custom option type that is declared as a service. -
Note 4: The
OptionSet::factory()method accepts an array of option service IDs, not instances.
Example 2: Using a service ID for custom types:
use RebelCode\WpSdk\Module;
use RebelCode\WpSdk\Wp\Option;
use Dhii\Services\Factories\Constructor;
class MyModule extends Module
{
public function getFactories() : array
{
return [
// Your custom type's service
'custom_type' => new Constructor(CustomType::class, []),
// An option that uses the custom type
'my_option' => Option::factory('my_option', 'custom_type', 'Hello, world!'),
];
}
}