Repository navigation
Conversation
Code in a Domain namespace now neither imports an Infrastructure namespace (ARCH-01) nor calls a global WordPress function (ARCH-02). Each call moves behind a port declared in the module's domain, implemented in its Infrastructure layer and bound by its existing service provider: - Theme: ThemeFeatureRegistrarInterface (register_nav_menus, register_sidebar, add_image_size), ContentUrlResolverInterface (content_url) and ThemeAssetUrlResolverInterface (AssetFile) - Dashboard: WordPressEnvironmentInterface for SystemInfoCollector - Taxonomy: LabelTranslatorInterface for AbstractTaxonomy's labels - WooCommerce: WooCommerceEnvironmentInterface, implemented by the existing WordPressWooCommerceAdapter - VersionCheck: the contract no longer imports its Packagist implementation New constructor parameters are optional with a WordPress-free default, so no public signature changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B7X25PLDN5YXW2HX2YpYQi
Brain Monkey leaves a function it defined declared for the rest of the process, and PatternService's unit tests rely on wp_get_theme() being undefined. The adapter's theme test moves to the Feature suite, where the doctor checks already stub it. Also drop a type guard PHPStan reports as always true, and cover the default WooCommerce environment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B7X25PLDN5YXW2HX2YpYQi
…I debug The phpunit/bootstrap change only reports failing tests as annotations so they can be read without the job log; it will be reverted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B7X25PLDN5YXW2HX2YpYQi
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B7X25PLDN5YXW2HX2YpYQi
get_option() is stubbed for every test by the suite, so the permalink test overrides the stub instead of expecting the call. The provider test that resolved WooCommerceService through the real adapter reached WC() and is gone: WooCommerceService is now autowired onto the environment port, which the remaining provider test checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B7X25PLDN5YXW2HX2YpYQi
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B7X25PLDN5YXW2HX2YpYQi
Brain Monkey keeps a function it defined declared for the rest of the run, and the async hook runner tests rely on is_multisite() being absent. The adapter is covered on its WordPress-not-loaded path instead. Drops the temporary CI debug output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B7X25PLDN5YXW2HX2YpYQi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The new Pollora harness checks two rules on every
...\Domainnamespace:Illuminate\...nor any...\Infrastructure\...or...\UI\...namespace.add_action,get_option,wp_*,__,esc_*,get_bloginfo…). PHP built-ins are fine.The domain is what keeps Pollora portable. The same rules have to run inside Laravel, inside a plain WordPress through the upcoming mu-plugin, and in unit tests with no WordPress loaded. A WordPress call or an Infrastructure import in the domain ties all three to one host.
This PR clears every ARCH-02 offence and every ARCH-01 offence that can be fixed without changing a public signature.
What changed
Each offence moves behind a port. The port is an interface in the module's
Domain, the implementation lives in the module'sInfrastructurelayer, and the module's existing service provider binds the two.src/Theme/Domain/Models/Menus.phpregister_nav_menus()Theme\Domain\Contracts\ThemeFeatureRegistrarInterfaceTheme\Infrastructure\Services\WordPressThemeFeatureRegistrar(ThemeServiceProvider)src/Theme/Domain/Models/Sidebar.phpregister_sidebar()src/Theme/Domain/Models/ImageSize.phpadd_image_size()src/Theme/Domain/Models/ThemeInitializer.phpcontent_url()Theme\Domain\Contracts\ContentUrlResolverInterfaceTheme\Infrastructure\Services\WordPressContentUrlResolver(ThemeServiceProvider)src/Theme/Domain/Models/ThemeInitializer.phpAsset\Infrastructure\Services\AssetFileTheme\Domain\Contracts\ThemeAssetUrlResolverInterfaceTheme\Infrastructure\Services\ThemeAssetFileResolver(ThemeServiceProvider)src/Dashboard/Domain/Services/SystemInfoCollector.phpget_locale,get_bloginfo,is_multisite,get_option,get_post_type_object,get_taxonomy,wp_get_themeDashboard\Domain\Contracts\WordPressEnvironmentInterfaceDashboard\Infrastructure\Adapters\WordPressEnvironment(DashboardServiceProvider)src/Taxonomy/Domain/Models/AbstractTaxonomy.php__()×14 ingetLabels()Taxonomy\Domain\Contracts\LabelTranslatorInterfaceTaxonomy\Infrastructure\Services\WordPressLabelTranslator(TaxonomyServiceProvider)src/ThirdParty/WooCommerce/Domain/Services/WooCommerceService.phpis_child_theme,get_template_directory,WC()ThirdParty\WooCommerce\Domain\Contracts\WooCommerceEnvironmentInterfaceWordPressWooCommerceAdapter, which now implements it (WooCommerceServiceProvider)src/VersionCheck/Domain/Contracts/VersionCheckerInterface.phpInfrastructure\Services\PackagistVersionChecker(only for a@see)Public API is unchanged
Menus,Sidebar,ImageSize,ThemeInitializer) already take a container. They get the new ports from it, the same way they already getAction,FilterandWordPressThemeInterface. Their constructors stay as they were.SystemInfoCollectorgets a trailing optionalWordPressEnvironmentInterface $wordpressparameter. Its default,Dashboard\Domain\Support\UnavailableWordPressEnvironment, reports "not loaded", which is what the oldfunction_exists()guards answered without WordPress.WooCommerceServicegets an optional constructor parameter. Its default,DefaultWooCommerceEnvironment, means no child theme and thewoocommerce/folder, which is what the old guards answered without WordPress.new WooCommerceServicekeeps working.AbstractTaxonomyis extended by applications, and discovery instantiates subclasses without arguments, so constructor injection would break every subclass. The translator is set once, statically, byTaxonomyServiceProvider(AbstractTaxonomy::useLabelTranslator()). Without one, the label templates come back untranslated. The text domain stayspollora, so the msgids are unchanged and the existing.pocatalogues still apply.The behaviour of every adapter is the same code that used to run in the domain,
function_exists()guards included.Deliberately left out (follow-up)
These two files still break ARCH-01, and fixing them would change public API:
src/Modules/Domain/Models/ModuleCollection.phpsrc/Plugin/Domain/Support/PluginCollection.phpBoth
extend Illuminate\Support\Collection. Any project can call or type-hint the wholeCollectionAPI on them (map,filter,toArray, …). Removing the parent class, or swapping it for a domain collection, is a breaking change. It belongs in a major version, or behind a deprecation path that ships a domain collection type next to these two first.Found while scanning, outside the brief (not changed here):
src/Theme/Domain/Models/ThemeInitializer.phpstill calls Laravel'sbase_path()helper.src/Theme/Domain/Models/ThemeMetadata.phpandsrc/Plugin/Domain/Models/PluginMetadata.phpcallapp_path().src/Modules/Domain/Models/AbstractModule.phpcallsdata_get()/data_set(), andAbstractTaxonomyandSystemInfoCollectorcallclass_basename().These are Laravel global helpers, not WordPress functions and not
use Illuminate\...imports, so neither ARCH-01 nor ARCH-02 flags them. They still tie the domain to Laravel, so they are worth their own pass.How it was verified
src/**/Domain/**:use Illuminate\...import except the two collections above;use Pollora\...\(Infrastructure|UI)\...import;php-stubs/wordpress-stubs, reading only top-levelfunctiondeclarations, as the harness'sNoWordPressCallInDomainRuledoes.tests/Unit/Theme/Infrastructure/Services/WordPressThemePortsTest.php: the three Theme adapters call the right WordPress function or asset container.tests/Unit/Theme/{Menus,Sidebar,ImageSize}Test.php: each component registers its configured features through the port.tests/Unit/Theme/ThemeInitializerTest.php: the harness passes port doubles instead of stubbingcontent_url(). New cases cover a built asset URL and a resolver that throws.tests/Unit/Dashboard/Infrastructure/WordPressEnvironmentTest.php: the adapter and the "unavailable" default.activeTheme()is tested intests/Feature/Dashboard/WordPressEnvironmentThemeTest.php, andisMultisite()only on its not-loaded path. Once Brain Monkey defineswp_get_theme()oris_multisite(), the function stays defined for the rest of the process.PatternService's unit tests and the pollora/hook async runner both rely on those functions being undefined.tests/Unit/Dashboard/SystemInfoCollectorTest.php: the collector reads the version, multisite flag, permalinks, labels, theme and locale from the port.tests/Unit/Taxonomy/AbstractTaxonomyLabelsTest.php: untranslated fallback, translation in thepolloradomain, the adapter, and the provider binding.tests/Unit/Plugins/WooCommerce/...: the service on a port double and on its default environment, plus the provider binding the port to the WordPress adapter.WooCommerceServicestays autowired (singleton(WooCommerceService::class)) and receives the bound port.php -land Pint (pint --test, repopint.json) on every changed file, plus a rough PHPStan level 5 pass over the new and changed classes. The full suite (Pest on 8.3/8.4, Pint, PHPStan with Larastan, Rector, type coverage, skeleton install, E2E) runs in this PR's CI.phpunit.xml.distandtests/bootstrap.phpare identical todevelop. Please squash-merge so they stay out ofdevelop's history.https://claude.ai/code/session_01B7X25PLDN5YXW2HX2YpYQi
Generated by Claude Code