Here are two sample scripts along with an API to provide automatic updates for plugins and themes you host on your own server.
/api you’ll find
index.php which processes all the update requests. You should place this in something like
http://updates.example.com and update
/theme/portfolio-racer/inc/updates.php accordingly. If you activate these sample plugins without changing API URL, updates will be checked against my test server. If you decide to update, both plugin and theme will be replaced with exactly the same version of each.
Quite the awesome idea but I can’t seem to get it to work when I change the API url to the correct path on my own server.
I did some investigation and found that if I print_r($raw_response); after line 44 in the test-plugin-update.php file, which is the activated plugin, I’m getting an error on line 41 of the index.php file in the api folder. The error is as follows:
Any ideas would be welcome. Thanks!
It looks like
$packages[$args->slug]['versions']is not an array. You could check if
$packages[$args->slug]is an array before selecting
Thanks for the reply! I added:
And now the plugin reports that it is, in fact, out of date as expected. However, I now receive the message:
There is a new version of Test Plugin Update available. View version Details automatic upgrade unavailable for this plugin.
Ivan, I really can’t debug it without direct access to the code. If you are going to implement this into any of your themes/plugins, this might be a good opportunity to take the time and learn how the update procedure works.
Kaspars, thanks for your assistance in getting me on the right path to solving the problem. It is truly appreciated. The problem ended up being that the
wp_remote_post();function actually adds slashes within the
$_POST['request']serialized array. A simple addition of
$_POST['reqeust']around line 36 does the trick, like so:
All the best.
Just a quick(ish) couple of questions.
Does the api index.php file work by informing WordPress that an update is necessary if the date OR the version are different (or both different)? And does it make a difference what the actual date is of the new version (zip file), i.e. is it just the date specified in the index.php api page that rules whether an update is necessary.
Also, if I wanted to update just by version number and date, is this easy to do?
David, this script does only a version comparison.
I’m not sure I follow.
So the actual date of the Plugin/theme zip file, and date entered into the $packages array, never cause an update to occur? And it is purely the version number entered in the api index.php that triggers the update?
If I wanted to trigger an update do I just change the version number in index.php, and that’s it?
Great script by the way.
Correct, David — the date is used only for refference, so that both you and the user know when the update was released. In the API index.php you see a version comparison, which triggers the actual update:
I can’t for the life of me get the theme updater to achknowledge an update. It’s a shame because that is the only part I want. This class does a good job of the plugins. If only it support themes too or if I could get this one to work :P http://w-shadow.com/blog/2010/09/02/automatic-updates-for-any-plugin/
Are there any special requirements that might not be obvious?
Robin, did you try enabling the forced update check on every page request? Otherwise it will do it only on cron runs.
yep I enabled that. I’ve tried on my local host and on a remote server. I even tried just uploading the unmodified racer theme to one of my sites and it still didn’t do anything even with forced requests on :P
Thank you so much for making this available!
I’m currently using the code in both a theme and a plugin with great success.
I’m working on a new plugin that will auto-update, and it’s raised one question – do you know what I need to add to the $package returned by the API in order to change the message inside WordPress > Updates from “Compatibility with WordPress 3.0.5: Unknown” to “Compatibility with WordPress 3.0.5: 100% (according to its author)”??
My plugin is confirmed to work up through the latest development trunk of WP, and it’s a shame to see the Update page say that compatibility is “Unknown”
Thanks again for everything!
p.s. don’t copy and paste the code from my earlier comment. It looks like WP cropped some of the longer lines.
Simply add a ‘tested’ value to the $packages array, like so:
And then, reflect that change in the ‘plugin_information’ check further down in the document:
That’s it. Worked for me anyway.
Important: if you want to use this system to update multiple plugins (on the same environment) … the “plugins_api” filter should never at any point return “false”. Instead, based off of the args it receives it needs to lookup and return a result.
Additionally consider using a hash/assoc-array when calling the wp_remote_post() function … something like the following, this will ensure that a slug is directly tied to a api_url.
$request = wp_remote_post($hosts[$args->slug], $request_string);
The plugins_api has a weird implementation, see /wp-admin/includes/plugin-install.php … plugins_api() function … note how when the filters are applied, it needs to return a result. Having an implementation which returns false some of the time and a result other times causes problems here.
Thank you Kaspars, thank you others in the comment thread. Useful stuff, got it working for my plugin in no time.
That’s really great. I got it working but I have a question:
I would like to protect the package url. Now it is a direct link to a zip file but I would like to point to a download.php file. So, my question is, how the file content (of the zip file) has to be served from the download.php file that wordpress can install it?
Daniel, here is how I would do it — store all your client domain names and use them as identifiers (set as an HTTP referrer) when an update request is made. Once the request hits your
download.php, simply check if that domain is in your database. Yes, this approach is not 100% reliable as that header can be spoofed, but it’s a very simple and fast way of doing it.
To make it work with my theme on WordPress 3.3.1 I had to apply Ivan’s fix and change 2 lines of code to this:
$theme_base/$theme_base.php, but just simple
Hope it helps.
Thanks for the tip, Valentin!
Amazing script. Thanks Kaspars. I got it working with some struggle. First I was not getting the slug on my server, so I had to hard-code it in the script. Then I changed the packages array to add lot more information so that it feels like the update is coming from the WordPress server (now it also generates that Details pop-up when a user clicks the link – get version x.x details).
Only thing I’m not able to figure out is the Upgrade Notice. Is there a way to get that working?
Ivan Novak, I also faced this same issue and the stripslashes() fixed it. Thanks for the same. I wouldn’t have figured it out myself.
Also, I could figure out about the upgrade notice part. Just add a field called ‘upgrade_notice’ in the response.
I really appreciate you sharing such a great solution. I’m having an issue with the versioning of my theme. No matter what version I’ve identified in the styles.css, the script always displays that there is an upgrade, even if the theme is a newer version that identified in the api/index.php. Not sure what I’m doing wrong.
Weemo, I created this script just as a proof of concept because there were no alternatives out there at the time. Therefore, I suggest that in a production environment you use this Auto Update class by Jānis Elsts instead.
I took this script and made some changes so that management is little easier. You can take a look at it here – https://github.com/ronakg/wp-plugin-auto-update
Thanks for the link, RonakG! I am sure some people will find it useful.
Ah, Perfect. Thanks for the link.
Just wondering if anyone managed to get the theme api working and if so can you please share any updates that you may have made?
There is this commercial Plugin and Theme Update API manager for WooCommerce.
OMG !! This API rocks!! Thank you so much Kaspers :) I was searching for a solution like this. Found many paid services that I can not afford. Thank you so much.
Even after 5 years this script works like charm.
but i got a question i protected archive folders with basic access authentication with htaceess. i do have stored logins in my .htpasswd. and i am able to get update details from secured folder by adding this header in wp_remote_post
But when click to update it comes with
Download failed. Authorization Required
i am not sure where its lacking, can you help ?
Thank you very much.
Amit, I think your approach doesn’t actually protect the archive folder because anyone with access to your source code will be able to extract the
base64encoded authorization header.
Secondly, you won’t be able to change those credentials at a later date because you’ll break the update functionality for everyone using the old credentials.
Maybe I misunderstood you question, so please feel free to post a followup question.
If you’re looking for a service that manages this for you check out https://kernl.us. It provides automatic WordPress plugin & theme updates, license management, git deployment, and more.
Looks really useful! How does it compare to Software Licensing from EDD?