Skip to content

Storage & ORM

The plugin provides a lightweight ORM for custom database tables. All models extend ORMModel and interact with the database directly via $wpdb.

ORMModel

Barberklingen\BasePlugin\Storage\ORMModel

Defining a model

use Barberklingen\BasePlugin\Storage\ORMModel;
use Barberklingen\BasePlugin\Storage\Casts\DateTimeCast;
use Barberklingen\BasePlugin\Storage\Casts\Json;

class MyRecord extends ORMModel {
    protected ?int $id = null;
    protected string $name = '';
    protected ?array $config = null;
    protected ?string $created_at = null;

    protected array $casts = [
        'config'     => Json::class,
        'created_at' => DateTimeCast::class,
    ];

    public static function raw_table_name(): string {
        return 'my_records'; // wp_ prefix added automatically
    }

    public static function create_table(): void {
        global $wpdb;
        $wpdb->query("CREATE TABLE IF NOT EXISTS {$wpdb->prefix}my_records (
            id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            name VARCHAR(255) NOT NULL,
            config JSON,
            created_at DATETIME
        )");
    }
}

CRUD operations

// Create
$record = new MyRecord(['name' => 'example', 'config' => ['key' => 'value']]);
$record->save(); // calls create() internally, sets $record->id

// Find one (throws EntityNotFoundException if missing)
$record = MyRecord::find(['name' => 'example']);

// Find many
$records = MyRecord::get(['name' => 'example'], limit: 10);

// Update
$record->name = 'updated';
$record->save(); // calls update() because $id is set

// Delete
$record->delete();
MyRecord::delete_by_id(42);
MyRecord::delete_where(['name' => 'old']);

Raw query

$records = MyRecord::query('id, name', "WHERE name LIKE '%foo%' LIMIT 5");

Table name

MyRecord::get_table(); // "wp_my_records"

WordPress hooks

Every write operation fires hooks with the model instance:

Hook When
orm-model/before-create Before INSERT
orm-model/created After INSERT
orm-model/before-update Before UPDATE
orm-model/updated After UPDATE
orm-model/before-delete Before DELETE
orm-model/deleted After DELETE (receives ID, not instance)

Casting

Casts are declared in $casts and transform values on read/write automatically.

Built-in casts

Class get() set()
Json json_decode($value, true) json_encode($value)
DateTimeCast WC_DateTime from string/timestamp/object Y-m-d H:i:s (GMT)
UnPrefixedPostStatus Strips wc- prefix Strips wc- prefix

Custom cast

use Barberklingen\BasePlugin\Storage\Casts\CastsAttributes;

class BooleanCast implements CastsAttributes {
    public function get($value): bool { return (bool) $value; }
    public function set($value): int  { return $value ? 1 : 0; }
}

WHERE queries with operators

SQLHelper::prepare_where_query() supports comparison operators for more complex queries:

use Barberklingen\BasePlugin\Helpers\SQLHelper;

// Simple equality
MyRecord::get(['status' => 'active']);

// Comparison operator
MyRecord::get(['count' => ['compare' => '>', 'value' => 5]]);

// NULL check
MyRecord::get(['deleted_at' => null]); // generates IS NULL

ORMModelWithMeta

Extends ORMModel with a MetaData side table for arbitrary key/value pairs. Use this when a model needs extensible metadata without schema changes.

BaseModel / BaseStore

An alternative pattern for tables where you want to separate read logic from the model. Implement BaseStore for CRUD operations and have the model delegate via get_store():

class MyModel {
    use BaseModel;

    public function get_store(): MyStore { return new MyStore(); }
}

Built-in models

Model Table Description
WCEntityType wc_entity_types Registry of WC entity slugs
WCStatus wc_statuses Registry of all WC/WP statuses

These are populated by the base plugin's versioned migrations and kept up to date by the WCStatusCheckerTask.