Skip to content

SOLID/DI architecture rebuild, selectable lint target, caching + custom DB table modules, expanded test tooling (v2.0.0) - #8

Merged
akshat009 merged 2 commits into
mainfrom
feat/solid-di-architecture-v2
Aug 25, 2026
Merged

SOLID/DI architecture rebuild, selectable lint target, caching + custom DB table modules, expanded test tooling (v2.0.0)#8
akshat009 merged 2 commits into
mainfrom
feat/solid-di-architecture-v2

Conversation

@akshat009

Copy link
Copy Markdown
Owner

Summary

Major (breaking) rebuild of the generated plugin's architecture around a Container + Service_Provider composition root, plus several new modules and a much larger generated test suite. Addresses Section A of AUDIT_BACKLOG.md almost in full.

Architecture

  • Plugin is a plain composition root (create() + boot()) — no more singleton/get_instance().
  • New Core\Container, Contracts\Service_Provider, Contracts\Conditional, Contracts\Activatable/Deactivatable.
  • Activator/Deactivator are instance classes resolved via the container (fixes a real bug: the old Activator referenced PostTypes\Post_Types unqualified from the Core namespace — would have fataled on activation with cpt_taxonomy selected).
  • Woo_Hooks god class → 5 focused, Conditional providers under Woo\Providers\.
  • Settings_PageSettings_Repository + Settings_Registrar + src/Admin/views/.
  • Elementor's widget-discovery methods (previously injected into Plugin.php via a JS template literal in index.js) → real Elementor\Widget_Registrar.php.
  • Rest_Controller now extends WP_REST_Controller. strict_types everywhere.

New modules

  • caching — object-cache + transient-fallback wrapper.
  • custom_tabledbDelta() schema + auto-migration + repository (audit item E3, marked P0).

Selectable lint target

--lint-target wp-org|vip|both (new interactive prompt too) — phpcs.xml/composer.json now generate the right ruleset(s) instead of always bundling WordPress-VIP-Go.

Test tooling

  • Real-WordPress integration suite via wp-phpunit/wp-phpunit (composer test:integration), separate from the existing Brain Monkey unit suite.
  • Jest for the React admin app (npm run test:js).
  • Playwright E2E (npm run test:e2e), with an admin_settings-aware spec when that module is selected.

