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
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.
Leave a Reply
You must be logged in to post a comment.