134

If I write a private plugin, is there any way to use the WordPress auto-update mechanism to update it?

I want to encapsulate the functionality, but it's specific to my own 5 or so blogs, so it's not a good candidate for the public plugins resource. But I love the easy-updating mechanism.

Is there a way to do this?

2
  • I believe this was discussed as a filterable option on the wp-hackers mailing list back in the day. It was never resolved, IIRC. I think the relevant discussion was in this thread: lists.automattic.com/pipermail/wp-hackers/2009-February/… ...but I could be wrong.
    – ZaMoose
    Commented Aug 11, 2010 at 20:20
  • If you don't want to roll your own solution, you can use kernl.us for hosted plugin updates. Commented May 8, 2015 at 14:01

8 Answers 8

15

Since Wordpress v5.8, it is a lot simpler to create yourself a basic version of custom plugin update functionality.

Step 1

Create JSON file on your server. It will contain info about latest version number of your plugin(s) and link to ZIP file(s) for Wordpress to automatically download it when update is triggered.

Example location: https://my-domain.com/custom-plugins/plugins-info.json

Example content:

{
    "my-plugin/my-plugin.php":{
        "version":"1.1",
        "package":"https://my-domain.com/custom-plugins/my-plugin.zip"
    }
}

You can add multiple plugins info to that JSON. Just ensure that plugin key for each is in directory_name/file_name.php format.

Of course, only when plugin version in JSON is larger than version you have installed, Wordpress will show you that new version is available.

For full list of plugin(s) data you can set in JSON file, check $update parameter here

Step 2

Add "Update URI" to plugin's main file (comment section). It should link to your custom JSON file you created in step 1.

<?php
/**
 * Plugin Name: My plugin
 * Version:     1.0
 * Update URI:  https://my-domain.com/custom-plugins/plugins-info.json
 * 
 */

Step 3

Add this code to custom plugin's main file (or to functions.php)

IMPORTANT: Change "my-domain.com" inside add_filter function to actual domain you are using for JSON file.

if( ! function_exists( 'my_plugin_check_for_updates' ) ){
    
    function my_plugin_check_for_updates( $update, $plugin_data, $plugin_file ){
        
        static $response = false;
        
        if( empty( $plugin_data['UpdateURI'] ) || ! empty( $update ) )
            return $update;
        
        if( $response === false )
            $response = wp_remote_get( $plugin_data['UpdateURI'] );
        
        if( empty( $response['body'] ) )
            return $update;
        
        $custom_plugins_data = json_decode( $response['body'], true );
        
        if( ! empty( $custom_plugins_data[ $plugin_file ] ) )
            return $custom_plugins_data[ $plugin_file ];
        else
            return $update;
        
    }
    
    add_filter('update_plugins_my-domain.com', 'my_plugin_check_for_updates', 10, 3);
    
}
2
  • This was really helpful, thanks!
    – Gavin
    Commented Jan 9, 2023 at 12:32
  • How would you protect this against anybody downloading plugin?
    – Toniq
    Commented Jan 11 at 19:26
51

Looks like the applicable code is in wp-includes/update.php, wp_update_plugins():

$to_send = (object) compact('plugins', 'active');

$options = array(
    'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3), 
    'body' => array( 'plugins' => serialize( $to_send ) ),
    'user-agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' )
);  

$raw_response = wp_remote_post('http://api.wordpress.org/plugins/update-check/1.0/', $options);

It specifically checks api.wordpress.org. Technically speaking it would be possible to pass a key inside $to_send to delegate the check, but to my knowledge that is not a supported feature.

If you hook into set_site_transient_update_plugins you could add your own package details into this variable. It looks like those values will be trusted when you run the plugin updater. See wp-admin/update.php and wp-admin/includes/class-wp-upgrader.php. Given the code in these two functions, I think it would be possible to inject your own update server, you just need to look at how the package details are formatted and match that.

46

This plugin does it for you:

Automatic Updates For Private And Commercial Plugins

