Skip to content

Fix multisite extension discovery by scanning all sites/*/ directories#956

Merged
mglaman merged 6 commits intomglaman:mainfrom
dpagini:320
Apr 8, 2026
Merged

Fix multisite extension discovery by scanning all sites/*/ directories#956
mglaman merged 6 commits intomglaman:mainfrom
dpagini:320

Conversation

@dpagini
Copy link
Copy Markdown
Contributor

@dpagini dpagini commented Mar 26, 2026

ExtensionDiscovery doesn't scan multisite directories, causing false "module is not found" errors

Fixes #320

Problem

ExtensionDiscovery hardcodes the site path to sites/default:

$this->sitePath = 'sites/default';

In a Drupal multisite setup, modules can live under other site-specific directories like sites/acme/modules/. Because ExtensionDiscovery::scan() only searches sites/default for the ORIGIN_SITE weight, modules in any other site directory are never added to the ExtensionMap.

This causes the LoadIncludes rule (and ModuleLoadInclude) to report false positives:

File acme_module.inc could not be loaded from Drupal\Core\Extension\ModuleHandlerInterface::loadInclude because acme_module module is not found.

Steps to reproduce

  1. Place a module under a non-default site directory, e.g. sites/acme/modules/acme_module/
  2. Reference that module via loadInclude():
    \Drupal::moduleHandler()->loadInclude('acme_module', 'inc');
  3. Run PHPStan — the module is not found

Failing test

Failing test evidence for commit 718ef91

Branch 320 adds a test demonstrating this bug. The test places a fixture module under tests/fixtures/drupal/sites/acme/modules/ and asserts that loadInclude() resolves it without errors. It currently fails:

FAILURES!
Tests: 6, Assertions: 6, Failures: 1

1) LoadIncludesRuleTest::test with data set "multisite module in sites/acme/"
  File acme_module.inc could not be loaded from
  Drupal\Core\Extension\ModuleHandlerInterface::loadInclude
  because acme_module module is not found.

Proposed fix

Replace the single $sitePath property with discovery of all site directories under sites/*/. In scan(), iterate through each discovered site path with the ORIGIN_SITE weight, skipping sites/all (already handled) and sites/simpletest (irrelevant).

This mirrors what Drupal core's own ExtensionDiscovery does when no specific site path is provided — it scans all site directories.

Disclaimer: some contents written with help of AI

@dpagini
Copy link
Copy Markdown
Contributor Author

dpagini commented Mar 26, 2026

@aweingarten just pinging you here b/c you opened #320 (even though it was 6 years ago). Not sure if you have any thoughts on this one...

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes multisite Drupal setups where modules placed under non-default sites/<site>/modules directories were not discovered by ExtensionDiscovery, causing false “module is not found” errors during PHPStan analysis.

Changes:

  • Add a multisite fixture module under tests/fixtures/drupal/sites/acme/modules/acme_module.
  • Add a new rule test case validating loadInclude() works for a module located in a non-default site directory.
  • Update ExtensionDiscovery to discover and scan all sites/* directories (excluding sites/all and sites/simpletest) as ORIGIN_SITE.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/src/Rules/data/multisite-load-include.php Adds a PHPStan analysis snippet exercising loadInclude() for a multisite module.
tests/src/Rules/LoadIncludesRuleTest.php Adds a test case asserting no errors for the multisite fixture scenario.
tests/fixtures/drupal/sites/acme/modules/acme_module/acme_module.module Adds a site-specific module fixture entrypoint file.
tests/fixtures/drupal/sites/acme/modules/acme_module/acme_module.info.yml Adds the module metadata for the multisite fixture.
tests/fixtures/drupal/sites/acme/modules/acme_module/acme_module.inc Adds an include file so loadInclude('acme_module', 'inc') can resolve successfully.
src/Drupal/ExtensionDiscovery.php Discovers all site directories under sites/* and scans them as site-specific origins.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@mglaman mglaman changed the title Closes #320: Extensions in sites/<site-dir>/modules not discovered and autoloaded Fix multisite extension discovery by scanning all sites/*/ directories Apr 8, 2026
@mglaman mglaman merged commit 5882da9 into mglaman:main Apr 8, 2026
14 of 15 checks passed
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.

Extensions in sites/<site-dir>/modules not discovered and autoloaded

4 participants