Skip to content

Jetpack: defer Import and My Jetpack on front-end GETs (JETPACK-1747)#49936

Open
kraftbj wants to merge 6 commits into
trunkfrom
jetpack-1747-gate-feature-packages
Open

Jetpack: defer Import and My Jetpack on front-end GETs (JETPACK-1747)#49936
kraftbj wants to merge 6 commits into
trunkfrom
jetpack-1747-gate-feature-packages

Conversation

@kraftbj

@kraftbj kraftbj commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Proposed changes

Part of the JETPACK-1747 per-request PHP/opcache reduction work. This is the package-gating slice for two Jetpack surfaces that do not need to load on a plain front-end GET page view: the Import package and My Jetpack.

Before this change, Jetpack::configure() eagerly ensured the Import package on every request, and Jetpack::late_initialization() eagerly initialized My Jetpack on every request. That loaded admin/REST-only PHP into the front-end hot path even when neither surface could do work.

This gates those two initializers so the only request that skips them is the one where they are inert: a plain front-end GET page view. Every other request type keeps loading them as before:

  • wp-admin - My Jetpack's admin surfaces and plugin-action links still initialize eagerly.
  • REST - both packages initialize on rest_api_init, because REST cannot be identified yet when plugins_loaded runs.
  • cron / POST / WP-CLI - package initialization remains eager to preserve non-page-view behavior and package-version/reporting parity.

JITM intentionally stays eager. Its registration adds sync bookkeeping for jetpack_last_plugin_sync, and dedicated-sync GET requests can run on init and exit before rest_api_init; deferring JITM would skip that bookkeeping.

Measured impact

TODO: add measurement data before marking this ready for review.

Expected shape to confirm:

Request Import package My Jetpack Outcome
Front page (GET) skipped skipped fewer front-end PHP files loaded
REST (/wp-json/) loaded on rest_api_init loaded on rest_api_init routes/surfaces preserved
wp-admin / cron / POST / WP-CLI loaded eagerly loaded eagerly unchanged from trunk

Review

Ran multiple /ce-code-review and Codex adversarial passes while shaping this. Fixes made during review include keeping JITM eager, preserving the Import package's jetpack_feature_import_enabled lifecycle action in the deferred path, and adding focused PHPUnit coverage for the request-type gate plus deferred/eager Import and My Jetpack behavior.

Related product discussion/links

Does this pull request change what data or activity we track or use?

No. The same Import and My Jetpack hooks/routes initialize on request types where they can do work; this only avoids loading them on plain front-end GET page views where they would no-op.

Testing instructions

  1. Build and activate Jetpack on a test site.
  2. With a connected site, visit a plain front-end GET page view and use the existing JETPACK-1747 get_included_files()/opcache harness to confirm the Import package and My Jetpack PHP no longer load on that request. Add the measured before/after numbers above before moving the PR out of draft.
  3. Request /wp-json/ and confirm the Import and My Jetpack REST surfaces still initialize.
  4. Open wp-admin and confirm My Jetpack still initializes normally.
  5. Exercise a front-end POST, cron, and WP-CLI request if available; those request types should keep eager package initialization.
  6. Run the focused PHPUnit coverage:
    jp docker phpunit jetpack -- --filter=Jetpack_Eager_Load_Packages_Test

Other information

  • Changelog entry added (plugins/jetpack, type other).
  • Local syntax checks passed for class.jetpack.php and Jetpack_Eager_Load_Packages_Test.php.
  • Targeted PHPUnit is currently blocked in this local Docker env because the WordPress container exits while checking out the test suite (svn: E200030: sqlite[S11]: database disk image is malformed).

kraftbj added 5 commits June 23, 2026 09:35
Jetpack::configure() ran $config->ensure( 'jitm' ) and
$config->ensure( 'import' ) on every request, so both packages' PHP
autoloaded into opcache even on plain front-end GET page views where
they do no work. JITMs surface only as admin notices (current_screen)
and a jetpack/v4/jitm REST endpoint; the Import package only registers
jetpack/v4/import REST routes. Neither participates in rendering a
front-end page.

