We Need Better Abstraction in WordPress Projects

When it comes to programming – regardless of the platform, language, or system that you’re using – there’s a concept of abstraction that most programmers understand even if they don’t know that that’s what the concept is called.

Perhaps the clearest definition on abstraction in programming (straight from Wikipedia) explains:

Abstraction is the process by which data and programs are defined with a representation similar in form to its meaning (semantics), while hiding away the implementation details.

A simple, practical example of an abstraction would be the concept of functions: It completes a unit of work and optionally accepts parameters and returns data to the caller

The details are implemented – are abstracted – into the function so that other programmers (or even the original developer himself or herself) can simply make a single call to the function.

Easy enough, right? Especially since we’ve all written functions.

Of course, abstractions can be more complex. Starting from functions, moving up to classes, moving up to full API’s and so on. Everything in programming lives at some level of abstraction.

I bring all of this up because I’ve seen – and continue to see – huge opportunities for refactoring WordPress-based code (specifically in themes and plugins) into more abstract units in other code as well as my own.

An Example of Abstraction

Suffice it to say that I’m a huge proponent of abstraction. I think that it makes code easier to follow, easier to maintain, and it eases development in existing projects because it provides conventions for which new code and/or files should be introduced.

Though you could argue that this is technically more of a “convention over configuration” scenario, I try to pull this practice through most everything I do especially with both the Plugin and Widget boilerplates.

  • There is a specific place for each type of file be it JavaScript, stylesheets, markup, or functions.
  • There are specific places in the code for core functions, public functions, and private functions.
  • There are conventions by which certain things should be followed so that adding or removing components is relatively easy.

Even still, this is a weak example because when I think of abstraction – especially at the functional level – it all goes back to code.

So what would this look like in terms of WordPress-specific code?

Abstracting a User Query

An Abstract Superman

Our code should be as abstract and awesome as Abstract Superman.

Here’s an example that I’ve seen in template files in which a programmer is using WP_User_Query to retrieve 25 users at a time all of who currently exist (or aren’t deleted, as set in the meta data).

A Look at the Unabstracted

The original template file looked something like this:

$number = 25;
$individuals_query = new WP_User_Query(
	array(
		'meta_key'		=>	'status',
		'meta_value'	=>	'deleted',
		'meta_compare'	=>	'!=',
		'offset'		=>	get_query_var( 'page' ) * $number,
		'number'		=>	$number
	)
);
$individuals = $individuals_query->get_results();
?>

<tbody>
	<?php foreach( $individuals as $individual ) { ?>

		<?php // Exclude the admin! ?>
		<?php if( 1 != $individual->ID ) { ?>
			<tr>
				<td><?php echo get_user_meta( $individual->ID, 'first_name', true ); ?></td>
				<td><?php echo get_user_meta( $individual->ID, 'last_name', true ); ?></td>
				<td><?php echo $individual->user_email; ?></a></td>
			</tr>
		<?php } // end if ?>

	<?php } // end foreach ?>
</tbody>

Notice that I’ve snipped out some irrelevant code in an attempt to make this as clear as possible.

The key things to notice are that:

  • The template is responsible for building and executing the query
  • Looping through the query to render the data
  • Presenting the information from the results of the query

If you subscribe to the idea that functions, templates, and other building blocks of building applications should do one thing and do them well, then you’ll notice that there’s already a problem: The template is building the query and rendering it’s data.

Generally speaking, templates should be responsible for rendering the data, right?

Abstracting The Above

To introduce a level of abstraction in the code above would be to break this into two logical components:

  • A function responsible for building the query and returning results
  • A template for rendering the content of the results

Now, because of the nature of PHP and templating files, we can’t completely get away without mixing languages in our template files, but we can certainly improve it.

So the first step is to abstract the query functionality into its own function into a place such as functions.php:

function example_get_individuals() {

	$number = 25;
	$individuals_query = new WP_User_Query(
		array(
			'meta_key'		=>	'status',
			'meta_value'	=>	'deleted',
			'meta_compare'	=>	'!=',
			'offset'		=>	get_query_var( 'page' ) * $number,
			'number'		=>	$number
		)
	);

	return $individuals_query->get_results();

} // end example_get_individuals

Then we can update the template so that it makes a call to the function and properly renders the data:

