Skip to main content
WooCommerce uses a PSR-11 compliant dependency injection (DI) container to manage class dependencies and improve code testability.

Why Dependency Injection?

Dependency injection provides several benefits over traditional singleton and global access patterns:
  • Testability: Easy to mock dependencies in unit tests
  • Maintainability: Clear dependencies make code easier to understand
  • Flexibility: Swap implementations without changing dependent code
  • Single Responsibility: Classes focus on their core purpose, not dependency management

The Container

WooCommerce’s container is available globally via the wc_get_container() function.

Container Setup

The container is initialized in the main plugin file:
plugins/woocommerce/woocommerce.php

Container Implementation

The container is a PSR-11 compliant implementation:
src/Container.php

Getting Services

Retrieve services from the container using the get() method.

From Legacy Code

In includes/ directory, use wc_get_container():
includes/class-woocommerce.php

From Modern Code

In src/ directory, inject dependencies via the init() method:
src/Internal/MyClass.php
The container automatically resolves dependencies when you type-hint them in the init() method.

The init() Method Pattern

All classes in src/ that require initialization should implement an init() method.

Basic Pattern

With Dependencies

With Container Access

If you need the container itself:

Container Patterns

Common patterns for using the container effectively.

Automatic Resolution

The container uses reflection to automatically resolve dependencies:
src/Internal/DependencyManagement/RuntimeContainer.php

Singleton Behavior

The container provides singleton behavior automatically:

Allowed Classes

Only classes in the Automattic\WooCommerce namespace can be resolved:
src/Internal/DependencyManagement/RuntimeContainer.php
Attempting to resolve classes outside the Automattic\WooCommerce namespace will throw a ContainerException.

Circular Dependency Detection

The container detects and prevents circular dependencies:

Dependency Requirements

Follow these rules when declaring dependencies in init() methods.

Valid Dependency Types

Type-hint class dependencies:

Constructor Requirements

Classes resolved by the container must have either:
  1. No constructor, or
  2. A public constructor with only optional parameters

Real-World Example

Here’s a complete example from WooCommerce core:
src/Internal/AssignDefaultCategory.php

Common Patterns

Proxies for WordPress Functions

Use proxies to interact with WordPress and legacy code:

Multiple Dependencies

Inject multiple services:

Optional Container Access

Some classes may need the container for lazy loading:

Testing with the Container

The container makes testing easier by allowing dependency mocking.

Unit Test Example

tests/php/src/Internal/MyClassTest.php

Best Practices

1

Use init() Method

Always inject dependencies via the init() method:
2

Mark init() as Final

Prevent overriding the init method:
3

Type-Hint Dependencies

Always use type hints for clarity and automatic resolution:
4

Store Dependencies as Properties

Save injected dependencies for later use:
5

Use Proxies for WordPress

Don’t call WordPress functions directly; use proxies:
6

Register Hooks in init()

Add all hooks inside the init method:

Error Handling

The container throws ContainerException for various errors:

Class Not Found

Outside Namespace

Circular Dependency

Next Steps

Modern vs Legacy

Understand when to use dependency injection

Architecture

Learn about WooCommerce’s overall architecture