wpify / model
WPify Model
Installs: 14 916
Dependents: 0
Suggesters: 0
Security: 0
Stars: 3
Watchers: 2
Forks: 0
Open Issues: 1
Requires
- php: >=8.0.0
- dev-master
- 4.1.18
- 4.1.17
- 4.1.16
- 4.1.15
- 4.1.14
- 4.1.13
- 4.1.12
- 4.1.11
- 4.1.10
- 4.1.9
- 4.1.8
- 4.1.7
- 4.1.6
- 4.1.5
- 4.1.4
- 4.1.3
- 4.1.2
- 4.1.1
- 4.1.0
- 4.0.21
- 4.0.20
- 4.0.19
- 4.0.18
- 4.0.17
- 4.0.16
- 4.0.15
- 4.0.14
- 4.0.13
- 4.0.12
- 4.0.11
- 4.0.10
- 4.0.9
- 4.0.8
- 4.0.7
- 4.0.6
- 4.0.5
- 4.0.4
- 4.0.3
- 4.0.2
- 4.0.1
- 4.0.0
- v3.x-dev
- 3.1.10
- 3.1.9
- 3.1.8
- 3.1.7
- 3.1.6
- 3.1.5
- 3.1.4
- 3.1.3
- 3.1.2
- 3.1.1
- 3.1.0
- 3.0.9
- 3.0.8
- 3.0.7
- 3.0.6
- 3.0.5
- 3.0.4
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 2.1.97
- 2.1.96
- 2.1.95
- 2.1.94
- 2.1.93
- 2.1.92
- 2.1.91
- 2.1.9
- 2.1.8
- 2.1.7
- 2.1.6
- 2.1.5
- 2.1.4
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.1
- 2.0.0
- 1.0.0
This package is auto-updated.
Last update: 2024-11-15 11:45:26 UTC
README
This library provides a better access to data in WordPress. It is a wrapper around the WordPress API, which provides a more object-oriented approach to the data. It also provides a way to define custom models for your data, for example to define a model for a custom post type, custom taxonomy or custom database table.
Benefits
- Object-oriented access to data.
- Easy to use.
- Easy to extend.
- Easy to define and use custom tables.
- Minimise the number of queries to the database.
- Uses modern PHP 8 features for better developer experience.
Core concepts
The library uses a few types of objects:
- Model: A model is a class that contains data of one entity, e.g. single post, term or table row. Model has clearly defined properties and methods to access the data.
- Repository: A repository is a class that provides access to the data. Repository can retrieve data from the database, from the cache or from other sources.
- Manager: Manager keeps the list of registered models and repositories. It also provides a way to retrieve a model or repository by its name.
Requirements
- PHP 8.0 or higher
Installation
Install the library using composer:
composer require wpify/model
Basic usage
First think you need to do is to initialize the Manager to have access to built-in models and repositories:
use Wpify\Model\Manager; $manager = new Manager();
With the manager you can use a built-in models and repositories. For example, to get all published posts you can use the following code:
$post_repository = $manager->get_repository( Wpify\Model\Post::class ); $posts = $post_repository->find_published();
And then you can access the data using the model:
foreach ( $posts as $post ) { echo $post->title; }
You can also retrieve a single post by its ID or other keys:
$post = $post_repository->get( 123 ); $post = $post_repository->get( 'article-slug' ); $post = $post_repository->get( 'https://myblog.con/article-url/' );
Updating the model
To update the data, you simply update model's properties and then save the data by calling the save()
method on the repository:
$post->title = 'New title'; $post_repository->save( $post ); echo $post->title; // New title
Creating new entries
To create a new entry, you need to create a new model via repository and then save it:
$post = $post_repository->create( array( 'title' => 'New post', 'content' => 'New content', ) ); $post_repository->save( $post ); echo $post->id; // 123
Deleting the entry
To delete the entry, you need to call the delete()
method on the repository:
$post_repository->delete( $post );
Custom models
You can define your own models to access the data in custom post types, custom taxonomies or custom database tables.
All your custom models must extend the Wpify\Model\Model
class or other models. Every custom model must have
a repository, which must extend the Wpify\Model\Repository
class or other repositories.
Defining a custom model
In this example, we will define a model for a custom post type with some meta fields:
use Wpify\Model\Post; use Wpify\Model\Attributes; class Book extends Post { #[Attributes\Meta] public string $isbn; #[Attributes\Meta] public string $author; }
All properties have a definition in the form of a PHP attribute. You can use the following attributes:
Attributes\AliasOf
- defines an alias for another property.Attributes\AccessorObject
- defines a getter and setter from the source object.Attributes\ChildPostRelation
- defines a relation to a child post (for post models only).Attributes\ChildTermRelation
- defines a relation to a child term (for term models only).Attributes\Column
- defines a column in a custom table (for custom table models only).Attributes\IdsRelation
- retrieves related posts by IDs.Attributes\ManyToOneRelation
- retrieves related models by foreign model's ID in another property.Attributes\Meta
- defines a meta field.Attributes\OrderItemsRelation
- retrieves order items.Attributes\PostTermsRelation
- retrieves related terms by post ID. This attribute also persists the post-term relation.Attributes\PostTermRelation
- retrieves related term by post ID. This attribute also persists the post-term relation. Beware, that if the post has more than one term, only the first one will be returned or persisted.Attributes\SourceObject
- defines a value in a source object for the model (e.g. WP_Post property).Attributes\TermPostsRelation
- retrieves related posts of term (for term models only).
There are also attributes that can modify a behaviour of the propery:
Attributes\ReadOnlyProperty
- makes the property read-only.
Some of the attributes have additional parameters, that can be passed by named constructor arguments:
#[Attributes\SourceObject( 'ID' )] public int $id; #[Attributes\Meta( '_isbn' )] public string $isbn; #[Attributes\Meta( meta_key: '_author' )] public string $author; #[Attributes\Column( type: Attributes\Column::VARCHAR, params: 1000, unique: true )] public string $custom_column;
Most of the attributes have a default values, so you can omit some of the parameters.
Defining a custom repository
To actually use the model, you need to define a repository for it. In this example, we will define a repository for the Book
model:
use Wpify\Model\PostRepository; class BookRepository extends PostRepository { public function model() : string{ return Book::class; } public function post_types() : array{ array( 'book' ); } }
After repository creation, you need to register it in the manager:
$manager->register_repository( BookRepository::class );
You can also register the repository in the constructor of the manager:
$manager = new Manager( new BookRepository() );
If you use a PHP-DI, you can register the repository in the container:
use DI; use Wpify\Model\Manager; $container_builder = new DI\ContainerBuilder(); $container_builder->addDefinitions( array( Manager::class => DI\create()->constructor( DI\get( BookRepository::class ), ), ) ); $container = $container_builder->build(); $manager = $container->get( Manager::class ); $book_repo = $manager->get_repository( BookRepository::class );
Built-in models
The library provides a few built-in models and repositories. You can use them also to define your custom models by extending them.
Post
andPostRepository
for posts.Page
andPageRepository
for pages.Attachment
andAttachmentRepository
for attachments.Category
andCategoryRepository
for categories.PostTag
andPostTagRepository
for post tags.User
andUserRepository
for users.Comment
andCommentRepository
for comments.User
andUserRepository
for users.Menu
andMenuRepository
for menus.Site
andSiteRepository
for sites.Product
andProductRepository
for WooCommerce products.Order
andOrderRepository
for WooCommerce orders.OrderItem
andOrderItemRepository
for WooCommerce order items.ProductCat
andProductCatRepository
for WooCommerce product categories.
Custom table models
You can create and use custom table models. To do this, you need to define a repository for the model and a model itself. The table is created automatically, so you don't need to handle it manually, but you can disable this behaviour.
Example:
class MyModelRepository extends CustomTableRepository { public function model(): string { return MyModel::class; } public function table_name(): string { return 'my_model'; } }
You also need to define the model with column attributes:
class MyModel extends Model { #[Column( type: Column::INT, auto_increment: true, primary_key: true )] public int $id = 0; #[Column( type: Column::VARCHAR, params: 255 )] public string $name = ''; }
The Column attribute accepts the following parameters:
name
: The name of the column. If not specified, the name of the property will be used.type
: The type of the column. If not specified, the type will be inferred from the property type.params
: The parameters for the column type. For example, for VARCHAR, you can specify the length.unsigned
: Whether the column is unsigned. Default is false.nullable
: Whether the column is nullable. Default is false.default
: Column default value.on_update
: Column default value on update.auto_increment
: Whether the column is auto-increment. Default is false.primary_key
: Whether the column is primary key. Default is false.unique
: Whether the column is unique. Default is false.foreign_key
: Array with data to set foreign key.
The model must contain exactly one primary key column.
Column can be one of the following types:
Column::TINYINT
(tinyint
)Column::INT
(int
)Column::BIGINT
(bigint
)Column::BOOLEAN
(boolean
)Column::DECIMAL
(decimal
)Column::DATE
(date
)Column::DATETIME
(datetime
)Column::TIMESTAMP
(timestamp
)Column::TIME
(time
)Column::CHAR
(char
)Column::VARCHAR
(varchar
)Column::BLOB
(blob
)Column::TEXT
(text
)Column::ENUM
(enum
)Column::SET
(set
)Column::JSON
(json
)
Foreign key array contains these items:
Column::FOREIGN_TABLE
: Foreign table name without WP prefix (e.g.posts
).Column::FOREIGN_COLUMN
: Foreign column name (e.g.ID
).Column::FOREIGN_SETTINGS
: Optional settings, for exampleON DELETE CASCADE
.
The repository will automatically create the table when the repository is used. If you want to disable automatic migrations,
you can pass false
to the auto_migrate
parameter in the constructor. You can then manually migrate the table by calling
the migrate()
method in appropriate place, e.g. plugin activation hook, admin_init
hook, etc.
$repository = new MyModelRepository( auto_migrate: false ); $manager->register_repository( $repository ); add_action( 'admin_init', array( $repository, 'migrate' ) );
The table name is automatically prefixed with the WordPress table prefix. If you want to disable this, you can pass false
to the use_prefix
parameter in the constructor.
$repository = new MyModelRepository( use_prefix: false ); $manager->register_repository( $repository );
If you want to drop the database table, you can call the drop_table()
method. This is useful when uninstalling the plugin.
$repository = new MyModelRepository(); $manager->register_repository( $repository ); register_uninstall_hook( $main_php_file_path, array( $repository, 'drop_table' ) );
Querying the custom table
You can query custom tables with find function:
$items = $repository->find( array( 'where' => "name = '" . esc_sql( 'Alex' ) . "'", ) );
Even this works, it is not recommended to use this method, because it is vulnerable to SQL injection. Instead, you should use array as arguments, that sanitizes the values, and you can use complex queries:
$items = $repository->find( array( array( 'table.col0 <>' => true, 'OR', 'table.col1' => true, 'or', array( 'table.col2' => 'active', 'table.col3 <>' => 'active' ) ), 'table.col4' => array( 1, 2, 3 ), 'table.col5 NOT IN' => array( 'test', 'test2', 'test3' ), 'table.col6 BETWEEN 1 AND 10', 'table.col7 BETWEEN' => array( 1, 10 ), 'EXISTS' => 'SELECT * FROM table2 WHERE table.id = table2.table_id', ) );
As you can see, you can use even nested queries or specify the operator in the key. You can also define, whether to use OR, or AND operator.
TODO:
- make generated documentation
- add tests
- custom tables - caching, metadata
- implement other WooCommerce models:
- VariableProduct
- SimpleProduct
- GroupedProduct
- ExternalProduct
- DownloadableProduct
- ProductTag
- ProductAttribute
- ProductVariation
- ShopCoupon
- ShopWebhook
- implement WooCommerce Subscriptions models
- implement SQL query model