Docs / Read-Only Mode

Read-Only Mode

Freeze the site during a migration or deploy. Visitors keep reading; nothing written gets lost.

Hooks

Every default, limit and message has a filter, and every change fires an action.

axle_read_only_mode_default_durationFilter
( int $minutes )

Length when none is given: the admin bar quick freeze, wp axle-read-only-mode on and the PHP API. Also preselected on the screen. Default 60, 0 for no end

axle_read_only_mode_durationsFilter
( int[] $minutes )

Lengths offered on Tools > Read-Only Mode. Default 30, 60, 120, 240, 480 and 0

axle_read_only_mode_scopesFilter
( array $scopes )

The scopes a freeze can have. Each: label, status, description, covers (the areas it freezes, content and code). Keep all first

axle_read_only_mode_default_scopeFilter
( string $scope )

Scope when none is chosen: the admin bar quick freeze, WP-CLI, abilities, the PHP API. Also preselected on the screen. Default all

axle_read_only_mode_scopeFilter
( string $scope, array $state )

The scope of the freeze in force

axle_read_only_mode_request_areaFilter
( string $area, string $kind, string $subject, array $context )

Sort one request into content or code. $kind is admin, rest, ajax, ability, cron or front-end

axle_read_only_mode_code_screensFilter
( string[] $screens )

Admin files that change settings, plugins, themes, updates or accounts

axle_read_only_mode_code_routesFilter
( string[] $routes )

REST route prefixes that change settings, plugins, themes, templates or accounts

axle_read_only_mode_code_ajax_actionsFilter
( string[] $actions )

Ajax actions that install, change or update code and settings

axle_read_only_mode_code_ability_wordsFilter
( string[] $words )

Words in an ability name that mark it as settings or code

axle_read_only_mode_code_cron_hooksFilter
( string[] $hooks )

Scheduled events that check for updates or run site checks. Every other event counts as content

axle_read_only_mode_code_xmlrpc_methodsFilter
( string[] $methods )

XML-RPC methods a settings and code freeze removes

axle_read_only_mode_checksFilter
( array $checks, array $context )

The checks on the Before you freeze card: ID to callable. Add yours, or unset a built-in one: editing, scheduled_posts, orders, cron. A callable gets the context (start, end, until, minutes, scope, cron, visitors, now, user_id) and returns an item (tone, word, title, detail, rows, count) or null

axle_read_only_mode_check_itemsFilter
( array $items, array $context )

The items after every check ran

axle_read_only_mode_check_editorsFilter
( array $editors )

The people the card says are editing. Each: post_id, title, user_id, name, time

axle_read_only_mode_check_open_windowFilter
( int $seconds )

How far ahead the checks look when a freeze has no end time. Default one day

axle_read_only_mode_check_order_ageFilter
( int $seconds )

How recent an unpaid WooCommerce order must be to count as waiting for payment. Default two hours

axle_read_only_mode_extend_minutesFilter
( int[] $minutes )

The extend buttons. The first one is also the admin bar’s "Add 30 minutes". Default 30 and 60

axle_read_only_mode_is_frozenFilter
( bool $frozen, array $state )

Freeze or unfreeze from outside, such as one switch for every site. $frozen includes a network freeze. Add it from a must-use plugin. AXLE_READ_ONLY_MODE always wins

axle_read_only_mode_messageFilter
( string $message, array $state )

What logged-in users see

axle_read_only_mode_visitor_messageFilter
( string $message, array $state )

What visitors get when they send a form

axle_read_only_mode_user_can_bypassFilter
( bool $exempt, int $user_id )

Let a user keep working during a freeze

axle_read_only_mode_allowed_ajax_actionsFilter
( string[] $actions )

Admin-ajax actions that keep working: the read-only ones plus the ones on the allow-list. Add one, or take one off

axle_read_only_mode_allow_requestFilter
( bool $allow, string $where, string $source )

Let one wp-admin or front-end request through, such as a single sign-on callback. $allow is already true when the allow-list lets the request through, so code can return false to stop it

