Automatic Updates For Private And Commercial Themes

Update 2017-06-20: This library has been deprecated. Please use PUC instead. It’s more current and it supports both themes and plugins.


This is a PHP library that lets you add automatic update notifications and single-click updates to any WordPress theme. It’s purpose is to be easy to integrate for developers and to provide a familiar experience to theme users. From the users’ point of view, update notifications generated by this library will look and function just like those displayed by WP itself.

Dashboard screenshot

An update notification for a theme not hosted on wordpress.org

Download

License

This library is licensed under the GPL and is distributed free of charge. If you find it useful, consider making a donation. Commercial licensing (e.g. for projects that can’t use an open-source license) is available upon request.

Quick-Start Guide

There are two things you will need to do:

  1. Create a publicly accessible “metadata file” that describes the latest version of your theme.
  2. Add the update checker to your theme and tell it where to find that file.

First, the metadata file. Open your favourite text editor and copy the following JSON code into a new file:

{
  "version" : "2.0",
  "details_url" : "http://example.com/example-theme/details.html",
  "download_url" : "http://examle.com/example-theme/example-theme.zip"
}

Replace the placeholder values with your own data. As you can probably guess, version is the version number of your theme. details_url specifies the page that the user will see if they click the “View version 1.2.3 details” link in an update notification. Set this field to your “What’s New In Version 1.2.3” page or the theme homepage (tip: if you notice that your page looks strange when viewed from the WP dashboard, see this comment).

Finally, download_url is the URL where the latest version of the theme can be downloaded. This field is optional. If you leave it out, the user will still get an update notification when a new version comes out, but there will be no “update automatically” link. They’ll have to download and install the update manually.

Upload the metadata file to your website. You can use any directory and file name you like; just remember that the file URL should be accessible from wherever someone might install your theme.

Next, lets add the update checker library to you theme. Copy the “theme-updates” directory from the client library to your theme. Then add the following to your functions.php:

//Initialize the update checker.
require 'theme-updates/theme-update-checker.php';
$example_update_checker = new ThemeUpdateChecker(
    'example-theme',
    'http://example.com/example-theme/info.json'
);

Again, replace the placeholders with your own settings. The first argument should be the name of your theme’s directory. For example, if your theme lives in /wp-content/themes/my-theme/, use “my-theme” here. The second argument should be the URL of the metadata file you just created.

Congratulations, your theme now supports automatic updates 🙂 The update checker will automatically query the metadata file every 12 hours, checking to see if a new version is available. If it finds one, it will display a standard theme update notification on the Dashboard. Your users will be able to install the new version with a single click.

The ThemeUpdateChecker class

Class constructor
The library is configured by passing a number of arguments to the ThemeUpdateChecker constructor. They are, in order :

  • $theme –  The theme directory name, sometimes called the “slug”.
  • $metadataUrl – The URL of the theme metadata file.
  • $enableAutomaticChecking – Enable/disable automatic update checking. If set to FALSE, you’ll need to explicitly call the checkForUpdates method to, err, check for updates. Defaults to TRUE.

checkForUpdates()
Manually trigger an update check. This is useful if you want to do update checks on your own schedule. checkForUpdates has no parameters and does not return anything. If you want to actually retrieve the latest update, use requestUpdate instead.

requestUpdate()
Retrieve update information from the configured metadata URL. Returns either an instance of ThemeUpdate, or NULL if there is no newer version available or if there’s an error.

deleteStoredData()
The update checker stores various update-related bookkeeping data in a DB option. Call this method to delete that data. This is can be useful is your theme provides some kind of “uninstall” feature.

addQueryArgFilter($callback)
Register a callback for filtering query arguments. Whenever the update checker needs to retrieve the metadata file, it will first run each filter callback and attach the query arguments that they return to the metadata URL. This lets you pass arbitrary data to the server hosting the metadata. For example, commercial themes could use it to implement some kind of authorization scheme where only paying users get automatic updates.

The callback function will be passed an associative array of query arguments and should return a modified array. By default, the update checker will append the following query arguments to the URL:

  • installed_version – the currently installed version of the theme.

This method takes one parameter – the callback function.

addHttpRequestArgFilter($callback)
Register a callback for filtering arguments passed to wp_remote_get. The callback function should take one argument – an associative array of arguments – and return a modified array or arguments. See the WP documentation for details about what arguments are available and how they work. This method takes one parameter – the callback function.

addResultFilter($callback)
Register a callback for filtering theme info retrieved from the metadata URL. The callback function should take two arguments. If a theme update was retrieved successfully, the first argument will be an instance of ThemeUpdate. Otherwise, it will be NULL. The second argument will be the corresponding return value of wp_remote_get (see WP docs for details). The callback function should return an instance of ThemeUpdate, or NULL. This method takes one parameter – the callback function.

Related posts :