Other

  • Generated plugin version now defaults to 1.0.0 (was 0.1.0).
  • Fixed trailing whitespace in the plugin header when --author/--author-uri are left blank.
  • composer install retry logic (transient network blips / Windows AV file-lock flake) in scripts/verify.sh and the generated CI workflow.
  • scripts/verify.sh had a latent bug (3-char --prefix values failing the CLI's own 4-char minimum) that meant it silently never completed — fixed, and restructured to verify each fixture independently.

Testing

  • 35/35 regression tests pass (npm test, up from 20).
  • php -l clean on every generated file across all module combinations.
  • composer install/lint/test verified successfully multiple times during development (this machine's antivirus intermittently locks files mid-composer install, unrelated to the code — see commit message / session notes).

🤖 Generated with Claude Code

…m DB table modules, expanded test tooling
BREAKING CHANGE: generated plugin architecture is rebuilt around a Container +
Service_Provider composition root, replacing the Plugin singleton and its
hardcoded build_services(). Existing generated plugins are unaffected, but
newly-generated output is structurally different (Registrable -> Service_Provider,
Woo_Hooks split, Settings_Page split, etc.) — bump to 2.0.0 accordingly.
Architecture (audit AUDIT_BACKLOG.md Section A):
- Plugin is a plain composition root (Plugin::create() + boot()), no longer a
singleton with a private constructor/get_instance().
- New Core\Container (bind/singleton/instance/get) and contracts:
Contracts\Service_Provider (register()+boot()), Contracts\Conditional
(is_needed() self-exclusion), Contracts\Activatable/Deactivatable.
- Activator/Deactivator are now instance classes resolved from the container
instead of static methods that bypassed it — this also fixes a real bug:
the old Activator referenced "PostTypes\Post_Types" unqualified from inside
the Core namespace, which resolved to a nonexistent class and would have
fataled on activation whenever cpt_taxonomy was selected.
- uninstall.php delegates to a new OOP Core\Uninstaller.
- Woo_Hooks (113-line god class) split into 5 focused providers under
Woo\Providers\ (Gateway/Shipping/Email/Product_Type/Blocks), each
Conditional on WooCommerce being active. The shared woocommerce_blocks_loaded
hook needed no coordination once split — WordPress fires every registered
callback, so the original nested-closure design was solving a non-problem.
- Admin\Settings_Page split into Settings_Repository (data access),
Settings_Registrar (hooks), and src/Admin/views/ (markup).
- Elementor's widget-discovery methods, previously injected into Plugin.php
via a ~100-line JS template literal in index.js, now live in a real
Elementor\Widget_Registrar.php template file.
- Rest_Controller now extends WP_REST_Controller.
- declare(strict_types=1) across every template file.
New modules:
- caching: Cache_Service (object cache + transient fallback, remember()).
- custom_table: Database\Schema (dbDelta schema + automatic migration
checked on every request) + Database\Item_Repository (CRUD example).
Selectable lint target (--lint-target wp-org|vip|both, new interactive
prompt): phpcs.xml and composer.json now generate WordPress-Extra/-Docs
and/or WordPress-VIP-Go (+ automattic/vipwpcs) based on this instead of
always bundling both rulesets unconditionally.
Test tooling:
- WP integration test suite via wp-phpunit/wp-phpunit + yoast/phpunit-polyfills
(tests/Integration/, phpunit-integration.xml.dist, composer test:integration)
always scaffolded, separate from the existing Brain Monkey unit suite.
- Jest (jest.config.js + tests/js/App.test.js, npm run test:js) alongside the
React admin app — assets/src/index.js now exports App for testability.
- Playwright E2E (playwright.config.js + tests/e2e/, npm run test:e2e)
alongside any JS pipeline; an admin_settings-aware spec is added when that
module is selected.
Other fixes found while rebuilding this:
- Generated plugin version now defaults to 1.0.0 instead of 0.1.0.
- Trailing whitespace in the plugin header when --author/--author-uri are
left blank (fixed-width label lines) now gets trimmed post-substitution.
- composer install retry logic (transient network blips, or the Windows
antivirus/Search Indexer file-lock flake) in both scripts/verify.sh and
the generated CI workflow's Install Composer Dependencies steps.
- scripts/verify.sh itself had a latent bug (3-char --prefix values that
fail the CLI's own 4-char minimum) that meant it silently never ran to
completion; also restructured to verify each fixture independently so one
flaky/failing variant doesn't hide results for the other four.
35 regression tests in tests/generator.test.js (up from 20).
- Cache_Service::get()'s $default parameter renamed to $fallback —
Universal.NamingConventions.NoReservedKeywordParameterNames flags
default as a reserved-keyword-ish parameter name.
- Schema::drop_table()'s phpcs:ignore comment cited the wrong sniff code
(WordPress.DB.PreparedSQL.NotPrepared instead of the actual
WordPress.DB.PreparedSQL.InterpolatedNotPrepared that fires for an
interpolated variable in a query string), so it never suppressed
anything. Fixed the sniff name; the actual DROP TABLE + table name
reasoning is unchanged.
Both confirmed via the PR's own CI logs (self-consumption job, both
ubuntu-latest and macos-latest hit the identical two findings).
@akshat009
akshat009 merged commit 00f9359 into mainAug 25, 2026
4 checks passed
@akshat009
akshat009 deleted the feat/solid-di-architecture-v2 branch August 25, 2026 12:27
Sign up for freeto 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

@akshat009