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. Tejas says:

    Hello Janis,

    Thanks for such a good work.

    I have a little issue after updating the theme.
    that its changing my theme name with xyz.tmp.

    Suppose i have a theme called ‘xyz’ and when i update the theme it is changing theme folder to ‘xyz.tmp’. Though the site is working correctly with updated theme folder name.

    Any solution to prevent this folder rename?

    Thanks
    Tejas

  2. Jānis Elsts says:

    That usually means the update ZIP file is not structured correctly. The ZIP file should contain a folder with the desired name, and all theme files should be inside that folder. When you get something like “xyz.tmp”, that indicates that the files were at the top of the archive instead inside a folder.

  3. David says:

    Thank you for sharing exactly what I need for some private themes I am building for web clients. It was getting tedious to have to reinstall new theme versions each time I made an improvement to them.

    Just to clarify what you said, and because I don’t trust myself to remember everything in order, I created the following step-by-step checklist of instructions for myself. If I have gotten these wrong, please let me know so I can correct them; if they are right as-is, then perhaps they can help some of your other readers.

    Here’s the way I read what you said above:
    =================================
    Directions for making a private theme automatically check for updates

    1. Create a publicly accessible server location to store updates & info
    Probably at http://www.[myserver].com/wpthemes/%5Bthemename%5D
    Let’s call this “ThemeHome”.

    2. Modify info.json appropriately and upload it to ThemeHome.

    3. Create an HTML page at the details_url specified in info.json; on
    that page, describe the theme and the latest updates. (Put an 88-px
    blank div at the top to accommodate WP negative-margin anomaly.)

    4. Copy the theme-updates directory/folder into the theme’s directory.
    This can go inside the theme’s zip file.

    5. Modify the contents of “Add to functions-dot-php.txt” as follows:
    (that’s the name I gave to the text file containing the functions.php
    code to add)
    Change the parameters of $example_update_checker() so
    a. the first parameter is the theme name, same as theme’s WP folder.
    b. the second parameter is the URL of info.json at ThemeHome

    6. Add the contents of “Add to functions-dot-php.txt” to the
    functions.php file of the theme.

    ———————————————
    TO ISSUE AN UPDATED THEME:

    1. Update the theme and change the version metadata. (Instructions?)

    2. Upload the zip containing the updated theme to ThemeHome

    3. Update info.json (at ThemeHome) with the latest version number.

    That’s it. The theme will find the new update within 12 hours and alert any theme users that the new version is available, or will automatically update the theme if automatic updating is turned on.
    =================================

    Is that right? Thanks again for providing this.

    David

  4. Jānis Elsts says:

    All of that sounds correct.

    There’s just one more thing that I would add as it sometimes trips people up: when making the zip file, put all theme files inside a directory and not at the top/root of the zip file. Placing the files at the top of the archive will confuse the WordPress update installer, which usually means that updates will fail or get installed in the wrong directory.

  5. Michael Oeser says:

    Hi,

    I´m using Theme Update Checker Library 1.2 and I wonder how that deals with the latest
    XSS problem?

    See https://make.wordpress.org/plugins/2015/04/20/fixing-add_query_arg-and-remove_query_arg-usage/

    Is there an issue and if when will it be fixed?

    Thanks for a great piece of work that helps me a lot.

    Cheers
    Michael

  6. Jānis Elsts says:

    That XSS problem doesn’t apply to this library. The update checker only uses the add_query_arg() function for one thing: to add query arguments to $metadataUrl. Since it doesn’t use the current URL and it doesn’t display the result to the user, it is not vulnerable to this particular attack.

  7. Michael Oeser says:

    Awesome. Thanks.

  8. Tejas says:

    Hi Janis,

    Thanks for the your reply. It was awesome.
    As per your comment my archive was wrong.

    Now it works perfect.

    Thanks again.
    Tejas

  9. […] ざ式では、Theme-update-checker のライブラリを利用して、テーマの更新通知に対応しています。この機能は便利なのですが、zattaが思いつきや気まぐれでちょこちょこ修正をかけるたびに更新通知が来てしまうと煩わしいと思うので、デフォルトでは安定版(最終更新から1週間経過してバグフィックスのなかったもの)だけ更新通知をするようにしています。この設定はカスタマイザの「テーマ更新通知の設定」から変更することができます。「開発版を含めて通知」を選択すると、細かな修正やテストを含めた更新通知が届きます。また、「通知をオフにする」を選択すると、更新通知を行わない設定も可能です。 […]

  10. Dan says:

    FYI: If you’re hosting your updates on a server that resolves to a local IP like 10.X.X.X, WP 3.6+ has a security function that blocks downloads from those servers. To override place the following at the end of your wp-config:

    /** Enable my local themes and plugins repository FFS!!! */
    add_filter( 'http_request_host_is_external', 'allow_my_custom_host', 10, 3 );
    function allow_my_custom_host( $allow, $host, $url ) {
      if ( $host == 'ecmpublishers.com' )
        $allow = true;
      return $allow;
    }
    
  11. Dan says:

    ^ where $host = ‘your-internal-website’

    😀

  12. Ali says:

    Great library… thank you…

  13. Thank you very much for this information and code. It worked like a charm for our premium WordPress Theme WP Gel. This was a great tutorial and explained the work flow very well. We appreciate all your hard work and effort!

  14. Dzimi says:

    Hello,

    Looks great though I haven’t tested it yet, I set it up locally and hopefully it will hit the live server?

    Also, can the time be reduced to less than 12 hours?

  15. Jānis Elsts says:

    Assuming that it’s set up correctly and there is an update available, it should show up pretty soon. Visiting “Dashboard -> Updates” generally makes that happen faster because WP checks updates more often on certain admin pages.

    The time can’t be changed, at least not easily. The update checker detects when WordPress is checking for theme updates and checks your metadata URL at the same time. It doesn’t have a scheduling mechanism of its own.

  16. Dinko says:

    Thanks a lot. The library is great and works perfect. I just tested it with WordPress 4.3.1 and it work.

  17. paul says:

    i changed the URL of my theme + json file and updates no longer work. any ideas why?

  18. Jānis Elsts says:

    The obvious question would be: are you sure that the new URL is correct and that your JSON file is valid?

    Also, could you elaborate on “no longer work” – which step specifically no longer works? Is it that updates don’t show up (in which case, have you tried changing the version number to force a refresh)? Or do they show up, but you can’t install them?

  19. paul says:

    Thanks Janis! Yes, the JSON validates and I’ve triple-checked the URL is correct.

    The specific step that no longer works is that when I add a new version, sites that use the theme don’t show it as an update. Even if I wait 12+ hours.

  20. Jānis Elsts says:

    Hmm, that’s interesting. Since the JSON and URL are correct, it would have to be either something in the code that initializes the update checker, or a network problem of some kind (updates worked before the change, so it probably isn’t a bug in the update checker itself).

    Can you show the old and the new code? If you don’t want to post it publicly, you can contact me via email: whiteshadow@w-shadow.com.

Leave a Reply