306 Responses to “Automatic Updates For Private And Commercial Themes”

  1. White Shadow says:

    No, I’m not the one selling it (though now I wish I had thought of that. Damn.).

  2. Benjamin says:

    Just wanted to know so that I could donate to you rather than the other guy.

  3. Sisir says:

    I have one question. Is there any way that i can protect my theme/plugin because commercial plugins or theme have to be password protected or login required. If they are publicly available then its really no point to selling them (people will go to the link and download). Any script for that should open window for commercial plugin developers to using this script.

  4. Connor says:

    @Sisir, you need to have the client pass along their license key in the update request to your server. You can then verify that the key is valid and supply them with the download. If the key is invalid, deny the update download. This way, only people with legitimate versions can download.

  5. White Shadow says:

    I think you could just omit the download URL and the notification would show up without an “update automatically” link. The user would have to actually go to your (password-protected) site to get the new version. I haven’t tested this myself, though.

  6. danix says:

    Hello, I’m trying to make your class work with my theme but with no luck so far… here’s how I call theme-update-checker.php in my functions.php:

    // include the theme update checker class
    require( dirname( __FILE__ ) . '/include/theme-update-checker.php' );
    $sog_update_checker = new ThemeUpdateChecker(
    'danixland-sog',
    'http://[deleted]/info.json'
    );

    and here’s the output from the requestUpdate() function:

    object(ThemeUpdate)#159 (3) { ["version"]=> string(4) "0.51" ["details_url"]=> string(54) "http://[deleted]" ["download_url"]=> string(50) "http://[deleted]/latest.zip" }

    so I’m assuming it works well.. I’ve also tried using the file with debug info enabled that was linked in some comment but it kept telling me that there were no updates available for my theme..

    another thing I tried was calling the deleteStoredData() function to see if it cleared something, but with no luck too.. 🙁

    is there something you could suggest in order to make it work?? of course the version I’m currently using is lower than the one served by the json file.. 😉

    Thanks in advance, hope you’ll find the time to answer me..

  7. danix says:

    some other info:
    I tried removing completely my theme and reinstalling the latest version, then pushing the version up on the json and checking for updates and it worked, but after the update my theme directory changed from danixland-sog (which is also the slug used for the update) to danixland-sog.tmp…
    I think this will break the update in the future, so is this a bug?? what should I check?

    Thanks a lot 😉

  8. White Shadow says:

    Your theme directory changed because your .zip file doesn’t have the directory structure that WordPress expects theme updates to have. Specifically, the archive should contain a directory named “danixland-sog” (i.e. matching the slug), and all the theme files should be inside that directory.

  9. danix says:

    thanks a lot.. I’m generating my zip files using git archive.. I think I’ll have to study a better solution.. 😉

    You’re great!!

  10. danix says:

    just an update, sorry for bothering you..

    I’ve fixed the issue with git archive but now automatic update doesn’t work anymore.. it keeps telling me that there are no updates for my theme which is at version 0.52 but the json is at 0.54.. I already tried removing the theme and reinstalling it..

    any suggestions??

  11. White Shadow says:

    Hmm, seems to work for me. I installed your theme (from the URL in the info.json file), changed the version number to 0.52, and the update notification showed up.

    If it still doesn’t work for you, try explicitly calling the checkForUpdate() method.

  12. danix says:

    ok, I tried lowering the theme version and the notification came out for me too.. I think WordPress keeps some kind of cache because changing the version in the json while the notification is visible doesn’t change nothing..
    e.g. in notification I have V 0.55 available and my theme is 0.52, if I change the json to 0.54 the notification keeps telling me that the available version is 0.55..

    however, this is a minor issue, I’ll test it in the next days and see how it works leaving the 12 hours delay which is default for WordPress..

    btw, I’m sure you already did it, but could you delete my theme? could you also edit my posts to remove the link to my server? It would be really kind if you do so..

    thanks a lot for your help, I really appreciated it!!

  13. White Shadow says:

    Yes, it does keep a cache. It would be very inefficient to re-download the update info every time someone views a Dashboard page. So, by default, both WordPress and this library will check for updates only once every 12 hours. However, changing the version number in style.css will force an immediate update check.

    I’ve deleted your theme and edited your comments to remove the links (let me know if I missed any).

  14. matt says:

    Is there a way to force it to re-download the json update info? This would be useful for testing things…

  15. White Shadow says:

    Yes. You can call the $updater->checkForUpdates() method to check for updates immediately.

  16. Casey says:

    Just wanted to say thanks for your hard work on this. The code is clean, and easy to understand. Donation sent. Thank you again.

  17. Ryan Hellyer says:

    I’m having troubles with this and looking for a quickfix solution.

    If anyone is able to help, feel free to earn a few dollars in the process:
    http://wpquestions.com/question/show/id/3090

  18. Jānis Elsts says:

    [Can’t be bothered to make a wpquestions.com account.]

    There is a syntax error in your JSON. Remove the trailing comma from this line and it should work: "download_url" : "[url removed]",

    Tip: Use http://jsonlint.com/ to check if a JSON document is valid.

  19. Ryan Hellyer says:

    Thanks Jānis Elsts 🙂 Your help is much appreciated!

  20. […] the criteria for inclusion in the WordPress.org theme repository, and it doesn’t implement any PHP code that allows independent themes to be notified of updates, so the only way I can find out about new version releases is to check their blog for […]

Leave a Reply