WooCommerce Development
Guidelines for developing WooCommerce plugins and themes with HPOS (High-Performance Order Storage) compatibility.
HPOS Compatibility
All WooCommerce sites in this project use High-Performance Order Storage (HPOS), which stores orders in custom database tables instead of the wp_posts table. This requires specific coding patterns to ensure compatibility.
✅ Correct Patterns
Order Meta Access
Always use WC_Order object methods:
// ✅ CORRECT - HPOS compatible
$order = wc_get_order( $order_id );
$value = $order->get_meta( 'meta_key' );
$order->update_meta_data( 'meta_key', 'value' );
$order->save();
Never use WordPress post meta functions directly:
// ❌ WRONG - Not HPOS compatible
$value = get_post_meta( $order_id, 'meta_key', true );
update_post_meta( $order_id, 'meta_key', 'value' );
delete_post_meta( $order_id, 'meta_key' );
Order ID Access
// ✅ CORRECT
$order_id = $order->get_id();
// ❌ WRONG - Deprecated
$order_id = $order->id;
Custom Admin Columns
When adding custom columns to the orders admin screen, you must register both legacy and HPOS hooks:
// Legacy post-based orders
add_filter( 'manage_edit-shop_order_columns', 'add_column' );
add_action( 'manage_shop_order_posts_custom_column', 'render_column', 10, 2 );
// HPOS orders
add_filter( 'manage_woocommerce_page_wc-orders_columns', 'add_column' );
add_action( 'manage_woocommerce_page_wc-orders_custom_column', 'render_column_hpos', 10, 2 );
function render_column( $column_name, $post_id ) {
$order = wc_get_order( $post_id );
// Render column content
}
function render_column_hpos( $column_name, $order ) {
// $order is already a WC_Order object
// Render column content
}
See examples:
Automatic Compatibility Checking
Command Line
Run HPOS compatibility check manually:
composer check-hpos
This scans for:
get_post_meta()/update_post_meta()usage on orders- Deprecated
$order->idproperty access - Legacy admin column hooks without HPOS equivalents
Pre-commit Hook
The HPOS check runs automatically on WooCommerce files via husky pre-commit hook configured in package.json:
"lint-staged": {
"packages/wordpress/plugins/*woocommerce*/**/*.php": [
"./tools/check-hpos-compat.sh"
],
"packages/wordpress/themes/nettbutikk/**/*.php": [
"./tools/check-hpos-compat.sh"
]
}
CI/CD
GitHub Actions runs the check on all pull requests. See .github/workflows/lint.yaml.
Common Pitfalls
1. Direct Database Queries
// ❌ WRONG - Queries wp_posts table
$wpdb->get_results("
SELECT * FROM {$wpdb->posts}
WHERE post_type = 'shop_order'
");
// ✅ CORRECT - Use WooCommerce APIs
$orders = wc_get_orders( [
'status' => 'completed',
'limit' => -1,
] );
2. Order Hooks
// ❌ WRONG - Only works with legacy storage
add_action( 'save_post_shop_order', 'callback' );
// ✅ CORRECT - Works with both
add_action( 'woocommerce_update_order', 'callback' );
add_action( 'woocommerce_new_order', 'callback' );
3. Admin Editing
// ❌ WRONG - Only works with legacy post-based editing
add_action( 'woocommerce_process_shop_order_meta', 'callback', 10, 2 );
// ✅ CORRECT - Works with HPOS admin editing
add_action( 'woocommerce_process_shop_order_meta', 'callback', 10, 2 ); // Legacy
add_action( 'woocommerce_update_order', 'callback' ); // HPOS
Plugin Examples
Compatible Plugins in This Repo
- ✅
nb-woocommerce-participant- Custom participant fields - ✅
nb-woocommerce-contact- Contact information fields - ✅
nb-woocommerce-invoice-payment- Invoice payment gateway - ✅
nb-woocommerce-employee-discount- Employee discount system - ✅
nb-woocommerce-retailer-discount- Retailer discount system
External Plugins (Verified Compatible)
- ✅ DIBS Easy for WooCommerce (Nexi) - v2.0+
- ✅ Advanced Custom Fields Pro - v6.1+
- ✅ Gravity Forms - v2.7+
- ✅ WooCommerce Stripe Gateway - Official, HPOS compatible
External Integrations
Python integrations in integrations/ use the WooCommerce REST API, which is fully HPOS compatible. No code changes are needed for REST API consumers.
# ✅ REST API works identically with HPOS
response = requests.get(
f'{site_url}/wp-json/wc/v3/orders',
auth=(consumer_key, consumer_secret)
)
Resources
Migration Checklist
When creating or updating WooCommerce plugins:
- [ ] Use
$order->get_meta()/$order->update_meta_data()instead ofget_post_meta()/update_post_meta() - [ ] Use
$order->get_id()instead of$order->id - [ ] Register both legacy and HPOS admin column hooks
- [ ] Use WooCommerce order APIs instead of
WP_Queryfor orders - [ ] Test with HPOS enabled in local environment
- [ ] Run
composer check-hposbefore committing - [ ] Verify pre-commit hook passes