The need or desire to use a personal remote management service makes a few assumptions.
It assumes that the developer has personal or client projects that are under version control on a system like GitHub, Bitbucket, GitLab, or some other system.
It assumes that these projects are utilized on multiple sites.
Lastly, it assumes that the developer would like a simple method of pushing updates to these multiple sites.
GitHub Updater allows for updating of plugins and themes that are developed outside of the official WordPress repository. Often these projects reside in GitHub, Bitbucket, or GitLab. Updating these repositories to a handful of sites usually involves visiting that site’s dashboard and updating the plugin or theme in the usual manner. The difficulty arises when you’re managing the same plugin(s) or theme(s) on many, many sites.
Current State of Updating
You don’t want to spend time visiting each site to update these repositories. It takes too long and quickly becomes inconvenient. It’s much simpler to use a remote management system and push updates to multiple sites. There are several commercial plugins and services to accomplish this. Among them are iThemes Sync, ManageWP, MainWP, and InfiniteWP.
The problem is that these services were designed only to work with the official WordPress repository and not with GitHub, etc. These plugins all work by showing you that an update is pending and allow you to update all the plugins for a site en masse or all of a particular plugin on multiple sites. Set up of these plugins requires a variable degree of effort and occasional errors can be difficult to troubleshoot.
GitHub Updater has had the ability to utilize many of these remote management services for a couple of years but it’s always been a bit unstable and difficult to test. Recently much of this instability has been removed by allowing for GitHub Updater’s API calls regardless of the web site visitor’s privileges. However, it still requires someone visit the site to ensure that WP-Cron runs and GitHub Updater maintains current update information.
GitHub Updater has also been able to utilize a webhook to update repositories too. This method doesn’t require WP-Cron or anyone to even visit the site. Send the appropriate webhook and the repository will update. Personally, I use a webhook to update GitHub Updater on the develop branch on my test site every time a GitHub push is identified. This way I can ensure I’m always testing with the most recent commits.
Updating via a webhook is a more of a push than a pull. For reference, my idea of a pull would be the site shows that an update is pending and pulls the update from the remote source. A push would be similar to a re-installation of the plugin from the current source. In GitHub Updater’s parlance, it’s exactly like branch switching. If you switch to the same branch it’s simply re-installing with the latest code. There is no version checking in this process.
REST API Endpoint Updating
GitHub Updater previously used a admin-ajax.php request to provide for webhook updating. I have finally re-written this to an actual REST API endpoint and it has made the Git Remote Updater possible.
Currently there are 3 endpoints.
repos – returns a listing of the sites GitHub Updater enabled plugins and themes along with their current branch.
Recently I’ve written a plugin to facilitate your own personal remote management system, Git Remote Updater. Git Remote Updater will allow you to update individual repositories on multiple sites or all the repositories in a single site with a single button click.
How It Works
Functionally, the Git Remote Updater Plugin simply sends a webhook as an HTTP GET request to the site. This allows GitHub Updater to update the repository. The best part is that Git Remote Updater is able to send multiple webhook requests with a single click.
Git Remote Updater only needs the site’s URL and API key from GitHub Updater to enter into the Git Remote Updater Settings tab.
This site specific data is all that is necessary to validate with the site and update the repositories. This data only needs to be updated if the site’s Remote Management API key changes.
The API key is easily reset and only functions on the update endpoint to authorize an update on the site and one the repos endpoint to collect repository data.
There is a REST API endpoint that returns the site’s GitHub Updater enabled plugins and themes along with data regarding the installed branch. The second REST API endpoint is for updating. It utilizes data from the JSON file to form a correct webhook for updating. Both of these endpoints require an API key for authentication.
In order to ensure that this remote updating works, updating must work on the site’s dashboard too. This means that any access tokens or username/password data must be correctly saved on the remote site. I have found that utilizing the Git Remote Updater works best on a local development environment.
Update by Repository or by Site
There are 2 ways to update in Git Remote Updater. You may update individual repositories on multiple sites or you may update multiple repositories on an individual site. A dropdown menu conveniently switches between the two options.
An example of the type of feedback supplied is below.
Git Remote Updater doesn’t seek to provide feedback about the update status of a particular plugin or theme. It simply forces an update based on the installed branch of the remote repository. This is functionally equivalent to a reinstallation or branch switch to the same installed branch of the repository.
A separate one-click install using git://develop.git.wordpress.org/ would also be great but that will require installing npm and setting the database to display /build as the home URL endpoint.
As above you will need to create a new site in Local Lightning and then Open Site Shell from Local Lightning.
To make this function, before running the commands you must ensure that your local environment has wget and npm installed. If you’re on a Mac I highly recommend using Homebrew and brew install wget. Installing npm using Homebrew can be done but isn’t necessarily the recommended method.
As of EDD Software Licensing v3.6, there are a couple of action hooks in the plugin/theme updater samples that allow for this integration. As part of the setup for using EDD SL, you need to create a new EDD SL updater class with a configuration array customized to your plugin.
This array is contains data regarding the specific plugin or theme that uses EDD Software Licensing. Integration with the Translations Updater library only requires the addition of 2 elements to the configuration array and a slightly different command that runs the translations updater.
The additional array elements are a designation to where the translations repository is hosted, GitHub, Bitbucket, GitLab, or Gitea, and the URI to the repository.
As part of the GitHub Updater I introduced a process for independent language pack updating. The normal process is to include translation files, as part of your plugins, in a /languages directory inside of your plugin and load them via load_plugin_textdomain(). This also works for themes.
Decoupled Language Packs
If your plugin is in the dot org plugin directory you benefit from translations that are done by the community on GlotPress. If your particular WordPress installation is localized and the plugin has a translation file for that locale, the translation file will be automatically added and none of the other unused translation files will be added.
These translations take precedence over those included in your plugin as of WordPress 4.6. If there are updates for the translation file, they will be added via the normal dashboard update process.
This allows for a decoupled language pack updating experience where the plugin doesn’t need to include additional files that can contribute significantly to the overall plugin size; but can benefit from maintaining the translations independently from the main plugin.
Get Your Own Decoupled Language Packs
The language pack updating method I created in GitHub Updater works in the same manner as in the dot org plugin directory. The developer maintains a separate repository that contains the language packs and the Translations Updater code independently installs the needed translation files. This allows for a more efficient method of distribution of language packs and allows the main plugin and translations to be developed and maintained separately.
Recently I have converted the Translations Updater to a Composer library. In this way it can be installed in any plugin or theme via composer require afragen/translations-updater:dev-master and decoupled language pack updating can be used. This does require a separate, public repository that contains the translations files.
I have created a Language Pack Maker library that will create the language packs from a folder of translation MO/PO files and create a language-pack.json file that contains the data regarding the current state of all the language packs.
Real World Example
I maintain the translations for GitHub Updater using this method. What I do is maintain the public repository of translations and take PRs for updated or new translations. These PRs are only for the MO/PO files. I would then update the repository locally where I would run the Language Pack Maker and then push the new language packs and language-pack.json to the public repository.
As always, ask questions. I’m happy to explain in more detail as needed.
If you maintain your codebase on GitHub, or another git host, the standard download of your repository from within GitHub is an automatically generated zipfile created from your repository. GitHub Updater uses this generated zipfile when it updates or installs a repository from GitHub.
Sometimes your project may require build tools such as Grunt, Gulp, Webpack, or some other process. The built project is usually added as a release asset to your release. GitHub Updater is capable of updating using this release asset.
I created a solution where a Zipfile was merely one more type of git host for Remote Installation using GitHub Updater. You may either drop a local file path into the Plugin URI field or insert the URI to the remote zipfile.
I was actually pleasantly surprised at how easy it was to add this functionality.