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:
| Field | Description |
|---|---|
| Name | Human-friendly plugin name shown in the dashboard. |
| Slug | Lowercase identifier used by WordPress and the API, e.g. dw-ai-blog-automation. Must be unique. |
| GitHub Repo | Repo 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. |
| Description | Optional short summary. |
Cutting a release
The server reads the latest published release of the linked repo. To ship an update:
- Bump the version in your plugin header (e.g.
Version: 1.3.0). - Tag and publish a GitHub release. The tag becomes the version — a leading
vis stripped, sov1.3.0and1.3.0are equivalent. - 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/
├── dw-ai-blog-automation.php
├── includes/
├── assets/
└── ...A simple GitHub Actions step to attach a clean zip on every tag:
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.