Saturday, February 25, 2012

Refactoring your wordpress theme with Skellie

Skellie allows for maintainable, readable, reusable code within wordpress themes without breaking wordpress or plugins. It gives you a simple but powerful toolbox with structured partials, layouts and templates.

TL;DR

If you want to see what other problems Skellie solves view my presentation about it

Installation
  • Download Skellie
  • Copy the directories: layouts, library and partials into your theme's main dir.
  • Add the following in your functions.php :

Refactoring a single template
Let's refactor the home page.
Remove get_header() and get_footer() from your template and choose a layout at the top within comments like this:
/**
 * @layout myOwnLayout
 */ 
Enabling the cherry picking requirement during installation allows Skellie to take over rendering but only for templates that explicitely ask for a layout. All your remaining templates will continue using wordpress. 

Refactoring the template into a layout and basic partials 
Step 1 - Merge into a working layout
By convention wordpress themes split wrapping code into header.php and footer.php and then call get_header(), get_footer() within the template.
Create layouts/myOwnLayout.php and copy the contents of your header.php.
Add 
<?php echo $this->content(); ?>
then finish up with the contents of footer.php.
Your homepage template is now powered by Skellie, is pretty much an unreadable mess, but should work as before and you can begin cleaning it up.

Step 2 - Split into default partials
Now you can start cleaning up the mess.
  1. Move your starting html-tag and <head>.*</head> into partials/header.php and replace the code in the layout with
    <?php echo $this->partial('header'); ?>
  2. Leave the starting body-tag intact or replace it with
    <body <?php body_class('layout-'.$this->layout); ?>>
    That will give the body-tag classes of both the layout and the template, so you can minimize the need of creating more layouts. 
  3. Move your common html code that lies right before the ending body-tag [including wp_foot()] into partials/footer.php. Mine contains just a wp_foot call and a chrome-frame snippet.
  4. Replace that code with
    <?php echo $this->partial('footer'); ?>
Up until this point you haven't won anything special. It's basically the same as wordpress does but renaming "template" to "layout".
Let's bring it up a notch.

Step 3 - Split your layout in organized partials
  1. Replace all get_template_part($slug, $name) calls with:
    <?php echo $this->partial($slug, $name); ?>
    Copy the contents of {$slug}-{$name}.php into partials/$slug/$name.php
    The idea is to eventually delete all partials from the main theme dir when templates no longer need them.
  2. Create a directory partials/navigation
  3. Move every navigation menu code into it's own file in partials/navigation/{$name}.php and replace the code in the layout with:
    <?php echo $this->partial('navigation', $name); ?>
  4. Move remaining wordpress (e.g. a search form or sidebars) or plugin code (e.g. breadcrumbs) to its own file and replace it with partial() calls.
    If you do not use subtypes for a certain partial you can store the code in partials/{$slug}.php and there is no need to create a directory for it.
Step 4 - Cleanup your template code
Now the layout should be clean but your template is still full of code.
You can use partials however you want to lighten it up.
My conventions are : 
  • partials/list/$type.php for aggregating posts of a type (cat, post_type etc)
  • partials/preview/$type.php for showing an excerpt of a single post
  • partials/content/$type.php for showing the full content of a single post
  • partials/pagination/$type.php for things like next/previous article, wp_paginate or link to a list of articles
But first the fun part.
Chance is you would end up creating partials for a certain slug that do not differ that much between types.
Use the 3rd parameter of partial() to pass arguments to your partial:

Whatever parameters are passed through the associative array are accessible through the partial as public variables of $this. (If a param is not set it always returns null)
For example within partials/list/category.php you could do:
Conclusion
That's it.
Feel free to fork it or submit issues that arise on github.

Wednesday, February 15, 2012

Skellie after a sprint


The last 2 weeks I got to use Skellie in action, in order to build a new wordpress project from scratch.

The results are encouraging.
The code seems cleaner and readable and partials are easily reusable.
The main layout file is just so clear:


During development I came accross two dark corners of wordpress, namely the search and comment forms.

Search form
By default wordpress prints the same id in the search form which ends up in invalid html if you need 2 instances of it (e.g. repeating the search form within the search results page). The solution was to ignore the search form and come up with a new partial in partials/search-form.php


Comment form
The comment form was less of a hassle. Hiding the tips and title was enough to get going.
Using 2 partials to loop through the comments and print them finishes up the story.

