Plugins & Releases

Every plugin you license is registered once and linked to a GitHub repository. Updates are driven entirely by GitHub releases — you never upload a zip here.

Registering a plugin

Go to Plugins → Add Plugin and provide:

FieldDescription
NameHuman-friendly plugin name shown in the dashboard.
SlugLowercase identifier used by WordPress and the API, e.g. dw-ai-blog-automation. Must be unique.
GitHub RepoRepo name only (not the full URL). The org is set by GITHUB_ORG, so dw-ai-blog-automation resolves to github.com/devswizard/dw-ai-blog-automation.
DescriptionOptional short summary.

Cutting a release

The server reads the latest published release of the linked repo. To ship an update:

  1. Bump the version in your plugin header (e.g. Version: 1.3.0).
  2. Tag and publish a GitHub release. The tag becomes the version — a leading v is stripped, so v1.3.0 and 1.3.0 are equivalent.
  3. Attach a built .zipasset to the release (recommended). If no asset is attached, the server falls back to GitHub's auto-generated source zipball.

The release body becomes the changelog shown to WordPress and on the plugin detail page.

Release zip structure

WordPress expects the plugin folder inside the zip. Build your asset so it extracts to a single top-level directory matching your plugin slug:

dw-ai-blog-automation-1.3.0.zip
dw-ai-blog-automation/
├── dw-ai-blog-automation.php
├── includes/
├── assets/
└── ...

A simple GitHub Actions step to attach a clean zip on every tag:

.github/workflows/release.yml
name: Release
on:
  push:
    tags: ['v*']
jobs:
  zip:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build zip
        run: |
          SLUG=dw-ai-blog-automation
          mkdir -p build/$SLUG
          rsync -a --exclude '.git' --exclude 'build' ./ build/$SLUG/
          cd build && zip -r ../$SLUG-${GITHUB_REF_NAME#v}.zip $SLUG
      - name: Attach to release
        uses: softprops/action-gh-release@v2
        with:
          files: '*.zip'

How the update check works

When a WordPress site checks for updates, it calls /api/update/check with its current version. The server compares it against the latest GitHub release using numeric dotted-version comparison and responds with update_available. It also keeps the plugin's current_version in the dashboard in sync with GitHub automatically.

The actual download runs through /api/update/download, which re-validates the license before proxying the zip — so an expired or revoked license cannot pull updates even if it once could.