Learn to build a robust Model layer in your WordPress plugin. Discover how to abstract database logic, centralize queries, and improve your code's architecture.
Previously in this course, we explored Secure CRUD Operations and Querying with WP_Query. While those lessons focused on how to talk to the database, this lesson focuses on where that code belongs. By introducing the Model layer, we move away from scattered, inline SQL queries and toward a clean, professional MVC architecture.
In WordPress development, it's tempting to sprinkle $wpdb calls or get_posts() functions directly inside your controllers or template files. This is a "code smell." When your database schema changes or you need to optimize a query, you end up hunting through dozens of files to find every instance of that query.
The Model acts as the single source of truth for your data. Its sole responsibility is to communicate with the database and return structured data to the Controller. By abstracting this logic, your Controller doesn't need to know how an article is fetched; it only needs to know that it asked the Model for an article and got one back.
We will now create a class specifically designed to handle all interactions for our Knowledge Base articles. This class will encapsulate the table logic and query parameters.
Create a new file at includes/Models/KnowledgeBaseModel.php:
PHP<?php namespace KnowledgeBase\Models; class KnowledgeBaseModel { #6A9955">/** * Fetch a single article by ID. * * @param int $article_id * @return \WP_Post|null */ public function get_article(int $article_id) { $post = get_post($article_id); if (!$post || $post->post_type !== 'kb_article') { return null; } return $post; } #6A9955">/** * Fetch all published articles. * * @return \WP_Post[] */ public function get_all_articles() { return get_posts([ 'post_type' => 'kb_article', 'post_status' => 'publish', 'posts_per_page' => -1, ]); } }
By wrapping these functions, we’ve achieved two things:
get_all_articles, we only edit this one file.If you ever need to interact with custom database tables (not just posts), you would place that logic here, using $wpdb as we discussed in Secure CRUD Operations.
Your task is to extend the KnowledgeBaseModel class. Add a method named get_articles_by_category that accepts a category slug as an argument and returns the associated posts.
Hint: Use tax_query within get_posts to filter by your custom taxonomy.
get_posts, avoid accessing $_POST or $_GET inside your Model. Keep the Model's inputs strictly defined by its method parameters.ArticleModel, CategoryModel).We've successfully moved our data access logic out of the Controller and into a dedicated Model class. This abstraction ensures that our plugin remains modular, testable, and significantly easier to maintain as it grows. Just as we discussed in Saving Meta Data, maintaining a clean separation of concerns is the secret to professional-grade WordPress development.
Up next: We will learn how to bridge the gap between our new Model and the user interface by enqueuing scripts and styles properly.
Learn to extend the WordPress REST API by registering custom endpoints. We'll show you how to securely serve your Knowledge Base data as structured JSON.
The Model Layer for Data
Plugin Security Best Practices
Composer for Dependencies
Theme Integration Hooks
Managing Assets with Gulp/Webpack
Documentation Standards
Plugin Deployment Strategy
Advanced MVC: Dependency Injection
Handling Large Datasets
Error Handling and Logging