onstage2426/wp-plugin-updater
最新稳定版本:v0.1.8
Composer 安装命令:
composer require onstage2426/wp-plugin-updater
包简介
README 文档
README
Delivers WordPress plugin and theme updates from a private GitHub repository. Hooks into the standard WordPress update system so your plugin or theme appears in the Updates screen and can be installed with a single click.
Requirements
- PHP 8.3+
- WordPress 6.6+
- Plugin or theme hosted on GitHub (public or private)
Installation
composer require onstage2426/wp-updater
Quick start
Plugin:
use Onstage2426\WpUpdater\Plugin\PluginUpdater; $updater = PluginUpdater::build( 'https://github.com/your-org/your-repo', __FILE__ );
Theme:
use Onstage2426\WpUpdater\Theme\ThemeUpdater; $updater = ThemeUpdater::build( 'https://github.com/your-org/your-theme', 'your-theme' // theme directory name / slug );
Call this at plugin/theme load time — at the top level of your main file, or in a very early action. The updater registers all its WP hooks internally.
PluginUpdater::build() — factory method
PluginUpdater::build(
string $repositoryUrl,
string $pluginFile,
string $slug = "",
int $checkPeriod = 12,
string $optionName = "",
): static
| Parameter | Type | Default | Description |
|---|---|---|---|
$repositoryUrl |
string |
— | Full GitHub URL, e.g. https://github.com/owner/repo |
$pluginFile |
string |
— | Absolute path to the plugin's main PHP file. Pass __FILE__ from your plugin's main file |
$slug |
string |
"" |
Unique identifier. Defaults to the filename without .php. Must be unique across all active updater instances |
$checkPeriod |
int |
12 |
How often to check for updates, in hours. Set to 0 to disable automatic checks entirely |
$optionName |
string |
"" |
WP site option name used to persist check state. Defaults to external_updates-{slug} |
ThemeUpdater::build() — factory method
ThemeUpdater::build(
string $repositoryUrl,
string $themeSlug,
int $checkPeriod = 12,
string $optionName = "",
): static
| Parameter | Type | Default | Description |
|---|---|---|---|
$repositoryUrl |
string |
— | Full GitHub URL |
$themeSlug |
string |
— | Theme directory name, e.g. my-theme. This is also used as the update checker slug |
$checkPeriod |
int |
12 |
How often to check for updates, in hours |
$optionName |
string |
"" |
WP site option name used to persist check state |
Public properties
Shared (both PluginUpdater and ThemeUpdater):
| Property | Type | Description |
|---|---|---|
$updater->slug |
string |
Unique slug for this updater instance |
$updater->updateState |
UpdateState |
Persisted check state. See UpdateState |
Plugin-only (PluginUpdater):
| Property | Type | Description |
|---|---|---|
$updater->pluginFile |
string |
Plugin basename as returned by plugin_basename(), e.g. my-plugin/my-plugin.php |
$updater->directoryName |
string |
Plugin directory name, e.g. my-plugin |
$updater->muPluginFile |
string |
MU-plugin filename; empty string for regular plugins |
Theme-only (ThemeUpdater):
| Property | Type | Description |
|---|---|---|
$updater->directoryName |
string |
Theme directory name (same as slug) |
Configuration methods
All methods are defined on the shared base class and return static for chaining. They apply to both PluginUpdater and ThemeUpdater unless noted otherwise.
setMuPluginFile(string $muPluginFile): static (plugin only)
Only needed for MU-plugins. Sets the relative filename of the MU-plugin as it appears in wp-content/mu-plugins/. See MU-plugins.
$updater->setMuPluginFile('my-mu-plugin.php');
setBranch(string $branch): static
Sets which branch to use as the update source. Default is "master".
When the branch is "master" or "main", the updater tries strategies in order:
- Latest GitHub release
- Latest version tag
- Branch HEAD
For any other branch name, only the branch HEAD is used. The branch strategy carries no version number (null), so the update checker cannot determine a newer version from the branch alone. Use releases or tags on master/main for version-based updates.
$updater->setBranch('main');
setAccessToken(string $token): static
Sets the GitHub personal access token used to authenticate API requests and ZIP downloads. Required for private repositories.
$updater->setAccessToken('ghp_xxxx');
The token is injected as an Authorization: token … header on every GitHub API call and on the ZIP download request WordPress makes during upgrade. It is held in memory only — never written to any WordPress option or transient.
Public repositories work without a token and are unaffected when this method is not called.
To generate a token: GitHub → Settings → Developer settings → Personal access tokens. For a private repository the token needs at minimum the repo scope (classic token) or Contents: Read permission (fine-grained token).
setReleaseFilter(callable $callback, int $releaseTypes, int $maxReleases): static
Applies a custom filter when picking the latest release. The updater fetches up to $maxReleases releases and calls $callback for each one to decide whether to use it.
setReleaseFilter(
callable $callback,
int $releaseTypes = PluginUpdater::RELEASE_FILTER_SKIP_PRERELEASE,
int $maxReleases = 20,
): static
| Parameter | Type | Default | Description |
|---|---|---|---|
$callback |
callable |
— | Called as fn(string $version, object $release): bool. Return true to accept the release, false to skip it. $release is the raw GitHub API release object |
$releaseTypes |
int |
RELEASE_FILTER_SKIP_PRERELEASE |
::RELEASE_FILTER_ALL to include pre-releases, ::RELEASE_FILTER_SKIP_PRERELEASE to exclude them |
$maxReleases |
int |
20 |
How many recent releases to fetch and examine. Min 1, max 100 |
// Accept only releases whose version contains "-stable" $updater->setReleaseFilter( fn(string $version) => str_contains($version, '-stable'), PluginUpdater::RELEASE_FILTER_ALL, 50 );
Constants (available on both PluginUpdater and ThemeUpdater):
| Constant | Value | Description |
|---|---|---|
::RELEASE_FILTER_ALL |
3 |
Examine both stable releases and pre-releases |
::RELEASE_FILTER_SKIP_PRERELEASE |
1 |
Skip releases marked as pre-release on GitHub |
setReleaseVersionFilter(string $regex, int $releaseTypes, int $maxReleasesToExamine): static
Convenience wrapper around setReleaseFilter() for filtering by version number using a regular expression.
// Only pick up releases whose version starts with "2." $updater->setReleaseVersionFilter('/^2\./'); // Include pre-releases, look back up to 30 releases $updater->setReleaseVersionFilter('/^2\./', PluginUpdater::RELEASE_FILTER_ALL, 30);
setAssetFilter(string $pattern): static
When a release has multiple assets, selects the first asset whose name contains $pattern as a substring. Falls back to the first asset when no match is found. Without this call the first asset is always used.
// Pick the production ZIP, not the debug build $updater->setAssetFilter('my-plugin-');
throttleRedundantChecks(bool $enable, int $hours): static
When enabled, the updater skips scheduled checks if an update is already sitting in the queue waiting to be installed. This avoids hammering the GitHub API when nothing has changed.
$updater->throttleRedundantChecks(); // enable with default 72 hours $updater->throttleRedundantChecks(hours: 48); // enable with custom period $updater->throttleRedundantChecks(false); // disable
setCooldown(int $hours = 24): static
Sets how many hours must pass after a release is published before the update is surfaced to WordPress. Defaults to 24. Set to 0 to disable.
This creates a window to catch and yank a bad release before it reaches any site — useful protection against supply-chain compromises, broken builds, or accidental publishes.
$updater->setCooldown(); // 24-hour cooldown (default) $updater->setCooldown(48); // 48-hour cooldown $updater->setCooldown(0); // disabled — surface updates immediately
The cooldown is based on the release's created_at timestamp from GitHub. It has no effect on branch-based update sources (those carry no release timestamp).
enableAutoUpdates(bool $enable): static
Opts this plugin or theme into WordPress automatic background updates by writing to the same site option the admin UI toggle uses (auto_update_plugins / auto_update_themes). The toggle on the Plugins or Themes screen immediately reflects the change.
$updater->enableAutoUpdates(); // enable $updater->enableAutoUpdates(false); // disable
The admin can still override this at any time using the toggle in the WordPress UI — calling this method does not lock the preference or fight the admin's choice.
enableDebugMode(bool $enable): static
Controls whether errors and warnings are sent to the PHP error log. Defaults to the value of the WP_DEBUG constant.
$updater->enableDebugMode(); // enable $updater->enableDebugMode(false); // disable
setMaxRetries(int $maxRetries, int $initialDelayMs): static
Controls how many times a failed GitHub API request is retried before giving up.
setMaxRetries(
int $maxRetries = 2,
int $initialDelayMs = 500,
): static
| Parameter | Type | Default | Description |
|---|---|---|---|
$maxRetries |
int |
2 |
Maximum number of extra attempts after the first request fails |
$initialDelayMs |
int |
500 |
Delay before the first retry, in milliseconds. Doubles with each subsequent retry (exponential backoff), capped at 5 seconds |
Retries apply only to transient failures: network errors (WP_Error) and server-side errors (500, 502, 503, 504). Rate-limit responses, auth failures, and 404s are not retried.
During interactive page loads (not WP-Cron), retries are automatically capped at 1 regardless of $maxRetries, to avoid stalling the page response.
$updater->setMaxRetries(3, 250); // up to 3 retries, starting at 250 ms $updater->setMaxRetries(0); // disable retries entirely
removeHooks(): void
Removes all WordPress hooks registered by this updater instance. Called automatically on plugin uninstall. Call manually if you need to tear down the updater at runtime.
$updater->removeHooks();
Reading state
checkForUpdates(): ?Update
Forces an immediate update check against the GitHub API, regardless of the normal schedule. Updates updateState with the result. Returns an Update object if a newer version is available, null otherwise.
$update = $updater->checkForUpdates(); if ($update) { error_log("New version available: " . $update->version); }
getUpdate(): ?Update
Reads the last known update from updateState without making any API calls. Returns an Update object only if the stored version is newer than what is currently installed. Returns null if up to date or if no check has been run yet.
$update = $updater->getUpdate();
getLastRequestApiErrors(): array
Returns API errors collected during the most recent checkForUpdates() call. Each entry is an associative array with keys error (WP_Error), httpResponse (raw WP HTTP response or null), and url (string|null).
$updater->checkForUpdates(); foreach ($updater->getLastRequestApiErrors() as $item) { $wpError = $item['error']; error_log($wpError->get_error_message() . ' [' . $item['url'] . ']'); }
getStatus(): array
Returns a flat associative array of the current update state, suitable for display. Does not make any API calls.
$status = $updater->getStatus(); // [ // 'slug' => 'my-plugin', // 'type' => 'plugin', // 'installed_version' => '1.3.0', // 'last_check' => '2026-06-09 10:34:21 UTC', // 'available_version' => '1.4.2', // 'update_available' => 'yes', // 'cooldown_active' => 'no', // ]
available_version reflects the raw stored version (ignoring cooldown). update_available is 'yes' only when the update would actually be surfaced to WordPress (cooldown has passed). cooldown_active is 'yes' when an update exists in state but is currently suppressed by the cooldown window.
getEntityTitle(): string
Returns the entity's human-readable display name — from the plugin file header for plugins, from wp_get_theme() for themes. Returns an empty string if the header cannot be read.
echo $updater->getEntityTitle(); // e.g. "My Plugin" or "My Theme"
getUniqueName(string $baseTag): string
Generates a scoped hook name: pu_{baseTag}-{slug}. Used to namespace all filters and actions to this specific instance.
$filterName = $updater->getUniqueName('request_info_result'); // returns e.g. "pu_request_info_result-my-plugin"
triggerError(string $message, int $errorType): void
Fires trigger_error() if debug mode is active. Use E_USER_WARNING or E_USER_ERROR as $errorType.
$updater->triggerError('Something went wrong.', E_USER_WARNING);
WordPress filters
All filter tags are scoped with $updater->getUniqueName('tag') → pu_{tag}-{slug}.
pu_request_info_result-{slug}
Fired after the GitHub API is called to build the info shown in the "View details" popup. Receives the populated info object (PluginInfo or ThemeInfo, or null on failure). Return a modified info object or null to suppress the popup.
use Onstage2426\WpUpdater\Plugin\PluginInfo; add_filter($updater->getUniqueName('request_info_result'), function (?PluginInfo $info): ?PluginInfo { if ($info) { $info->sections['changelog'] = '<p>See GitHub releases for changelog.</p>'; } return $info; });
pu_request_update_result-{slug}
Fired after the GitHub API is called during a scheduled or manual check, before the result is written to state. Receives the Update object (or null). Return a modified Update or null to suppress the update.
add_filter($updater->getUniqueName('request_update_result'), function (?Update $update): ?Update { return $update; });
pu_pre_inject_info-{slug}
Fired just before entity info is returned to WordPress for the popup. Last chance to modify or suppress the info.
pu_pre_inject_update-{slug}
Fired just before an update is written into the update transient. Last chance to modify the Update object before WordPress sees it.
add_filter($updater->getUniqueName('pre_inject_update'), function (Update $update): Update { // e.g. override the download URL $update->download_url = 'https://example.com/my-plugin.zip'; return $update; });
pu_check_now-{slug}
Controls whether the scheduler should run a check right now. Receives bool $shouldCheck, the timestamp of the last check as int, and the configured check period in hours as int.
add_filter($updater->getUniqueName('check_now'), function (bool $should, int $lastCheck, int $period): bool { return (time() - $lastCheck) > DAY_IN_SECONDS; }, 10, 3);
pu_first_check_time-{slug}
Controls the timestamp of the first scheduled cron event. Defaults to a random offset within the first checkPeriod window to spread load across installations.
add_filter($updater->getUniqueName('first_check_time'), function (int $timestamp): int { return time(); // check immediately on the next cron run });
pu_vcs_update_detection_strategies-{slug}
Lets you reorder, replace, or extend the array of detection strategies passed to GitHubClient::chooseReference().
use Onstage2426\WpUpdater\GitHubClient; add_filter($updater->getUniqueName('vcs_update_detection_strategies'), function (array $strategies): array { // Remove the tag strategy, only use releases unset($strategies[GitHubClient::STRATEGY_LATEST_TAG]); return $strategies; });
Available strategy keys: GitHubClient::STRATEGY_LATEST_RELEASE, GitHubClient::STRATEGY_LATEST_TAG, GitHubClient::STRATEGY_BRANCH.
pu_remove_from_default_update_checks-{slug}
By default this entity is excluded from the WP.org update payload (it has no WP.org entry). Return false to include it in the payload anyway.
add_filter($updater->getUniqueName('remove_from_default_update_checks'), '__return_false');
Tip (plugins only): If your plugin header includes
Update URI: https://github.com/your-org/your-repo, WordPress 5.8+ natively excludes it from the WP.org check and the library skips registering the exclusion filter entirely. No additional code is required — just adding the header is enough.
pu_retain_fields-{slug}
Controls which fields are copied from the info object into an Update during checkForUpdates(). This filter fires only during update detection — not when stored state is reloaded on the next page.
add_filter('pu_retain_fields-my-plugin', function (array $fields): array { $fields[] = 'my_custom_field'; return $fields; });
The custom field must also exist as a public property on Update or it will be silently skipped.
pu_api_error (action)
Fired whenever the GitHub API returns an error (network failure, rate limit, or non-200 response). Receives WP_Error $error, the raw HTTP response, the request URL, and the entity slug.
Notable error codes:
| Code | Meaning |
|---|---|
pu-github-http-error |
Non-200 response that is not a rate limit |
pu-github-rate-limited |
429 or 403 with x-ratelimit-remaining: 0. The WP_Error data array includes reset_time (Unix timestamp or null). Follow-on requests are automatically blocked until the reset time |
pu-no-update-source |
All detection strategies returned null |
pu-no-plugin-version |
Source found but carried no version number |
add_action('pu_api_error', function (WP_Error $error, mixed $response, ?string $url, ?string $slug): void { if ($slug === 'my-plugin') { error_log('[my-plugin updater] ' . $error->get_error_message()); } }, 10, 4);
Data classes
Update
The minimal record written to the update transient.
| Property | Type | Source |
|---|---|---|
$slug |
?string |
Entity slug |
$version |
?string |
Version string from the GitHub release/tag, e.g. "1.4.2" |
$download_url |
?string |
ZIP download URL |
$homepage |
?string |
URI from the plugin/theme header |
$icons |
array |
Icon URLs loaded from the local assets/ directory (plugins only) |
$filename |
?string |
Plugin basename, set at injection time (plugins only) |
$last_updated |
?string |
Release created_at timestamp from GitHub; null for branch-based sources |
PluginInfo
The full metadata object shown in the "View details" popup for plugins.
| Property | Type | Source |
|---|---|---|
$name |
?string |
Plugin Name header |
$slug |
?string |
Plugin slug |
$version |
?string |
Version from GitHub release/tag |
$homepage |
?string |
Plugin URI header |
$sections |
array |
Keyed sections shown in the popup. description from plugin header; changelog from GitHub release body or local changelog file |
$download_url |
?string |
ZIP download URL |
$banners |
mixed |
Banner images loaded from the local assets/ directory |
$icons |
array |
Icon images loaded from the local assets/ directory |
$author |
?string |
Author header |
$author_homepage |
?string |
Author URI header |
$downloaded |
?int |
Download count from the selected GitHub release asset |
$last_updated |
?string |
Release creation timestamp (created_at from GitHub) |
$filename |
?string |
Plugin basename |
ThemeInfo
The full metadata object shown in the theme info popup.
| Property | Type | Source |
|---|---|---|
$name |
?string |
Theme Name header |
$slug |
?string |
Theme slug |
$version |
?string |
Version from GitHub release/tag |
$homepage |
?string |
Theme URI header |
$sections |
array |
Keyed sections shown in the popup. description from theme header; changelog from GitHub release body or local changelog file |
$download_url |
?string |
ZIP download URL |
$screenshot_url |
?string |
Screenshot URL from wp_get_theme()->get_screenshot() |
$author |
?string |
Author header |
$author_homepage |
?string |
Author URI header |
$downloaded |
?int |
Download count from the selected GitHub release asset |
$last_updated |
?string |
Release creation timestamp (created_at from GitHub) |
UpdateState
Persists the update check state to a WP site option. Accessible as $updater->updateState.
| Method | Returns | Description |
|---|---|---|
getUpdate() |
?Update |
The last stored update record, or null |
getLastCheck() |
int |
Unix timestamp of the last check, or 0 if never checked |
timeSinceLastCheck() |
int |
Seconds since the last check |
reset() |
void |
Zeroes all state fields (last-check timestamp, checked version, stored update) and persists the result |
Reliability features
The following behaviours are active out of the box with no configuration required.
Concurrent check lock — if two requests (e.g. a cron job and an admin page load) try to run checkForUpdates() at the same time, one of them acquires a short-lived lock and performs the API call while the other immediately returns the last-known stored update. The lock expires automatically after 60 seconds, so a crashed process can never block future checks indefinitely.
Transient-failure retries — failed API requests (network errors, 500/502/503/504) are automatically retried with exponential backoff. See setMaxRetries() to change the defaults.
Automatic rollback on upgrade failure — before each upgrade starts, the updater captures the download URL of the currently-installed version and passes it to the WordPress upgrader as rollback data. If the upgrade fails partway through, WordPress uses that URL to restore the previous version automatically.
ETag cache integrity — the ETag cache (used to avoid redownloading unchanged API responses) is validated every time it is loaded from the database and again before each request. Corrupt or partially-written entries are discarded automatically.
Local assets (plugins only)
Place assets in an assets/ subdirectory inside your plugin directory. The updater loads them automatically for the update popup.
Icons (shown on the Plugins screen and in the popup):
| Filename | Size slot |
|---|---|
assets/icon.svg |
SVG (preferred) |
assets/icon-256x256.png or .jpg |
2× |
assets/icon-128x128.png or .jpg |
1× |
Banners (shown at the top of the "View details" popup):
| Filename | Size slot |
|---|---|
assets/banner-772x250.png or .jpg |
Standard |
assets/banner-1544x500.png or .jpg |
High-DPI |
Themes use the screenshot file already present in the theme directory — no assets/ directory is needed.
Distribution — Composer, assets, and built files
The updater downloads whichever ZIP GitHub provides for a release. How you handle dependencies and build artifacts depends on your workflow.
Option A — Commit built files (simple): run composer install --no-dev and commit the vendor/ directory, commit compiled CSS/JS, and never commit node_modules/. The source ZIP GitHub generates will include everything.
Option B — GitHub Actions release pipeline (recommended): keep vendor/, node_modules/, and build output out of git. On each tag push, a workflow installs dependencies, runs the build, stamps the version header, creates a clean ZIP, and uploads it as a release asset. The updater automatically prefers the first release asset over GitHub's source ZIP when one is present.
Why the workflow must create the release as a draft first
When a GitHub release is published, the release asset (your ZIP) is uploaded by the workflow job after the release becomes publicly visible. During that gap — typically around two minutes — the updater falls back to GitHub's auto-generated source ZIP, which does not contain vendor/ or any built output. Any site that updates during this window will get a broken install.
The fix is to publish the release as a draft, upload the asset, then remove the draft flag in a final step. GitHub's /releases/latest endpoint only returns non-draft releases, so the updater cannot see the release until the asset is fully attached.
Version stamping
The tag name is used as the authoritative version. The workflow stamps the Version: header in your main PHP file from the tag before zipping, so the installed plugin's header always matches the GitHub release version.
Complete workflow (.github/workflows/release.yml)
Push a tag (git tag v1.2.0 && git push --tags) to trigger it.
on: push: tags: ["v*"] jobs: release: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v6 - name: Stamp version from tag run: | sed -i "s/^ \* Version:.*/ * Version: ${GITHUB_REF_NAME#v}/" your-plugin.php - uses: shivammathur/setup-php@v2 with: php-version: "8.3" - run: composer install --no-dev --optimize-autoloader # Remove the next two steps if you have no JS build - uses: actions/setup-node@v4 with: node-version: "20" - run: npm ci && npm run build - name: Create plugin ZIP run: | zip -r your-plugin.zip . \ --exclude=".git/*" --exclude=".github/*" \ --exclude="node_modules/*" --exclude="*.config.js" \ --exclude="package*.json" - name: Create draft release with asset run: | gh release create "$GITHUB_REF_NAME" your-plugin.zip \ --draft \ --generate-notes \ --title "$GITHUB_REF_NAME" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Publish release run: gh release edit "$GITHUB_REF_NAME" --draft=false env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Replace your-plugin.php and your-plugin.zip with your actual filenames.
If your plugin or theme is PHP-only with no Composer dependencies and no JS build, the source ZIP is fine and no workflow is required.
Changelog
If the GitHub release has a body, it is used as the changelog in the popup. If not, the updater looks for a changelog file in the plugin/theme directory:
CHANGELOG.mdCHANGES.mdchangelog.mdchanges.md
If Parsedown is installed, Markdown is rendered to HTML. Otherwise the raw text is shown.
MU-plugins
MU-plugins that live directly in wp-content/mu-plugins/ (not in a subdirectory) must call setMuPluginFile() so WordPress can match the plugin correctly:
$updater = PluginUpdater::build( 'https://github.com/your-org/your-repo', __FILE__, )->setMuPluginFile('my-mu-plugin.php');
MU-plugins installed in a subdirectory (e.g. mu-plugins/my-plugin/my-plugin.php) are detected automatically — no call needed.
Debugging
$updater->enableDebugMode();
This sends warnings to error_log() when the plugin/theme file cannot be read, the version header is missing, or the API returns no usable version.
You can also inspect errors from the last check directly:
$update = $updater->checkForUpdates(); foreach ($updater->getLastRequestApiErrors() as $item) { error_log($item['error']->get_error_message() . ' — ' . $item['url']); }
WP-CLI
When WP-CLI is active, the updater automatically registers a command group for each configured updater instance. No extra setup is required — calling build() is sufficient.
Command namespace: wp pu <slug>
wp pu <slug> check
Triggers an immediate update check against the GitHub API and prints the result. API warnings (rate limits, network errors) are printed before the final status line.
$ wp pu my-plugin check
Checking for updates...
Success: Update available: 1.4.2
wp pu <slug> status
Displays the current update state without making any API calls — equivalent to reading getStatus() from PHP.
$ wp pu my-plugin status
slug: my-plugin
type: plugin
installed version: 1.3.0
last check: 2026-06-09 10:34:21 UTC
available version: 1.4.2
update available: yes
cooldown active: no
wp pu <slug> clear
Resets the stored state — clears the last-check timestamp and any stored update record. Useful when testing, or after a manual install that bypassed the update system.
$ wp pu my-plugin clear
Success: Update state cleared.
wp pu <slug> enable-auto-updates / disable-auto-updates
Opts the entity in or out of WordPress automatic background updates. Equivalent to the toggle in the Plugins or Themes screen.
$ wp pu my-plugin enable-auto-updates
Success: Automatic updates enabled.
$ wp pu my-plugin disable-auto-updates
Success: Automatic updates disabled.
To actually install a pending update, use the standard WP-CLI command after check confirms one is available:
$ wp plugin update my-plugin # or: wp theme update my-theme
Full example
use Onstage2426\WpUpdater\Plugin\PluginUpdater; use Onstage2426\WpUpdater\Plugin\PluginInfo; $updater = PluginUpdater::build( 'https://github.com/acme/my-plugin', __FILE__, 'my-plugin', 24 // check every 24 hours ); // Only ship stable 2.x releases $updater ->setReleaseVersionFilter('/^2\./') ->throttleRedundantChecks(hours: 72) ->enableDebugMode(); // Append a note to the changelog in the popup add_filter($updater->getUniqueName('request_info_result'), function (?PluginInfo $info): ?PluginInfo { if ($info && !empty($info->sections['changelog'])) { $info->sections['changelog'] .= '<p><a href="https://github.com/acme/my-plugin/releases">Full release history on GitHub</a></p>'; } return $info; });
统计信息
- 总下载量: 28
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 1
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-06