axle_read_only_mode_allow_rest_requestFilter
( bool $allow, WP_REST_Request $request )

Let one REST request through. Like the one above, it runs after the allow-list

axle_read_only_mode_read_only_routesFilter
( string[] $routes )

REST route prefixes that only read even when called with POST. Default /wp/v2/block-renderer/

axle_read_only_mode_writing_screensFilter
( string[] $screens )

Admin screens blocked even when only opened. Default post-new.php and upgrade.php

axle_read_only_mode_logged_visitorsFilter
( int $limit )

Anonymous blocked attempts logged per freeze. Default 10, 0 for none. Requests let through have their own limit

axle_read_only_mode_log_sizeFilter
( int $size )

Entries the log keeps, blocked and allowed. Default 100

axle_read_only_mode_history_sizeFilter
( int $size )

Past freezes the history keeps. Default 10

axle_read_only_mode_capabilityFilter
( string $capability )

Who may freeze and unfreeze. Default manage_options

axle_read_only_mode_logged_allowedFilter
( int $limit )

Requests let through that the log keeps per freeze. Default 25, 0 for none

axle_read_only_mode_allow_limitFilter
( int $limit )

Entries each part of the allow-list holds. Default 50

axle_read_only_mode_validate_allow_entryFilter
( string $error, string $type, string|int $value )

Runs after the built-in checks of an allow-list entry. Return a message to refuse it. $type is rest, paths, ajax or users

axle_read_only_mode_allow_suggestionsFilter
( array $suggestions )

The "Add" buttons on the Settings tab. Each: plugin, type, value, why. They are only suggestions: nothing is added without a click

axle_read_only_mode_notify_eventsFilter
( string[] $events, bool $network )

The events that send an email: started, ended, expired, extended, scheduled_start

axle_read_only_mode_notify_recipientsFilter
( string[] $recipients, string $event, array $freeze, bool $network )

Who gets the email. Default the addresses in the settings, or the admin email

axle_read_only_mode_notify_subjectFilter
( string $subject, string $event, array $freeze, bool $network )

The email subject

axle_read_only_mode_notify_bodyFilter
( string $body, string $event, array $freeze, bool $network, array $context )

The plain-text body. $context has minutes (extended), ended_by and blocked (ended)

axle_read_only_mode_notify_intervalFilter
( int $seconds, string $event )

Seconds before the same event can send another email. Default 60, never less

axle_read_only_mode_health_overdue_minutesFilter
( int $minutes )

Minutes a freeze can run past its end time before Site Health calls it critical. Default 30

axle_read_only_mode_health_open_ended_hoursFilter
( int $hours )

Hours a freeze with no end time can last before Site Health calls it critical. Default 6

axle_read_only_mode_health_resultFilter
( array $result, string $code )

The Site Health result. $code is off, frozen, overdue, open_ended or constant

axle_read_only_mode_health_infoFilter
( array $fields )

The fields of the Site Health > Info section

axle_read_only_mode_network_capabilityFilter
( string $capability )

Who may freeze and unfreeze the network. Default manage_network_options

axle_read_only_mode_network_log_sitesFilter
( int $limit )

Sites the network log reads, most recently active first. Default 100

axle_read_only_mode_network_site_picker_limitFilter
( int $limit )

Sites the "chosen sites" list shows. Default 200

axle_read_only_mode_startedAction
( array $state )

A freeze started or was scheduled. $state['area'] is its scope: all, content or code

axle_read_only_mode_endedAction
( array $state, string $ended_by )

A freeze ended: user, cli, ability or expired

axle_read_only_mode_extendedAction
( array $state, int $minutes )

A freeze got longer

axle_read_only_mode_blockedAction
( string $where, string $source, int $user_id, string $area )

Every blocked request, including the ones the log leaves out. $area is content or code. For an outside log or an alert channel

axle_read_only_mode_checkedAction
( array $result )

