Jason Sultana

Follow this space for writings (and ramblings) about interesting things related to software development.

MVC in Wordpress

04 Oct 2020 » php, wordpress

G’day guys!

This week, I wanted to talk a bit about implementing the MVC pattern in a Wordpress application.

Wait, what was this MVC stuff again?

Just in case you’re not familiar with the paradigm, I’ll give a very quick overview here. MVC, which stands for Models, Views, Controllers is a design pattern that originally came out back in the 1970s as a way to organise code in desktop applications, but it’s pretty popular nowadays in web applications as well. The components are:

  1. Models. Models represent the data structures (or data models, if you prefer) that your application uses. The nitty-gritty details of this vary from between teams, projects and domains, but you can imagine C-style structs with data properties. Your application will use these models to perform various functions.

  2. Views. Views represent the user interface. In the context of web apps, this is usually HTML, but it can have some template code (eg: PHP) within it to make it more dynamic before returning it to the browser.

  3. Controllers. Controllers wire up the models and the views. When an action is executed (eg: making a HTTP request on a certain route), the controller gets invoked by the MVC engine, potentially with a payload from a POST request, which can be considered an input model. The controller will then probably interact with a database or another webservice and obtain a model that represents something that’ll be returned to the caller (eg: product details). The controller then returns a view which is populated based on that model. You can argue about various levels of abstraction that should be applied here, but the main point to take away is that controllers get invoked by the runtime and they return a view populated by the model.

For more information, you can take a quick read of the wiki page. Alrighty, let’s move on!

If your project is big enough to use MVC, you shouldn’t be using Wordpress!

I know, I know. I maintain that Wordpress is pretty good for blogging or single website maintenance for non-techy users, but definitely should not be used for probably anything that you could call an application that has business logic and something that you’d consider using MVC for. But sometimes, you don’t get to be the one that makes that decision. Sometimes that decision has already been made by a predecessor or a client, and the project is too far in to change that decision. So what are you going to do? You can whine and complain about it in a loop until you hit a buffer overlow, but that’s not solving any problems. So today I’d like to make a suggestion for how you might go about things if you’re stuck in a situation where you need to use Wordpress, but would like to add some sanity and structure to the project.

First, let’s talk a little bit about where I recommend you to write your code.

Um, there’s already a place for that?

Yep, good old functions.php in your theme. Need an ajax endpoint? functions.php. Need to return a view to the browser? functions.php. Need to override some Wordpress behaviour? functions.php. Reminds me of those good ol’ LJ Hooker TV commercials like this one.

The problem with making changes directly here (or in a child theme) is that you’re coupling the logic that you’re trying to implement with the website presentation (the theme). So now the end user is unable to change themes without losing all of the functionality. Instead, I’d recommend using the following plugin: https://github.com/woocommerce/theme-customisations. It does fall under the woocommerce account, but there’s nothing directly coupling the plugin to WooCommerce itself. Or of course, you could just write your own plugin from scratch.

Alrighty, let’s see it!

Very well :) Assuming you’re using the plugin I suggested earlier, your project might look something like this:

\custom\
    functions.php
    
    \app\
        \controllers\
            say_hello_controller.php
        \models\
            say_hello_model.php
        \views\
            say_hello_view.php

You’ll probably have additional resources like images, javascript and css, and maybe some database code in there as well, but this should be the core of it. Let’s explore these in a bit more details

say_hello_model.php

<?php
    class say_hello_model {
        public $message;
    }

The model is super simple, especially in this contrived example. Basically it just contains a message that we’ll want to display in the view. Oh, and if this is a genuine WP project you’ll be implementing this into, you’ll definitely want to decorate the class names with a prefix specific to your project, to avoid collisions with other plugins, etc.

say_hello_view.php

<h3><?php echo $model->message; ?></h3>

say_hello_controller.php

<?php
    add_action( 'wp_ajax_say_hello', 'say_hello' );    
    add_action( 'wp_ajax_nopriv_say_hello', 'say_hello');
    function say_hello() {
        $message = $_POST['message'];
        
        require_once(dirname(__FILE__) . '/../models/say_hello_model.php');
        $model = new say_hello_model();
        $model->message = $message;

	    ob_start();
        require_once(dirname(__FILE__) . '/../views/say_hello_view.php');
	    echo ob_get_clean();

        die();
    }

The controller accepts a message from the client payload, instantiates a new instance of the model with the message populated, and then loads and outputs the view. As I said earlier, extremely contrived, but you get the idea. It’d be easy to hook up extra calls to the database to load data dynamically. But, there’s still one more thing left before this will work. So far, Wordpress doesn’t know anything about our controller, so we need to register it.

functions.php

<?php
    // Add Controllers
    require_once(dirname(__FILE__) . '/app/controllers/say_hello_controller.php');

And that’s it! You can add subfolders as required as the project grows, and you should be able to keep things reasonably organised - at least compared to a single bloated functions.php file. Plus, since MVC is such a well-known paradigm, the project should be pretty easy to pick up for other devs as well.

Anyways, that’s all from me for now. See you again next week!

Catch ya!