Advertisement

Writing Better APIs and Libraries for WordPress

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →

It feels like everything we touch is carefully designed: websites, phones, subway maps, and so on. Even the things we used to take for granted: thermostats, smoke detectors and car dashboards now get a careful user experience treatment.

Design isn't just about the look and feel: it's about considering every way a user needs to interact with our device/tool/screen/object. 

This applies to programming, too.

(Un)designed programming

Programming languages are big, complicated worlds. Even PHP, which plenty of programming snobs think is too "easy", is actually a pretty complicated mix of functions and classes that behave in very inconsistent ways. 

The syntax, methods and naming have evolved over many years across millions of different users and applications. Most tend to reflect the underlying construction of the internals — not necessarily how you would want to use it.

Great moments in API design: jQuery

When I started writing JavaScript back in 2006 or so, it was a mess. Here's how I would find a tag with a certain class and move it around the DOM back then:

var uls = getElementsByTagName("ul");
var classToSearch = "foods";
for (var i = 0; i < uls.length; i++) {
    var classes = uls[i].getClasses();
    for (var j = 0; j < classes.length; j++){
        if (classes[j] == classToSearch){
            myUL = uls[i];
        }
    }
}

var $li = document.createElement('li');
$li.innerHTML = 'Steak';
myUL.innerHTML += $li;

Done!

jQuery made JavaScript fun again. In the late 2000s, the effect was so dramatic that I remember my dad asking me about "some jkwery thing" he read about in the Wall Street Journal. But despite its great effect, jQuery didn't add any "new features" to JavaScript. It just took the things developers had to do and broke it down into really clear patterns.

Rather than re-invent how to find stuff on the page, they leveraged what people already knew: CSS selectors. Then it was just a matter of collecting a lot of the common actions and organizing them into a few dozen functions. Let's try the the prior example again, now with jQuery:

var $li = $('<li>Steak</li>');
$("ul.foods").append($li);

In 2006, I bought a 680 page book on Ajax. With jQuery's great API, that was pretty much replaced by this:

$.post();

The WordPress API

Though API has come to signify "third-party service" it simply means the programming interface to talk to a system. Just like there is a Twitter API or a Facebook API there is a WordPress API. You don't do raw database queries to create a post, right? You use wp_insert_post.

But lots of design holes plague the WordPress API. You might use get_the_title but get_the_permalink generates an error, you use get_permalink. Hey, when you have a decades-long open-source project involving thousands of people's code and millions of users: you're gonna get some quirks.

You can save yourself lots of time by masking these quirks and writing to the habits and behaviors of the programmer you're writing for (which may be you). This is where you can design the right interface to program the plugins and themes that you do everyday.


The Solution

To speed up our work and cut down on repetitive tasks, I've created libraries to handle the commands and customizations I need all the time.

1. Shortcuts for Common Tasks

Take, for instance, grabbing the source of a post's thumbnail. Turns out there's no built-in WordPress function to grab a thumbnail based on a post's ID (only the attachment ID). 

Which means I often find myself doing this:

$thumb_id = get_post_thumbnail_id( get_the_ID() );
$src = wp_get_attachment_thumb_url( $thumb_id );
echo '<img alt="" src="' . $src . '" />';

But there's got to be a better way!

function get_thumbnail_src( $post ){

    $thumb_id = get_post_thumbnail_id( $post );
    $src = wp_get_attachment_thumb_url( $thumb_id );
    
    return $src;
}

echo '<img alt="" src="' . get_thumbnail_src( get_the_ID() ) . '" />';

2: Unpredictable Inputs, Predictable Output

Much better! In fact you find yourself using it all the time and then sharing with other developers at your company. 

Your friend is having trouble with it, so he calls you over to debug and you see:

echo '<img src="' . get_thumbnail_src( get_post() ) . '">';

So it looks like he accidentally used get_post instead of get_the_ID. You yell at him. But wait a second, why not make it more accepting? 

Maybe we can adjust our function so that it can take a WP_Post object and still give the user what they're expecting. Let's go back to that function:

function get_thumbnail_src( $post ){

    if ( is_object( $post ) && isset( $post->ID ) ){
    
        $post = $post->ID;
        
    } else if ( is_array( $post ) && isset( $post['ID'] ) ) {
        $post = $post['ID'];
    }
    
    $thumb_id = get_post_thumbnail_id( $post );
    $src = wp_get_attachment_thumb_url( $thumb_id );
    
    return $src;
    
}

So if they send a WP_Post object or an array, your function will still help them get what they need. This is a huge part of a successful API: hiding the messy guts. You could make separate functions for get_thumbnail_src_by_post_id and get_thumbnail_src_by_wp_post_object. 

In fact, for more complicated transformations it might be preferable, but you can simplify the interface by having a single function route to the correct subroutine. No matter what the user sends, the function consistently returns a string for the image source. 

Let's keep going: What if they send nothing?

3. Sensible Defaults

