Skip to content

Reduce frontend PHP bootstrap memory further - #1313

Merged
danieliser merged 4 commits into
developfrom
agent/php-memory-footprint-2
Aug 13, 2026
Merged

Reduce frontend PHP bootstrap memory further#1313
danieliser merged 4 commits into
developfrom
agent/php-memory-footprint-2

Conversation

@danieliser

@danieliser danieliser commented Aug 10, 2026

Copy link
Copy Markdown
Member

Stack

Builds on #1302 and can be reviewed/skipped as a separate layer. Retarget to develop after #1302 merges.

TL;DR

Removes another 124,616 B (-28.4%) from Popup Maker's retained frontend footprint and 131,344 B (-41.6%) from its peak footprint versus #1302. Cumulatively, the first two PRs reduce retained Popup Maker bootstrap overhead from about 1.45 MB on develop to 0.314 MB, or roughly 78%.

Measurement definitions

  • Popup Maker memory footprint = PHP request memory with Popup Maker enabled minus the matched WordPress request with Popup Maker unavailable. Memory percentages use this incremental footprint, not the entire WordPress/PHP process.
  • Whole-process memory is retained as a secondary audit metric.
  • Overall TTFB means full HTTP response time_starttransfer. It was not benchmarked for this PR.

Issues and gains

Legacy handler classes are compiled before their hooks run

Privacy, alerts, telemetry, and the popup/theme editor handlers were loaded on every frontend request just to register WordPress callbacks. The bootstrap now registers the same class-string callbacks without autoloading their implementations; frontend programmatic saves and the full eager admin bootstrap remain intact.

Isolated gain: 25,384 B retained, 32,112 B peak, 5 files, and 5 classes.

Notification providers boot when no notification API is used

The notification manager constructed WhatsNew and FeatureAnnouncements during init, even when no alert, dismissal, save, option-change, or plugin lifecycle event occurred. Priority-PHP_INT_MIN loaders now boot providers on the relevant event early enough to participate in that same hook; admin requests and explicit get_providers() calls stay eager.

Isolated gain: 4 files and 3 classes. Its direct byte delta is allocator-masked (~0.5 KB), but combining it with the handler deferral releases another PHP allocator slab.

Popup Maker footprint: before / after

Matched core-only WordPress bootstrap, theme skipped, other active plugins skipped, five stable runs.

Metric #1302 This PR Gain
Popup Maker incremental retained memory 439,040 B 314,424 B -124,616 B (-28.4%)
Popup Maker incremental peak memory 316,072 B 184,728 B -131,344 B (-41.6%)
Included files 842 833 -9
Declared classes 744 736 -8

Secondary whole-process measurements

Metric #1302 This PR Gain
Retained PHP memory 17,374,568 B 17,249,952 B -124,616 B (-0.7%)
Peak PHP memory 18,317,736 B 18,186,392 B -131,344 B (-0.7%)

PHP's allocator makes the two ablations non-additive; the combined process measurement is the number that matters.

Functional verification

  • Frontend popup/theme save hooks and popup slug filtering retain their original priorities and accepted argument counts.
  • Providers registered during the active pum_alert_list filter execute during that same iteration.
  • Deferred feature-announcement cache invalidation executes during the same option-update action.
  • Alert discovery loads both core providers at priorities 12 and 15.
  • Admin bootstrap remains eager for editor and notification UI behavior.

Validation

  • composer run tests: 910 tests, 1,918 assertions; 29 skipped.
  • Changed-file PHPCS: passed.
  • Full PHPCS and PHPStan retain the parent branch's existing baselines; no new findings.
  • PHP 7.4-compatible syntax only.

Summary by CodeRabbit

  • Performance

    • Reduced unnecessary frontend loading by deferring admin editors, notifications, privacy, alerts, and telemetry until needed.
    • Preserved popup and theme saves, notification alerts, and related integrations during frontend requests.
  • Bug Fixes

    • Ensured deferred notification providers initialize correctly when notification events are triggered.
    • Improved handling when notification events occur before deferred services are registered.
  • Tests

    • Added coverage for deferred loading, event registration, provider discovery, and alert behavior.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e6647020-d9e1-484c-8221-a02f7cc5e770

