Skip to content

Features: Preload the options experiments read on every request - #1119

Merged
dkotter merged 2 commits into
WordPress:developfrom
ekamran:shifteq/preload-feature-options
Oct 6, 2026
Merged

dkotter merged 2 commits into
WordPress:developfrom
ekamran:shifteq/preload-feature-options

Conversation

@ekamran

@ekamran ekamran commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

What?

Follow up to #1113. See #1112.

Loads the two options that experiments read on every request together with the feature toggles, so all of them come from one query instead of three.

Why?

#1113 loads the 21 feature toggles with one query. Two more options were still looked up one by one on every request: wpai_markdown_feeds_flush_rewrite (Markdown Feeds reads it on wp_loaded) and wpai_key_encryption_resume_migration (Key Encryption reads it on init). Both are flags that are deleted after use, so they are missing most of the time, and a missing option costs a query on every request on sites without a persistent object cache. Asked for as a new PR in #1113.

How?

  • Abstract_Feature::get_preloaded_options() is new. It returns the names of options a feature reads on every request, empty by default.
  • Markdown_Feeds and Key_Encryption return their flag from it.
  • The Loader adds those names to the toggle names and passes everything to wp_prime_option_caches() in the same call. A later get_option() of a flag is served from the cache, whether the row exists or not, so the flags are consumed exactly as before.
  • The persistent object cache check from Features: Load all feature toggles with one query #1113 is unchanged, nothing is primed there.
  • Third-party features get the same by defining get_preloaded_options(). Features that do not define it are skipped, the same optional-method pattern Settings_Registration uses for register_settings().

Queries per request on a fresh install with nothing switched on (MariaDB 12.3.3, WordPress 7.1.2, no persistent object cache, develop already has #1113):

Request develop This PR
Home page 27 25
Single post 31 29
REST index (/?rest_route=/) 11 9
Feed 18 16
wp-login.php 10 8
admin-ajax.php 11 9
wp-cron.php 7 5

Same 2 fewer queries on SQLite with WordPress 7.1. Against 1.4.0 the home page goes from 47 to 25 queries.

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code and Codex
Used for: Implementation, tests, measurements, and PR wording. I reviewed the reasoning and test results, and I take responsibility for the contribution.

Testing Instructions

  1. Use a site without a persistent object cache with the plugin active. Save the snippet from Features: every never-enabled feature costs one database query on every request #1112 as wp-content/mu-plugins/count-ai-option-queries.php.
  2. Load any page. On develop the log line shows 2 single lookups for wpai_ options. With this PR it shows 0.
  3. Enable Markdown Feeds under Settings > AI, load any page, then open /feed/markdown/. It shows the feed, so the flush flag was still read and consumed. Switch it off and the feed is a 404 again.

Automated:

  • npm run test:php -- --filter 'test_preloaded_options|test_get_preloaded_options_defaults_to_empty' runs the four new tests. All four fail on develop (three undefined method errors, one query count) and pass here.
  • The full PHP suite passes on single site and on multisite (1772 tests).
  • composer lint and PHPStan pass.

Changelog Entry

Fixed - The Markdown Feeds and Key Encryption flags are loaded together with the feature toggles instead of with one query each on every request.

Open WordPress Playground Preview

Markdown Feeds and Key Encryption each read a flag option on every request
(wpai_markdown_feeds_flush_rewrite on wp_loaded and
wpai_key_encryption_resume_migration on init). Both flags are deleted after
use, so they are missing most of the time and cost one query each on sites
without a persistent object cache, even after WordPress#1113 made the feature toggles
a single query.

Abstract_Feature::get_preloaded_options() lets a feature list the options
it reads on every request. The Loader adds them to the toggle names it
passes to wp_prime_option_caches(), so all of them come from the same query.
Markdown Feeds and Key Encryption return their flag from it.
@ekamran
ekamran requested a review from a team October 6, 2026 09:28
@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: ekamran <ekamran@git.wordpress.org>
Co-authored-by: dkotter <dkotter@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@codecov

codecov Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.30769% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 81.62%. Comparing base (da50fbb) to head (0096c06).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
includes/Features/Loader.php 85.71% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             develop    #1119   +/-   ##
==========================================
  Coverage      81.61%   81.62%           
- Complexity      3083     3088    +5     
==========================================
  Files            129      129           
  Lines          12289    12297    +8     
==========================================
+ Hits           10030    10037    +7     
- Misses          2259     2260    +1     
Flag Coverage Δ
unit 81.62% <92.30%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dkotter dkotter added this to the 1.5.0 milestone Oct 6, 2026
Comment thread includes/Abstracts/Abstract_Feature.php Outdated
Comment thread includes/Experiments/Key_Encryption/Key_Encryption.php Outdated
Comment thread includes/Experiments/Markdown_Feeds/Markdown_Feeds.php Outdated
Comment thread tests/Integration/Includes/Abstracts/Abstract_ExperimentTest.php Outdated
Comment thread tests/Integration/Includes/Experiments/Key_Encryption/Key_EncryptionTest.php Outdated
Comment thread includes/Abstracts/Abstract_Feature.php Outdated
Co-authored-by: Darin Kotter <darin.kotter@gmail.com>
@ekamran

ekamran commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the fixes. Noted for the next ones: @since x.x.x placeholders and list<string>.

@dkotter
dkotter merged commit 2cc9603 into WordPress:develop Oct 6, 2026
36 checks passed
@ekamran
ekamran deleted the shifteq/preload-feature-options branch October 6, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants