PHPackages                             hizzle/store - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. hizzle/store

ActiveLibrary[Database &amp; ORM](/categories/database)

hizzle/store
============

A standardized way of creating data stores for your projects

0.2.23(2mo ago)3467[1 issues](https://github.com/hizzle-co/datastore/issues)GPL-3.0+PHPPHP &gt;=5.3.0CI passing

Since Jun 24Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/hizzle-co/datastore)[ Packagist](https://packagist.org/packages/hizzle/store)[ Docs](http://github.com/hizzle-co/datastore/)[ RSS](/packages/hizzle-store/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (10)DependenciesVersions (43)Used By (0)

datastore
=========

[](#datastore)

This is currently in Beta so expect the API to change alot.

Installation
------------

[](#installation)

Install via Composer:

```
composer require hizzle/store
```

Features
--------

[](#features)

- **CRUD Operations**: Create, read, update, and delete records
- **Query Builder**: Powerful query builder with filtering, sorting, and pagination
- **Aggregate Functions**: Support for SUM, AVG, COUNT, MIN, MAX with grouping
- **JOIN Queries**: Relate collections together for complex data analysis
- **REST API**: Automatic REST API endpoints for all collections
- **Meta Fields**: Support for custom meta fields with multiple values
- **Custom Post Types**: Integrate with WordPress custom post types

Quick Start
-----------

[](#quick-start)

### Recommended: Using Main Class

[](#recommended-using-main-class)

The `Main` class provides a simplified API for interacting with your store:

```
use Hizzle\Store\Main;

// Get or create store instance
$db = Main::instance('my_store');

// Initialize store with collections
$db->init_store(
    array(
        'orders' => array(
            'object'        => 'Order',
            'singular_name' => 'order',
            'props'         => array(
                'id'          => array(
                    'type'        => 'BIGINT',
                    'length'      => 20,
                    'nullable'    => false,
                    'extra'       => 'AUTO_INCREMENT',
                    'description' => 'Order ID',
                ),
                'customer_id' => array(
                    'type'        => 'BIGINT',
                    'length'      => 20,
                    'nullable'    => false,
                    'description' => 'Customer ID',
                ),
                'total'       => array(
                    'type'        => 'DECIMAL',
                    'length'      => '10,2',
                    'nullable'    => false,
                    'description' => 'Order total',
                ),
                'status'      => array(
                    'type'        => 'VARCHAR',
                    'length'      => 20,
                    'default'     => 'pending',
                    'description' => 'Order status',
                ),
            ),
            'keys'          => array(
                'primary'     => array( 'id' ),
                'customer_id' => array( 'customer_id' ),
                'status'      => array( 'status' ),
            ),
            'labels'        => array(
                'name'          => __( 'Orders', 'textdomain' ),
                'singular_name' => __( 'Order', 'textdomain' ),
            ),
        ),
    )
);

// Work with records
$order = $db->get('orders', 123);
$orders = $db->query('orders', array('status' => 'completed'));
```

### Alternative: Using Store Class Directly

[](#alternative-using-store-class-directly)

```
use Hizzle\Store\Store;

// Initialize a store
$store = new Store(
    'my_store',
    array(
        'payments' => array(
            // This object must extend Hizzle\Store\Record
            'object'        => 'Payment',
            'singular_name' => 'payment',
            'props'         => array(
                'id'                  => array(
                    'type'        => 'BIGINT',
                    'length'      => 20,
                    'nullable'    => false,
                    'extra'       => 'AUTO_INCREMENT',
                    'description' => 'Payment ID',
                ),
                'customer_id'       => array(
                    'type'        => 'BIGINT',
                    'length'      => 20,
                    'nullable'    => false,
                    'description' => 'Customer ID',
                ),
                /* ... */
            ),
            'joins'         => array(
                'customers' => array(
                    'collection' => 'my_store_customers',
                    'on'         => 'customer_id',
                    'type'       => 'LEFT',
                ),
                'plans'     => array(
                    'collection' => 'my_store_plans',
                    'on'         => 'plan_id',
                    'type'       => 'LEFT',
                ),
                'products'  => array(
                    'collection' => 'my_store_products',
                    // We are assuming that the above payments schema has
                    // No 'plan_id' property, so we join via plans table
                    // Which is already joined above
                    'on'         => 'plans.product_id',
                    'type'       => 'LEFT',
                ),
            ),
            'keys'          => array(
                'primary'             => array( 'id' ),
                'customer_id'         => array( 'customer_id' ),
                'subscription_id'     => array( 'subscription_id' ),
                'status'              => array( 'status' ),
                'date_created_status' => array( 'date_created', 'status' ),
                'unique'              => array( 'uuid', 'transaction_id' ),
            ),
            'labels'        => array(
                'name'          => __( 'Payments', 'textdomain' ),
                'singular_name' => __( 'Payment', 'textdomain' ),
                'add_new'       => __( 'Add New', 'textdomain' ),
                'add_new_item'  => __( 'Add New Payment', 'textdomain' ),
                'edit_item'     => __( 'Overview', 'textdomain' ),
                'new_item'      => __( 'Add Payment', 'textdomain' ),
                'view_item'     => __( 'View Payment', 'textdomain' ),
                'view_items'    => __( 'View Payments', 'textdomain' ),
                'search_items'  => __( 'Search payments', 'textdomain' ),
                'not_found'     => __( 'No payments found.', 'textdomain' ),
                'import'        => __( 'Import Payments', 'textdomain' ),
            ),
        ),
        'customers' => array( /* ... */ ),
        /** Other collections **/
    )
);
```

### Working with Records

[](#working-with-records)

#### Create Records

[](#create-records)

```
// Using Main class (recommended)
$db = Main::instance('my_store');

// Get the collection first
$collection = Store::instance('my_store')->get('payments');

// Create a new payment
$payment = $collection->create(array(
    'customer_id' => 123,
    'amount' => 99.99,
    'status' => 'completed',
));

// Get the payment ID
$payment_id = $payment->get_id();
```

#### Read Records

[](#read-records)

```
// Using Main class (recommended)
$db = Main::instance('my_store');

// Get a single record by ID
$payment = $db->get('payments', $payment_id);

if ($payment && !is_wp_error($payment)) {
    echo $payment->get('amount'); // 99.99
    echo $payment->get('status'); // completed
}

// Get ID by a specific property
$payment_id = $db->get_id_by_prop('transaction_id', 'txn_abc123', 'payments');

// Using Collection directly
// Throws \Hizzle\Store\Store_Exception on failure
$collection = Store::instance('my_store')->get('payments');
$payment = $collection->get($payment_id);

// Check if a record exists
if ($collection->exists($payment_id)) {
    // Record exists
}
```

#### Update Records

[](#update-records)

```
// Get the record using Main class
$db = Main::instance('my_store');
$payment = $db->get('payments', $payment_id);

if ($payment && !is_wp_error($payment)) {
    $payment->set('status', 'refunded');
    $payment->set('refund_date', current_time('mysql'));
    $payment->save();
}

// Or update via collection
// Throws \Hizzle\Store\Store_Exception on failure
$collection = Store::instance('my_store')->get('payments');
$collection->update($payment_id, array(
    'status' => 'refunded',
    'refund_date' => current_time('mysql'),
));
```

#### Delete Records

[](#delete-records)

```
// Using Main class (recommended)
$db = Main::instance('my_store');

// Delete records matching criteria
$deleted = $db->delete_where(
    array(
        'status' => 'pending',
        'customer_id' => 123,
    ),
    'payments'
);

// Delete all records (use with caution!)
$db->delete_all('payments');

// Or delete via record object
$payment = $db->get('payments', $payment_id);
if ($payment && !is_wp_error($payment)) {
    $payment->delete();
}
```

### Querying Records

[](#querying-records)

```
// Using Main class (recommended)
$db = Main::instance('my_store');

// Basic query - returns results
$payments = $db->query('payments', array(
    'status' => 'completed',
    'customer_id' => 123,
    'per_page' => 10,
    'page' => 1,
));

// Count records
$count = $db->query('payments', array(
    'status' => 'completed',
), 'count');

// Aggregate query
$results = $db->query('payments', array(
    'aggregate' => array(
        'amount' => array('SUM', 'AVG', 'COUNT'),
    ),
    'groupby' => 'status',
), 'aggregate');

// Get Query object for more control
$query = $db->query('payments', array(
    'status' => 'completed',
), 'query');

$payments = $query->get_results();
$total = $query->get_total();

// Using Collection directly
$collection = Store::instance('my_store')->get('payments');
$query = $collection->query(array(
    'status' => 'completed',
    'customer_id' => 123,
    'per_page' => 10,
    'page' => 1,
));

$payments = $query->get_results();
$total = $query->get_total();

// Complex query with date filters
$payments = $db->query('payments', array(
    'status' => array('completed', 'pending'),
    'amount_min' => 50,
    'date_created_after' => '2026-01-01',
    'orderby' => 'date_created',
    'order' => 'DESC',
));
```

### Working with Metadata

[](#working-with-metadata)

```
// Using Main class (recommended)
$db = Main::instance('my_store');

// Add meta data
$db->add_record_meta($payment_id, 'gateway', 'stripe', false, 'payments');

// Get meta data
$gateway = $db->get_record_meta($payment_id, 'gateway', true, 'payments');

// Update meta data
$db->update_record_meta($payment_id, 'gateway', 'paypal', '', 'payments');

// Delete meta data
$db->delete_record_meta($payment_id, 'gateway', '', 'payments');

// Delete all metadata for a record
$db->delete_all_record_meta($payment_id, 'payments');

// Delete all metadata by key across all records
$db->delete_all_meta_by_key('old_field', 'payments');

// Check if meta exists
if ($db->record_meta_exists($payment_id, 'gateway', 'payments')) {
    // Meta exists
}

// Using Collection directly
$collection = Store::instance('my_store')->get('payments');
$collection->add_record_meta($payment_id, 'gateway', 'stripe');
$gateway = $collection->get_record_meta($payment_id, 'gateway', true);
$collection->update_record_meta($payment_id, 'gateway', 'paypal');
$collection->delete_record_meta($payment_id, 'gateway');
```

### Error Handling

[](#error-handling)

```
use Hizzle\Store\Main;

// Main class automatically converts exceptions to WP_Error
$db = Main::instance('my_store');
$payment = $db->get('payments', $payment_id);

if (is_wp_error($payment)) {
    error_log($payment->get_error_message());
} else {
    // Work with the payment
    echo $payment->get('amount');
}

// When using Store/Collection directly, use try/catch
try {
    $collection = Store::instance('my_store')->get('payments');
    $payment = $collection->get($payment_id);

    // Do something with the payment

} catch (\Hizzle\Store\Store_Exception $e) {
    error_log($e->getMessage());

    // Or convert to WP_Error
    $error = new WP_Error(
        $e->getErrorCode(),
        $e->getMessage(),
        $e->getErrorData()
    );
}
```

### JOIN Queries

[](#join-queries)

Define relationships between collections:

```
'customers' => array(
    'status' => 'complete',
    // ... other config
    'joins' => array(
        'payments' => array(
            'collection' => 'my_store_payments',
            'on' => 'id',
            'foreign_key' => 'customer_id',
            'type' => 'LEFT',
        ),
    ),
)
```

Use JOINs in aggregate queries:

```
$query = $collection->query(array(
    'join' => array('payments'),
    'aggregate' => array(
        'payments.amount' => array('SUM', 'COUNT'),
    ),
    'groupby' => 'id',
));
```

Documentation
-------------

[](#documentation)

### API Reference

[](#api-reference)

Complete documentation for all components is available in the [docs](docs/) folder:

- **Core Classes**

    - [Store](docs/store.md) - Main store management
    - [Collection](docs/collection.md) - Collection CRUD operations
    - [Record](docs/record.md) - Individual record operations
    - [Query](docs/query.md) - Query builder and filtering
- **Supporting Classes**

    - [Prop](docs/prop.md) - Property definitions
    - [REST\_Controller](docs/rest-controller.md) - REST API endpoints
    - [List\_Table](docs/list-table.md) - WordPress admin tables
    - [Webhooks](docs/webhooks.md) - Event-driven webhooks
- **Utilities**

    - [Date\_Time](docs/date-time.md) - Date/time handling
    - [Store\_Exception](docs/store-exception.md) - Exception handling

### Guides

[](#guides)

- [JOIN Queries Guide](docs/joins.md) - Comprehensive guide to using JOINs
- [Example Code](example-joins.php) - Working examples with JOINs

Requirements
------------

[](#requirements)

- PHP &gt;= 5.3.0
- WordPress &gt;= 4.7.0

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance77

Regular maintenance activity

Popularity18

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 94% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~34 days

Recently: every ~11 days

Total

41

Last Release

86d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9d7aa18c0c768343c01ea764382efd7ac5ce1f28cab87165c386e6eacdcea90e?d=identicon)[picocodes](/maintainers/picocodes)

---

Top Contributors

[![picocodes](https://avatars.githubusercontent.com/u/19934448?v=4)](https://github.com/picocodes "picocodes (188 commits)")[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (11 commits)")[![renovate[bot]](https://avatars.githubusercontent.com/in/2740?v=4)](https://github.com/renovate[bot] "renovate[bot] (1 commits)")

---

Tags

databasedatastorewordpresswordpressstorehizzle

### Embed Badge

![Health badge](/badges/hizzle-store/health.svg)

```
[![Health](https://phpackages.com/badges/hizzle-store/health.svg)](https://phpackages.com/packages/hizzle-store)
```

###  Alternatives

[dbout/wp-orm

WordPress ORM with Eloquent.

12910.2k1](/packages/dbout-wp-orm)[williarin/wordpress-interop

Interoperability library to work with WordPress database in third party apps

6611.3k2](/packages/williarin-wordpress-interop)[tiny-pixel/acorn-db

Eloquent database support for Acorn projects

368.8k](/packages/tiny-pixel-acorn-db)[devgeniem/better-wp-db-error

Better WordPress database error handling.

1161.7k](/packages/devgeniem-better-wp-db-error)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
