HTML in Functions Kills Kittens: MVC In WordPress Plugins and Themes

These are the speaker notes for the talk that I gave at WordCamp Ottawa or Toronto 2017. If that’s where you get the address from, you’re in the right place! I have an example boilerplate at the bottom of the post. I would love to hear from you on this talk. Questions? Kudos? Criticism? Leave a comment. Download the slides.

We’ve all seen it. We have a project that has some slightly complicated requirements that we know we’ve seen a plugin for. We find the plugin. It does 90% of what we need it to do. So we decide to dive in and edit some code.

Picture of badly formatted code

And we see this.

More code that may cause nausea, vomiting, upset stomach or diarrhea.

Or we see this. CAUTION!!! May cause nausea, vomiting, upset stomach or diarrhea.

We think “Could someone please teach this person to write code,” or “I could write better code with my all my limbs tied behind my back,” or “this looks like Clippy barfed on my [insert your favourite IDE here].”

What’s a better way? MVC. That stands for Model-View-Controller. It’s a structure that many programming languages use to separate the data access and the user interface so that you don’t have a giant mess of code and HTML.

But you’re saying, “WordPress is not MVC.” You’re right. But we aren’t talking about Core here.

Why would you want to build a plugin or a theme that way? For a few reasons:

  • Having this structure lends itself to writing clean, readable code. (Go to Shawn Hooper’s talk on Sunday [I’ll link here when he posts it] to go deeper in writing clean code.
  • You may have heard of the DRY Principle (Don’t Repeat Yourself). This principle states that if there are tasks that need to be run more than once, even with slight variation, you write it once and reuse it. Like a cookie cutter: you can have different types of cookies, like chocolate chip, peanut butter, or oatmeal. Just wash your cookie cutter thoroughly to avoid cross contamination.
  • Open Source is about sharing ideas and giving of your code freely. Shouldn’t that extend to the attitude of what you’re giving away? Making sure it’s something usable and modifiable for both developers and users alike.
  • Reduce confusion. Most of you, even if you are a plugin developer, will rarely ever field support requests from other developers. That doesn’t mean you’re not confusing them. Don’t confound other developers by how unreadable your code is, impress them with your ability to code something complex yet easy to follow.


How should I, as a WordPress developer, approach this way of building?

  • Like any project, planning is key. Know what the expectations are for the plugin, know what pieces of data will be utilised (Custom Post Types, APIs, does the plugin require an admin settings screen, etc.)
  • As a core concept of MVC, maintain a “separation of concerns.” Like separating recycling, compost, and other garbage; separate your data logic from your view logic and use a controller that melds those pieces together.
  • Be consistent. From indentation to method naming, stay consistent. Don’t use create, read, update and delete in one model and make, fetch, up_date and remove in another. Consistency in style of code? Are you a cuddler? Doesn’t matter if you are or not, just stick to your guns. Spaces vs tabs? Again, just use the same everywhere. Comments – comment well, comment often, comment consistently. And learn what a docblock is.


What are some best practices for using MVC in WordPress? Take all this with a grain of salt. Programming is an art. An art instructor will tell you how to hold the brush and how to use the paint, but they won’t tell you what to paint or how your style should be. This is my structure, use and mould it to your liking.

Plugin Structure

Controller (/classes/class-controller.php)

  • Handles setup and teardown (install, uninstall, startup, finishing tasks)
  • Handles hooks and actions required
  • Gets data from models
  • Handles views (separate public/admin views in separate files if you wanna)
  • Passes pertinent information to the view(s)
  • NO HTML.

Models (/classes/class-data-model.php)

  • Creates, reads, updates and deletes (CRUD!) data
  • Uses WP built-in functions for handling data
  • Can be from custom posts, custom tables or APIs (WordPress has a great cURL class. Further reading.)

Views (/views/view.php)

  • Made with HTML
  • Limit PHP functions to loops and echo/print

Theme Structure

Controller (functions.php)

  • Handles setup and teardown (install, uninstall, startup, finishing tasks)
  • Handles hooks and actions custom to your theme
  • Gets data from models
  • Let WordPress handle views (standard files in your theme like index.php, page.php, single.php, etc.)
  • Handle admin views (settings, customizations, etc.)
  • Easy access for complex data retrieval (via models) for view(s)
  • NO HTML.

Models (/classes/class-data-model.php)

  • Creates, reads, updates and deletes (CRUD!) data
  • Uses WP built-in functions for handling data
  • Can be from custom posts, custom tables or APIs


  • Stick to WordPress’ way of handling views
  • Less confusion for developers new to MVC development
  • Consistency – be consistent with other theme devs
  • But don’t be afraid to use /views/ for repeat use “partials” that don’t fit in the WordPress structure

Applies to both Plugins and Themes: Static Files (/static/js, /static/css, /static/img)

  • Store all the non-processed files
  • JavaScript can be processed, but use localization!
  • Images, CSS, Less/Sass/that other one

Examples of themes and plugins

Wrap it up

So those are a few guidelines that I follow. Again, remember the painting teacher analogy: I’m showing you the paint, the brush and the canvas; I’m showing you how I create a masterpiece. Everything considered, the main points¬†can be wrapped up in 3 concise points:

  1. Don’t put HTML inside a function.
  2. Keep your code clean
  3. Be a good open source citizen.

Let’s continue the conversation! We had a great discussion at #WCTO. Keep it going below!