# Allowed Domains Source: https://docs.wp-content.io/account/allowed-domains Each time a WordPress site connects to your account using an API key, its domain is automatically added to the list of allowed domains for the organization linked to that key. This includes local development environments. ## Domain Status Once a domain has been added, you can manage its status through the dashboard: * **Active**: The domain is authorized to install and receive updates for your plugins and themes. * **Disabled**: This acts like a blacklist. The connection with the site will be blocked, and it won’t be able to reconnect, even after deleting or reinstalling the plugin, unless it is manually re-enabled. * **Deleted**: The domain is removed from the list, but if the site connects again using a valid API key, the domain will be automatically re-added. This system allows you to keep control over which sites can use your private repositories. ## Requesting Additional Domains For security reasons, the number of allowed domains per organization may be limited depending on your plan. If you need to add more domains, please contact us at [support@wp-content.io](mailto:support@wp-content.io). We manually review these requests to ensure the service is not being misused for distributing pirated or malicious content. # Manage API Keys Source: https://docs.wp-content.io/account/api-keys API keys allow your WordPress sites to connect securely to your organization and retrieve update information for your private plugins and themes. ## Overview When an organization is created, two API Keys are generated named `publisher_key` and `readonly`. Both of the keys are scoped on "themes" and "plugins". The `readonly` key let you see the list and download your different plugins and themes versions but cannot be used to upload a new artifact. The `publisher_key` should be kept securely. **Everyone with this key** will be able to perform all actions on your account, including **deleting your data**. You can revoke a key anytime by deleting it. Be careful, each key are unique so if you delete it, you will have to change the key everywhere you use it. ## Understanding scopes and permissions There are two scopes available for API Keys : `plugins` and `themes`. For each scope, you can choose to apply permissions gradually: 1. `read` : See list and plugin or theme details 2. `update` : Upload a new artifact and update plugin or theme details 3. `create` : Create a new plugin or theme 4. `delete` : Delete an existing plugin or theme Only owners and admins can manage API Keys. **Need more details about scopes and permissions?** Check out the full list of available scopes and what each permission allows [on this page](/account/users#available-scopes-and-permissions). # Organizations Source: https://docs.wp-content.io/account/organizations You can manage multiple organizations from your account, each acting as a separate workspace for your plugins, themes, collaborators, and API keys. Each organization is tied to its own subscription. Plans are flexible and designed to fit individual developers, freelancers, and agencies. You’ll find full pricing details here: [wp-content.io/pricing](https://wp-content.io/pricing). Typical use cases for multiple organizations: * Separate projects or clients * Different internal teams * Distinct billing needs Everything related to deployment, API keys, and domain restrictions is managed per organization. # Users and permissions Source: https://docs.wp-content.io/account/users User management is available on the Agency plan only. It includes 5 users by default, with the option to add more seats if needed. Each user can be assigned fine-grained permissions across different scopes like plugins, themes, API keys, billing, and more. For every scope, you can define specific rights: read, edit, create, or delete. This makes it easy to collaborate while keeping full control over who can access and manage each part of your organization. Permissions can be configured at any time from your organization settings. ## Available scopes and permissions The table below lists all available scopes and the corresponding permissions that can be granted to a user. Each permission defines the level of access the user has for a given resource, such as viewing billing information, managing plugins, or inviting new members. Use this as a reference to configure user roles and API access appropriately. | Scope | `Read` | `Update` | `Create` | `Delete` | | -------------- | -------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------- | | `organization` | View organization details | Update organization details | | | | `billing` | View billing information and invoice history | Update billing details or change subscription plan | Subscribe to a paid plan (if not already subscribed) | Cancel the active subscription | | `api_keys` | View API keys and their permissions | Rename an existing API key | Create a new API key with specific permissions | Revoke (delete) an existing API key | | `users` | View organization members and their roles | Change a member’s role | Invite a new member to the organization or accept a pending invite | Remove a member from the organization | | `plugins` | View available plugins and their metadata | Upload a new ZIP version and edit plugin metadata (name, version, readme, etc.) | Add a new plugin to the registry | Delete a plugin from the registry | | `themes` | View available themes and their metadata | Upload a new ZIP version and edit theme metadata (name, version, readme, etc.) | Add a new theme to the registry | Delete a theme from the registry | # Introduction Source: https://docs.wp-content.io/api-reference/introduction This API allows you to manage the **plugins and themes** of your organization. It provides a simple and secure way to publish new versions, retrieve metadata, and automate deployments. To interact with the API, you'll need a valid API key associated with your organization. Keys can be generated and managed from your dashboard: [https://dashboard.wp-content.io](https://dashboard.wp-content.io) ## Scopes and permissions The REST API is built on a standard CRUD model. Each permission corresponds to an HTTP method: | **Method** | **Permission** | | ---------- | -------------- | | `GET` | read | | `POST` | create | | `PATCH` | update | | `DELETE` | delete | ## Authentication All requests must include a valid API key in the request header: ``` X-Api-Key: YOUR_API_KEY ``` You can find and manage your API keys in the **API Keys** section of your dashboard. # Delete a version Source: https://docs.wp-content.io/api-reference/plugin-versions/delete-a-version /api-reference/openapi.yaml delete /plugins/{slug}/versions/{version} # Get all plugin versions Source: https://docs.wp-content.io/api-reference/plugin-versions/get-all-plugin-versions /api-reference/openapi.yaml get /plugins/{slug}/versions Get versions of plugins with details. # Get plugin version details Source: https://docs.wp-content.io/api-reference/plugin-versions/get-plugin-version-details /api-reference/openapi.yaml get /plugins/{slug}/versions/{version} Get version detail for a given plugin # Update plugin version details Source: https://docs.wp-content.io/api-reference/plugin-versions/update-plugin-version-details /api-reference/openapi.yaml patch /plugins/{slug}/versions/{version} Update plugin version details. You can use this endpoint to change "latest" version of a plugin and add release notes. # Delete a plugin Source: https://docs.wp-content.io/api-reference/plugins/delete-a-plugin /api-reference/openapi.yaml delete /plugins/{slug} Delete a plugin organization. # Get plugin details Source: https://docs.wp-content.io/api-reference/plugins/get-plugin-details /api-reference/openapi.yaml get /plugins/{slug} Retrieve detailed information about a plugin from the organization. # List all plugins Source: https://docs.wp-content.io/api-reference/plugins/list-all-plugins /api-reference/openapi.yaml get /plugins Retrieve the list of plugins published in the organization. The response format is compatible with official Wordpress Repository format. # Update plugin informations Source: https://docs.wp-content.io/api-reference/plugins/update-plugin-informations /api-reference/openapi.yaml patch /plugins/{slug} # Upload a plugin Source: https://docs.wp-content.io/api-reference/plugins/upload-a-plugin /api-reference/openapi.yaml post /plugins # Profile Source: https://docs.wp-content.io/api-reference/repository/profile /api-reference/openapi.yaml get /author # Repository status Source: https://docs.wp-content.io/api-reference/repository/repository-status /api-reference/openapi.yaml get / # Delete a version Source: https://docs.wp-content.io/api-reference/theme-versions/delete-a-version /api-reference/openapi.yaml delete /themes/{slug}/versions/{version} # Get all plugin versions Source: https://docs.wp-content.io/api-reference/theme-versions/get-all-plugin-versions /api-reference/openapi.yaml get /themes/{slug}/versions Get versions of plugins with details. # Get theme version details Source: https://docs.wp-content.io/api-reference/theme-versions/get-theme-version-details /api-reference/openapi.yaml get /themes/{slug}/versions/{version} Get version detail for a given plugin # Update theme version details Source: https://docs.wp-content.io/api-reference/theme-versions/update-theme-version-details /api-reference/openapi.yaml patch /themes/{slug}/versions/{version} Update plugin version details. You can use this endpoint to change "latest" version of a plugin and add release notes. # Delete a theme Source: https://docs.wp-content.io/api-reference/themes/delete-a-theme /api-reference/openapi.yaml delete /themes/{slug} Delete a plugin organization. # Get theme details Source: https://docs.wp-content.io/api-reference/themes/get-theme-details /api-reference/openapi.yaml get /themes/{slug} Retrieve detailed information about a plugin from the organization. # List all themes Source: https://docs.wp-content.io/api-reference/themes/list-all-themes /api-reference/openapi.yaml get /themes Retrieve the list of plugins published in the organization. The response format is compatible with official Wordpress Repository format. # Update theme informations Source: https://docs.wp-content.io/api-reference/themes/update-theme-informations /api-reference/openapi.yaml patch /themes/{slug} # Upload a theme Source: https://docs.wp-content.io/api-reference/themes/upload-a-theme /api-reference/openapi.yaml post /themes # Integrate in your CI/CD Source: https://docs.wp-content.io/cli/automate Automate your workflow ## Use docker image The CLI is available in a docker image with PHP 8.2 and composer pre-installed on [Docker hub](https://hub.docker.com/r/wpcontent/wpc-cli). You can use `latest` tag or specify the version. ## Example of CI/CD with Gitlab Example of .gitlab-ci.yml file to put in your git project : ```yaml .gitlab-ci.yml theme={null} stages: - 📦️ build - 🚀 publish variables: GIT_SUBMODULE_STRATEGY: recursive GIT_SUBMODULE_FORCE_HTTPS: "true" PLUGIN_SLUG: dummy WPC_CLI_VERSION: 1.1 WPC_API_KEY: 00000000-0000-0000-0000-000000000000 ⛏️ generate zip: stage: 📦️ build image: wpcontent/wpc-cli:${WPC_CLI_VERSION} script: - composer install --no-dev --optimize-autoloader - wpc plugin:build --slug=${PLUGIN_SLUG} --output-dir=./ . artifacts: paths: - ./${PLUGIN_SLUG}.zip 🗂️ push to registry: stage: 🚀 publish image: wpcontent/wpc-cli:${WPC_CLI_VERSION} script: - wpc plugin:push -m "${CI_COMMIT_MESSAGE}" ./${PLUGIN_SLUG}.zip when: manual workflow: rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH ``` ## Use CLI in your Dockerfile You can grab the latest version by copying from the official repository : ```dockerfile Dockerfile theme={null} FROM php:8.3-alpine COPY --from=wpcontent/wpc-cli:latest /usr/local/bin/wpc /usr/local/bin/wpc # Run any command RUN wpc plugin:build ``` ## Original Dockerfile If you want to create your own image, you can find original Dockerfile below. ```dockerfile Dockerfile theme={null} FROM php:8.2-alpine AS build LABEL Maintainer="Happy Monkey " # Prepare system RUN apk update && apk add --no-cache \ gettext \ git \ zip \ libzip-dev \ curl \ sudo \ unzip \ icu-dev \ bzip2-dev \ libpng-dev \ libjpeg-turbo-dev \ freetype-dev \ postgresql-dev \ g++ \ make \ autoconf # Install PHP extensions RUN docker-php-ext-install \ pdo_mysql \ pdo_pgsql \ bcmath \ bz2 \ gd \ intl \ zip # Clean up RUN rm -rf /var/cache/apk/* # Install PHP modules RUN docker-php-ext-configure gd --with-freetype=/usr --with-jpeg=/usr && \ docker-php-ext-install \ bz2 \ zip \ gd \ intl \ bcmath \ opcache \ calendar \ pdo_mysql \ mysqli \ pdo_pgsql \ pgsql # Install Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer # Add main command COPY ./wpc.phar /usr/local/bin/wpc RUN chmod +x /usr/local/bin/wpc WORKDIR /app ``` # Installation Source: https://docs.wp-content.io/cli/install Manage your organization content from CLI. ## Installation Download [wpc.phar](https://downloads.wp-content.io/wpc-cli/latest/wpc.phar) using wget or curl. For example: ```bash theme={null} curl -O https://downloads.wp-content.io/wpc-cli/latest/wpc.phar ``` To be able to type just `wpc`, instead of php wpc.phar, you need to make the file executable and move it to somewhere in your PATH. For example: ```bash theme={null} chmod +x wpc.phar sudo mv wpc.phar /usr/local/bin/wpc ``` The CLI needs at least PHP 8.2 and zip extension installed to works. # Build a plugin archive Source: https://docs.wp-content.io/cli/plugins/build wpc plugin:build Generate a ZIP archive from a plugin folder, with optional metadata override and repository push. If a `.wpcignore` file is present in the plugin folder, it will be used to exclude files from the archive. See [documentation](/cli/wpcignore) for details. ## Usage ```bash theme={null} wpc plugin:build [options] [--] [] ``` ## Arguments Input directory containing plugin sources (default: current working directory). ## Options Plugin slug. If omitted, the working directory name will be used. Output directory for the ZIP archive. Name of the output ZIP file. Override one or more plugin headers (e.g. `--header="Version=1.2.3"`).\ Only existing headers in the plugin file will be replaced, new ones will be ignored. Original file will be unchanged. Push the archive to the configured repository. [See push documentation](/cli/plugins/push). Release notes used during push (ignored without push option). Delete the ZIP file after it has been uploaded (ignored without push option). ## Examples ```bash theme={null} # Build a zip from current working directory $ wpc plugin:build # Build a zip by providing all directories and files name $ wpc plugin:build --slug=my-plugin --output-dir=build --filename=my-plugin.zip my-plugin # Build and push a zip with a specific version and with release notes $ wpc plugin:build --header="Version=1.2.3" --push --m "Add new block" ``` # Generate a plugin manifest Source: https://docs.wp-content.io/cli/plugins/manifest wpc plugin:manifest Extract metadata from a plugin file using WordPress internals and output it as a structured manifest. ## Usage ```bash theme={null} wpc plugin:manifest [options] [--] ``` ## Arguments Path to the main plugin file (e.g. `my-plugin/my-plugin.php`). ## Options If set, outputs only the value of the specified property (e.g. `Name`, `Version`, `Author`, etc.). ## Examples ```bash theme={null} # Display full manifest $ wpc plugin:manifest my-plugin/my-plugin.php # Output only the version $ wpc plugin:manifest my-plugin/my-plugin.php --get=Version ``` # List and inspect plugins Source: https://docs.wp-content.io/cli/plugins/published wpc plugin:ls, wpc plugin:info Retrieve the list of plugins published by your organization, or fetch detailed information about a specific plugin. ## List plugins Use `wpc plugin:ls` to list plugins available on your account. ### Usage ```bash theme={null} wpc plugin:ls [options] ``` ### Options Page number to retrieve. Number of items per page. ### Examples ```bash theme={null} # Get all plugins from organization $ wpc plugin:ls # Provide pagination informations $ wpc plugin:ls --paged=2 --per-page=5 ``` ## Get plugin details Use `wpc plugin:info` to retrieve full information for a plugin from the repository. ### Usage ```bash theme={null} wpc plugin:info ``` ### Arguments Slug of the plugin on the repository. ### Examples ```bash theme={null} # Get info from plugin with slug `dummy` $ wpc plugin:info dummy ``` # Push a plugin archive Source: https://docs.wp-content.io/cli/plugins/push wpc plugin:push Upload a ZIP archive to the configured plugin repository. ## Usage ```bash theme={null} wpc plugin:push [options] [--] ``` ## Arguments Path to the ZIP file to upload. ## Options Release notes for this version. Delete the ZIP file after it has been uploaded. ## Examples ```bash theme={null} # Push the plugin archive without message $ wpc plugin:push dist/my-plugin.zip # Push the plugin archive with a commit message $ wpc plugin:push --m "🐛 Fix some bugs" dist/my-plugin.zip # Push the plugin archive and clean previous versions $ wpc plugin:push --clean dist/my-plugin.zip ``` # Start a new plugin Source: https://docs.wp-content.io/cli/plugins/start wpc plugin:start Create a folder with a minimal plugin file. If no arguments or options are passed to the command, they can be entered interactively. ## Usage ```bash theme={null} wpc plugin:start [options] [--] [ []] ``` ## Arguments Name of the plugin. This will be the folder name and the slug of the plugin. If you don’t specify the slug, the name will be used to create one. ## Options The options allow you to set the information in your plugin’s header ([see the WordPress documentation](https://developer.wordpress.org/plugins/plugin-basics/header-requirements/)). Plugin URI plugin header Description plugin header Version plugin header Requires at least plugin header Requires PHP plugin header Author plugin header Author URI plugin header License plugin header License URI plugin header Text Domain plugin header Domain Path plugin header Network plugin header Do not ask any interactive question ## Examples ```bash Input theme={null} $ cd /Users/mkey/Wordpress/wp-content/plugins/ $ wpc plugin:start --author="Happy Monkey" --author-uri="https://mkey.fr" --plugin-version=1.0.0 --no-interaction dummy Plugin initialized at path : /Users/mkey/Wordpress/wp-content/plugins/dummy ``` ```php Output file: dummy/dummy.php theme={null} ```bash Input theme={null} $ wpc plugin:start Plugin name: Would you like to define plugin additional headers ? [N/y] Plugin URI: <> Description: Version: <1.0.1> Requires at least: <6.0> Requires PHP: <8.2> Author: Author URI: License: <> License URI: <> Text Domain: Domain Path: <> Network:<> Plugin initialized at path : /Users/mkey/Wordpress/wp-content/plugins/dummy ``` ```php Output file: dummy/dummy.php theme={null} # Build a theme archive Source: https://docs.wp-content.io/cli/themes/build wpc theme:build Generate a ZIP archive from a theme folder, with optional metadata override and repository push. If a `.wpcignore` file is present in the theme folder, it will be used to exclude files from the archive. See [documentation](/cli/wpcignore) for details. ## Usage ```bash theme={null} wpc theme:build [options] [--] [] ``` ## Arguments Input directory containing theme sources (default: current working directory). ## Options Theme slug. If omitted, the working directory name will be used. Output directory for the ZIP archive. Name of the output ZIP file. Override one or more theme headers (e.g. `--header="Version=1.2.3"`). Only existing headers in the theme file will be replaced, new ones will be ignored. Original file will be unchanged. Push the archive to the configured repository. [See push documentation](/cli/themes/push). Release notes used during push (ignored without push option). Delete the ZIP file after it has been uploaded (ignored without push option). ## Examples ```bash theme={null} # Build a zip from current working directory $ wpc theme:build # Build a zip by providing all directories and files name $ wpc theme:build --slug=my-theme --output-dir=build --filename=my-theme.zip my-theme # Build and push a zip with a specific version and with release notes $ wpc theme:build --header="Version=1.2.3" --push --m "Add new block" ``` # Generate a theme manifest Source: https://docs.wp-content.io/cli/themes/manifest wpc theme:manifest Extract metadata from a theme file using WordPress internals and output it as a structured manifest. ## Usage ```bash theme={null} wpc theme:manifest [options] [--] ``` ## Arguments Path to the stylesheet file (e.g. `my-theme/style.css`). ## Options If set, outputs only the value of the specified property (e.g. `Name`, `Version`, `Author`, etc.). ## Examples ```bash theme={null} # Display full manifest $ wpc theme:manifest my-plugin/style.css # Output only the version $ wpc theme:manifest my-plugin/style.css --get=Version ``` # List and inspect themes Source: https://docs.wp-content.io/cli/themes/published wpc theme:ls, wpc theme:info Retrieve the list of themes published by your organization, or fetch detailed information about a specific theme. ## List themes Use `wpc theme:ls` to list themes available on your account. ### Usage ```bash theme={null} wpc theme:ls [options] ``` ### Options Page number to retrieve. Number of items per page. ### Examples ```bash theme={null} # Get all themes from organization $ wpc theme:ls # Provide pagination informations $ wpc theme:ls --paged=2 --per-page=5 ``` ## Get theme details Use `wpc theme:info` to retrieve full information for a theme from the repository. ### Usage ```bash theme={null} wpc theme:info ``` ### Arguments Slug of the theme on the repository. ### Examples ```bash theme={null} # Get info from theme with slug `dummy` $ wpc theme:info dummy ``` # Push a theme archive Source: https://docs.wp-content.io/cli/themes/push wpc theme:push Upload a ZIP archive to the configured theme repository. ## Usage ```bash theme={null} wpc theme:push [options] [--] ``` ## Arguments Path to the ZIP file to upload. ## Options Release notes for this version. Delete the ZIP file after it has been uploaded. ## Examples ```bash theme={null} # Push the theme archive without message $ wpc theme:push dist/my-theme.zip # Push the theme archive with a commit message $ wpc theme:push --m "🐛 Fix some bugs" dist/my-theme.zip # Push the theme archive and clean previous versions $ wpc theme:push --clean dist/my-theme.zip ``` # Start a new theme Source: https://docs.wp-content.io/cli/themes/start wpc theme:start Create a folder with a minimal theme file. If no arguments or options are passed to the command, they can be entered interactively. ## Usage ```bash theme={null} wpc theme:start [options] [--] [ []] ``` ## Arguments Name of the theme. This will be the folder name and the slug of the theme. If you don’t specify the slug, the name will be used to create one. ## Options The options allow you to set the information in your theme’s header ([see the WordPress documentation](https://developer.wordpress.org/themes/basics/main-stylesheet-style-css/)). Version theme header Author theme header Author URI theme header Theme URI theme header Description theme header Requires at least theme header Requires PHP theme header License theme header License URI theme header Text Domain theme header Domain Path theme header Tags theme header ## Interactive mode If you don't pass any argument or option, the command runs in interactive mode. You’ll be prompted to enter the theme name and can optionally define additional headers. ## Examples ```bash Input theme={null} $ cd /Users/mkey/Wordpress/wp-content/themes/ $ wpc theme:start --author="Happy Monkey" --author-uri="https://mkey.fr" --theme-version=1.0.0 --no-interaction dummy Theme initialized at path : /Users/mkey/Wordpress/wp-content/themes/dummy ``` ```css Output file: dummy/style.css theme={null} /** * Theme Name: dummy * Description: * Version: 1.0.0 * Author: Happy Monkey * Author URI: https://mkey.fr * Update URI: https://registry.wp-content.io * * Generated by WPC-CLI Generator (https://wp-content.io). */ ``` ```bash Input theme={null} $ wpc theme:start Theme name: Would you like to define plugin additional headers ? [N/y] Plugin URI: <> Description: Version: <1.0.1> Requires at least: <6.0> Requires PHP: <8.2> Author: Author URI: License: <> License URI: <> Text Domain: Domain Path: <> Tags: <> Network:<> Plugin initialized at path : /Users/mkey/Wordpress/wp-content/plugins/dummy ``` ```css Output file: dummy/style.css theme={null} /** * Theme Name: dummy * Description: Lorem ipsum dolor sit amet * Version: 1.0.1 * Requires at least: 6.0 * Requires PHP: 8.2 * Author: Happy Monkey * Author URI: https://mkey.fr * Text Domain: dummy * Update URI: https://registry.wp-content.io * * Generated by WPC-CLI Generator (https://wp-content.io). */ ``` # Usage Source: https://docs.wp-content.io/cli/usage Check installed version ```bash theme={null} wpc --version ``` Get available commands ```bash theme={null} wpc list ``` ## API Key Most actions require a valid API key. You can provide an API Key by using the global option or by defining an environment variable. [Manage API Keys](/account/api-keys). ## Global options Provide custom repository API url API Key to use Response format. Could be `json` or `human` ## Environment variables You can provide environment variables to override some global options. ```bash theme={null} export WPC_REPO_URL=https://registry.wp-content.io export WPC_API_KEY=00000000-0000-0000-0000-000000000000 ``` # Ignore files Source: https://docs.wp-content.io/cli/wpcignore Exclude files during plugin and theme build process. The `.wpcignore` file works like a `.gitignore`: it allows you to specify files or directories to exclude during the build process, especially when generating ZIP archives via the CLI. ## Purpose When executing build commands, the `.wpcignore` file is used to determine which files should be excluded from the final ZIP package. This helps avoid including unnecessary files like version control folders, logs, or local development artifacts. ## Format The `.wpcignore` file is a plain text file containing one pattern per line. It supports glob patterns, making it easy to match files or folders. ## Example ```gitignore .wpcignore theme={null} # Exclude Git-related files and folders .git* # Exclude all .log files *.log # Exclude temporary folders temp/ ``` ## Usage Place the `.wpcignore` file at the root of your project. During the build process, the CLI will automatically use it to determine what should be excluded from the archive. ## Notes * Patterns are relative to the root of the project. * Empty lines and lines starting with `#` are treated as comments. * Be careful not to exclude required files unintentionally. # External Repositories Source: https://docs.wp-content.io/guides/external-repositories Manage external sources for your plugins and themes, and bring private updates directly into the WordPress admin. This plugin cannot be published on the official WordPress repository, as their guidelines forbid plugins that implement custom update mechanisms. Once installed, it will behave like any other plugin, and future updates will be delivered directly from wp-content.io. ## Installation Download the plugin from the official website: [https://wp-content.io/external-repositories](https://wp-content.io/external-repositories). You’ll get a `.zip` file ready to install. In your WordPress admin, go to **Plugins > Add New**, click **Upload Plugin**, and select the downloaded ZIP file. Then click **Install Now**, and activate the plugin once the installation completes. After activation, you'll be redirected to the plugin settings page. Paste your API key to connect your site to your organization. A default **readonly key** was automatically created when you set up your organization. ## Configuration The screen below allows you to configure external sources for plugin and theme updates. Each **tab** represents a different source. You can connect multiple registries (for example, several wp-content.io accounts or custom APIs) to the same site. * **Name**: A unique label for this repository. It can be anything — for example, your organization name. * **Registry URL**: Choose between the official wp-content.io registry or a custom API endpoint compatible with the same structure ([API Reference](/api-reference)). * **API Key**: A read-only key is required for security. If `SECURE_AUTH_KEY` is defined in your `wp-config.php`, the key will be encrypted in the database. * **Supports**: Toggle whether this source should manage plugins, themes, or both. * **Enabled**: Allows you to temporarily disable a repository. When unchecked, no update checks will be made for that source. Once connected, the current site's domain is automatically added to your organization's **allowed domains**. You can revoke access at any time from your [dashboard](https://dashboard.wp-content.io). ## Programmatic Configuration Starting from version 1.1.2, the External Repositories plugin introduces new hooks that allow you to define repository sources and manage plugin visibility directly via code. This is useful for advanced setups or automated deployments. ### Adding repositories with code You can define one or more repositories using the `external_repositories` filter. Repositories added this way will not appear in the plugin’s admin interface, but will be active and used for updates. ```php theme={null} add_filter( 'external_repositories', function( $repositories ) { $repositories[] = [ 'name' => 'ACME', // Must be unique across all repositories 'api_key' => 'your-api-key', 'url' => 'https://registry.wp-content.io/', 'supports_themes' => true, 'supports_plugins' => true, ]; return $repositories; } ); ``` If `url`, `supports_themes`, or `supports_plugins` are not specified, the following defaults are applied: ```php theme={null} [ 'url' => 'https://registry.wp-content.io/', 'supports_themes' => true, 'supports_plugins' => true, ] ``` The name must be unique, even across repositories defined in the plugin settings UI. ### Hiding the plugin from the Plugins screen If you want to hide the plugin from the standard Plugins screen — for example, to avoid accidental deactivation — you can use the `hide_external_repositories_plugin` filter: ```php theme={null} add_filter( 'hide_external_repositories_plugin', '__return_true' ); ``` ### Recommended usage We recommend placing this configuration code inside a small MU plugin (`wp-content/mu-plugins/custom-repos.php`) to ensure it’s always loaded and easy to share across projects. # Plugin Setup Guide Source: https://docs.wp-content.io/guides/plugins How to prepare your plugin for private updates ## Prerequisites Before getting started, make sure you're familiar with how WordPress plugins work. This guide doesn't cover how to build a plugin from scratch, it focuses on adapting an existing one to work with wp-content.io. ## Plugin management To simplify the deployment of updates and make it as seamless as possible, the plugin’s release is based on the information provided in the plugin’s own file. You simply need to publish a zip file of your plugin (the folder name inside the zip should match the plugin’s slug). If the slug does not exist in your organization, the plugin will be created; otherwise, a new version will be created. When you publish an update, the version number need to be unique and greater than the latest version. ## File Header requirement This is the minimum header of your plugin file : ```php my-plugin/my-plugin.php theme={null} By default, only "Description" tab is shown and use the short plugin description (from main file header comment). If you want to customize tabs, you can add some files (in Markdown format) at your plugin root : | Filename | Corresponding tab | | ---------- | ----------------- | | README.md | Description | | INSTALL.md | Installation | | FAQ.md | FAQ | Example of zip structure : ``` my-plugin/ ├── my-plugin.php ├── FAQ.md ├── INSTALL.md └── README.md ``` ## Changelog tab The changelog is automatically generated from your plugin update history. You can manage your version (add release notes or delete a version) from your [dashboard](https://dashboard.wp-content.io). # Theme Setup Guide Source: https://docs.wp-content.io/guides/themes How to prepare your theme for private updates ## Prerequisites Before getting started, make sure you're familiar with how WordPress themes work. This guide doesn't cover how to build a theme from scratch, it focuses on adapting an existing one to work with wp-content.io. ## Theme management To simplify the deployment of updates and make it as seamless as possible, the theme’s release is based on the information provided in its stylesheet header. You simply need to publish a zip file of your theme (the folder name inside the zip should match the theme’s slug). If the slug does not exist in your organization, the theme will be created; otherwise, a new version will be created. When you publish an update, the version number needs to be unique and greater than the latest version. ## File Header requirement This is the minimum header of your `style.css` file: ```css my-theme/style.css theme={null} /* Theme Name: My Theme Version: 1.0.4 Author: Your company name Update URI: https://registry.wp-content.io */ ``` The name, version and author properties will be used to publish your theme data. The `Update URI` property is mandatory because it tells WordPress to check the wp-content.io registry instead of the official repository. ## Zip structure Here is an example of minimal theme structure: ``` my-theme/ ├── index.php └── style.css ``` ## Enhance your theme details view The following header shows the available customization options from the `style.css` file: ```css my-theme/style.css theme={null} /* Theme Name: My Theme Theme URI: Description: Fake theme Version: 1.0.4 Author: Happy Monkey Author URI: https://mkey.fr/ Requires at least: 6.4 Requires PHP: 8.1 Update URI: https://registry.wp-content.io */ ``` If you include a screenshot.png file in your theme, it will be used as the theme preview, but you can also customize it from the dashboard. ## Theme preview In the official WordPress repository, themes are usually presented with a live preview using a pre-installed demo site. We’ve made a different choice. Because we care deeply about the **security and confidentiality** of your code, wp-content.io does not deploy any of your files. All your archives stay securely hosted on the CDN, without being extracted or exposed. If you want to provide a live preview, you can define a **Preview URL** in the dashboard. If no URL is provided, users will instead see the changelog and version history of your theme. ## Child themes You can upload a child theme based on either: * a parent theme from the official WordPress repository, * a private theme managed by any organization (as long as the site is connected to your the organization account). When installing a child theme, the parent theme will be installed automatically if it’s not already present on the site. This allows you to safely distribute child themes without requiring any manual setup for the parent. ## Troubleshooting If you're having trouble uploading your theme, here are some common issues and how to resolve them: Make sure you're uploading a valid `.zip` file. Other formats like `.rar` or uncompressed folders are not supported. The maximum allowed file size is 512MB. If your archive is larger, consider optimizing your theme or reducing unused assets. Your ZIP file must contain a single folder named after your theme's slug. Inside that folder, there must be a `style.css` file that includes the required headers. ```text Example: theme={null} my-theme/ └── style.css ``` The theme slug may already exist on the official WordPress repository, be in use by another organization, or be restricted (e.g., for premium themes). Please choose a unique and authorized slug. Each plan has a limit on the number of themes. You can also manage your quota or upgrade your plan from your dashboard. If you're on the Agency plan, you can contact support to request additional slots. Make sure your `style.css` file includes the required headers: `Theme Name`, `Author`, `Version`, and `Update URI`. # Introduction Source: https://docs.wp-content.io/index Welcome to the official documentation Start now with [wp-content.io](https://wp-content.io/) and get the same smooth experience as the official WordPress repository, but for your private plugins and themes. No manual uploads, no repetitive code. Just a clean way to register external sources, deliver updates, and manage custom extensions and themes at scale. This guide will walk you through everything you need to get started, whether you’re building for a single site or maintaining dozens. Get an overview of the service. Check available plans. Use the command-line tool. Explore the API reference. # Quickstart Source: https://docs.wp-content.io/quickstart This quickstart guide will help you deploy your plugin or theme in just a few minutes. Recreate the official WordPress experience for your own plugins and themes with one-click installs and built-in updates, all without writing a single line of code. ## Ready in 3 simple steps There’s no library to install, no custom logic to write. All WordPress plugins and themes are compatible out of the box. Just follow these three simple steps to start deploying your code to any WordPress site cleanly, and without effort. If you haven’t already, [create an account](https://dashboard.wp-content.io/signup) and configure your first organization. You can start with a free plan, no credit card required. An organization is your workspace. From there, you can manage your private plugins and themes, browse all published versions, invite collaborators, configure API keys, and define which domains are allowed to receive updates. To enable updates from an external source, you need to add the Update URI header to your plugin or theme. For **plugins**, add it to the header of the main .php file: ```php my-plugin/my-plugin.php {6} theme={null} For **themes**, add it to the style.css file: ```css my-theme/style.css {5} theme={null} /* Theme Name: My Theme Author: Your Name Version: 1.0.0 Update URI: https://registry.wp-content.io */ ``` The Author, Version, and Update URI fields are required. Other headers like Description, Tags, or License are optional, but will be used to enrich the dashboard and update information. Once this is done, create a ZIP archive of your plugin or theme folder. You’ll upload it when creating your first release. To enable updates on your WordPress sites, install the External Repositories plugin. You can download it for free from [the official webpage](https://wp-content.io/external-repositories). Once installed and activated, you’ll be redirected to the plugin settings page. There, you can enter your API key to connect your site to your organization. When you create an organization, a readonly API key is automatically generated. You can use this key to allow update checks without exposing write access. ## You’re all set 🎉 Everything is ready, your site is now connected and can receive updates for your private plugins and themes. You’ll also find a new tab when adding a plugin or a theme from the WordPress admin. This view lets you browse the items linked to your account and install them in one click. When you publish a new version, it will appear directly in the WordPress admin, just like any plugin or theme from the official repository. ## Troubleshooting If you’re not familiar with WordPress headers or run into errors during upload, check the detailed setup guides: How to prepare your plugin for private updates How to prepare your theme for private updates