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
No hook matches that. Try a shorter word.
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-statusRead-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-freezeRead-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/freezeFreezes 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/extendAdds minutes to the running freeze
Who can run it: the freeze capability
axle-read-only-mode/unfreezeEnds the freeze now
Who can run it: the freeze capability
axle-read-only-mode/get-blockedRead-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-listRead-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_MODEtrue freezes the site with no end time, before the database is even needed. Remove it to unfreeze
AXLE_READ_ONLY_MODE_REASONThe reason shown while AXLE_READ_ONLY_MODE is on
AXLE_READ_ONLY_MODE_SCOPEall, 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