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 thehas
andget
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
andTestingContainer
, 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?
- 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.
- 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:
- You are using the WooCommerce’s
ExtendedContainer
class in your extension; or - 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:
- 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.
- 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 customBaseContainer
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:
- Add the following constant definition in the
wp-config.php
file of your site:define('WOOCOMMERCE_USE_OLD_DI_CONTAINER', true);
- 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.
Leave a Reply