Future development:
Some things that could be changed also became apparent during the building process.
I was thinking about the possibility of having the partial methods return the render result as a string instead of directly printing it like wordpress used to.
It makes sense. It allows for more flexibility and adjustment of output. You can cache it, alter it (if you have to), decorate it or just print it.
Also with the 5.4 short tag re-entering the game the overhead of manually printing will be minimal.
Get_template_part of wordpress used to directly print but get_template_part sucked anyway.

Saturday, February 4, 2012

Introducing Skellie, a real wordpress theme skeleton

So lately at work I've been stuck doing custom wordpress projects to keep the money flow steady while others do the cool stuff -.-

Problem #1:
Everytime a new project started we picked a new "empty" base theme.

It was supposed to be the basis for building our own. But almost no project looked the same.
We always had to go in and change everything in the templates.

Sometimes html5 was not allowed, sometimes the structure had to be totally different and functionality was not needed.
Sometimes it was grid960, sometimes boilerplate with again our implementation changing like using scss or not.

So have fun cleaning and recoding all the stupid wordpress templates that your theme came along with.

We ended up using almost nothing from the initial template but were stuck with 100 functions within functions.php to which we had to add 10 more.

Problem #2
So I started from scratch until I reached a point contemplating about get_template_part.

If you don't know what that is (lucky you), it's basically including a different file with a fallback to a default file:.
So you can get_template_part('loop', get_post_type()) and if there's a loop-$postType.php file found it will be loaded.
Otherwise loop.php is loaded.

No other configuration can happen. Also all those template parts have to reside in your base theme directory.

My last project had around 45 template parts...
There had to be a better way of doing this.

Thoughts on Problem #1
I couldn't care less about theme inheritance.
There's no point if your theme has no functionality you really need.

So the best theme for me would be a theme with nothing in functions.php (or at most just a few commented out lines code so I don't have to lookup things like how to add custom thumbnail sizes).

I would not want my theme to decide what kind of css framework I'm going to use and would not like 100 stupid functions printing html that I would have to edit or never use.

Thoughts on Problem #2
I would love to at least be able to configure my template parts. Pass some parameters in cleanly so I can skip putting logic in them or splitting them into more template parts.

Also I would love the ability to group and structure them differently. I want my preview templates (that do not show the full content) in a preview folder. Template parts are not templates.

In combination with the above, how cool would it be if I could pass the excerpt length as a parameter to the template part and then maybe with more parametrization I wouldn't need more than 1-2 template parts.

Enter Skellie

Skellie is a real skeleton of a theme and attempts to solve the aforementioned problems:

Solution to Problem #1
  • Your functions.php will be empty apart from a function allowing Skellie to provide the view architecture and take over from wordpress.
  • Your layout will be minimal.
  • Your default partials will be non-existent apart from examples and so you can test how it works. 
  • There are no stylesheets or javascript. Modernizr and normalise.css are in place if you want them but not enabled.
  • The header is html5 but together with the footer it's just 20 lines so feel free to remove it.
 Solution to Problem #2

Layouts and Templates
Skellie provides partials and layouts and redesigns the way templates work.
The template is still the main part of the application.

A layout is the wrapper around your page content. Calling the header, footer and sidebars amongst other common things should be in the layout.

You can have several layouts like 3-columns, 2-columns-1-sidebar along with your default but you shouldn't need that many. All of them will be in the same directory (layouts/) in any case.

You can still select a template for your pages as usual. However your template can now select its layout using with a special comment (or assume default.php).

The template should now only contain the main content of the page and call upon partials to help it render stuff.

Partials
Partials are like views, getting rid of get_template_part. From within a layout, template or even another partial you can use
echo $this->partial('<slug>', '<type>', $args)
and it will looks for the first partial it finds located in the following paths:
  1. partials/<slug>/<type>.php
  2. partials/<slug>.php
  3. partials/<slug>/default.php
$args is an optional associative array. Everything you pass into it along with some default arguments will be accessible using $this.

E.g. if $args is array('someVar' => 'someValue') then $this->someVar will be 'someValue' within the partial.

Notes:
PHP 5.3 is required.
I am aware that using Closures with including files is weird.
If something feels still extra it will be removed.
The code is experimental and everything can change.
Feedback is appreciated.