Skip to content

fix(domain-mapping): avoid get_option(blog_charset) in early bootstrap (#1164)#1165

Draft
superdav42 wants to merge 1 commit intomainfrom
fix/domain-mapping-early-wpsendjson
Draft

fix(domain-mapping): avoid get_option(blog_charset) in early bootstrap (#1164)#1165
superdav42 wants to merge 1 commit intomainfrom
fix/domain-mapping-early-wpsendjson

Conversation

@superdav42
Copy link
Copy Markdown
Collaborator

Summary

  • Fix MariaDB syntax error SELECT option_value FROM WHERE option_name = 'blog_charset' LIMIT 1 produced on every multisite request that hits Domain_Mapping::verify_dns_mapping() (pre_get_site_by_path / ms_site_not_found).
  • Replace the early-bootstrap wp_send_json() call (which calls get_option('blog_charset') before $wpdb->set_prefix() has run in wp-includes/ms-settings.php) with a direct header(); wp_json_encode(); exit; emit using a hard-coded charset=UTF-8.
  • Extract the emit step into a protected send_async_dns_response() method gated by a new wu_async_dns_response_short_circuit filter so plugins and tests can intercept without invoking exit.
  • Add a regression test that simulates the empty-$wpdb->options state and asserts no wpdb->last_error is produced.

Why

verify_dns_mapping() runs from inside ms_load_current_site_and_network() at wp-includes/ms-settings.php:77, before $wpdb->set_prefix( $table_prefix, false ) runs at line 102 of the same file. At that point $wpdb->options is the empty string. wp_send_json() (wp-includes/functions.php:4541) calls get_option('blog_charset') before sending the Content-Type header, which executes SELECT option_value FROM {$wpdb->options} … with an empty table name and produces the noisy SQL error reported in #1164.

The sibling DB call in the same path, Domain::get_by_domain() (inc/models/class-domain.php:704), already handles the early-bootstrap case by deriving the mapped-domains table name from $wpdb->base_prefix (set from wp-config.php before sunrise). wp_send_json() does not, so we bypass it for this single early-bootstrap response.

Verification

composer install
vendor/bin/phpcs inc/class-domain-mapping.php           # 0 errors, 0 warnings on touched code
vendor/bin/phpstan analyse inc/class-domain-mapping.php # OK
vendor/bin/phpunit --filter Domain_Mapping_Test         # OK (278 tests, 430 assertions)
vendor/bin/phpunit --filter test_verify_dns_mapping_does_not_query_options_table_in_early_bootstrap
# OK (1 test, 4 assertions) — fails on main, passes after fix

The two pre-existing PHPCS warnings on tests/WP_Ultimo/Domain_Mapping_Test.php (lines 530 and 878) are not introduced by this PR — they predate the change on origin/main and are out of scope.

Files

  • inc/class-domain-mapping.phpverify_dns_mapping() no longer calls wp_send_json; new send_async_dns_response() + wu_async_dns_response_short_circuit filter.
  • tests/WP_Ultimo/Domain_Mapping_Test.phptest_verify_dns_mapping_does_not_query_options_table_in_early_bootstrap regression test.

Resolves #1164


aidevops.sh v3.15.12 plugin for OpenCode v1.14.41 with claude-opus-4-7 spent 9m and 32,649 tokens on this with the user in an interactive session.

#1164)

`Domain_Mapping::verify_dns_mapping()` is hooked on `pre_get_site_by_path`
and `ms_site_not_found`, both of which fire from inside
`ms_load_current_site_and_network()` at `wp-includes/ms-settings.php:77`.
At that point `$wpdb->set_prefix()` (line 102 of the same file) has not
yet run, so `$wpdb->options` is the empty string.

The async DNS-check path called `wp_send_json($mapping->to_array())`,
and `wp_send_json()` calls `get_option('blog_charset')` before sending
the `Content-Type` header. With an empty `$wpdb->options`, `get_option()`
issued the malformed query

    SELECT option_value FROM  WHERE option_name = 'blog_charset' LIMIT 1

producing a noisy MariaDB syntax error on every triggering request.

Replace the `wp_send_json()` call with a direct emit of
`Content-Type: application/json; charset=UTF-8` (the WordPress default
for `blog_charset`) plus `wp_json_encode()` and `exit`, none of which
touch `get_option()` or `$wpdb->options`. Extract the emit step into a
protected `send_async_dns_response()` method gated by a new
`wu_async_dns_response_short_circuit` filter so plugins and tests can
intercept the response without invoking `exit`.

Add a regression test that simulates the empty-`$wpdb->options` state
and asserts `verify_dns_mapping()` produces no `wpdb->last_error` and
delivers the expected payload.

Resolves #1164
@superdav42 superdav42 added the origin:interactive Created by interactive user session label May 9, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 9, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cfd4c8dc-c9c5-45a9-965f-28018cd8b107

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/domain-mapping-early-wpsendjson

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

Performance Test Results

Performance test results for d9fa654 are in 🛎️!

Note: the numbers in parentheses show the difference to the previous (baseline) test run. Differences below 2% or 0.5 in absolute values are not shown.

URL: /

Run DB Queries Memory Before Template Template WP Total LCP TTFB LCP - TTFB
0 41 37.83 MB 804.50 ms (-46.50 ms / -6% ) 149.50 ms 1029.50 ms 2034.00 ms 1940.05 ms 95.40 ms (+9.45 ms / +10% )
1 56 49.12 MB 970.50 ms (+24.00 ms / +2% ) 141.00 ms 1112.50 ms (+27.50 ms / +2% ) 2114.00 ms 2032.05 ms 80.45 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

origin:interactive Created by interactive user session

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(domain-mapping): wp_send_json in verify_dns_mapping triggers malformed get_option(blog_charset) query during early multisite bootstrap

1 participant