WooCommerce is old enough that its most important string values (order statuses, product types, stock states, tax modes) predate almost every modern PHP convention. Across the WooCommerce codebase, and in many extensions, every one of those comparisons was written against a raw string literal:
if ( 'completed' === $order->get_status() ) { // hope you spelled it right!Over the last few years, WooCommerce has begun shipping a family of enum classes under Automattic\WooCommerce\Enums. These are named, documented constants for order statuses, product types, stock states, settings values, and more.
The enum classes are considered a public API, and extension developers are encouraged to use them. This post covers what’s available, why we built classes of string constants instead of native PHP enums, and what shipping them taught us about load order and backward compatibility.
The price of a “magic string”
String literals might feel easier to write or more simple than classes, but the come with tradeoffs. Spread across a codebase the size of WooCommerce and the many extensions, magic strings tax you four ways:
- Silent errors. Linters, autoloaders, and tests may not catch an error like typing
'complete'instead of'completed'. - Abiguity. WordPress stores post-prefixed order statuses as
wc-completed, while most WooCommerce APIs expect the un-prefixedcompleted, something a developer may only discover the hard way. - Discoverability. An agent searching
'simple'to find product-type logic returns half the codebase. Grepping forProductType::SIMPLEshould return a much narrower, accurate set of results. - Documentation. The definition for a status like
on-holdwill now live in a docblock next to its declaration.
Enum classes have the added benefit of clarifying empty strings based on intent. For example, woocommerce_default_customer_address treats '' as “no default”, which is unguessable without a named constant.
Why not native PHP enums
PHP has had enum support since 8.1, but for a few reasons, it wasn’t a viable solution for WooCommerce. Primarily, WooCommerce’s minimum supported PHP version is 7.4 which doesn’t include support for native enums.
There’s also an architectural difference. These values are already stored as plain strings in millions of databases, and thousands of extensions expect them to stay that way. Native PHP enums would turn those strings into objects, which could break existing code. String constants avoid this problem. OrderStatus::COMPLETED still produces the same 'completed' string, so developers can use the clearer name without changing how WooCommerce works. Existing code continues to work, and extensions can adopt the new constants when they are ready.
final class OrderStatus {
/**
* Order fulfilled and complete.
*/
public const COMPLETED = 'completed';
// ...
}Enum classes currently available
The src/Enums directory (and its README) is an authoritative list of what’s currently available. The highlights:
- Orders:
OrderStatus(unprefixed values likecompleted),OrderInternalStatus(thewc--prefixed variants stored in the database),OrderItemType - Products:
ProductType,ProductStatus,ProductStockStatus,ProductTaxStatus,CatalogVisibility - Payments:
PaymentGatewayFeature, the strings gateways declare in theirsupportsarrays - Settings values:
WeightUnit,DimensionUnit,CurrencyPosition,TaxBasedOn,TaxDisplayMode,DefaultCustomerAddress,StockDisplayFormat,CatalogSortOrder
Using the constants in your extension
These constants are intentionally a publicly discoverable API, with explicit public visibility, docblocks, and developer docs. Extension developers are welcome to rely on them.
use Automattic\WooCommerce\Enums\OrderStatus;
use Automattic\WooCommerce\Enums\ProductType;
if ( OrderStatus::COMPLETED === $order->get_status() ) {
// ...
}
$products = wc_get_products( array( 'type' => ProductType::SIMPLE ) );Two things to check before adopting them:
- Your minimum supported WooCommerce version. The classes landed incrementally:
OrderStatusin WooCommerce 9.5, the product classes around 9.7 and 9.8, the settings-value classes across the 10.x releases. If you support older versions, keep the literal or guard usage withclass_exists(). - Which string WooCommerce expects.
OrderStatus::COMPLETEDiscompleted;OrderInternalStatus::COMPLETEDiswc-completed. Most WooCommerce functions take the un-prefixed form; database-level andpost_statuscontexts use the prefixed one.
The product querying and order querying docs show the constants in use alongside the literal forms.
What’s next
New vocabularies in core should now get an enum class by default. WooCommerce still contains many string values that deserve names, and contributions are welcome.
Leave a Reply