3.1 The automatic updater model
WP_Automatic_Updater applies updates on a schedule without interactive credentials. You hook its decisions and outcomes separately from manual upgrader use.
How it works
During cron, wp_version_check() may call do_action( 'wp_maybe_auto_update' ) when not already inside that action. wp_maybe_auto_update() loads admin includes, instantiates WP_Automatic_Updater, and calls run(). The class uses Automatic_Upgrader_Skin, evaluates is_disabled() and per-item should_update(), selects packages from transients, and runs upgraders.
Inside run(), after acquiring the auto_updater lock, core processes updates in a fixed order: plugins (from update_plugins after wp_update_plugins()), then themes (update_themes after wp_update_themes()), then core (wp_version_check() plus find_core_auto_update()), then translation packs from wp_get_translation_updates().
The automatic_updates_complete hook fires at the end of a batch only when $update_results is non-empty. If nothing ran or nothing recorded results, the hook does not fire. See §4.7 for emails and that hook.
Process flow
- Cron or an external trigger runs
wp-cron.php. - Update checks may chain to
wp_maybe_auto_update. run()checksis_disabled(). If that check passes, the updater walks the plugin, theme, core, and translation sequence.- Each item downloads and installs through the same upgrader stack as manual flows, with a non-interactive skin.
- When results exist, completion fires notification paths and
automatic_updates_complete(Part 4).
Reference
| Class | File | Extends | Role |
|---|---|---|---|
WP_Automatic_Updater | class-wp-automatic-updater.php | — | Background decisions and execution; run() order: plugins, themes, core, translations |
Developer resources
WP_Automatic_Updaterclass reference — class reference.
3.2 Global disable conditions (is_disabled())
The automatic updater short-circuits when the site cannot or must not modify files, or when you explicitly disable it.
How it works
WP_Automatic_Updater::is_disabled() returns true when wp_is_file_mod_allowed( 'automatic_updater' ) is false (for example when DISALLOW_FILE_MODS is true unless filtered), when wp_installing() is true, or when AUTOMATIC_UPDATER_DISABLED is true or the automatic_updater_disabled filter returns true. Disabling the automatic updater also suppresses its notification emails in current core behavior.
Process flow
run()callsis_disabled().- If the method returns true, no automatic updates execute.
- Entry points that depend on background updates should surface this state in diagnostics.
Note:
should_update()also callsis_disabled()first on every item, so a global disable applies when evaluating offers insidefind_core_auto_update()and elsewhere — not only at the start ofrun().
Reference
| Condition | Effect |
|---|---|
wp_is_file_mod_allowed( 'automatic_updater' ) returns false | Updates blocked |
wp_installing() returns true | Updates blocked |
AUTOMATIC_UPDATER_DISABLED is true or automatic_updater_disabled returns true | Updates blocked |
Developer resources
automatic_updater_disabledfilter reference — filter to disable automatic updates.
3.3 Per-item eligibility (should_update())
Each candidate item passes through should_update( $type, $item, $context ), which merges filesystem reality, VCS detection, API flags, opt-ins, filters, and compatibility checks.
How it works
should_update() begins by calling is_disabled() again. If the automatic updater is globally disabled, the method returns false before any per-item logic, so find_core_auto_update() and other callers also respect the global disable.
The remaining checks combine: non-interactive filesystem access (background cannot show FTP forms); VCS checkout detection (see §3.4); per-type allow rules (Core_Upgrader::should_update_to_version() for core, or autoupdate plus auto_update_plugins and auto_update_themes for plugins and themes, or autoupdate for translations); disable_autoupdate on the offer (see §1.4); apply_filters( "auto_update_{$type}", … ); then for core, PHP and MySQL checks against the offer; for plugins and themes, requires_php if set.
For core, the PHP and MySQL compatibility checks run after disable_autoupdate and auto_update_core, not at the start (see §3.7).
Process flow
should_update()callsis_disabled(). If true, the method returns false immediately.- Core checks whether the filesystem supports non-interactive writes.
- VCS checkout detection runs for the relevant path.
- Type-specific allow rules evaluate: branch policy for core, or
autoupdateplus opt-in arrays for plugins and themes. - The
disable_autoupdateproperty may force the result to false. - The
auto_update_{$type}filter runs. - For core: PHP and MySQL compatibility checks evaluate against the offer. For plugins and themes:
requires_phpevaluates against runtime PHP. - A false result at any step aborts that item. A true result proceeds to download and install.
- The
pre_auto_updateaction fires once per item before the attempt (see §6.5).
Reference
| Check | Typical outcome if failed |
|---|---|
is_disabled() | Global disable; returns false (short-circuit) |
| Filesystem | No silent write capability; returns false |
| VCS | Checkout detected; returns false (unless filtered) |
Type allow (branch policy, autoupdate, or opt-in lists) | Returns false |
disable_autoupdate | Forces false before auto_update_{$type}; filter may re-enable |
auto_update_{$type} | Filter returns false; returns false (core may still trigger notification email) |
PHP or MySQL (core) or requires_php (plugin or theme) | Incompatible runtime; returns false |
Developer resources
WP_Automatic_Updater::should_update()reference — eligibility method.
3.4 VCS checkout detection
Automatic updates skip paths that look like version control working copies to avoid clobbering developer or deployment layouts.
How it works
WP_Automatic_Updater::is_vcs_checkout() walks upward from the package path and always checks ABSPATH for markers .svn, .git, .hg, or .bzr. A match disables auto-updates for that item without an admin notice. The filter automatic_updates_is_vcs_checkout receives ( bool $checkout, string $context ) and may return false to override the detection (for example on CI or managed hosts).
A Git clone of core or a plugin under wp-content can silently block automatic updates for that path.
Process flow
should_update()calls VCS detection for the relevant context.- If detection returns true, the item is skipped unless the filter clears the flag.
- Manual updates through the admin interface may still proceed with appropriate credentials.
Reference
| Hook | Type | Parameters | Notes |
|---|---|---|---|
automatic_updates_is_vcs_checkout | filter | $checkout, $context | Override VCS detection |
Developer resources
WP_Automatic_Updater::is_vcs_checkout()reference — detection helper.
3.5 PHP and MySQL compatibility guards
Offers may declare required PHP or database versions. Automatic updates refuse incompatible targets before an update attempt begins.
How it works
For core, should_update() compares the PHP version to $item->php_version and MySQL to $wpdb->db_version() unless a drop-in replaces MySQL. A mismatch returns false with no update attempt. For plugins and themes, if $item->requires_php is set and runtime PHP is lower, the result is false.
These checks run inside should_update() after filesystem and VCS guards, type-specific allow rules, disable_autoupdate, and auto_update_{$type} — not as the first gate (see §3.3 and §3.7).
Process flow
- Earlier guards may already return false.
- If the item is still eligible,
should_update()applies PHP and MySQL checks (core) orrequires_php(plugins and themes). - An incompatible runtime returns false before
update()runs.
Reference
| Type | Guard |
|---|---|
| Core | PHP and MySQL version comparison against the offer |
| Plugin or theme | requires_php comparison against runtime |
Developer resources
WP_Automatic_Updater::should_update()reference — documents guard behavior.
3.6 find_core_auto_update(): selecting the core offer
Only one core automatic offer runs per batch. find_core_auto_update() picks it from the update_core transient.
How it works
The function reads the update_core site transient, iterates the updates array, and skips any offer whose response is not autoupdate. For each remaining offer, it calls should_update( 'core', $update, ABSPATH ). It then picks the highest version among passing offers using version comparison on the current property, or returns false if none qualify.
A core auto-update never runs unless the offer exists with response === 'autoupdate' and should_update() passes. Manual-only entries in the interface do not flow through this selector.
Process flow
- Core loads the
update_coretransient. - Offers without
response === 'autoupdate'are dropped. - Each candidate passes through
should_update(). - The highest-passing version wins.
- If none qualify, the function returns false and no automatic core update runs this batch.
Reference
| Function | File | Returns | Notes |
|---|---|---|---|
find_core_auto_update() | wp-admin/includes/update.php | object or false | Selects the automatic core offer |
Developer resources
find_core_auto_update()reference — function reference.
3.7 Core branch policy and resolution order
Automatic core updates combine constant policy, site options, branch filters, offer vetoes, and the per-offer auto_update_core filter. The order below is the resolution chain you must reason about.
How it works
find_core_auto_update() considers only offers with response === 'autoupdate', then calls should_update( 'core', $update, ABSPATH ) for each candidate.
Core_Upgrader::should_update_to_version() applies the WP_AUTO_UPDATE_CORE constant when defined, or else the site options auto_update_core_dev, auto_update_core_minor, and auto_update_core_major. It also evaluates failure-history checks, branch logic, and the filters allow_dev_auto_core_updates, allow_minor_auto_core_updates, and allow_major_auto_core_updates depending on the branch. Each filter receives the boolean derived from constants and options.
The disable_autoupdate property on the offer can force the pending decision to false; filters may still re-enable the item. Then apply_filters( 'auto_update_core', $update, $item ) runs. PHP and MySQL compatibility checks on the offer follow.
Note:
apply_filters( 'wp_auto_update_core', … )is not invoked byCore_Upgraderin core as of inspected versions. Do not confuse this filter name with the site option or constant handling. Policy for which classes of core update are allowed lives inshould_update_to_version(). The dynamic hookauto_update_coreis the per-offer gate insideshould_update()after the initial allow or deny for that offer is computed.
Process flow
- Only offers with
response === 'autoupdate'are considered. Core_Upgrader::should_update_to_version()evaluates the constant,auto_update_core_*options, failure history, branch logic, andallow_*_auto_core_updatesfilters — yielding a boolean.disable_autoupdateon the offer can force false; filters may re-enable.apply_filters( 'auto_update_core', $update, $item )runs.- PHP and MySQL compatibility checks on the offer follow.
Reference
| Hook | Type | Parameters | Notes |
|---|---|---|---|
allow_dev_auto_core_updates | filter | bool | Development build installs |
allow_minor_auto_core_updates | filter | bool | Same x.y branch |
allow_major_auto_core_updates | filter | bool | x.y to x.y+1 |
auto_update_core | filter | bool, object | After the initial core decision for the offer |
Developer resources
auto_update_{$type}filter reference — includesauto_update_core.
3.8 Per-plugin and per-theme auto-update preferences
Site options list which plugins and themes have opted into automatic updates. These options merge with autoupdate flags on offers.
How it works
auto_update_plugins stores an array of plugin basenames. auto_update_themes stores opted-in theme identifiers. The AJAX action toggle-auto-updates persists these options without running the upgrader. should_update() merges them with the offer’s autoupdate flag when automatic updates are enabled for the type.
Multisite restricts who may change these toggles (see §5.11 and §5.4).
Process flow
- A user toggles the interface control, or a network policy change updates the options.
- The next
should_update()call reads the opt-in arrays. - An offer without
autoupdatestill requires opt-in for that item unless a filter changes the outcome.
Reference
| Name | Type | Default | Effect |
|---|---|---|---|
auto_update_plugins | site option (array) | empty | Plugin basenames opted into auto-updates |
auto_update_themes | site option (array) | empty | Theme identifiers opted into auto-updates |
Developer resources
- Controlling plugin and theme auto-updates UI in WordPress 5.5 — interface and storage.
3.9 Translation auto-updates and async chaining
Translations update automatically with their own filters and may install in a chained pass after another upgrade completes.
How it works
Two filters apply in different contexts.
async_update_translation runs inside Language_Pack_Upgrader::async_upgrade() only after a successful core, plugin, or theme upgrade in the same request. It governs whether to bulk-install translation packs in the follow-up pass; the default pending decision follows autoupdate on each language offer. Before installing, async_upgrade() returns without action if WP_Automatic_Updater::is_vcs_checkout( WP_CONTENT_DIR ) detects a VCS checkout under wp-content, matching the cautious behavior for that code path.
auto_update_translation participates in should_update() for cron-driven automatic translation updates, like other auto_update_{$type} hooks.
Changing one filter does not automatically change the other.
Process flow
- A primary upgrade completes.
- The
upgrader_process_completeaction fires. - At priority 20, async translation upgrade may run (unless VCS detection short-circuits it).
- Separately, cron-driven automatic updates evaluate translation items through
should_update(), including theauto_update_translationfilter.
Reference
| Hook | Type | Parameters | Notes |
|---|---|---|---|
async_update_translation | filter | bool | Post-upgrade chain in same request |
auto_update_translation | filter | bool | Background should_update() for translations |
Developer resources
async_update_translationfilter reference — post-upgrade chain.

