- Docs
- Troy Server
- Plugin Management
Adding Plugins to Your Repository
Once Troy Server is installed, adding plugins is straightforward. You have four options:
- Upload a ZIP file โ Select a file from your computer.
- Enter a ZIP URL โ Troy Server fetches and processes the file.
- Connect a GitHub repository โ Import releases from tags automatically.
- Connect a WordPress.org plugin โ Import releases from WordPress.org automatically.
Plugins vs Packages:
Plugins are for updates. Packages are for distribution.
If you distribute plugins directly, users need Troy Client installed firstโeither manually or through someone else's Package.
Packages are mini-installer plugins that bundle Troy Client. When users install your Package, they get Troy Client + your plugins in one step. Packages always fetch the latest version at install time, so you don't need to rebuild them for every release.
Use Packages to distribute. Use Plugins to serve updates.
Adding Your First Plugin
Create a New Plugin Post
In your WordPress admin:
- Go to Repo Plugins โ Add New Plugin.
- A new plugin post opens in the Block Editor.
Set the Plugin Slug
In the Block Editor sidebar, set the plugin slug (e.g., example-plugin). This slug becomes both the identifier for your plugin and the folder name when installed.
Upload a Version
In the Block Editor sidebar:
- In the Plugin Versions panel, click Add New Version.
- Choose a ZIP file from your computer, or enter a URL to a ZIP file.
- Click Process ZIP.
Troy Server automatically extracts metadata from two sources in your ZIP:
- Plugin file headers โ version, requirements, and Troy-specific headers.
- readme.txt or readme.md โ short description, homepage URL, support URI, donate link, locale, and content sections.
See Plugin Headers for the full reference.
Troy Header Required:
Your plugin must include a Troy header with your repository URL before uploading. Without this header, the upload fails. See Plugin File Headers for the format.
Set Version to Tag
New uploads start as Unreleased. In the Versions panel, click the version and change its type to Tag (stable) or Beta.
Unreleased versions cannot be downloaded.
Publish
Click Publish. Your plugin URL looks like:
https://repo.example.org/plugin/get/zip/example-plugin
When you publish, Troy Server updates the plugin status (under Plugin Settings in the sidebar) based on these rules:
- Pending changes to Public if at least one Tag or Beta version exists.
- Unlisted, Public, and Disabled stay unchanged.
- Any non-Disabled status reverts to Pending if no Tag or Beta version exists.
While a plugin is Pending or Disabled, it's unavailable through the API โ downloads, updates, and Composer requests won't work.
It's a 30-second setup (with some practice):
Optionally, add a banner (1544ร500), logo (256ร256), select an author, set a short description, and configure homepage/donation/support links.
Tip: Set the author's Display Name in their WordPress user profile for proper attribution.
Plugin File Headers
For users to receive updates from your Troy Server, your plugin's main file needs a Troy header with your repository URL.
Example Plugin Header
<?php
/**
* My Plugin Name
*
* @package Company\MyPluginName
* @author J Doe
* @copyright 2026 J Doe, Company (https://example.org/)
* @license MIT
*
* @troy-repo
* Troy: repo.example.org
*
* @wordpress-plugin
* Plugin Name: My Plugin Name
* Plugin URI: https://example.org/my-plugin
* Description: This is a short description of my plugin.
* Version: 1.3.0
* Author: J Doe
* Author URI: https://example.org/
* License: MIT
* Text Domain: my-plugin-slug
* Requires at least: 6.8
* Tested up to: 6.9
* Requires PHP: 7.4
*/
See Plugin Headers for the full header reference, URL format options, and readme file details.
Version Detection:
When importing via GitHub or WordPress.org integrations, Troy Server detects pre-release versions automatically. Any version matching PHP's version_compare() pre-release suffixes is classified as Beta. These are all considered beta: dev, alpha (or a), beta (or b), rc, #, pl (or p). For example, 1.2.3-beta.1 and 2.0.0-rc1 are both imported as beta versions. Manual uploads always default to Unreleased regardless of the version string.
Version Types
Every uploaded version has a type that determines its availability:
| Type | Description | Downloadable |
|---|---|---|
| Tag | Stable release. Troy Server serves this version to all users. | โ Yes |
| Beta | Pre-release. Troy Server only serves this version to users on the beta channel. | โ Yes (beta channel) |
| Unreleased | Not approved for distribution. This is the default for new uploads. | โ No |
Changing Version Types
- In the plugin editor sidebar, find the Versions panel.
- Click the version you want to modify.
- Select Tag, Beta, or Unreleased.
- Save or update the post.
Blocked Versions:
Blocked is not a version type you can select โ it's a processing outcome. If a version fails validation during upload (missing Troy header, invalid version format, etc.), Troy Server blocks it and stores the file hash to prevent re-processing.
To fix a blocked version, correct the issue in your plugin and upload a new version. Blocked entries appear in Settings โ Logs.
Plugin Status Options
| Status | Behavior |
|---|---|
| Public | The plugin is visible to everyone with Troy Client. |
| Unlisted | Troy Server only serves updates to users who already have the plugin installed. |
| Pending | The plugin is not yet available. This status converts to Public automatically when you publish. |
| Disabled | The plugin is blocked from all update requests. |
Deleting vs Disabling:
If you delete a plugin, its files move to a graveyard directory for potential recovery. If you're unsure, set it to Disabled insteadโthis blocks access while keeping everything intact. See File Recovery for details.
Dependencies
Plugins can declare dependencies on other Troy-hosted plugins using the Troy Dependency or Troy Dependencies header.
Troy Dependency: plugin-slug
Troy Dependency: plugin-slug <repo.example.org>
Troy Dependencies: first-plugin, second-plugin <repo.example.org>
Troy Server validates the dependency format on upload and displays them in the Versions panel. Troy Client auto-installs missing dependencies in the background. See Troy Dependencies for syntax, limits, and install behavior.
Prefer Packages Over Dependencies:
Dependencies install automatically โ the user sees a notification but doesn't get a choice. For optional or loosely-coupled plugins, use a Package instead. Packages are opt-in and give users control over what gets installed.
Connecting GitHub (Recommended)
Instead of manually uploading ZIPs, connect your GitHub repository:
- Go to your plugin's edit screen.
- Find the GitHub Integration panel.
- Enter your repository (e.g.,
your-username/your-plugin). - Optionally add a Personal Access Token for private repos.
- Set Auto-process to control which releases are imported.
- Save.
Troy Server checks for new tags every 30 minutes and processes up to 2 tags each minute.
Auto-Process Options
| Setting | Behavior |
|---|---|
| All new tags | Troy Server imports both stable and beta releases. |
| Stable releases only | Troy Server only imports versions without pre-release suffixes. |
| Beta releases only | Troy Server only imports pre-release versions. |
| None | Automatic imports are disabled (manual only). |
Version Type Mismatch:
If your tag name suggests a beta (e.g., v1.0.0-beta) but the plugin header contains a stable version (e.g., Version: 1.0.0), the version will be kept as Unreleased and you'll see a warning.
See GitHub Integration for detailed setup.
Readme File Format
Troy Server parses a readme file from your plugin ZIP to extract additional metadata. The search order is:
readme.txtREADME.txtreadme.mdREADME.md
The first match is used. This order prioritizes .txt (the WordPress.org standard) over .md (the GitHub standard), so you can maintain separate readmes for each platform.
See Plugin Headers for supported readme headers, sections, and examples.
Statistics
Troy Server tracks anonymous statistics:
- Download counts per version.
- Active installations (estimated via rotating weekly IDs).
- PHP and WordPress version distribution.
- Locale distribution.
All data is anonymized. No domain names or personal information is collected.
Next Steps
- Create a Package for easy distribution.
- Connect GitHub for automatic releases.
- Read the API docs if you need to integrate programmatically.