Gate both ensures so they still load on admin, cron, POST, WP-CLI, and
REST requests (REST is initialized directly on rest_api_init, since the
request type isn't known yet at plugins_loaded), and are skipped only on
a plain front-end GET — the request where they are provably inert. This
keeps their source out of opcache on the front-end hot path with no
behavior change.

Follows the same gating approach as the Stats packages. Other
unconditionally-ensured packages (videopress, search, account_protection,
waf) register front-end-GET or every-request surfaces and are left eager.

See JETPACK-1747.
…th (JETPACK-1747)

My Jetpack is a wp-admin dashboard, but Jetpack::late_initialization()
ran My_Jetpack_Initializer::init() on every request. That init eagerly
loads every product class (backup, boost, crm, protect, search, social,
videopress, jetpack-ai, …) just to register admin plugin-action links,
and calls JITM::configure() — roughly 13 files / ~160 KB of PHP pulled
into opcache on a plain front-end GET page view where none of it runs.

init() only registers admin-menu, admin_init, and rest_api_init surfaces;
the two pieces that do immediate work, Connection REST authentication and
Licensing, are already initialized unconditionally in Jetpack's
constructor, so deferring this call leaves them untouched. Product
activation sets/reads its transients via REST and admin_init only, never
on a front-end GET.

Gate the call through a shared should_load_admin_rest_only_packages()
helper (also now used by the JITM/Import gating): run init() eagerly on
admin, cron, POST, and WP-CLI requests, and on rest_api_init for REST
(which can't be detected yet at plugins_loaded). A plain page view never
fires rest_api_init, so My Jetpack — and the JITM package its init pulls
in — stays unloaded there. This also makes the JITM gating effective:
My Jetpack's init was the remaining front-end loader of JITM.

The my-jetpack admin page (admin_menu), the jetpack/v4 REST endpoints
(rest_api_init), and product-activation transients are all preserved.

See JETPACK-1747.
…-1747)

Code-review follow-up. Rename should_load_admin_rest_only_packages() to
should_eager_load_packages() and rewrite its docblock summary so the
"admin/REST-only" framing no longer reads as if REST returns true. The
helper returns true for admin/cron/POST/WP-CLI (eager load now) and false
for both a plain front-end GET and a REST request — REST is handled by
the callers' rest_api_init deferral, not by this predicate. Behavior is
unchanged; this is a naming/readability fix only.
…ts (JETPACK-1747)

Adversarial review follow-up. Stop gating the JITM package in configure()
and load it on every request as before; gate only the Import package.

JITM's register() adds a jetpack_sync_before_send_updated_option filter
that records the jetpack_last_plugin_sync transient, which JITM uses to
invalidate its message-envelope cache after a plugin change. A Jetpack
Sync send can fire on a plain front-end GET — including the dedicated-sync
spawn-sync request, which is a wp_remote_get() handled on `init` and exits
before rest_api_init ever fires. Deferring JITM off the front-end GET path
left that filter unregistered for those sends, so the transient could miss
an update and leave stale JITMs until the cache TTL. The Import package has
no such always-on side effect (REST routes only), so it stays gated.

Dropping JITM from the gate also removes the rest_api_init closure that
duplicated Config::enable_jitm()'s namespace-fallback and double-invoked
JITM::configure() on REST. The My Jetpack deferral — the bulk of the
opcache win — is unchanged.

Add Jetpack_Eager_Load_Packages_Test covering should_eager_load_packages():
admin, POST (incl. lower-case), and cron eager-load; a plain front-end GET
does not.

See JETPACK-1747.
@kraftbj kraftbj added [Status] In Progress [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Tests] Includes Tests labels Jun 24, 2026
@kraftbj kraftbj self-assigned this Jun 24, 2026
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack), and enable the jetpack-1747-gate-feature-packages branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack jetpack-1747-gate-feature-packages

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

The Jetpack plugin has different release cadences depending on the platform:

  • WordPress.com Simple releases happen as soon as you deploy your changes after merging this PR (PCYsg-Jjm-p2).
  • WoA releases happen weekly.
  • Releases to self-hosted sites happen monthly:
    • Scheduled release: July 7, 2026
    • Code freeze: July 6, 2026

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

@jp-launch-control

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/plugins/jetpack/class.jetpack.php 841/2324 (36.19%) 2.71% -53 💚

Full summary · PHP report · JS report

@LiamSarsfield

Copy link
Copy Markdown
Contributor

@kraftbj Nice analysis here. The JITM-stays-eager call and the spawn-sync reasoning behind it stood out. A few things before I'd sign off, most of them small:

  1. Add an end-to-end REST test for the deferred path. The current tests confirm the priority-0 callbacks are attached but never fire rest_api_init, so nothing proves the routes actually register through the pri-0 to pri-10 re-add. That re-entrancy is the load-bearing part of the change. A future priority tweak could 404 the importer and the My Jetpack dashboard with every unit test still green. Jetpack_REST_TestCase and Products_Rest_Test already have the patterns; fire rest_api_init and assert /jetpack/v4/import/* and /my-jetpack/v1/* show up in rest_get_server()->get_routes().

  2. Scope the "no behavior change" wording. jetpack_import_initialized, jetpack_feature_import_enabled, and my_jetpack_init stop firing on a plain front-end GET. Nothing in-repo depends on that, but they're @since-documented hooks, so I'd note the front-end timing change in the PR/changelog instead of a blanket "no behavior change."

  3. While you're in that test file: 0 === $count ? 1 : $count works today, but the else branch is dead and goes vacuous if the baseline ever shifts. $count + 1 is clearer.

  4. configure_import_package() is missing @since $$next-version$$.

I can't check the footprint numbers from the diff, so I'm assuming your loopback measurements still hold now that JITM is out of scope.

@kraftbj kraftbj marked this pull request as ready for review June 26, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] Needs Review This PR is ready for review. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants