Tribune DataViz

Matters of interest, from the data reporters and developers across Tribune Publishing

Archive for the ‘PHP’ Category

We’re hiring: WordPress, HTML5 developer extraordinaire

with one comment

We are looking for an experienced web developer who can help us build sites for the Chicago Tribune and Chicago Tribune Media Group. Somebody who has a passion for code and getting things done. Somebody who likes having a problem to solve.

On the News Apps team, you will help us research, design, and build online news products. You will be a generalist: sometimes interviewing or helping users, sometimes writing HTML and CSS, sometimes coding in Python, PHP or Javascript, and sometimes working on servers.

You will work with a group of talented, passionate folks who enjoy making websites and software. We have short deadlines so we work iteratively and try to work closely with our users and stakeholders. It can be stressful at times, but it’s worth it. We build good stuff fast and you will become a better programmer. You will always be refining your tools and trying out bleeding edge web technologies. You will make things you will be proud to show mom.

Acronyms and buzzwords:

These are the tools we use. Apply if you can rock them.

  • WordPress & PHP development
  • Git
  • HTML5, CSS3, SASS and Responsive Design
  • Javascript & Coffeescript: Backbone.js, Underscore.js, jQuery
  • Python and Django
  • Amazon Web Services: EC2, S3, RDS
  • Linux/Ubuntu server administration: Apache, Nginx, Varnish

P.S. You don’t have to know them all to apply.

Stuff we’ve done:

You will be working on these sites, and new ones like them.

And you’ll be contributing to our blog and our github.

Gear you’ll get:

  • One shiny, new MacBook Pro (or an iMac, if you’d prefer)
  • One CDM (Cheap Dell Monitor)
  • One comfy Aeron chair
  • …all at a desk somewhere in the Tribune newsroom, where you’ll be surrounded by reporters arguing with the cops, yelling about the ball game, telling crazy stories, and otherwise practicing their trade.
Interested? Send a cover letter and resume to newsapps at


Written by Ryan Mark

January 12, 2012 at 10:12 am

Posted in Jobs, PHP, Python

Turning WordPress into a framework with MTV

with 30 comments

A couple of months ago, Ryan Nagle described how he and Ryan Mark had unravelled WordPress and reknit it into something prettier for ChicagoNow. Since we finally got around to releasing the code, we thought it might be helpful to share a few thoughts on getting started with the MTV setup.

The beauty is that with MTV, WordPress now works just like any modern web framework. Once you get over the initial weirdness of working with WordPress in this sort of environment, writing themes gets a whole lot more pleasant than it used to be.

Why on Earth is this necessary, you ask? Ryan Mark answers that question in our GitHub docs:

We love WordPress, but we need it to be more serviceable. We need to be able to look under the hood and figure things out quickly. We need a code base that is simple, explicit, legible and self-documenting. That’s what we’re trying to do with MTV.

Development in WordPress becomes a mess very easily. It’s difficult to look at a new theme and figure what’s going on where, because it’s common practice to have a lot of PHP in your HTML and vice versa. Additionally, WordPress packs so much into some functions that sometimes it’s difficult to determine which one you want to track down and modify. If you’re doing heavy customization, you’d better be prepared to spend a good chunk of time playing code detective.

So WordPress functions tend to be extremely implicit. Essentially, MTV creates a more organized, explicit layer on top of WordPress’ native functionality.

Making WordPress behave like a framework removes a lot of hassle by separating markup, request handling, and data manipulation from the site’s core functionality. It’s a little like the way stylesheets separate markup from layout and design.

To make this work, the MTV plugin breaks The Loop and WordPress’ template processing. Fair warning: this means that some of the functions that rely on WordPress “magic” aren’t going to work. If you’re used to writing WordPress themes, this brave new world is going to take a little getting used to. But like the Guide says, “Don’t Panic.”

Let’s walk through how to get MTV up and running. Then we’ll look at how it works by setting up a simple theme.

Before you begin
Check to make sure your host is running PHP 5.3. Because MTV relies on namespaces, a feature introduced in 5.3, earlier versions of PHP won’t suffice.

1. Install WordPress on your local machine (more about that here, though in the latest versions of WordPress, you shouldn’t need to edit the wp-config file manually).

2. Clone MTV from our GitHub account. Drag the “mtv” folder into your wp-content/plugins folder .

