HPOS staat voor High Performance Order Storage. Klinkt als iets waarvoor je naar de huisarts gaat, maar het is de nieuwe manier waarop WooCommerce bestellingen opslaat. Sinds oktober 2023 is HPOS de standaard voor nieuwe webshops. Draai je een shop die eerder is gebouwd, dan staat het er waarschijnlijk nog niet aan.
Dat is zonde, want het is één van de weinige 'magische' knoppen waarmee je de beheeromgeving van een webshop in één keer een stuk sneller maakt.
Het probleem: bestellingen waren blogartikelen
WordPress kent één centrale tabel voor content: wp_posts. Daar staan pagina's in, blogartikelen, media, menu-items, en meer.
Toen WooCommerce werd gebouwd, is daar dankbaar gebruik van gemaakt. Een bestelling wordt opgeslagen als een artikel van het type shop_order. Alle unieke onderdelen van een bestelling (afleveradres, totaalbedrag, betaalmethode, transactie-ID, klant) past niet in zo'n algemene posts-tabel. Daarom worden die data opgeslagen in de tabel wp_postmeta: een lange lijst met sleutel-waardeparen, zonder structuur.
Wat je daarvan merkt:
- Het besteloverzicht wordt traag. Om één regel te tonen met klantnaam, bedrag en status moet de database die gegevens uit tientallen losse rijen bij elkaar sprokkelen. Twintig bestellingen op een pagina betekent honderden opzoekacties.
- Zoeken op e-mailadres of ordernummer duurt seconden. De waarden in
wp_postmetastaan in één kolom die alles moet kunnen bevatten. Daardoor kan er geen gebruik worden gemaakt van versnellende database-indexes. - Filteren op status of datum is 'duur'. Elk filter levert exponentieel veel meer queries op.
- Back-ups zijn onhandig. Bestellingen en blogartikelen worden in dezelfde tabellen opgeslagen. Daardoor kun je lastig wél posts en niet orderhistorie terugzetten, bijvoorbeeld.
Op een shop met vijfhonderd bestellingen valt dat allemaal reuze mee. Vanaf een paar tienduizend gaat je klant bellen dat "wp-admin zo traag is".
Hoe HPOS de performance terugbrengt
HPOS haalt bestellingen weg uit wp_posts en wp_postmeta en geeft ze vier eigen, geoptimaliseerde tabellen:
wp_wc_orders- de bestelling zelf: status, valuta, totaalbedrag, klant, datumwp_wc_order_addresses- factuur- en afleveradreswp_wc_order_operational_data- de operationele kant: betaalmethode, transactie-ID, of de voorraad al is afgeboektwp_wc_orders_meta- wat er verder nog aan een bestelling hangt, meestal vanuit plug-ins
Het verschil zit in de kolommen. Een totaalbedrag is nu een getal in een kolom die getallen verwacht. Een status is een waarde in een kolom met een index erop. De database hoeft niet meer alles bij elkaar te zoeken, want het staat al bij elkaar.
Concreet: het besteloverzicht in wp-admin laadt in een paar queries, in plaats van honderden, die ook nog eens veel sneller zijn dankzij indexes.
Aanzetten: hoe het werkt
Je vindt de schakelaar onder WooCommerce → Instellingen → Geavanceerd → Functies. Daar staan drie opties:
- WordPress posts storage (legacy) - de oude situatie
- High-performance order storage - de nieuwe tabellen zijn leidend
- Compatibiliteitsmodus - een vinkje dat beide sets tabellen synchroon houdt
Onder water is er altijd één set tabellen 'leidend': daar wordt uit gelezen en naar geschreven. De andere set is dan een kopie. Welke set leidend is, staat in de optie woocommerce_custom_orders_table_enabled. Of er wordt gesynchroniseerd, staat in woocommerce_custom_orders_table_data_sync_enabled.
Die compatibiliteitsmodus is je vangnet. Zolang die aanstaat, houdt WooCommerce beide sets bij. Blijkt er een verouderde plug-in te zijn die zich in HPOS verslikt - alle plug-ins moeten namelijk met HPOS compatibel zijn, en de meeste zijn dat - dan zet je de schakelaar terug op de oude opslag en verlies je niets. Het kost wel dubbel schrijfwerk, dus je zet hem weer uit zodra je er zeker van bent dat de shop helemaal op HPOS kan draaien.
Bij het aanzetten van HPOS migreert WooCommerce je bestaande bestellingen in batches op de achtergrond, via de Action Scheduler. Zet HPOS dus aan wanneer de shop het rustigst is. Bij grote shops duurt dat een tijd. Je kunt het in de gaten houden met WP-CLI:
wp wc cot sync --status
Voordat je omzet
- Kijk eerst welke plug-ins WooCommerce als incompatibel aanmerkt. Die lijst staat op dezelfde instellingenpagina. Zolang daar iets in staat, kun je de schakelaar niet omzetten.
- Doe het op een acceptatie-omgeving met een kopie van de echte data. Een shop met twaalf testbestellingen zegt niets over een shop met tachtigduizend.
- Zorg dat je een backup hebt waar je op terug kunt vallen. Op ons managed-hosting-platform Core is die er sowieso.
- Zet de compatibiliteitsmodus aan, laat de synchronisatie afronden, en pas daarna de schakelaar om.
- Loop de bestelflow na: een order plaatsen, terugbetalen, exporteren, een factuur genereren.
Voor ontwikkelaars: wat er in je code moet veranderen
Bouw je zelf plug-ins of maatwerk voor een WooCommerce-shop, dan is dit het deel dat telt. Alle code die een bestelling behandelt als een WordPress-artikel, gaat stuk zodra HPOS aanstaat. De bestelling staat immers niet meer in wp_posts.
Meld dat je plug-in meekan
WooCommerce gaat er standaard vanuit dat een plug-in nog niet klaar is voor HPOS. Zolang je niet expliciet definieert van wel, staat jouw plug-in op de lijst met incompatibele extensies en kan de shopbeheerder de schakelaar niet omzetten. Meld het dus:
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
);
}
} );
Gebruik de CRUD-methoden, niet de post-functies
Gebruik de functies van WooCommerce, in plaats van dat je posts direct manipuleert:
// Breekt onder HPOS
$post = get_post( $order_id );
$total = get_post_meta( $order_id, '_order_total', true );
update_post_meta( $order_id, '_mijn_veld', $waarde );
// Werkt in beide situaties
$order = wc_get_order( $order_id );
$total = $order->get_total();
$order->update_meta_data( '_mijn_veld', $waarde );
$order->save();
Voor het opvragen van meerdere bestellingen vervang je WP_Query door wc_get_orders():
$orders = wc_get_orders( [
'status' => 'processing',
'date_created' => '>' . ( time() - DAY_IN_SECONDS ),
'limit' => 50,
] );
Nog een laatste eigenaardigheid
Staat HPOS aan zonder synchronisatie, dan maakt WooCommerce nog steeds een lege rij in wp_posts aan, met het type shop_order_placehold. Puur om het bestel-ID te reserveren, zodat een eventuele latere synchronisatie de nummers niet door elkaar haalt. Kom je die tegen tijdens het opschonen van je database: laat staan.
Op Core controleren we HPOS elke dag voor je
Een bureau met veertig WooCommerce-shops in beheer wil niet veertig keer op wp-admin inloggen, en veertig keer naar dezelfde instellingenpagina klikken.
Op ons managed-hosting-platform Core controleren we actief of HPOS aanstaat: we voeren elke dag automatisch health-checks uit op alle sites die op Core draaien. Eén van die health-checks: controleren of HPOS wel aanstaat. Zo niet, dan herinneren we jullie daar actief aan.
Geen shop die er tussenuit glipt, geen jaarlijkse inventarisatieronde. Voor zover wij weten zijn wij de eerste en enige hoster die dit doet.
Kortom
HPOS is uit de experimentele fase. Het is de standaard voor nieuwe shops sinds WooCommerce 8.2, de oude opslag heet inmiddels officieel 'legacy', en het overgrote deel van de serieuze plug-ins is bij. Voor een shop van enige omvang is er alle reden om HPOS aan te zetten.
Twijfel je of het bij jullie shops aanstaat, of loop je vast op een plug-in die niet meewil? Neem contact met ons op. We kijken graag mee.
← Terug naar Insights