WooCommerce CRUD & Data Stores
Before writing code
Fetch live docs:
- Web-search
site:developer.woocommerce.com crud data storesfor CRUD documentation - Web-search
site:github.com woocommerce woocommerce HPOSfor HPOS architecture - Fetch
https://github.com/woocommerce/woocommerce/wikifor architecture decisions
CRUD Architecture
Data Objects
WooCommerce's core entities extend WC_Data:
WC_Product— products (and subtypes:WC_Product_Simple,WC_Product_Variable, etc.)WC_Order— orders (andWC_Order_Refund)WC_Customer— customer profilesWC_Coupon— discount couponsWC_Shipping_Zone— shipping zones
WC_Data Base Class
All CRUD objects inherit from WC_Data:
$data— array of core properties with defaults$meta_data— array ofWC_Meta_Dataobjects$id— object ID$object_type— string identifier (e.g., 'product', 'order')$data_store— theWC_Data_Storeinstance handling persistence
Getters and Setters
get_{prop}( $context = 'view' )— retrieve a property'view'context — runswoocommerce_{object_type}_get_{prop}filter (for display)'edit'context — returns raw stored value (for forms/admin)
set_{prop}( $value )— set a property (in memory, not persisted untilsave())save()— persist to database (calls data store'screate()orupdate())delete( $force_delete )— remove from database
Meta Data
get_meta( $key, $single, $context )— get meta valueupdate_meta_data( $key, $value, $meta_id )— set meta (in memory)delete_meta_data( $key )— mark meta for deletionsave_meta_data()— persist meta changes (called automatically bysave())
Data Stores
What Data Stores Do
Data stores abstract the persistence layer. The CRUD object calls generic methods (read, create, update, delete) on its data store, which handles the actual SQL.
Built-In Data Stores
| Object | Data Store | Storage |
|---|---|---|
| Product | WC_Product_Data_Store_CPT | wp_posts + wp_postmeta |
| Order (legacy) | WC_Order_Data_Store_CPT | wp_posts + wp_postmeta |
| Order (HPOS) | Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore | wp_wc_orders + related tables |
| Customer | WC_Customer_Data_Store | wp_users + wp_usermeta |
| Coupon | WC_Coupon_Data_Store_CPT | wp_posts + wp_postmeta |
Custom Data Stores
You can swap data stores via the woocommerce_{object}_data_store filter:
- Implement
WC_Object_Data_Store_Interface(or extend an existing data store) - Implement methods:
create(),read(),update(),delete(),read_meta(),update_meta(),delete_meta() - Filter:
add_filter( 'woocommerce_product_data_store', function() { return 'My_Custom_Store'; } )
HPOS (High-Performance Order Storage)
What Changed
HPOS moves order data from wp_posts/wp_postmeta to dedicated tables:
wp_wc_orders— core order fields (status, currency, total, customer_id, dates)wp_wc_orders_meta— order metawp_wc_order_addresses— billing/shipping addresseswp_wc_order_operational_data— internal operational data
Why HPOS
- Massive performance improvement for stores with many orders
- Orders no longer pollute the
wp_poststable - Dedicated indexes for order queries
- Cleaner separation of concerns
Compatibility Modes
- Sync enabled — both posts and custom tables are written (transition period)
- Authoritative: Custom tables — custom tables are the source of truth
- Authoritative: Posts — legacy mode, posts are source of truth
Declaring HPOS Compatibility
add_action( 'before_woocommerce_init', function() {
if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) {
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
'custom_order_tables', __FILE__, true
);
}
});
HPOS-Compatible Code
- DO: Use
$order->get_meta(),$order->update_meta_data(),$order->save() - DO: Use
wc_get_orders()with proper args for querying - DON'T: Use
get_post_meta(),update_post_meta()on orders - DON'T: Use
WP_Queryto query orders directly - DON'T: Assume
$order->get_id()is awp_postsID
Querying
wc_get_orders()
The proper way to query orders (HPOS-compatible):
- Accepts args like
status,customer_id,date_created,meta_key,meta_value - Returns array of
WC_Orderobjects - Under the hood, delegates to the active order data store
wc_get_products()
Query products — delegates to WC_Product_Query:
type,status,sku,category,tag,price,meta_key, etc.- Returns array of
WC_Productobjects
Best Practices
- Always use CRUD getters/setters, never access
$datadirectly - Always call
save()after modifying an object - Use
'edit'context for admin forms,'view'context for frontend display - Use
wc_get_orders()/wc_get_products()for queries, notWP_Query - Declare HPOS compatibility in every extension
- Test with HPOS authoritative mode enabled
Fetch the WooCommerce CRUD and HPOS documentation for exact method signatures, query parameters, and compatibility requirements before implementing.