📥 Commits

Reviewing files that changed from the base of the PR and between 9bd5fa7 and 287b2e3.

📒 Files selected for processing (3)
  • classes/Plugin/Core.php
  • classes/Services/Notifications/Manager.php
  • tests/php/tests/Notification_Manager_Loader_Test.php

Walkthrough

Frontend requests now defer selected admin, legacy, and notification initialization until related hooks execute. Notification provider access initializes the manager. Tests verify deferred hook registration and provider loading.

Changes

Deferred initialization

Layer / File(s) Summary
Admin and legacy hook deferral
classes/Admin.php, includes/legacy/class-popup-maker.php, tests/php/tests/PUM_Admin_Loader_Test.php, tests/php/tests/PUM_Deferred_Hooks_Test.php
Admin editor classes load only in the admin area. Frontend save hooks remain registered. Legacy privacy, alert, and telemetry callbacks use deferred class-string hooks. Tests verify the loading behavior and hook priorities.
Deferred notification boot
classes/Plugin/Core.php, classes/Services/Notifications/Manager.php, classes/Services/Notifications/Provider.php
Frontend notification initialization attaches to configured hooks. Hooks that already fired trigger immediate initialization. get_providers() initializes the manager before returning providers. Provider documentation describes deferred frontend boot.
Notification provider validation
tests/php/fixtures/class-pum-test-deferred-notification-provider.php, tests/php/tests/Notification_Manager_Loader_Test.php
The test provider registers an alert callback. Separate-process tests verify alert-triggered, custom-hook, already-fired-hook, and core-wired provider loading.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: 🟡 Moderate · up to 287b2

This change defers notification and legacy handler loading to reduce frontend memory, but notification providers may be skipped for version updates or addon-defined events, and malformed deferred-hook configuration can cause runtime errors. The PR is not merge-ready until these bounded notification-path risks are fixed or explicitly accepted.

Sequence Diagram(s)

sequenceDiagram
  participant FrontendRequest
  participant WordPressHooks
  participant NotificationManager
  participant DeferredProvider
  FrontendRequest->>NotificationManager: Register lazy boot
  NotificationManager->>WordPressHooks: Register deferred boot callbacks
  WordPressHooks->>NotificationManager: Fire notification-related hook
  NotificationManager->>DeferredProvider: Initialize provider
  DeferredProvider->>WordPressHooks: Register pum_alert_list callback
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the pull request's primary change: reducing frontend PHP bootstrap memory usage.
Docstring Coverage ✅ Passed Docstring coverage is 84.62% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/php-memory-footprint-2

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.

@danieliser
danieliser deleted the branch develop August 12, 2026 07:16
@danieliser danieliser closed this Aug 12, 2026
@danieliser danieliser reopened this Aug 12, 2026
@danieliser
danieliser changed the base branch from agent/php-memory-footprint to develop August 12, 2026 07:18
@danieliser
danieliser force-pushed the agent/php-memory-footprint-2 branch from 37934ea to 9bd5fa7 Compare August 12, 2026 07:35
…ble hooks

Per review feedback: the deferral mechanism now lives in the
Notifications Manager itself instead of Plugin\Core, and the trigger
hook list is extensible via the
popup_maker/notifications/deferred_boot_hooks filter so Pro, Pro+, and
legacy extensions can register their own. get_providers() remains the
universal lazy-boot fallback, so unregistered consumers still work.
@danieliser

Copy link
Copy Markdown
Member Author

Addressed review feedback (via chat): the deferred-boot mechanism moved out of Plugin\Core into the Notifications Manager itself — register_lazy_boot() + boot_on_demand() — and the hook list is now extensible via the popup_maker/notifications/deferred_boot_hooks filter, so Pro/Pro+/legacy extensions can register their own trigger hooks. get_providers() remains the universal lazy-boot fallback: any consumer that actually reads notifications boots the manager regardless, making the hook list an optimization rather than a correctness requirement. New test covers filter-registered hooks booting the manager on frontend.

