Siren

Querying Data

How get_post, WP_Query, and $wpdb translate to Siren's typed datastore system.

Last updated: April 9, 2026

Querying Data

In WordPress, you query data through get_post(), WP_Query, get_posts(), or direct $wpdb calls. Siren replaces all of these with typed datastores (one per domain model) that return typed model instances with getter methods. No more working with generic WP_Post objects or raw database rows.

Fetching a single record

The most common operation: get one record by ID. In WordPress this is get_post(). In Siren, each domain model has a facade and a datastore with getById().

// WordPress: returns a generic WP_Post object
$post = get_post(42);
echo $post->post_title;
echo get_post_meta(42, '_custom_field', true);
// Siren facade: returns a typed Program model
use Siren\Programs\Core\Facades\Programs;

$program = Programs::getById(42);
echo $program->getName();
echo $program->getStatus();
// IDE autocomplete shows all available getters
// Siren DI: inject the datastore, call getById()
use Siren\Programs\Core\Datastores\Program\Interfaces\ProgramDatastore;

class MyService
{
    protected ProgramDatastore $programs;

    public function __construct(ProgramDatastore $programs)
    {
        $this->programs = $programs;
    }

    public function getProgramName(int $id): string
    {
        $program = $this->programs->getById($id);
        return $program->getName();
    }
}

The model you get back is a typed object, not a generic post or array. $program->getName() returns a string. $program->getStatus() returns a status value. Your IDE knows every available method.

Filtered queries

WordPress provides get_posts() with meta queries and $wpdb->get_results() for direct SQL. Siren uses andWhere() and where() with a structured condition array.

// WordPress: WP_Query with meta query
$posts = get_posts([
    'post_type'  => 'program',
    'meta_key'   => 'status',
    'meta_value' => 'active',
]);

// Or direct $wpdb for complex queries
global $wpdb;
$results = $wpdb->get_results(
    "SELECT * FROM {$wpdb->prefix}programs WHERE status = 'active'"
);
// Siren facade: andWhere() with typed conditions
use Siren\Programs\Core\Facades\Programs;

$activePrograms = Programs::andWhere([
    ['column' => 'status', 'operator' => '=', 'value' => 'active'],
]);
// Returns an array of typed Program model instances
// Siren DI: same query through the injected datastore
use Siren\Programs\Core\Datastores\Program\Interfaces\ProgramDatastore;

class ProgramListService
{
    protected ProgramDatastore $programs;

    public function __construct(ProgramDatastore $programs)
    {
        $this->programs = $programs;
    }

    public function getActivePrograms(): array
    {
        return $this->programs->andWhere([
            ['column' => 'status', 'operator' => '=', 'value' => 'active'],
        ]);
    }

    public function getActiveProgramsPaginated(int $page, int $perPage): array
    {
        return $this->programs->where(
            [['column' => 'status', 'operator' => '=', 'value' => 'active']],
            $perPage,   // limit
            ($page - 1) * $perPage,  // offset
            'name',     // order by
            'asc'       // direction
        );
    }
}

Supported query operators

The condition array supports the following operators:

OperatorExample
=['column' => 'status', 'operator' => '=', 'value' => 'active']
!=['column' => 'status', 'operator' => '!=', 'value' => 'draft']
>['column' => 'total', 'operator' => '>', 'value' => 1000]
<['column' => 'total', 'operator' => '<', 'value' => 5000]
>=['column' => 'quantity', 'operator' => '>=', 'value' => 1]
<=['column' => 'quantity', 'operator' => '<=', 'value' => 100]
LIKE['column' => 'name', 'operator' => 'LIKE', 'value' => '%affiliate%']
NOT LIKE['column' => 'name', 'operator' => 'NOT LIKE', 'value' => '%test%']
IN['column' => 'status', 'operator' => 'IN', 'value' => ['active', 'pending']]
NOT IN['column' => 'status', 'operator' => 'NOT IN', 'value' => ['archived']]

Multiple conditions are combined with AND. Each condition is an associative array with column, operator, and value keys.

What is different from WordPress queries?

Every query returns typed model instances, not generic arrays or WP_Post objects. You call $program->getName() instead of $post->post_title. The column names are real database column names, not meta keys. There is no meta table indirection.

Datastores operate on Siren’s own database tables, not the WordPress posts/postmeta tables. Siren does not use custom post types for its domain models. Programs, collaborators, conversions, and other entities each have dedicated tables with proper columns and indexes.

For the full query syntax including pagination, sorting, and all available datastore methods, see the Resource Reference Introduction.

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