DEV Community

Eduardo Villão
Eduardo Villão

Posted on • Originally published at eduardovillao.me

How to Self-Host WordPress Plugins on GitHub and Deliver Updates

Managing plugin updates can be a challenge, especially if you're not relying on the WordPress Plugin Repository. But what if you could self-host your plugins on GitHub and deliver updates seamlessly, without the need for complex libraries or third-party services?

In this guide, I'll walk you through a simple yet powerful solution that adheres to WordPress's standard for updates, making the process completely transparent for your users. To make this possible, I've developed a custom GitHub Action and a PHP script that work together to handle updates effortlessly. This is the same solution I use for some of my own plugins, and now I'm sharing it with the community so you can benefit from it too.

No extra dependencies, no fuss — just GitHub and a bit of PHP magic. Let's get started! 🚀

What is Self-Hosting Plugins?

Before diving in, let's take a step back: self-hosting plugins means managing your plugin's storage and updates independently, outside the WordPress.org repository. You take control of where your WordPress plugins are stored and how updates are delivered, without relying on the official WordPress Plugin Repository. Instead of hosting your plugin on WordPress.org, you use your own infrastructure — such as GitHub, a private server, or any other file host — to manage your plugin's lifecycle.

In essence, self-hosting empowers developers to build, distribute, and update plugins on their own terms, while still providing users with a seamless and familiar update experience.

What is Required?

At a high level, you'll need two things:

1. A server (in our case GitHub):

  • Host metadata about your plugin, including the latest version, download URL, and other required information.
  • Store the .zip distribution file, which will be downloaded during the update process.

2. An Update Checker Script in Your Plugin:

  • Fetch data from the server (GitHub) to retrieve the latest plugin details.
  • Compare versions to check whether the installed version is outdated.
  • Forward updates seamlessly into WordPress's default update system.

With these two components working together, you can deliver a smooth and automated update experience for your plugins, all while retaining full control over the distribution process.

The Server Side on GitHub

The GitHub Action automates the creation of everything needed for the plugin update process. Here's the high-level flow:

1. Generate JSON Metadata

The action parses your readme.txt and other relevant files to create a JSON file containing metadata about your plugin — version, download URL, description, and more. This metadata is essential for the PHP script on the plugin side to query the server and verify if the plugin is up to date.

The download URL is automatically generated to point directly to the .zip file in the release created by the action, ensuring WordPress fetches updates directly from GitHub.

2. Prepare the Distribution Package

The action compiles your plugin files into a .zip package, ready for distribution. During this process, specific rules can be defined to exclude unnecessary folders or files — such as development directories, test cases, or build artifacts. This ensures a clean and optimized distribution file.

3. Release Creation

Once the metadata and distribution package are prepared, the action automates the creation of a new GitHub Release. The release is tagged with the corresponding plugin version, ensuring WordPress and the PHP script can correctly fetch the latest version.

This streamlined process ensures that every time you create a new tag/version of your plugin, all required files and metadata are automatically prepared and hosted, ready to deliver updates to your users.

👉 Check the full implementation: wp-self-host-updater-generator

The Plugin Side — Update Checker

The PHP script serves as the "bridge" between the plugin installed on the WordPress site and the server-side metadata hosted on GitHub. Here's how it operates:

1. Add a Simple PHP File to Manage Updates

The update checker script is integrated directly into your plugin. It hooks into WordPress's native update events via filters like plugins_api and site_transient_update_plugins to manage and provide update information dynamically.

2. Request JSON Data from GitHub

The script queries the GitHub-hosted JSON metadata file for the latest information about your plugin — current version, description, download URL, and other details. This ensures the site always has access to accurate, up-to-date plugin information.

3. Compare Current Version vs. Latest Version

Once the JSON data is retrieved, the script compares the currently installed version with the version available in the metadata. If the versions match, no action is taken. If a newer version exists, the script forwards the update information to WordPress's built-in update system.

4. Follow the Default WordPress Flow to Upgrade

If a new version is available, WordPress takes over using its default upgrade mechanism. This ensures a seamless and familiar experience for end users, who can update the plugin just like they would with any other WordPress plugin.

👉 Check the full implementation: wp-self-host-updater-checker


And that's it! 🎉

If you have any questions, need help with implementation, or have tested this solution and want to share feedback, feel free to drop a comment below. I'd love to hear from you!

FAQ

1. Will this work with mu-plugins?
Partially! The server side on GitHub is fully capable of managing MU-Plugins. However, since MU-Plugins don't follow the same update flow as regular WordPress plugins, the PHP script will require some adjustments. Coming soon.

2. Will this work with themes?
Not yet. Some modifications are needed to support themes. For now, this solution works exclusively with plugins — theme support is in progress.

3. Can I validate the user license before delivering updates?
This flow is designed for "free" plugins, so license validation isn't currently supported. I'm exploring ways to incorporate this feature and will share updates soon.

4. Will this work with private repositories?
Almost! The action works as-is, but the PHP script needs changes because a token is required to authenticate requests for the JSON data from private repos. Details coming soon.

Top comments (0)