I just got off a call with a new client. They were at their wit’s end with a “simple” membership plugin another dev built. The problem? Every time they tried to create a new membership level, the whole site would crawl to a halt. Turns out, the original developer, who clearly came from a Laravel background, had tried to force a full-blown WordPress MVC pattern right into the plugin. It was a tangled mess of controllers and models fighting against WordPress’s core event-driven system. A total nightmare.
And I get it. When you first move into serious WordPress development, especially from other frameworks, your first instinct is to impose structure. MVC (Model-View-Controller) feels like the “right” way to build things. It’s organized, it separates concerns, and it’s what all the big-boy frameworks use. But here’s the hard truth: WordPress isn’t built that way. At. All.
The Time I Tried It and Massively Failed
Trust me on this, I’ve made this exact mistake myself. Years ago, I was building a custom scheduling system for a client. I thought, “I’ll be smart about this.” I built out a beautiful set of controllers to handle booking requests and models to manage appointment data. My code was clean, self-contained, and completely wrong for WordPress. The vulnerability in my approach became obvious when the client wanted to add a simple sidebar widget to show “Upcoming Appointments.” My MVC structure had completely bypassed the WordPress Loop and the standard template hierarchy. There was no easy way to hook into my data. My perfect little black box was useless to the rest of the site. I had to rip it out and start over, the right way.
Embracing the WordPress Way: Hooks and Filters
Instead of a “Controller” that handles a specific URL, you build a class that hooks into `init` to register a post type, and then hooks into `save_post` to process meta fields. It feels different, but it’s how you work *with* the platform, not against it.
<?php
// The WordPress Way: A Class that hooks into the system.
class My_Custom_Post_Type {
public function __construct() {
// This is our entry point. Instead of a router, we use an action hook.
add_action( 'init', [ $this, 'register_cpt' ] );
add_action( 'save_post', [ $this, 'save_meta_data' ], 10, 2 );
}
public function register_cpt() {
// ... code to register custom post type ...
}
public function save_meta_data( $post_id, $post ) {
// ... code to handle saving custom fields ...
// This only runs when a post is saved. Simple. Effective.
}
}
// And to kick it all off:
new My_Custom_Post_Type();So What’s the Real Answer?
The conversation around architectural patterns in WordPress is a deep one. Some really smart people have explored alternatives, like the Action-Domain-Responder (ADR) pattern, which is an interesting take I first read about in an article over at carlalexander.ca. But for 99% of the projects out there, the answer is simpler: don’t force it. The only place a true WordPress MVC pattern makes sense is in a headless setup, where WordPress is just a data source via the REST API. In that case, your front-end JavaScript application can be MVC, MVVM, or whatever you want. The PHP side, however, should stick to the script.
Look, this stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want your site to work, drop my team a line. We’ve probably seen it before.
The takeaway here isn’t that MVC is bad. It’s that context is everything. A good developer uses the right tool for the job, and in WordPress, the right tools are actions and filters. Period.
Leave a Reply