MVC in WordPress: The Pattern Everyone Learns, Few Truly Apply

π Originally published on 4wp.dev β MVC Pattern in WordPress. Long read on LinkedIn: MVC in WordPress: the pattern everyone learns, few truly apply.
Every WordPress developer has heard of MVC. Very few plugins actually follow it.
https://www.youtube.com/watch?v=C2DnJEmbk4A
WordPress isn't an MVC framework β but its building blocks map cleanly onto Model Β· View Β· Controller once you know where to look.
π Interactive diagram with all examples: 4wp.dev/architectures/mvc
1. Controller β the traffic director
Receives the request, validates it, calls the Model, picks the View. No SQL. No HTML.
In WordPress, Controllers are:
// Controller β REST endpoint
register_rest_route( 'myplugin/v1', '/products', [
'methods' => 'GET',
'permission_callback' => fn() => current_user_can( 'read' ),
'callback' => function ( WP_REST_Request $req ) {
$products = get_all_products( $req->get_param( 'category' ) ); // β Model
return rest_ensure_response( $products );
},
] );
β‘οΈ More Controller examples (hooks, AJAX): 4wp.dev/architectures/mvc/#mvc-detail-controller
2. Model β the data layer
Owns data and business rules. Returns clean data. Never renders HTML.
In WordPress, Models are:
Custom Post Types, taxonomies, registered meta (schema)
$wpdbdata-access functions/classesOptions API settings classes
// Model β the only layer that touches options
class PluginSettings {
private const KEY = 'myplugin_settings';
public static function get( string $key, $default = null ) {
return ( get_option( self::KEY, [] ) )[ $key ] ?? $default;
}
}
β‘οΈ CPT schema and $wpdb examples: 4wp.dev/architectures/mvc/#mvc-detail-model
3. View β the presentation layer
Renders data it receives. No queries. No business logic.
In WordPress, Views are:
theme templates (
single.php,archive.php)shortcode output
Gutenberg block
save()/ render templates
<!-- View β escape, display, nothing else -->
<article class="product">
<h1><?php echo esc_html( $product['title'] ); ?></h1>
<p class="price"><?php echo esc_html( $product['price'] ); ?></p>
</article>
β‘οΈ Shortcode and block examples: 4wp.dev/architectures/mvc/#mvc-detail-view
4. Real plugin: 4WP Weather
4WP Weather (GitHub) is built along the same lines:
| Layer | In the plugin |
|---|---|
| Controller | REST route forwp-weather/v1/weather β the block calls it, PHP does the remote request |
| Model | Provider (OpenWeatherMap), API key in Options API, transient cache |
| View | Gutenberg block with Small / Compact / Advanced templates |
Result: the API key never reaches the browser, cache lives in one place, and the block only renders.
Another example of the 4WP approach: 4WP SEO Helper (GitHub).
5. Quick checklist
[ ] Controllers are thin: validate β call Model β return/render
[ ] Only the Model touches
$wpdb, options, meta[ ] Views contain only escaping and markup
[ ] Nonces and capability checks live in the Controller
[ ] Templates never call
WP_Querydirectly
Go deeper
π§© MVC & Layers
π§± SOLID in WordPress
π― OOP
π Design Patterns
ποΈ All Architectures
π 4WP plugins
Written by Anatoliy Dovgun Β· 4wp.dev β FSE WordPress development. Follow: GitHub Β· X Β· DEV Β· Medium Β· Hashnode Β· YouTube



