Composer Repository

Troy Server provides a native Composer 2 repository. Every plugin and package you publish becomes available via composer require — alongside WordPress.org plugins from WP Packages or WPackagist.


Prerequisites

RequirementDetails
Troy ServerInstalled and active, with at least one published plugin. Packages are recommended — they include Troy Client for update request filtering and active install reporting.
ComposerVersion 2+. Troy Server uses the metadata-url protocol.
HTTPSYour Troy Server must be accessible over HTTPS. Composer rejects plain HTTP repositories by default.

Vendor Slug

Every Troy Server has a vendor slug — a short prefix that identifies your repository in Composer package names. It appears in:

  • Plugin names: {vendor}-plugin/my-plugin.
  • Package names: {vendor}-package/my-package.

Set the vendor slug in Settings → Troy Server → Composer. Troy pre-fills it from your site name at install time.

The Vendor Slug Is Immutable:

Once consumers reference your vendor slug in their composer.json, do not ever change it. Changing the slug breaks Composer resolution for every existing consumer — and the error message they get will not mention the vendor change, making the breakage difficult to diagnose.


Plugins vs Packages

Troy Server provides these Composer package types, where {vendor} is your repository's vendor slug:

TypePatternComposer TypeIncludes Troy Client
Plugin{vendor}-plugin/{slug}wordpress-pluginNo.
Package{vendor}-package/{slug}metapackageYes.
Which type to use:

Use {vendor}-package when setting up a site for the first time. The metapackage bundles Troy Client alongside your plugins.


Full Project Example

The composer.json below installs plugins from three different sources in a single composer update:

  1. The Gentime plugin hosted at WordPress.org from WP Packages.
  2. Troy Client from Deploy Troy's repository via The SEO Framework's installer package.
  3. The SEO Framework + Extension Manager from its own Troy Server.

Composer resolves each package from the correct source automatically — no manual downloads, no ZIP uploads.

Copy this file, replace the repository URLs and package names with your own, and run composer install.

{
  "name": "deploytroy/example-project",
  "description": "A WordPress project using both Troy Server and WP Packages",
  "repositories": [
    {
      "name": "wp-packages",
      "type": "composer",
      "url": "https://repo.wp-packages.org",
      "only": ["wp-plugin/*", "wp-theme/*"]
    },
    {
      "type": "composer",
      "url": "https://repo.deploytroy.org/composer/get"
    },
    {
      "type": "composer",
      "url": "https://repo.theseoframework.com/composer/get"
    }
  ],
  "require": {
    "wp-plugin/gentime": "^2.0",
    "tsf-package/tsf-em-installer": "*"
  }
}
JSON Breakdown
KeyDescription
"name"The Composer project name. Required for a valid composer.json.
"description"A short summary of the project. Required for a valid composer.json.
"repositories"An array of package sources. This example uses three: WP Packages, Deploy Troy, and a Troy Server for The SEO Framework.
  ⤷ "name"A label for the WP Packages repository. Composer uses it for display only.
  ⤷ "type"Set to "composer". Tells Composer this is a Composer repository (as opposed to VCS, path, etc.).
  ⤷ "url" (WP Packages)The WP Packages endpoint. Serves WordPress.org plugins and themes.
  ⤷ "only"Limits WP Packages to wp-plugin/* and wp-theme/*. Composer won't ask it about tsf-package/* or deploytroy-plugin/* names.
  ⤷ "url" (Deploy Troy)Deploy Troy's Composer endpoint. The tsf-em-installer metapackage requires deploytroy-plugin/troy-client, which lives here.
  ⤷ "url" (Troy Server)The Troy Server endpoint for The SEO Framework. Its available-package-patterns list tsf-package/* and tsf-plugin/*, so Composer knows where those packages live.
"require"A map of packages to install. Each key is a package name, each value is a version constraint.
  ⤷ "wp-plugin/gentime"Gentime from WP Packages. Composer matches wp-plugin/* against the WP Packages only filter. The "^2.0" constraint requires version 2.x.
  ⤷ "tsf-package/tsf-em-installer"The SEO Framework's installer metapackage. Composer matches tsf-package/* against the Troy Server's listed patterns and fetches the metadata from there. The "*" constraint accepts any version.

See How Composer Resolution Works for the full packages.json response format that drives this matching.


Bedrock Setup

Bedrock already manages WordPress plugins via Composer. Adding a Troy repository takes one entry.

1

Add the Repositories

Choose method:

Run these from your Bedrock project root:

composer config repositories.deploytroy composer https://repo.deploytroy.org/composer/get
composer config repositories.example composer https://repo.example.org/composer/get

Replace example and repo.example.org with your Troy Server's vendor and URL.

No Trailing Slash:

The repository URL has no trailing slash. Composer appends /packages.json automatically.

2

Require the Package

Choose method:

Run this from your Bedrock project root. It adds the package to your composer.json and installs it immediately.

composer require deploytroy-package/troy-server-installer

Troy plugins land in web/app/plugins/ — Bedrock's installer-paths already maps the wordpress-plugin type to that directory.

𒄈

How Composer Resolution Works

When Composer encounters your Troy repository, it fetches packages.json at the repository URL. That response contains no package data — only instructions for fetching individual packages:

{
  "packages": {},
  "metadata-url": "/composer/get/%package%.json",
  "available-package-patterns": [
    "deploytroy-plugin/*",
    "deploytroy-package/*"
  ]
}
Response Breakdown
KeyDescription
"packages"Empty object. The root response contains no package data — Composer fetches each package individually.
"metadata-url"Tells Composer where to fetch metadata for a specific package. Composer replaces %package% with the full package name (e.g., deploytroy-plugin/troy-server) and fetches only what it needs. No full catalog download.
"available-package-patterns"Tells Composer which namespaces this repository provides. Composer skips repositories that don't match the package it's looking for — this is why Troy and WP Packages don't interfere with each other by default.

You can inspect live responses from Deploy Troy's repository:


Troubleshooting

Composer Reports "Package Not Found"

  • Verify that the vendor slug in your composer require command matches the vendor slug configured in Troy Server.
  • Verify that the plugin or package is published and has at least one released version.
  • Verify that the repository URL in your composer.json is correct — no trailing slash, and the path ends with /composer/get.

HTTPS Errors

Troy Server requires HTTPS. If your server uses a self-signed certificate, Composer will reject it. Use a valid certificate (Let's Encrypt is free) or pass --no-verify-ssl during development only.

Stale Results After Publishing

Composer caches repository metadata. Run composer clear-cache and then composer update to force a fresh fetch.

Namespace Collisions

Troy's available-package-patterns tells Composer which namespaces your repository provides. Composer skips repositories that don't match the package it's resolving, so collisions are unlikely in practice.

If a misconfigured third-party repository still interferes, you can add an only filter to each repository entry in your composer.json to explicitly scope which packages it may resolve. See the Composer documentation on repository priorities for details.


Next Steps

  • Installation — Set up your Composer repository by using Composer to install Troy Server.
  • Packages — Bundle plugins into installable metapackages with Troy Client included.
  • Troubleshooting — Resolve common Troy Server issues.