Skip to content

07: Sub_Plugin - #7

Open
nikolaystrikhar wants to merge 5 commits into
06-conflict-policyfrom
07-sub-plugin
Open

07: Sub_Plugin#7
nikolaystrikhar wants to merge 5 commits into
06-conflict-policyfrom
07-sub-plugin

Conversation

@nikolaystrikhar

@nikolaystrikhar nikolaystrikhar commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Sub_Plugin holds one registered sub-plugin, its configuration, and every per-sub-plugin decision. Each predicate is a plain method taking no hooks, so later collaborators stay thin and each decision is testable directly.

Stacked on #6.

This was referenced Aug 3, 2026
- is_callable() was the type discriminator on every string-or-callable key,
  and it is true for any string naming an existing function. conflict_policy
  is designed to be readable from an option, so a stored 'date' or 'flush'
  was invoked instead of used: a TypeError at plugins_loaded on PHP 8, a
  silent empty policy on 7.4. Strings and bools are values now.
- Type-check required keys. An array passed the truthiness check and cast to
  "Array", which every sub-plugin making that mistake would have shared as
  its registry key, activation key, and notice id.
- Reject an uncallable dependency_check or activation_callback at
  registration. Read-time is_callable() made "not configured" and
  "configured but uncallable" indistinguishable, so a dependency_check
  pointing at a private method reported dependencies met and let the load
  run into the fatal it guards.
- Drop the redundant network check: WordPress's is_plugin_active() already
  ORs it in. The test that pinned it described a state WordPress cannot
  produce.
- Guard the plugin.php require on is_plugin_active_for_network, since
  is_plugin_active is a function third parties shim.
- Give get_conflict_notice_message() a default, guard the filter result with
  is_scalar(), and pass the Sub_Plugin to every configured callable.
…ugin

Sub_Plugin named DEACTIVATE as its own fallback, which put "which policy
applies when none is configured" in the object that only holds one
sub-plugin's config. Conflict_Policy::default() states it now. The value
is unchanged.

The two fallbacks stay different, and now say why: unconfigured means the
sub-plugin accepted the default, whereas an unrecognised policy is a value
nobody chose, and reading a typo as consent to deactivate is the outcome
worth refusing.

Plugin_State_Interface becomes the library's only route to WordPress's
plugin functions. Sub_Plugin was a config value object that also queried
global plugin state and required wp-admin/includes/plugin.php -- a second
reason to change, and the reason these tests had to stub WordPress
functions to exercise plain config reads. The gateway owns the reads and
the deactivation, so the include exists once, guarded on deactivate_plugins:
a function the library actually calls, and still not is_plugin_active,
whose third-party shims would short-circuit the require.

is_standalone_plugin_active() is deleted rather than delegated -- forwarding
would have bought Sub_Plugin a collaborator to answer a question that was
never about its configuration. It keeps the two accessors that name the
plugin to ask about, and the consumer pairs them with the gateway. That
wiring needs Loader and Conflict\Resolver, neither of which exists yet, so
it lands with Task 12.

is_standalone_plugin_network_active() is deleted outright: no production
caller ever appeared, and its stated reason for existing was disproved --
core's null $network_wide already covers both scopes.

Sub_Plugin now makes no global WordPress call beyond the defined() that is
intrinsic to it.
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