Announcing Capstone, a WordPress theme for Photographers

A screenshot of Capstone’s demo site

I’m very excited to announce Capstone, a WordPress theme for photographers. I designed and developed the theme over the last few months of 2014. It’s completely free and released under the GNU GPL v2 license.

The theme has a single page exhibiting the theme’s features, and the theme can be previewed on the demo site. Capstone’s source code is available on Github.

The theme isn’t in the official WordPress theme repository for a few technical reasons. As a previous blog post may have hinted, Capstone still offers seamless theme updates. The code for the update server is also available under the GNU license.

A paid “pro” version of Capstone is in the works. Stay tuned for updates!

Everyone JavaScripts

The ShopTalk Show podcast had Tom Dale on a few weeks ago. The entire episode is entertaining and informative, (especially with regards to Ember, but Mr. Dale’s rant about disabling JavaScript as a means of testing “progressive enhancement” around 42:00 was particularly poignant:

The web is a platform. There’s basically three major pillars that prop it up. There’s HTML, there’s CSS and there’s JavaScript. And for some reason, people decide that they’re going to disable JavaScript and decide that that is some arbitrary hoop that people have to jump through. We need to disable this part of the platform that, by the way, no one actually does in practice…The vast, vast majority of your users aren’t going around disabling JavaScript. Almost no one uses a browser that doesn’t support JavaScript anymore…

Pick a date or pick support metrics. You don’t just get to say this entire piece of technology that drives the entire freaking web, we need to be able to rip it out and basically make our websites brain dead and they should continue to operate fully functionally.

I am partially guilty of this, usually as a manner of showcasing frivolous content-blocking scripts. But, Mr. Dale’s right: everyone runs JavaScript. Even so, the Ember team is working on server-side rendering for the page load, which is exciting news for application performance, especially on slower mobile devices.

WordPress Custom Theme Updates

I’m exploring offering updates for a custom WordPress theme. My theme can’t be in the official WordPress.org registry for a few reasons (mostly because I don’t want to wait months for approval). You may be in the same boat if you’re developing a commercial theme.

Offering updates for your custom theme is a good idea: you can provide security updates and take advantage of WordPress features that weren’t available when you first authored your theme. Unfortunately, documentation on offering your own updates for themes – outside of WordPress.org – is sadly scarce.

I came across Jeremy Clark’s blog post and automatic update repo, but the code is confusing and unreadable. Hannes Diercks repo is similarly inscrutable. Since there’s a real lack of documentation and knowledge about this topic, I figured I’d write up my findings. Get ready, things are about to get real technical.

WordPress Update Caching

WordPress handles theme updates directly by the wp_update_themes function, found in wp-includes/update.php. A piece of this function’s code hints at how WordPress keeps track of updates:

$last_update = get_site_transient( 'update_themes' );

This function also has a hard-coded URL that WordPress uses to check for updates (http://api.wordpress.org/themes/update-check/1.1/). As a theme author, you can’t alter this URL: there’s no actions or filters that would allow it. So, we must dig deeper. What’s up with that transient?

It turns out that WordPress caches theme update information in the database. Assuming you stuck with the default wp_ prefix, you can run this query:

SELECT option_value
  FROM wp_options
  WHERE option_name = '_site_transient_update_themes';

The query should reveal a serialized PHP object. It should look something like this:

O:8:"stdClass":4:{s:12:"last_checked";i:1413096401;s:7:"checked";a:3:{s:14:"twentyfourteen";s:3:"1.2";s:14:"twentythirteen";s:3:"1.3";s:12:"twentytwelve";s:3:"1.5";}s:8:"response";a:0:{}s:12:"translations";a:0:{}}

Unserialized, the object’s purpose becomes apparent:

stdClass Object
(
    [last_checked] => 1413096401
    [checked] => Array
        (
            [twentyfifteen] => 1.0
            [twentyfourteen] => 1.3
            [twentythirteen] => 1.4
        )

    [response] => Array
        (
        )

    [translations] => Array
        (
        )

)

WordPress relies on a theme’s stylesheet to keep track of the theme’s name, version, and a variety of other information. Let’s test what happens when the version number in Twenty Fourteen’s stylesheet is changed from “1.3” to “1.2”. After changing this, go the admin Update page (this calls wp_update_themes). You can see that the transient has changed:

stdClass Object
(
    [last_checked] => 1419725292
    [checked] => Array
        (
            [twentyfifteen] => 1.0
            [twentyfourteen] => 1.2
            [twentythirteen] => 1.4
        )

    [response] => Array
        (
            [twentyfourteen] => Array
                (
                    [theme] => twentyfourteen
                    [new_version] => 1.3
                    [url] => https://wordpress.org/themes/twentyfourteen
                    [package] => https://downloads.wordpress.org/theme/twentyfourteen.1.3.zip
                )

        )

    [translations] => Array
        (
        )

)

Refreshing the Update caused wp_update_themes to fire off a request to WordPress.org’s themes API. The server sent a response notifying WordPress that Twenty Fourteen had an update. The wp_update_themes updated the transient’s response property appropriately.

Digging around for wp_update_themes calls reveals that the Theme_Upgrader class (found in wp-admin/includes/class-wp-upgrader.php) does the hard work of actually upgrading the theme. It appears to read the response property for the theme’s package property, downloads it, installs it and cleans up.

Hijacking The Core

We’ll need to add our custom theme’s information to that transient. Just as a test, I’m going to make a dummy theme I’ll call “my-test-theme.” It will be composed of the bare minimum:

/* my-test-theme/style.css */
/*
Theme Name: My Test Theme
Description: This is a test theme.
Version: 1.0.0
*/
<?php
// my-test-theme/index.php

echo '<h1>My Test Theme!</h1>';

?>

I activated our little test theme. A quick check on the (unserialized) update transient shows this:

stdClass Object
(
    [last_checked] => 1419742507
    [checked] => Array
        (
            [my-test-theme] => 1.0.0
            [twentyfifteen] => 1.0
            [twentyfourteen] => 1.3
            [twentythirteen] => 1.4
        )

    [response] => Array
        (
        )

    [translations] => Array
        (
        )

)

Great. As a test, we’ll add a fake response array to the transient. This should notify WordPress of an available theme update. Here’s what we want to put in:

//...
$object->response = array(
    'my-test-theme' => array(
        'theme'       => 'my-test-theme',
        'new_version' => '1.1.0',
        'url'         => 'http://test.dev',
        'package'     => 'http://test.dev/update/my-test-theme.1.1.0.zip'
    )
);
//...

I’ve spun up a local server at test.dev, and placed an “updated” version of the theme at update/my-test-theme.1.1.0.zip. Hopefully, WordPress will pick up on this new response array and trigger an update notification in the admin. Here’s SQL to update _site_transient_update_themes value if you’re following along at home:

UPDATE wp_options
  SET option_value = 'O:8:"stdClass":4:{s:12:"last_checked";i:1419800807;s:7:"checked";a:4:{s:13:"my-test-theme";s:5:"1.0.0";s:13:"twentyfifteen";s:3:"1.0";s:14:"twentyfourteen";s:3:"1.3";s:14:"twentythirteen";s:3:"1.4";}s:8:"response";a:1:{s:13:"my-test-theme";a:4:{s:5:"theme";s:13:"my-test-theme";s:11:"new_version";s:5:"1.1.0";s:3:"url";s:15:"http://test.dev";s:7:"package";s:46:"http://test.dev/update/my-test-theme.1.1.0.zip";}}s:12:"translations";a:0:{}}'
  WHERE option_name = '_site_transient_update_themes';

This shows a little “1” by the Updates page link, but actually the page makes the “1” disappear. Loading this page calls wp_update_themes function, which checks the API. The API responds with no updates, and thus the transient is reset. We’ll need to make that our response array is persisted, and we’ll need to do it in our theme to avoid touching WordPress’s core code.

It turns out, there’s a little-known hook for filtering transients:

apply_filters ( "pre_set_site_transient_{$transient}", mixed $value )

Filter the value of a specific site transient before it is set.

The dynamic portion of the hook name, $transient, refers to the transient name.

Perfect! We’ll use that on the update_themes transient. Add a functions.php file to the theme like so:

<?php
// my-test-theme/functions.php

function test_check_for_update($data) {
  $data->response['my-test-theme'] = array(
    'theme'       => 'my-test-theme',
    'new_version' => '1.1.0',
    'url'         => 'http://test.dev',
    'package'     => 'http://test.dev/update/my-test-theme.1.1.0.zip',
  );

  return $data;
}
add_filter('pre_set_site_transient_update_themes', 'test_check_for_update', 100, 1);

?>

This persists our “response” to the transient. When the Update page is reloaded we see some UI for updating our theme:

“My Test Theme” has an update

I made a copy of my-test-theme, changed the version in the style.css file to “1.1.0”, zipped it up, and placed it in the /update directory. Sure enough, WordPress’s update worked!

“My Test Theme” updated

Now What?

We can successfully make our theme “update” by using the pre_set_site_transient_update_themes hook. It isn’t a stretch to make updates actually work. Here’s a blueprint:

  1. Set up your own API server that tracks theme updates.
  2. Add a function in your theme that queries your API server. Attach this function to pre_set_site_transient_update_themes so it fires when WordPress looks for theme updates.
  3. Have the server return information about the latest package.
  4. Make your theme’s function update the transient if the latest package is new.

You could concievably only offer theme updates for users with API keys or valid site URLs. The server could even support multiple themes. The sky’s the limit!

This In JavaScript

I recall the use of this being cryptic when first learning the JavaScript. Bjorn Tipling wrote an exhaustive explanation of this. The article covers (nearly) every imaginable use case, and taught me a thing or two.