wpdiggerstudio / wpzylos-model
Lightweight ORM/Model layer for WPZylos Framework
Fund package maintenance!
v1.0.0
2026-06-14 08:19 UTC
Requires
- php: ^8.0
- wpdiggerstudio/wpzylos-core: ^1.0
- wpdiggerstudio/wpzylos-database: ^1.0
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: ^3.7
- szepeviktor/phpstan-wordpress: ^1.3
This package is auto-updated.
Last update: 2026-06-14 11:48:27 UTC
README
Lightweight ORM/Model layer for the WPZylos Framework — an elegant Active Record implementation built on top of WordPress's $wpdb, giving you the expressive model syntax you love without the overhead.
✨ Features
- 🏗️ Active Record Pattern — Intuitive model classes that map to database tables
- 🔄 Attribute Casting — Automatic type casting for
int,float,bool,string,array,json,datetime - 🔧 Accessors & Mutators — Custom
getXxxAttribute/setXxxAttributemethods - 🔗 Relationships —
hasOne,hasMany,belongsTowith lazy loading and caching - 🗑️ Soft Deletes — Trash records instead of permanently deleting them
- ⏱️ Timestamps — Automatic
created_at/updated_atmanagement - 📡 Model Events — Lifecycle hooks: creating, created, updating, updated, deleting, deleted
- 🔍 Query Scopes — Reusable local scopes with
scopeXxx()convention - 📦 ModelCollection — Rich collection wrapper with
pluck,map,filter,each,contains - 🛡️ Mass Assignment Protection —
$fillableand$guardedfor security - 📋 JSON Serialization —
toArray(),toJson()with$hiddenattribute support
📋 Requirements
| Requirement | Version |
|---|---|
| PHP | >= 8.0 |
| WordPress | >= 6.0 |
| wpzylos-core | ^1.0 |
| wpzylos-database | ^1.0 |
📦 Installation
composer require wpdiggerstudio/wpzylos-model
🚀 Quick Start
Define a Model
<?php declare(strict_types=1); namespace App\Models; use WPZylos\Framework\Model\Model; class User extends Model { protected static string $table = 'users'; protected array $fillable = ['name', 'email', 'role']; protected array $casts = [ 'is_active' => 'bool', 'metadata' => 'json', ]; protected array $hidden = ['password']; }
Basic CRUD Operations
use App\Models\User; // Create a new user $user = User::create([ 'name' => 'John Doe', 'email' => 'john@example.com', 'role' => 'admin', ]); // Find by primary key $user = User::find(1); // Find or throw an exception $user = User::findOrFail(42); // Update attributes $user->update(['name' => 'Jane Doe']); // Delete $user->delete();
Query with Scopes
// Static where() proxies to QueryBuilder $admins = User::where('role', 'admin')->get(); // Get all records $users = User::all(); // Define and use local scopes class User extends Model { protected static string $table = 'users'; protected array $fillable = ['name', 'email', 'role', 'is_active']; public function scopeActive($query) { return $query->where('is_active', 1); } public function scopeByRole($query, string $role) { return $query->where('role', $role); } } // Use scopes $activeAdmins = User::active()->where('role', 'admin')->get();
🔧 Core Features
Attribute Casting
class Order extends Model { protected static string $table = 'orders'; protected array $fillable = ['customer_id', 'total', 'is_paid', 'items', 'shipped_at']; protected array $casts = [ 'customer_id' => 'integer', 'total' => 'float', 'is_paid' => 'bool', 'items' => 'json', 'shipped_at' => 'datetime', ]; } $order = Order::find(1); $order->total; // float: 99.50 $order->is_paid; // bool: true $order->items; // array: ['widget', 'gadget'] $order->shipped_at; // DateTimeImmutable
Accessors & Mutators
class User extends Model { protected static string $table = 'users'; protected array $fillable = ['first_name', 'last_name', 'email', 'password']; // Accessor: $user->full_name public function getFullNameAttribute($value): string { return $this->attributes['first_name'] . ' ' . $this->attributes['last_name']; } // Mutator: $user->password = 'secret' public function setPasswordAttribute($value): void { $this->attributes['password'] = wp_hash_password($value); } }
Relationships
class Post extends Model { protected static string $table = 'posts'; protected array $fillable = ['title', 'body', 'user_id']; // Post belongs to a User public function user() { return $this->belongsTo(User::class); } // Post has many Comments public function comments() { return $this->hasMany(Comment::class); } } class User extends Model { protected static string $table = 'users'; protected array $fillable = ['name', 'email']; // User has one Profile public function profile() { return $this->hasOne(Profile::class); } // User has many Posts public function posts() { return $this->hasMany(Post::class); } } // Lazy-loaded, cached on first access $post = Post::find(1); $author = $post->user; // belongsTo $comments = $post->comments; // hasMany (ModelCollection)
Soft Deletes
use WPZylos\Framework\Model\Model; use WPZylos\Framework\Model\Concerns\SoftDeletes; class Article extends Model { use SoftDeletes; protected static string $table = 'articles'; protected array $fillable = ['title', 'body']; } $article = Article::find(1); // Soft delete (sets deleted_at timestamp) $article->delete(); // Check if trashed $article->trashed(); // true // Restore $article->restore(); // Permanently delete $article->forceDelete(); // Query trashed records $trashed = Article::onlyTrashed()->get(); $all = Article::withTrashed()->get();
Model Events
class User extends Model { protected static string $table = 'users'; protected array $fillable = ['name', 'email', 'slug']; protected static function boot(): void { // Generate slug before creating static::creating(function (User $user) { $user->slug = sanitize_title($user->name); }); // Log after creation static::created(function (User $user) { error_log("User created: {$user->name}"); }); // Prevent deletion of admins static::deleting(function (User $user) { if ($user->role === 'admin') { return false; // Cancel deletion } }); } }
ModelCollection
$users = User::all(); // Pluck a single attribute $names = $users->pluck('name'); // ['John', 'Jane', 'Bob'] // Map to transform $emails = $users->map(fn($u) => strtolower($u->email)); // Filter $admins = $users->filter(fn($u) => $u->role === 'admin'); // Iteration foreach ($users as $user) { echo $user->name; } // Count and check $users->count(); // 3 $users->isEmpty(); // false $users->isNotEmpty(); // true $users->first(); // First user $users->last(); // Last user // Serialize $array = $users->toArray(); $json = $users->toJson();
Service Provider Registration
// In your plugin bootstrap use WPZylos\Framework\Model\ModelServiceProvider; $app->register(new ModelServiceProvider());
📦 Related Packages
| Package | Description |
|---|---|
| wpzylos-core | Application foundation and container |
| wpzylos-database | Query builder and database connection |
| wpzylos-migrations | Database schema management |
📖 Documentation
Full documentation is available at: https://wpzylos.com/docs/latest/packages/wpzylos-model
💬 Support
- 🐛 Bug Reports: GitHub Issues
- 💡 Feature Requests: GitHub Issues
- 📖 Documentation: wpzylos.com
Support the Project
📄 License
This package is open-sourced software licensed under the MIT License.
🤝 Contributing
Please see CONTRIBUTING.md for details.
Made with ❤️ by WPDiggerStudio