<tbody>
	<?php foreach( example_get_individuals() as $individual ) { ?>

		<?php // Exclude the admin! ?>
		<?php if( 1 != $individual->ID ) { ?>
			<tr>
				<td><?php echo get_user_meta( $individual->ID, 'first_name', true ); ?></td>
				<td><?php echo get_user_meta( $individual->ID, 'last_name', true ); ?></td>
				<td><?php echo $individual->user_email; ?></a></td>
			</tr>
		<?php } // end if ?>

	<?php } // end foreach ?>
</tbody>

Though we’ve technically introduced two files in place of one, we’ve simplified what each part of the application is doing.

This makes readability and maintenance easier and arguably improves overall cohesion.

What About Doing Right It?

One of the most common things that developers see in the WordPress development community is the idea of “doing it right,” versus “doing it wrong.”

Whenever it comes to developers doing thing incorrectly, I try to believe the best in that it’s simply a lack of experience that leads them to do so – not an attitude of “I can do it this way, so I will do it this way.”

But who knows.

That said, I think a case can be made that implementing custom queries in template files rather than abstracting them out into their own functions is the WordPress way to do it. I don’t really know, but I do know that abstraction improves overall development and decreases technical debt.

So, with that said, I want to be clear that I’m a huge proponent of doing it the WordPress way, but I also think it’s important to question what and why we are doing something the way we are doing it.

Usually, especially in open source software, there’s a reason things are the way they are, but I don’t think we should take that for granted. Rather, I’d love to evaluate ways we’re doing things, offer ways to improve it, and see if it sticks.

9 Comments

Something I’ve started doing to abstract queries is build a new class extending WP_Query.

I do struggle, on larger projects, with how much to abstract things. There is a point at which abstraction just adds layers of confusion.

    Yes – abstraction can be a dangerous thing especially for those of us that care deeply about well-designed systems. You don’t want to be an architecture astronaught, but you don’t want to simply throw something together and have it hold together just enough to work.

    It’s like Han Solo said, “She’ll hold together! … Hear me, baby, hold together!”

      The best method I’ve come up with on large projects is to start with little abstraction. When I need the same thing 2X, I put it in a spot on it’s own for reuse.

      I also try to stick to the single responsibility principle. A method or function should only have 1 job. So if it’s to show content, it contains little/no logic to sort out the content.

When we take an html template and turn it into php, we’re doing the same thing, turning a block of header code into a single line in the index.php file. In the same manner, abstracting a function actually gives you the chance to give the theme user more control over their theme. In your example, rather than hard-coding the 25, you could add the choice for that number into the theme options, or make the number change depending on the template.

Thanks for the thoughts, I’m going to pull some old themes out and start abstracting.

    Good stuff, Evan.

    One person actually emailed me and mentioned that $number could be a parameter that’s passed into a function which fits nicely with your suggestion about making it an option.

    Both cases are right and I definitely agree.

    When it comes to posts like this, I have to balance giving fair example code without getting too complicated so that the actual point of the code isn’t missed. Regardless, love the feedback you guys always offer!

Good post. I think it also depends where the code is going, or what it will be used for. I’ll write code differently, for instance, if it’s going to be distributed and (hopefully) used by a bunch of people. In those cases I’m less likely to abstract as much code, I think. Given your example, I would likely include the query in the template itself, since that’s where most would expect it to be.

But for something a bit more complete, for a project of my own or for something where it isn’t likely to be distributed and plugged into something else — and where things are likely a bit more complex — I’ll abstract a bit more and organize a little differently.

I’ll pay more attention to my abstraction habits and see how much it really does change project to project, though.

    I agree with you to a point. Depending on how the code is going to be distributed dictates just show well organized and well abstracted the code is.

    I’m not sure what that says about me :), but if I’m the only one using it then I’m way more comfortable with just making sure it’s working; however, if other people are going to see it, if it’s a larger project that I’ll be adding on to later, and/or I want others to contribute to it, I’ll work to make sure that the architecture is as solid as I can get it at least for a 1.0.

    Still – dig your thoughts, Ryan. Glad to have you chime in as I always enjoy hearing how others programmers approach the similar situations.

      On projects that are just for clients/myself I definitely have a point where awesome code design goes out the window in favour of deadlines or just getting the beast off by back.

      I try to put in code comments that at least acknowledge lack of planning in a particular section, just so a programmer that comes after me doesn’t think I was a bozo.

Trackbacks and Pingbacks

Why Extensions? | Pippins PluginsMarch 28, 2013 at 1:23 pm

[...] more you abstract your code, the easier it is to maintain. Separate “pieces” of code are dramatically easier to fix [...]

Leave a Reply

Name and email address are required. Your email address will not be published.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>