fix: safe mode fatals with an undefined wp_get_current_user() - #484
Merged
imantsk merged 2 commits intoAug 31, 2026
Conversation
imantsk
force-pushed
the
fix/safe-mode-early-cap-check/core
branch
from
August 31, 2026 17:28
64d066c to
c87e537
Compare
Evaluate_Functions is constructed from Plugin::load_plugin(), which Core/load.php calls at include time. WordPress includes active plugins at wp-settings.php:574 but does not load pluggable.php until line 604, so wp_get_current_user() does not exist yet. The constructor called is_safe_mode_requested(), which checks a capability, so any request carrying the snippets-safe-mode query var died with: Call to undefined function wp_get_current_user() in wp-includes/capabilities.php:914 Only the empty() short-circuit on the query var kept this from firing on every request. Safe mode was unusable as a result, which matters because it is the recovery route offered when a snippet breaks a site. Split the check in two: the constructor now tests only for the query var, and the capability is checked inside the callback, which never runs before URLs are being generated. Behaviour is unchanged for a user without the capability, as the query var is still never added. Also loosen the parameter types on this file's two filter callbacks. Neither can trust its input, since an earlier callback in the chain may return anything, and a non-nullable scalar turns that into a TypeError. Reported for screen_settings by Sam on the support forum.
imantsk
force-pushed
the
fix/safe-mode-early-cap-check/core
branch
from
August 31, 2026 17:40
c87e537 to
4d7d60d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Safe mode is currently unusable. Any request carrying
?snippets-safe-mode=1dies with a fatal, on 3.10.0 and on released 3.10.1. Reported by hannab in this forum thread — they were told to use safe mode to recover, and hit this instead.The bug
Evaluate_Functionsis constructed fromPlugin::load_plugin(), whichCore/load.php:88calls at include time. The order inwp-settings.phpis:require pluggable.php—wp_get_current_user()defined hereplugins_loadedfiresSo the constructor runs 30 lines before the function it depends on exists. The only reason this is not fatal on every request is the
empty()short-circuit on the query var:Set the query var and the second operand is evaluated, and the request is over.
This matters more than a normal edge case: safe mode is what we tell people to use when a snippet has broken their site, so it fails exactly when it is needed.
The fix
Split the check in two. The constructor tests only for the query var, which reads nothing but the request and is safe at any point. The capability is checked inside the callback, which cannot run before URLs are being generated, long after pluggable functions are available.
Behaviour is unchanged for a user without the capability — the query var is still never added to URLs.
Also included
The two filter callbacks in this same file declared non-nullable scalar parameters:
Neither can trust its input, because an earlier callback in the chain may return anything, and on PHP 8 passing null to a non-nullable scalar is a TypeError regardless of
strict_types. This is the same defect Sam reported on the forum forscreen_settings, fixed in #481, and they suggested auditing the rest.disable_snippet_executionis hooked tocode_snippets/execute_snippets, a filter we publish for third parties, and a null there takes down the front end rather than one admin screen.One remains after this:
Snippet_Files::add_settings_fields( array $fields )oncode_snippets_settings_fields. Left out to keep this diff to a single file — happy to follow up.Testing
4 new tests in
Evaluate_Functions_Safe_Mode_Test. All 4 fail oncoretoday: two withCall to undefined method ...::is_safe_mode_query_var_set()and two with the exact TypeErrors above.Full suite: 161 tests, 0 failures.
phpcsclean.Verified end to end against released 3.10.1 on WP 7.1 / PHP 8.5:
/?snippets-safe-mode=1</html>//wp-admin/(Worth noting when testing by hand: opcache will happily serve the old bytecode after you swap the file in, which cost me a confusing minute.)