Developer Advisory: Changes to the dependency injection container in WooCommerce

Back in WooCommerce 4.7, we introduced a dependency injection container to handle class dependencies on all the new code, as a means to keep a decoupled architecture and to ease unit testing. In WooCommerce 9.5 we are introducing a significant change in the internal implementation of that container. While this theoretically shouldn’t affect you as a WooCommerce extension developer, we have decided to write this advisory with all the relevant details because we have found instances of internal code used outside WooCommerce core.

Ultimately, The ExtendedContainer class, the PHP League’s Container package, and the mechanism that allows its use will be removed in WooCommerce 10.0. We will provide a transition period and transition mechanism for developers who are using that part of the code.

Read below to learn more about this change.

The container as of WooCommerce 9.4

Since WooCommerce 4.7, there’s a public Automattic\WooCommerce\Container class that has two methods

  • has: checks if a given class is managed by the container
  • get: obtains an instance of a class that is managed by the container

Dependencies are declared as arguments in a public init method in the classes registered in the container, and there’s a wc_get_container function that retrieves the single instance of the container class in use.

That summarizes the entire public interface of the WooCommerce dependency injection container as far as extensions development is concerned. Internally, that simple container class delegates its functionality to an ExtendedContainer class (in the Automattic\WooCommerce\Internal namespace), which contains extra functionality that’s useful mainly for unit tests. This class in turn extends the “real” dependency injection container class in use, which is provided by the PHP League’s Container package, included in WooCommerce as a dependency.

Classes are registered in the container using service providers. In WooCommerce, all classes are registered as single-instance (the class is instantiated only once and multiple calls to the container’s get method return the same instance).

What changes (and what doesn’t) in WooCommerce 9.5

In WooCommerce 9.5, the described public interface won’t change.

  • The public Automattic\WooCommerce\Container class will remain with the has and get methods
  • The wc_get_container function will remain intact
  • Class dependencies will still be declared as arguments in a public init method in the relevant classes

Internally, however, there are significant changes:

  • The ExtendedContainer class is no longer used.
  • Two new classes are introduced: RuntimeContainer and TestingContainer, to be used in production code and in unit tests, respectively.
  • The PHP League’s Container package is no longer used: the new container classes handle the class instantiations and the dependencies directly, using reflection.
  • Explicit class registration is no longer needed: the new container can be used to resolve any class in the Automattic\WooCommerce namespace – and all classes are implicitly assumed to be single-instance classes.

Why are we making these changes?

  1. Simplicity. The PHP League’s Container package is very powerful, but so far WooCommerce has been making very basic usage of it by only registering classes by class name and always in single-instance mode. By switching to smaller custom classes, we’ll have one less dependency on external packages.
  2. Performance. Benchmarking shows that using custom code instead of the League’s Container reduces the execution time of the init_hooks method by roughly 66%.

How can I tell if this change affects me?

If you are using WooCommerce as it is intended, this change doesn’t affect you. The ExtendedContainer class is in the Automattic\WooCommerce\Internal namespace, which is documented as being for WooCommerce core internal usage only.

That said, this change does affect you if:

  1. You are using the WooCommerce’s ExtendedContainer class in your extension; or
  2. You are using any of the classes from the PHP League’s Container directly from the package code present in WooCommerce (with the Automattic\WooCommerce\Vendor\League\Container namespace) in your extension.

What action should I take?

If this change affects you, you should make changes in your extension as follows:

  1. Add a copy of the PHP League’s Container package inside your extension, with a custom namespace. You may want to use a tool like Mozart for this.
  2. If you are using the ExtendedContainer class, add a copy of the class inside your extension, again with a custom namespace, and inheriting from the custom BaseContainer resulting from the previous step.

The transition period and deprecation

We understand that, although purely internal, this is a big change in the WooCommerce codebase, and we want to play it safe. For this reason, we’re temporarily keeping the ExtendedContainer class and the PHP League’s Container package as part of WooCommerce, even though in normal circumstances it won’t be used.

Additionally, we have added provided two ways to force WooCommerce to use the ExtendedContainer instead of RuntimeContainer in case any issues caused by RuntimeContainer prevent your site from being working properly. You can do this in one of two ways:

  1. Add the following constant definition in the wp-config.php file of your site: define('WOOCOMMERCE_USE_OLD_DI_CONTAINER', true);
  2. Add the following code snippet to your site: add_filter('woocommerce_use_old_di_container', '__return_true');

As mentioned, these workarounds are temporary. The ExtendedContainer class, the PHP League’s Container package, and the mechanism that allows its use will be removed in WooCommerce 10.0. This should give you plenty of time to adapt your extensions, and should give us plenty of time to fix any issues that might result from this change.

A note on internal code

We would like to emphasize that all the code in the Automattic\WooCommerce\Internal namespace is for internal usage of WooCommerce core only. We don’t guarantee backwards compatibility of the code in this namespace. We could change or remove any part of this code in future versions of WooCommerce. Before doing so, we’ll give advance notice , but please remember that this code isn’t intended for use in third party extensions.


Keep yourself in the loop!

This field is hidden when viewing the form
This field is hidden when viewing the form
This field is hidden when viewing the form


Leave a Reply

Your email address will not be published. Required fields are marked *