Skip to content

[Task]: Auto-inject Logger into LoggerAwareInterface implementations via DI #23213

@diedexx

Description

@diedexx

Context - Why was this issue created?

Yoast SEO ships a thin PSR-3 logger at src/loggers/Logger.php that wraps a NullLogger by default and exposes a wpseo_logger filter so a host can swap in a real logger. In practice it's hardly used: the only real call sites today are two LogLevel::ERROR lines in src/integrations/watchers/indexable-post-watcher.php (lines 224 and 248), and src/repositories/indexable-repository.php injects the logger but never calls it. The barrier to using it more widely is friction: every class that wants to log has to add the Logger to its constructor, update every test that instantiates it, and trigger a DI recompile — for a concern that is orthogonal to the class's actual responsibility.

PSR-3 already defines the standard solution for this: Psr\Log\LoggerAwareInterface (with the optional LoggerAwareTrait). A class declares "give me a logger if you have one" by implementing the interface, and the container calls setLogger() after construction. Symfony's DI supports this out of the box via registerForAutoconfiguration(), but our container never registers that rule, so today implementing LoggerAwareInterface does nothing — $this->logger stays null.

What is the goal of this issue?

Make the existing Yoast\WP\SEO\Loggers\Logger automatically available to any class in src/ that opts in via LoggerAwareInterface, without that class having to declare the logger as a constructor dependency.

What needs to be done to achieve the goal?

  • Wire the DI container so classes implementing LoggerAwareInterface automatically receive the Yoast Logger after construction.
  • Verify the wiring works against a representative consumer (an integration class implementing LoggerAwareInterface + using LoggerAwareTrait).
  • Confirm composer compile-di regenerates the container correctly and that no existing constructor-injected logger usages regress.

Does the issue still need UX or research?

No — this is purely an internal DI/architecture change.

What is the expected result/behavior?

A class anywhere in src/ can:

class Some_Integration implements Integration_Interface, LoggerAwareInterface {
    use LoggerAwareTrait;

    public function register_hooks() {
        $this->logger->info( 'something happened', [ 'context' => $value ] );
    }
}

…and $this->logger is the Yoast Logger instance after the container resolves the service — no constructor changes, no test plumbing, no manual setter call. Classes that don't implement the interface are unaffected. Existing constructor-injected logger usages (Indexable_Post_Watcher, Indexable_Repository) continue to work unchanged.

Known caveat to address during implementation: instances created outside the container (new Foo() in legacy code) will have $this->logger === null until/unless setLogger() is called. The PSR-3 idiom is to default $this->logger to a NullLogger so log calls are always safe.

Should documentation be added or updated for this change? And if so, where?

Yes — .github/CONTRIBUTING.md (the "Dependency injection" section) should mention LoggerAwareInterface as the preferred way to opt into logging, alongside the existing guidance on autowiring and composer compile-di.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions