Back to Blog
Lesson 34 of the Advanced WordPress Plugin Engineering: Scale, Security & React UIs course
WordPressJune 28, 20263 min read

Automated Update API: Building a Secure WordPress Plugin Delivery System

Learn how to build a custom Update API to deliver secure, versioned plugin updates. Master the WordPress update process to automate deployments for your customers.

WordPressPlugin DevelopmentUpdatesAPIDeploymentSecurityphpplugin-development

Previously in this course, we built a Licensing Infrastructure: Secure Remote Verification for WordPress Plugins to gate access to our premium features. Now that we can verify customer entitlements, we need to deliver the code itself. This lesson adds the final piece of the distribution puzzle: building a custom Update API to notify WordPress sites of new versions and facilitate seamless, secure plugin updates.

The WordPress Update Mechanism

WordPress checks for updates by firing the site_transient_update_plugins filter. Every time the dashboard updates its update transients (usually every 12 hours), it triggers this hook. Our goal is to intercept this request, check our remote server for a newer version, and inject our plugin's update metadata if a newer version exists.

The Communication Flow

To build a robust system, your update server should behave like the official WordPress.org API. When a request hits your endpoint, it provides the current plugin version and the site's license key.

Sequence diagram: participant Site as WordPress Site; participant API as Update Server; Site → API: GET /check-update version, license; API → API: Verify License & Version; API → Site: JSON new_version, package_url, changelog; Site → Site: Displays "Update Available"; Site → API: Download Request authorized; API → Site: Plugin ZIP file

Implementing the Update API Client

On the client side (inside your plugin), you need a Service Provider that listens for the update transient check. You shouldn't hardcode this; it should be handled via a dedicated UpdateManager class.

PHP
namespace KnowledgeBase\Services;

class UpdateManager {
    private $api_url = 'https:#6A9955">//updates.yourdomain.com/v1/';
    private $plugin_slug = 'knowledge-base/knowledge-base.php';

    public function __construct() {
        add_filter('site_transient_update_plugins', [$this, 'check_for_updates']);
    }

    public function check_for_updates($transient) {
        if (empty($transient->checked)) return $transient;

        $response = wp_remote_get($this->api_url . 'check', [
            'body' => [
                'version' => $transient->checked[$this->plugin_slug],
                'license' => get_option('kb_license_key')
            ]
        ]);

        if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
            return $transient;
        }

        $data = json_decode(wp_remote_retrieve_body($response));

        if (version_compare($data->new_version, $transient->checked[$this->plugin_slug], '>')) {
            $transient->response[$this->plugin_slug] = (object) [
                'slug'        => 'knowledge-base',
                'plugin'      => $this->plugin_slug,
                'new_version' => $data->new_version,
                'package'     => $data->download_url, #6A9955">// Must be a secure, expiring URL
                'url'         => $data->changelog_url
            ];
        }

        return $transient;
    }
}

Securing the Delivery Pipeline

The package URL is the most critical part. Never expose a static link to your ZIP file. If a user shares that link, anyone can download your premium code.

  1. Expiring URLs: When the client requests an update, generate a one-time-use, expiring URL (e.g., valid for 5 minutes).
  2. Signature Verification: Use a private key to sign the download request. Ensure the server validates the license key headers before streaming the file.
  3. Authentication: Use the Automated CI/CD Pipelines: Streamlining WordPress Plugin Delivery to push your build artifacts to a secure S3 bucket, and have your API generate a pre-signed URL from there.

Hands-on Exercise: Implementing the Mock API

  1. Create a local PHP script (or a separate microservice) that acts as your Update API.
  2. Ensure it returns a JSON object containing new_version, download_url, and changelog_url.
  3. In your KnowledgeBase plugin, register the UpdateManager service.
  4. Force the transient update by deleting the update_plugins transient in wp_options via delete_site_transient('update_plugins');.
  5. Observe your plugin showing an "Update Available" notification in the WordPress admin panel.

Common Pitfalls

  • Caching the Response: The site_transient_update_plugins filter runs frequently. If your API is slow, you'll degrade site performance. Always cache your remote API response for at least 12 hours.
  • The "Package" URL Format: WordPress expects the package key to be a direct URL to a .zip file. If you use a redirect, ensure your server follows it correctly and that the final URL ends in .zip (WordPress enforces this).
  • Missing plugin_slug: If the slug in your API response doesn't match the folder structure of your plugin (e.g., knowledge-base/knowledge-base.php), the update will fail to unzip correctly.

Recap

We've bridged our plugin to a custom distribution server. By leveraging the site_transient_update_plugins filter, we provide a native WordPress experience for our customers while maintaining total control over licensing and versioning. This completes the distribution architecture we began in the earlier modules.

Up next: Documentation Systems — we'll automate the generation of API docs and user manuals directly from your codebase.

Similar Posts