3. Install Twig, either manually or with Pear, PHP’s package manager.
With Pear:

sudo pear channel-discover
sudo pear install twig/Twig-1.0.0

Manual install:
Grab the tarball and put the extracted Twig folder in the MTV plugin.

4. Go activate the plugin!

Roll your own theme

A lot has changed since our initial blog post on this subject. This section provides some bare-bones sample code to get you started and referenced the original post where appropriate.

WordPress only requires inclusion of two theme files: style.css and index.php. We won’t be messing with the CSS here, so just make sure you’ve got WordPress’ required comment header in your otherwise-empty stylesheet.  As for index.php:

// Your princess is in another castle.

That’s it. Since WordPress expects this file to exist, we have to have a placeholder file. But we’ll create a template for the index page elsewhere.

Next, we need to register the theme as an app, similar to installing an app in Django. We do this by creating a functions.php:

// Configure MTV
if ( function_exists('mtv\register_app') )
    mtv\register_app('mtv_theme', __DIR__);

// Setup enabled apps
global $apps;
$apps = array('mtv_theme', 'wp');

We’re doing two things here. First, we register the app. This works similarly to registering a function, custom taxonomy or custom post type in WordPress. All we need to provide is the theme’s name and the path it’s on. Since our functions.php is in the same directory as the rest of our theme files, we can just use __DIR__.

Second, we declare a global variable that contains an array of all our installed apps. You can register as many apps as you like. Keep in mind that the order of items in the $apps array matters. When rendering a template, Twig uses this order to look for templates that match. In this case, Tiwg will look in the theme first and then the wp app.

What’s that “wp” app, you ask? That’s part of the MTV plugin. Inside, we register a bunch of WordPress functions we want to use.

Frameworkin’ it

