Skip to content

4. Gate the notice queue on the capability the conflict gate asks for - #56

Merged
nikolaystrikhar merged 2 commits into
mainfrom
42-notice-capability-matches-the-gate
Aug 24, 2026
Merged

4. Gate the notice queue on the capability the conflict gate asks for#56
nikolaystrikhar merged 2 commits into
mainfrom
42-notice-capability-matches-the-gate

Conversation

@nikolaystrikhar

@nikolaystrikhar nikolaystrikhar commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

What: Notices\Presenter::render(), reached from all_admin_notices, now asks the same capability as Conflict\Gatekeeper::user_may_resolve() at plugins_loaded priority 5, answered once by the new Traits\Guards_Plugin_Capability.

Usage:

update_site_option( 'menu_items', [ 'plugins' => 1 ] );  // per-site Plugins menu on
wp_set_current_user( $site_administrator );

do_action( 'all_admin_notices' );                   // prints nothing,
get_site_option( 'give_plugin_absorber_notices' );  // and the queue survives.

Why this way:

The queue was written behind one capability and consumed behind a narrower one. It is a single network option and rendering clears it, so a site administrator opening any admin screen drained the merge notice — raised once, never re-queued — before the super admin who authorised the deactivation saw it. It bites only where the per-site Plugins menu is on; elsewhere map_meta_cap() folds the two gates together by accident, which is why no test caught it.

One answer, in a trait, for the reason Guards_Hook_Prefix is one. All that is shared is which capability to name, so a collaborator would want a binding, a constructor argument on both classes and an interface nothing dispatches on. What it may not be is a literal in each class: that is what shipped, and the two disagreed.

Summary by CodeRabbit

  • Bug Fixes

    • Improved notice and conflict handling authorization across single-site and multisite installations.
    • Prevented site administrators from consuming network-shared notices, including when the Plugins menu is enabled for individual sites.
    • Ensured queued notices are only displayed or cleared by users with the required plugin-management permission.
    • Aligned authorization behavior across conflict resolution and notice handling.
  • Documentation

    • Clarified capability requirements and multisite behavior for notices and conflict resolution.

Notices\Presenter asked for activate_plugins unconditionally while
Conflict\Gatekeeper asked for manage_network_plugins on multisite. Core folds
the two together only while the network keeps the per-site Plugins menu off, so
on a network that opened it a site administrator could print a merge notice
raised by a super admin's deactivation and clear it -- out of one network option
shared by every site -- leaving the only person who could undo the deactivation
never told.

The shared answer lives in Traits\Guards_Plugin_Capability rather than in either
class, for the reason Guards_Hook_Prefix is a trait: the answer comes from
current_user_can() either way and all that is shared is which capability to
name. A collaborator would want a container binding, a constructor argument on
both classes and an interface nothing dispatches on, to carry one boolean; a
literal in each class with a docblock in each pointing at the other is what
these two already had, and it is what drifted.

Raising the consume gate also withholds the dependency notice from a site
administrator on multisite. That is right: the queue is one network option
either way, so what they were consuming was never only their own site's.
@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Enterprise

Run ID: cf280b94-9887-4f35-a320-ed2f71f3c7cd

📥 Commits

Reviewing files that changed from the base of the PR and between 3fbbe84 and afdcb77.

📒 Files selected for processing (3)
  • AGENTS.md
  • src/Notices/Presenter.php
  • tests/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Notices/Presenter.php

Included review availability: Your plan provides up to 12 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

The change adds a shared multisite-aware plugin capability guard. Conflict resolution and notice presentation use the guard. Documentation and tests cover network notice consumption by site and network administrators.

Changes

Capability authorization

Layer / File(s) Summary
Shared capability guard
src/Traits/Guards_Plugin_Capability.php
The shared helper checks manage_network_plugins on multisite and activate_plugins otherwise.
Authorization consumers
src/Conflict/Gatekeeper.php, src/Notices/Presenter.php, docs/conflict-handling.md, docs/notices.md
Conflict resolution and notice presentation use the shared authorization helper before processing notices. Documentation describes the multisite-aware capability rule.
Multisite validation and supporting documentation
tests/unit/Notices/PresenterTest.php, tests/unit/Scenario/Bootstrap_Test_Case.php, AGENTS.md, tests/README.md
Tests verify that site administrators cannot consume network notices when the Plugins menu is open, while network administrators can. Test setup restores network menu state. Supporting documentation records the shared capability rule.

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

Merge Risk: ⚪ Minimal · up to afdcb

The capability check and notice-queue behavior change has no actionable merge-blocking risk remaining based on the supplied evidence and is merge-ready after normal checks and review.

Suggested reviewers: d4mation

🚥 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 describes the main change: aligning notice-queue access with the capability used by the conflict gate.
Docstring Coverage ✅ Passed Docstring check was indeterminate for this PR — some files could not be analyzed in time. Not blocking.
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 42-notice-capability-matches-the-gate

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

@nikolaystrikhar nikolaystrikhar changed the title Gate the notice queue on the capability the conflict gate asks for 4. Gate the notice queue on the capability the conflict gate asks for Aug 24, 2026
@nikolaystrikhar
nikolaystrikhar merged commit 0605ffe into main Aug 24, 2026
6 checks passed
@nikolaystrikhar
nikolaystrikhar deleted the 42-notice-capability-matches-the-gate branch August 24, 2026 13:59
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