@danieliser
danieliser marked this pull request as ready for review August 12, 2026 22:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@classes/Plugin/Core.php`:
- Around line 384-386: Update the deferred-hook setup around
self::DEFERRED_NOTIFICATION_HOOKS to apply the
popup_maker/notifications/deferred_boot_hooks filter, retaining the default list
when the callback returns invalid data. Before add_filter(), discard non-string
hook names, then register init_notifications_on_demand for each valid hook.
- Around line 28-30: Remove popup_maker/update_version from
DEFERRED_NOTIFICATION_HOOKS and ensure its dispatch occurs after init_services()
registers the init callback, or preserve the upgrade state and dispatch it from
the init flow so frontend notification providers receive the event.

In `@tests/php/tests/Notification_Manager_Loader_Test.php`:
- Around line 22-30: Update the test setup around
PUM_Test_Deferred_Notification_Provider and Manager so it uses the global
notifications service instead of the local $loader that directly calls
Manager::init(). Apply the pum_alert_list filter, assert the expected alert
exists, and then verify the provider is booted, ensuring the test exercises
Core’s lazy-boot registration and init_notifications_on_demand() path.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e9e923dd-7342-41dd-a42c-a61eb7b9c87a

📥 Commits

Reviewing files that changed from the base of the PR and between 4c3a3ee and 9bd5fa7.

📒 Files selected for processing (9)
  • classes/Admin.php
  • classes/Plugin/Core.php
  • classes/Services/Notifications/Manager.php
  • classes/Services/Notifications/Provider.php
  • includes/legacy/class-popup-maker.php
  • tests/php/fixtures/class-pum-test-deferred-notification-provider.php
  • tests/php/tests/Notification_Manager_Loader_Test.php
  • tests/php/tests/PUM_Admin_Loader_Test.php
  • tests/php/tests/PUM_Deferred_Hooks_Test.php

Comment thread classes/Plugin/Core.php Outdated
Comment thread classes/Plugin/Core.php Outdated
Comment thread tests/php/tests/Notification_Manager_Loader_Test.php Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9bd5fa7a2d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread classes/Plugin/Core.php Outdated
Comment on lines +384 to +386
foreach ( self::DEFERRED_NOTIFICATION_HOOKS as $hook ) {
add_filter( $hook, [ $this, 'init_notifications_on_demand' ], PHP_INT_MIN );
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Initialize extension providers before arbitrary frontend hooks

On frontend and REST requests, providers are now initialized only when one of the hard-coded DEFERRED_NOTIFICATION_HOOKS fires. The provider contract explicitly permits providers to register callbacks for “other plugin events,” so an addon provider listening to an event outside that list—for example, a form or commerce submission hook—will never be initialized before its event and will silently miss it; previously every provider was initialized on init. Preserve automatic initialization for extension providers or provide a mechanism that does not require core to know every provider-specific hook.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Covered by 9f7d898b + fd07bc77 (pushed after your review): (1) hook list is extensible via popup_maker/notifications/deferred_boot_hooks, (2) get_providers() lazy-boots as a universal fallback for any consumer, (3) hooks that fired before init now boot the manager immediately. Extension providers registered via popup_maker/notification_providers resolve at boot regardless of which path triggered it.

danieliser and others added 2 commits August 12, 2026 18:49
An upgrade dispatches popup_maker/update_version during plugins_loaded,
before init@5 registers the lazy boot filters. Check did_action() and
did_filter() for each deferred hook and boot the manager immediately if
the event already fired this request. Adds a regression test plus a
Core-wiring assertion through the booted plugin.
@danieliser
danieliser merged commit 15c213f into develop Aug 13, 2026
1 check passed
@danieliser
danieliser deleted the agent/php-memory-footprint-2 branch August 13, 2026 00:58
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.

1 participant