From here, we get into more familiar territory for those of you who have dealt with web frameworks. (If you don’t have framework experience, don’t worry; we’ll explain as we go.) We’ll write some URL regex patterns in urls.php:

 $url_patterns = array(
     '/^$/' =>
    '/(?:[0-9]{4}\/)(?:[0-9]{2}\/){1}(?P[^\/]+)\/?$/' => # year/month/slug
    '/(?P[^\/]+)\/?$/' =>

**Important: Your WordPress permalinks must be enabled in the admin, and they must match the regex for your URLs. We’re using month and name permalinks in this tutorial.

These patterns basically say, “When the URI matches this regex, call this function in views.php.” The patterns are only concerned with what comes after the domain. So in the first object, we’re calling the “home” function when the URI ends after the domain (and possibly a trailing slash). More info on URL patterns is available on our GitHub wiki.

Introducing views

“View” is a bit of a confusing name. It sounds like it should be a page template, but those are, well, templates. (We’ll get to those in a bit.) Views contain the logic that specifies what data is available to your templates. This is where this whole crazy mess comes together. Instead of putting code in our templates, we’ve isolated it in our views.

An example: We said that in our first URL pattern above, whenever a URL ends after the domain, urls.php calls the “home” function in views.php. The home function then does the heavy lifting of assembling the info to serve to the assigned template.

Here’s what a complete view looks like:

namespace mtv_theme_example\views;
use mtv\wp\models\PostCollection,
function home( $request ) {
 	 $args = array('post_type' = 'post',
                  'posts_per_page' => 10,
                  'order' => 'DESC');
     $posts = PostCollection::filter($args);
 	 $template_array = array(
        'posts' => $posts->models

    shortcuts\display_template('index.html', $template_array);

The paths to the functions served in urls.php are based on the namespace we mentioned earlier. The namespace gets declared at the top of views.php:

namespace mtv_theme_example\views; 

Let’s step through writing a view for our index page:

 function home( $request ) { 

When we defined our URL patterns, we set up some groupings to capture data. $request passes the data we captured to our function. The first thing we do is set query flags (also known as conditional tags). WordPress sets these by default, but we reset them in MTV when we break The Loop. So when urls.php calls a view, we reset the query flag in the function. Resetting them makes it possible to use familiar conditionals like is_home, is_page and is_single (including with body_class).

     $args = array('post_type' => 'post',
                  'posts_per_page' => 10,
                  'order' => 'DESC');
    $posts = PostCollection::filter($args);

The heart of this view function is the PostCollection model. Models, very simply, are blueprints of your data. Their contents usually correspond to fields in your database and describe the data’s attributes. The PostCollection model is what grabs the data from The Loop and makes it available for MTV.

Ryan explained PostCollection in his introductory post:

Note that the $args array passed to PostCollection::filter() is exactly the same array you would pass to WP_Query() to get recent posts. The difference is that returned objects are more robust (for example, all post meta/custom fields are included as attributes of returned posts) and have methods consistent with those found in Backbone.js models (for example, get(), fetch(), set(), save()). Also note that these Backbone-like methods do exactly what you think they do. You don’t have to remember the 101 different WordPress functions related to post objects and the variety of possible return values.

MTV’s models are defined in mtv/models.php and mtv/wp/models.php. In views.php, the PostCollection model is included at the top of the file, directly after the namespace declaration:

 namespace mtv_theme_example\views;
 use mtv\wp\models\PostCollection,

Our template loader function is in “shortcuts.” But back to our index view, where we’ll create an array of the data we’re interested in exposing in the template:

    $template_array = array(
         'posts' => $posts->models

    shortcuts\display_template('index.html', $template_array);

That last line loads a template file and passes data to it. Templates only have access to variables that you provide in $template_array. If we ever decide to change our index page, we can just swap out the template reference here and point it somewhere new.


Now that we’ve got a view, we need a template to go with it. We can write clean, readable, easily modified templates using Twig’s syntax. This should be pretty intuitive if you’ve used Django, and Twig has some good documentation if you need to brush up.

Make a templates folder within your theme. Here, we’ve thrown all of our common template code, like doctype, stylesheets, headers and footers, into a base.html template and then extended it to create a lovely index page (or at least a non-blank index page):

{% extends 'base.html' %}

{% block content %}
  <div id="primary">
    <div id="content">{# if we've got posts, show 'em. #}
      {% if posts %}
        {% for post in posts %}
        {# show headlines of recent posts #}
        <article id="post-{{ }}" post="" post_class="">
          <header class="entry-header">
            <h1 class="entry-title"><a title="Permalink to {{ esc_attr(post.post_title) }}" href="{{ post.permalink }}" rel="bookmark">{{ post.post_title }}</a></h1>
       {% endfor %}

      {# if we have no posts, show an "oops, sorry" page. #}
      {% else %}
        <article id="post-0" class="post no-results not-found">
          <header class="entry-header">
            <h1 class="entry-title">Nothing Found</h1>
        <div class="entry-content">'Apologies, but no results were found for the requested archive.</div>
     {% endif %}
   </div><!-- #content -->
  </div><!-- #primary -->
{% endblock %}

As expected, we can use dot notation to access any of the attributes in objects passed to the template via the view.

**Important: You can only use WordPress functions in templates if you’ve made them accessible to Twig. MTV comes with a pared-down list of functions we find the most useful. Ryan’s initial post goes over how this works.

You can’t use WordPress’ functions in Twig templates out of the box.

Thankfully, the overhead of making functions accessible in Twig templates is negligible. This means, however, we were forced to consider what functions we would allow in our templates.

Here’s how to make a WordPress function accessible in Twig templates, using home_url() as an example:

    global $twig;
    $twig->addFunction('home_url', new \Twig_Function_Function('home_url'));

Over time, we compiled a list of all the WordPress functions we needed to get things done. Nothing more, nothing less.

That list of available functions can be found on MTV’s wiki. You can also find an extended version of these sample theme files here.

We hope this will prove a useful way to write clean, easily maintained WordPress themes. Have ideas and want to lend a hand? Find us on GitHub here.

Written by Heather Billings

October 19, 2011 at 8:48 am

Posted in Open Source, PHP

WordPress network auto-deployment

with 5 comments

Going from Django development to WordPress development is rough, not only because I generally dislike PHP (the flashbacks), but mainly because tools that we’ve come to rely on in Python simply don’t exist for WordPress.

Repeatable automated deployment

Our Django apps are deployable with the push of a button and each of us have identical code and data for testing. We found nothing like this for php or WordPress, and we really looked, honest.

Much of a WordPress blog’s configuration is stored in a table in the database. In a WordPress network, each blog has it’s own configuration table. For TribLocal, we needed to create and manage almost 90 network blogs. Each is practically identical but still needed to be customizable. There was no way we would configure each blog by hand.

So with the power of fabric, and a pile of php scripts reverse-engineered from the WordPress code, we built a rig to bootstrap WordPress — from the vanilla download to a customized, functional blog with a single command. Kudos to our contractors, Human Made, who helped quite a bit to make this all work.

Hello Network!

This tutorial is written for folks on Mac OS X. Much of the instructions will work on any UNIX variant. If you’re on Windows, I’d love to hear how you got this to work.

You’ll need to have fabric installed.

sudo easy_install fabric

Let’s grab the scripts for this tutorial. You can clone them from github here. Next you need to grab the latest WordPress. Download and unzip the WordPress archive. You want to take all the files from the wordpress folder created by the archive and move them to the folder you just cloned from github with all your fancy new scripts.

git clone wp-deploy
cd wp-deploy
curl -O
tar -zxf latest.tar.gz
mv wordpress/* .
rmdir wordpress

To get this new mess of code to do anything interesting, you will need an Apache, PHP and MySQL stack on your machine. We do all WordPress development locally and deploy stuff to a server when we want to test or show off our work. Since we all work on Mac OS X, we decided to use MAMP for development. We chose MAMP because it’s a tight package that made it trivial for everyone to get running quickly. Feel free to setup your stack however you like, but this tutorial assumes you’re using MAMP.

Out of the box, MAMP needs a few tweaks before it will serve our project. Download the latest version, install it to your Applications folder and run the MAMP application. MAMP will immediately start Apache and MySQL and open its web control panel in your browser.

Find MAMP on your dock and click it to bring up the status window. Click “Preferences…”. Under the “Ports” tab, set the Apache port to 80. WordPress gets cranky if you try to run it on a port other than port 80. Under the “Apache” tab, change the “Document Root” to the project folder with your new scripts and wordpress code.

If you’ve ever turned on web sharing, turn it off now. If you already have MySQL installed on your machine, you’ll probably run into trouble.

You need to add MAMP’s MySQL binaries to your path, so you can use mysql from the command line.

export PATH=$PATH:/Applications/MAMP/Library/bin

Add this command to the end of your ~/.bash_profile so you can always access the MySQL commands.

echo "export PATH=$PATH:/Applications/MAMP/Library/bin" >> ~/.bash_profile

Add the demo WordPress domain name to your hosts file.

sudo bash -c 'echo "" >> /etc/hosts'

(If you’re on Leopard or earlier, your hosts file is /private/etc/hosts)

At this point you should be able to fire up a WordPress site with the demo settings. Just run the bootstrap fabric command.

fab bootstrap

You should have wordpress running now. Visit You also should have network blogs running at and

Configuration juiciness

These scripts are just a starting point. The ones we use for TribLocal are heavily customized. Dig through them and tweak to your hearts content. We’ve annotated them a bunch, but ask us more questions if you find something that isn’t clear.

The scripts:

    Where all the deployment settings are put. Use this to setup your production or staging server or to change settings for local development.
  • scripts/na-options.php
    Most important file. Holds all the config information for the WordPress side of the automatic setup.
  • scripts/na-install.php
    First script that runs. Installs the WordPress database, root blog and network.
  • scripts/na-postinstall.php
    Second script that runs. Configures the root blog and network with settings from the na-options.php.
  • scripts/na-createblog.php
    Script that creates a network blog. Pass it an index, uses that index to fetch data about the blog it should create from the $sites array in na-options.php.
  • scripts/na-setup-plugins.php
    Enables plugins.

One more thing

Something that always bothered me about WordPress is the way the domain name is stored in the database. You can’t just dump and load the database in a new location without also moving the domain name. We want it to be push-button to deploy an identical copy of the site in multiple places.

So I wrote a few fabric commands to shuttle a WordPress database across servers and domain names.

fab dump_db
fab load_db
fab reload_db

These commands will create or load data/dump.sql.bz2. They’ll correct the domain name in the WordPress database to whatever you have defined in your fabfile. It just pipes the database content through sed to replace the domain names. Super useful, eh?

UPDATED: Fixed the git clone URL.

Written by Ryan Mark

October 5, 2010 at 3:11 pm

Posted in PHP, Recipes