Critical Zero

The online refuge of Andy Pearson
He’s been gone for a while, the posts are gathering dust...

Development

The WordPress (L)OOP

25th January 2010
11:06pm

It’s becoming clear that I have a strange relationship with WordPress. For years, it has been my blogging platform of choice and I recommend it to a lot of people. I bought it into the workplace and we used it on a number of projects, we even rebuilt the Binamic website using it. The admin interface is solid, the feature set broad and the community strong. I love WordPress.

It’s when I have to actually work with WordPress that the cracks start to form. I find the theme API inconsistent and awkward. Functions are badly named, parameter ordering is all over the place, global variables are chucked around like they are going out of fashion and everything feels a bit sketchy. I hate WordPress.

Don’t even get me started on the fucking date function.

The Loop

One of the constant pain points for me is “The Loop“. This arcane little nest of statements is the backbone to every WordPress theme, but it’s a foundation that leaves a bad taste in my mouth.

Consider the homepage of a blog, which lists the latest ten posts, a loop to that effect would look something like:

<?php if (have_posts()) : ?>
    <ul>
        <?php while (have_posts()) : the_post() ?>
            <li id="post-<?php the_ID() ?>">
                <h2><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h2>
                <?php the_content('Continue Reading...'); ?>
            </li>
        <?php endwhile ?>
    </ul>
<?php endif ?>

Incase you are not sure exactly what’s going on here I’ll give you a quick rundown:

  1. If there is at least one post
  2. Print an unordered list element
  3. Loop through all of the available posts using while
  4. Call the_post() to set up the $post global variable
  5. Print a list element with the ID set to the post ID
  6. Print a header element, with a link to the full post
  7. Print out the post content, with the link to “Continue Reading”
  8. Close of the tags and statements

It works, but it’s ugly – Step #4 is pretty awful alone, nearly all of the template tags are dependant on that function call which isn’t particularly elegant.

It also doesn’t lend itself to easy reuse (copy and paste is not DRY) and can lead to massively over complicated templates.

It doesn’t need to be this way…

The (L)OOP

I don’t enjoy writing ugly code, and I want to have fun with this blog, so I’m writing my own Theme API on top of the existing one.

The style and structure of what I have so far is mainly based on the Model View Controller design pattern (MVC) which was (probably) made popular by Rails. At work we do a lot of work with CakePHP and I’ve become fairly familiar with how MVC looks within PHP and what you can and can’t do (you have to leave all the really cool stuff out, this just ain’t Ruby). I’m also using Object Orientated Programming (OOP) to pass around dynamic objects instead of static arrays.

Now my loop looks like:

<?php echo $posts->all() ?>

One line. Well, not really one line, there’s a lot of stuff this function does…

First thing to note, I call echo to print out the posts, all functions in my new API return values, noting “auto prints”. I think this is more true to PHP and it means if a function doesn’t return what you need, you can bend it to do what you want.

The $posts variable is actually a Collection instance, all of the posts are actually stored in $posts->data.

The all() method renders a partial:

<?php if (!empty($posts)) : ?>
    <ul>
        <?php foreach ($posts as $post) : ?>
            <?php echo $post->render() ?>
        <?php endforeach ?>
    </ul>
<?php endif ?>

This is very similar to the core WordPress loop, but I use a foreach to loop round the contents of $posts (which gets passed down into the partial) and prints them out by calling render() on each individual post.

Another partial is rendered, this time it’s only concern is the $post of the current iteration:

<li id="post-<?php echo $post->id() ?>">
    <?php echo $post->header() ?>
    <?php echo $post->excerpt() ?>
    <?php echo $post->more() ?>
</li>

I hope you’ll agree, that’s pretty clean! Down here, $post is actually an instance of a PostsPresenter class, this wraps the original data with a set of handy methods which you can use to show the post.

Here’s an example of a cut down PostPresenter, which contains everything to use $post->header():

class PostsPresenter extends Presenter
{
    var $name = 'posts';
    var $singular_name = 'post';

    var $title = null;
    var $header = null;
    var $permalink = null;

    function id()
    {
        return $this->data->ID;
    }

    function title()
    {
        if (!$this->title) {
            $this->title = apply_filters('the_title', $this->data->post_title, $this->id());
        }
        return $this->title;
    }

    function header()
    {
        if (!$this->header) {
            $this->header = '<h2>'.$this->link($this->title()).'</h2>'."\n";
        }
        return $this->header;
    }

    function permalink()
    {
        if (!$this->permalink) {
            $this->permalink = apply_filters('the_permalink', get_permalink($this->data));
        }
        return $this->permalink;
    }

    function link($text)
    {
        return '<a href="'.$this->permalink().'>'.$text.'</a>';
    }
}

This looks like a lot of code, and compared to the original loop example it is but all this is built in by default. If you are happy with the default formatting you only need to call $posts->all() and you’re done.

I’ve built this API so there are several points where you can step in and customise the output:

  1. Override partials/posts.php to change the way the collection is displayed
  2. Override partials/post.php to change the way each single post is displayed
  3. Override the Posts Presenter to change how each individual post attribute works

By keeping everything small, self contained and consistent I am hoping to keep the system as flexible as possible.

I’ve already built a load of good stuff into the API and I’ve got more planned, right now it’s just fun to love developing on the platform I love.

Roadmap

This isn’t ready for public consumption, I haven’t even finished building this blog yet! Once I have, expect a release to GitHub so you can get your hands on it if you think it is something you are going to want to use.

After that, I’m going to wait for WordPress 3 which is dropping with a new default theme. I’m going to work to bring this API up to date and make sure it can handle everything in the new theme – after that, the sky is the limit!

  1. Daniel Sentker

    11th August 2010

    Hey,

    i was searching vor “wordpress oop” via Google – and came to your post! It’s really annoying to see the wordpress code – i would love to see wordpress complete OO.

    I love your OOP approach, but why develop OOP code which just calls existing functions from the wp core? I would love to see WP complete OOP, from the beginning without annoying function like get_the_categories(‘, ‘) or using $globals.

    Greets from Germany & sorry for my bad english :]

    Greets

  2. tydeas

    30th December 2010

    Hello, I had a conversation with a “friend” when he had to debug something in the wordpress code. He commented about it and make me curious to take a look at it’s code. When i came in front of this procedural monster ( which i suppose due to i have never used it ) that works pretty well, i thought to look if someone has tried to turn the wordpress code to a more oop. I googled “wordpress in oop” and came up your site. Read some lines…anyway. I checked you mentioned cake as well rails. Well, my and my “friends” use the Yii framework, i don’t know if you already know about it, but after reading your article i had to let you know about it. You can find as at the irc.freenode.org #yii Greetings from Greece, and a happy new year. Friendly

  3. Pascal

    11th August 2011

    Thanks a lot for sharing! This ugly part of wordpress drives me crazy every time I would like to create a theme and I end up having done some work but then I break up and I just spend time on something useless – just because it really sucks how the essential part – the loop – is crap.

    Sadly you haven’t provided a full build so I’ll have to continue on my own where you stopped (within this post) but if I get something I think is worth sharing you’ll be the first getting in ;)

  4. Covi

    9th September 2011

    Hi Andy, I’ve the same (exactly) experience, impressions and relationship with Wordpress since I know MVC and ZendFW a few years ago.

    I’ve written too my own OOP Themes, Plugins. Even I proposed WP_Theme abstract interface… with no answers. WP code sucks :S

    Glad to read someone who’s thinks like me ;)