Adding Plugins to Your Repository

Once Troy Server is installed, adding plugins is straightforward. You have four options:

  1. Upload a ZIP file โ€” Select a file from your computer.
  2. Enter a ZIP URL โ€” Troy Server fetches and processes the file.
  3. Connect a GitHub repository โ€” Import releases from tags automatically.
  4. 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

1

Create a New Plugin Post

In your WordPress admin:

  1. Go to Repo Plugins โ†’ Add New Plugin.
  2. A new plugin post opens in the Block Editor.
2

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.

3

Upload a Version

In the Block Editor sidebar:

Upload method:
  1. In the Plugin Versions panel, click Add New Version.
  2. Choose a ZIP file from your computer, or enter a URL to a ZIP file.
  3. 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.

4

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.

5

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:

TypeDescriptionDownloadable
TagStable release. Troy Server serves this version to all users.โœ… Yes
BetaPre-release. Troy Server only serves this version to users on the beta channel.โœ… Yes (beta channel)
UnreleasedNot approved for distribution. This is the default for new uploads.โŒ No

Changing Version Types

  1. In the plugin editor sidebar, find the Versions panel.
  2. Click the version you want to modify.
  3. Select Tag, Beta, or Unreleased.
  4. 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

StatusBehavior
PublicThe plugin is visible to everyone with Troy Client.
UnlistedTroy Server only serves updates to users who already have the plugin installed.
PendingThe plugin is not yet available. This status converts to Public automatically when you publish.
DisabledThe 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.


Instead of manually uploading ZIPs, connect your GitHub repository:

  1. Go to your plugin's edit screen.
  2. Find the GitHub Integration panel.
  3. Enter your repository (e.g., your-username/your-plugin).
  4. Optionally add a Personal Access Token for private repos.
  5. Set Auto-process to control which releases are imported.
  6. Save.

Troy Server checks for new tags every 30 minutes and processes up to 2 tags each minute.

Auto-Process Options

SettingBehavior
All new tagsTroy Server imports both stable and beta releases.
Stable releases onlyTroy Server only imports versions without pre-release suffixes.
Beta releases onlyTroy Server only imports pre-release versions.
NoneAutomatic 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:

  1. readme.txt
  2. README.txt
  3. readme.md
  4. README.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