Since time immemorial, only plugins hosted in the official WordPress.org plugin directory have supported automatic updates. Now, I’ve written a PHP library that you can use to add automatic update capabilities to any plugin. Public, private and commercial plugins alike – all can now enjoy the benefits of automatic update notifications and one-click upgrades.

GitHub repository

3
10

If you like free ... and want to use something like GitHub, GitLab, or BitBucket, this is a good quality and supported plugin for handling it (supports private and enterprise):

https://github.com/afragen/github-updater

3
  • 1
    Wow! Looks like a well-supported and mature project! Commented Oct 12, 2016 at 20:44
  • 1
    Relying on another plugin doesn't seem a very clean solution.
    – kontur
    Commented Feb 13, 2018 at 11:25
  • 3
    @kontur very true, but being as though this is open source, and constantly being updated, it could be used as a framework, or just as a code example to build your own with.
    – sMyles
    Commented Feb 13, 2018 at 14:28
8

I'm looking into the same thing. A couple of links that I've found that might be helpful:

The first is some info and pointers to the upgrades API. The second is a code snippet showing how to actually request info from the API.

get_api_data()

<?php
/*
Retrieve items from the plugin API
*/
function get_api_data($per_page, $page)
{
    $fields = array(
        'downloaded' => true,
        'author' => false,
        'author_profile' => false,
        'contributors' => false,
        'requires' => true,
        'tested' => false,
        'compatibility' => false,
        'homepage' => false,
        'description' => false,
        'last_updated' => true,
        'added' => true
    );
    $body = (object) array('browse' => 'new', 'page' => $page, 'per_page' => $per_page, 'fields' => $fields);
    $post_data = array('action' => 'query_plugins', 'request' => serialize($body));
 
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_URL, 'http://api.wordpress.org/plugins/info/1.0/');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $return = curl_exec($ch);
    curl_close($ch);
 
    return unserialize($return);
}
2
  • 1
    @Dougal - Nice links! Commented Oct 21, 2010 at 8:53
  • The second link is dead, this is the reason why you really should try to include content from external links from the beginning if possible. Commented Jan 16, 2021 at 13:03
2

If you want a hosted solution that you don't have to manage, check out Kernl (https://kernl.us). Its a service that provides the infrastructure for updating plugins and makes it easy to integrate into your own plugins.

1
  • This seems viable.
    – kontur
    Commented Feb 13, 2018 at 18:33
1

You may want to check out the WordPress Development Kit plugin. I recently migrated my proprietary update system to this plugin. The plugin now serves as the back-end processor for my premium plugin updates.

This is similar in setup to the solution provided by agileapricot above. It will install as a standard plugin on a WordPress site. You host your premium .zip files and the plugins.json in production or prerelease directories on your server (specified in the settings for the plugin).

The plugin also allows you to list plugin versions and can even provide a download for the files on public, password-protected, or subscription-protected pages. You can see an example of the on-page version list here.

I have been using the plugin for months to publish the change log for my premium add-ons, the current versions list, and download lists for my Premier Subscription holders. Now, with version 0.7.01, it is working as the query destination for inline WordPress updates.

Hope some of you find it useful.

1

If you're interested in creating your own update server, it is easy enough to do without libraries using only two filter hooks plugins_api and site_transient_update_plugins

plugins_api – used to get the plugin information and display it in modal window, example:

enter image description here

site_transient_update_plugins is needed to push the update from your server.

More on that in this tutorial: https://rudrastyh.com/wordpress/self-hosted-plugin-update.html

3
  • I have tried your code but getting error Parse error: syntax error, unexpected '{' in Commented Nov 24, 2022 at 2:56
  • In this code i am getting the error // do nothing if we don't get the correct response from the server if( is_wp_error( $remote ) || 200 !== wp_remote_retrieve_response_code( $remote ) || empty( wp_remote_retrieve_body( $remote ) ) { return $res; } Commented Nov 24, 2022 at 2:56
  • ) missing in your code Commented Nov 24, 2022 at 3:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.