function get_thumbnail_src( $post = false ) {

    if (  false === $post ) {
        $post = get_the_ID();
    } else if ( is_object( $post ) && isset( $post->ID ) ) {
        $post = $post->ID;
    } else if ( is_array( $post ) && isset( $post['ID'] ) ) {
        $post = $post['ID'];
    }
    
    $thumb_id = get_post_thumbnail_id( $post );
    $src = wp_get_attachment_thumb_url( $thumb_id );
    
    return $src;
    
}

We've simplified yet again so the user doesn't have to send a post or even a post ID. When in the loop, all that's needed is:

echo '<img src="'.get_thumbnail_src().'" />';

Our function will default to the current post's ID. This is turning into a really valuable function. To make sure this will play nicely, let's wrap it inside a class so it doesn't pollute the global namespace.

/*
Plugin Name: JaredTools
Description: My toolbox for WordPress themes.
Author: Jared Novack
Version: 0.1
Author URI: http://upstatement.com/
*/

class JaredsTools {

    public static function get_thumbnail_src( $post = false ) {
    
        if (false === $post ) {
            $post = get_the_ID();
        } else if ( is_object( $post ) && isset( $post->ID ) ) {
            $post = $post->ID;
        } else if ( is_array( $post ) && isset( $post['ID'] ) ) {
            $post = $post['ID'];
        }
        
        $thumb_id = get_post_thumbnail_id( $post );
        $src = wp_get_attachment_thumb_url( $thumb_id );
        
        return $src;
        
    }
    
}

And please don't prefix your class with WP. I'm making this a public static function because I want it accessible everywhere, and it doesn't change: the input or execution doesn't change the function or object. 

The final call to this function is:

echo '<img src="'.JaredsTools::get_thumbnail_src().'">';

Design First, Build Later

Let's move on a more complicated need. When I write plugins I find I always need to generate different types of error and/or update messages. 

But the event-based syntax has always bugged me:

add_action( 'admin_notices', 'show_my_notice');
functon show_my_notice(){
    echo '<div class="updated"><p>Your thing has been updated</p></div>';
}

There are lots of good reasons that WordPress follows this event-based architecture. But it's not intuitive, unless you want to sit around and memorize different filters and actions

Let's make this match the simplest use-case: I need to show an admin notice. I like to design this API-first: where I figure out the best way to refer to the function in my code. I'd like it to read like this:

function thing_that_happens_in_my_plugin($post_id, $value){
    $updated = update_post_meta($post_id, $value);
    if ($updated){
        JaredsTools::show_admin_notice("Your thing has been updated")
    } else {
        JaredsTools::show_admin_notice("Error updating your thing", "error");
    }
}

Once I have the end-point designed, I can fulfil the design requirement:

class JaredsTools {
    public static function show_admin_notice($message, $class = 'updated'){
        add_action('admin_notices', function() use ($message, $class){
            echo '<div class="'.$class.'"><p>'.$message.'</p></div>';
        });
    }
}

Way better! Now I don't need to create all these extra functions or remember crazy hook names. Here I'm using PHP anonymous functions (also called "closures") that lets us tie a function directly to an action or filter. 

This saves you from having a bunch of extra functions floating around your files. The use command lets us pass arguments from the parent function into the child closure.

Be Intuitive

Now another co-worker calls you over. She doesn't know why her admin notice isn't turning red:

JaredsTools::show_admin_notice("Error updating your thing", "red");

It's because she's sending "red" (which she would expect would turn the box red) when in fact she should be sending the name of the class that triggers red. But why not make it easier?

public static function show_notice( $message, $class = 'updated' ) {

    $class = trim( strtolower( $class ) );
    if ( 'yellow' == $class ) {
        $class = 'updated';
    }
    
    if ('red' == $class ) {
        $class = 'error';
    }
    
    add_action( 'admin_notices', function() use ( $text, $class ) {
        echo '<div class="'.$class.'"><p>' . $text . '</p></div>';
    });
}

We've now accepted for more user tolerance that will make it easier to share and for us when we come back to use it months from now.


Conclusion

After building a number of these, here are some of the principles I've learned to make these really useful for my team and me.

1. Design first and let the function's build match how people want to use it.
2. Save your keyboard! Make shortcuts for common tasks.
3. Provide sensible defaults.
4. Be minimal. Let your library handle the processing.
5. Be forgiving on input, but precise on output.
6. That said use as few function arguments as possible, four is a good max. After that, you should make it an options array.
7. Organize your library into separate classes to cover different areas (admin, images, custom posts, etc.).
8. Document with example code.

At Upstatement, our libraries for Timber make it easier to build themes and Jigsaw provides time-saving shortcuts to customize each install.

The time savings these tools provide lets us spend more time building the new and innovative parts of each site or app. By taking the commands that are otherwise esoteric (like adding a column to the admin post tables) and making simple interfaces: any designer or developer at our company can fully customize each site with the same power as a pro WordPress developer.

Advertisement