The Before you freeze checks ran, from the screen, WP-CLI or an ability. $result has items, editing, attention and context

axle_read_only_mode_scheduled_startedAction
( array $state )

A freeze that was set for later has started. Fires on the first request after its start time

axle_read_only_mode_allowedAction
( string $where, string $source, int $user_id, string $via, string $area )

Every request the allow-list (settings) or a filter (code) let through a freeze, including the ones the log leaves out

axle_read_only_mode_allow_list_savedAction
( array $allow, bool $network )

The allow-list was saved, from the screen, WP-CLI or a suggestion button

axle_read_only_mode_notify_settings_savedAction
( array $notify, bool $network )

The email settings were saved

axle_read_only_mode_notifiedAction
( string $event, string[] $recipients, string $subject, bool $sent, array $freeze, bool $network )

An email was handed to wp_mail()

axle_read_only_mode_network_startedAction
( array $state )

A network freeze started or was scheduled

axle_read_only_mode_network_scheduled_startedAction
( array $state )

A network freeze that was set for later has started

axle_read_only_mode_network_extendedAction
( array $state, int $minutes )

A network freeze got longer

axle_read_only_mode_network_endedAction
( array $state, string $ended_by )

A network freeze ended

WP-CLI

wp axle-read-only-mode check [--minutes=<n>] [--start=<datetime>] [--scope=<all|content|code>] [--no-cron] [--no-visitors] [--format=table|json]
wp axle-read-only-mode on [--minutes=<n>] [--reason=<text>] [--visitor-message=<text>] [--scope=<all|content|code>] [--no-visitors] [--no-cron] [--network] [--sites=<ids>]
wp axle-read-only-mode off [--network]
wp axle-read-only-mode extend <minutes> [--network]
wp axle-read-only-mode status [--network]
wp axle-read-only-mode log [--network] [--format=table|csv|json|count]
wp axle-read-only-mode allow <rest|path|ajax|user> <value> [--network]
wp axle-read-only-mode disallow <rest|path|ajax|user> <value> [--network]
wp axle-read-only-mode allowed [--network] [--format=table|csv|json|count]
wp axle-read-only-mode notify [--enable|--disable] [--to=<emails>] [--events=<list>] [--network]
wp axle-read-only-mode health [--format=table|json]

Abilities

What AI agents can do through the WordPress Abilities API and MCP, with the same permissions as the screen.

axle-read-only-mode/get-status

Read-only. Whether the site is frozen, until when and why, what holds it (source: site, network or constant), and its scope

Who can run it: edit_posts

axle-read-only-mode/check-freeze

Read-only. What a freeze would interrupt right now: people editing, scheduled posts and tasks due, orders waiting for payment. Input: minutes, start, scope, cron, visitors. Run it before freeze

Who can run it: the freeze capability

axle-read-only-mode/freeze

Freezes the site. Input: minutes, reason, visitor_message, visitors, cron, scope (all, content or code)

Who can run it: the freeze capability

axle-read-only-mode/extend

Adds minutes to the running freeze

Who can run it: the freeze capability

axle-read-only-mode/unfreeze

Ends the freeze now

Who can run it: the freeze capability

axle-read-only-mode/get-blocked

Read-only. What the freeze blocked, and the requests the allow-list let through (result), newest first. Input: limit

Who can run it: the freeze capability

axle-read-only-mode/get-allow-list

Read-only. The allow-list: REST routes, paths, ajax actions and user IDs

Who can run it: the freeze capability

Constants

Set these in wp-config.php.

AXLE_READ_ONLY_MODE

true freezes the site with no end time, before the database is even needed. Remove it to unfreeze

AXLE_READ_ONLY_MODE_REASON

The reason shown while AXLE_READ_ONLY_MODE is on

AXLE_READ_ONLY_MODE_SCOPE

all, content or code: the scope of a freeze that AXLE_READ_ONLY_MODE forces. Default all

The full reference, with the PHP API and examples, is in REFERENCE.md for version 3.1.0