This is currently in Beta so expect the API to change alot.
Install via Composer:
composer require hizzle/store- 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
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'));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 **/
)
);// 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();// 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
}// 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'),
));// 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();
}// 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',
));// 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');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()
);
}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',
));Complete documentation for all components is available in the docs folder:
-
Core Classes
- Store - Main store management
- Collection - Collection CRUD operations
- Record - Individual record operations
- Query - Query builder and filtering
-
Supporting Classes
- Prop - Property definitions
- REST_Controller - REST API endpoints
- List_Table - WordPress admin tables
- Webhooks - Event-driven webhooks
-
Utilities
- Date_Time - Date/time handling
- Store_Exception - Exception handling
- JOIN Queries Guide - Comprehensive guide to using JOINs
- Example Code - Working examples with JOINs
- PHP >= 5.3.0
- WordPress >= 4.7.0