Skip to content
codecollab.pl
§ Blog woocommerce hpos

WooCommerce HPOS - what changes and how to migrate without breaking orders

If your store has been running on WooCommerce for a few years, it most likely still keeps orders in the same place as blog posts

Krystian Kacik 11 min read
Contents

If your store has been running on WooCommerce for a few years, it most likely still keeps orders in the same place as blog posts - in the generic WordPress tables. WooCommerce HPOS, short for High-Performance Order Storage, is the newer way of storing orders: the store gets its own database tables, designed for commerce rather than for content. Stores created today have it switched on from day one. Older ones do not, until somebody changes the setting by hand.

And this is exactly the kind of change that takes a quarter of an hour at one client and ends at another with an order screen where half the integrations stop seeing new purchases. The difference is not in the switch itself, but in what surrounds it: invoicing plugins, courier plugins, warehouse integrations, custom theme code somebody wrote years ago.

Below I go through it in order: what the change really does in the database, what tends to break, how to run it so that you can still go back, and when it is worth touching at all. Without going deeper into code than a store owner needs.

WooCommerce HPOS - what changes in the database and why older stores do not have it

WordPress has always kept nearly everything in two tables: one for posts and one for their extra data. A blog post, a page, a product and, for years, an order too - all of it landed in the same bucket. For a blog that is perfectly fine. For a store that has accumulated tens of thousands of orders it gets cramped: every question along the lines of “show me this customer’s orders from last month” has to dig through a table that holds the rest of the site as well.

HPOS solves this in the simplest possible way: orders get their own tables. The database gains wc_orders, wc_order_addresses, wc_order_operational_data and wc_orders_meta - separate homes for the order itself, for addresses, for operational data and for metadata. Queries no longer have to fight their way through posts, because they ask about orders directly.

Why might your store not have it? Because WooCommerce never flipped the switch retroactively. Since version 8.2, released in October 2023, HPOS is the default for new installations. Stores set up earlier stayed on the old order storage and will stay there until somebody deliberately changes the setting. That is a sensible call: migrating data automatically across thousands of stores with an unknown mix of plugins would have produced a wave of outages.

Checking what you run takes a minute. In the admin you go to WooCommerce > Settings > Advanced > Features and look at the order data storage section. You will see two options there: WordPress posts storage (legacy) and High-performance order storage (recommended). The one selected is what your store works on right now.

What helps: before you change anything, take a screenshot of that setting together with your plugin list. When something starts behaving oddly a week later, you will know what state you started from.

What can break - plugins, integrations and custom code

Moving orders to different tables is safe in itself. What is risky is that a good chunk of the code around a store was written on the assumption that an order is a WordPress post.

The most common sources of trouble, in the order I run into them:

  • Plugins that write straight into the posts table. An order note, a tracking number, a shipping status - if a plugin saves it the old way, under HPOS it goes into a void. The order works, but that particular field disappears.
  • Custom theme code. The classic case is update_post_meta() and get_post_meta() used on orders. They work as long as the store sits on the old tables, and quietly stop after the switch. The correct approach is the order object’s own methods, $order->update_meta_data() and $order->get_meta(). I wrote about this in more detail in the piece on custom checkout fields.
  • External integrations. Warehouse systems, invoicing tools, courier plugins and accounting exports - most well-known solutions are compatible today, but a two-year-old version nobody has updated is a different story. If your order sync stops right after the change, an outdated connector plugin is the first suspect.
  • Old reports and one-off scripts. Anything somebody once wrote to pull data with a direct database query once a month has to be reviewed separately. The admin will not warn you about those.

The good news is that WooCommerce will not let you walk into this blindfolded. On the settings screen it checks installed extensions for compatibility, and if any of them does not declare support for the new order storage, the option to switch is disabled and a View and manage link appears next to it with the list of incompatible extensions. That list is your first concrete piece of work: either you update them to newer versions, or you find replacements, or you stay on the old storage.

Worth knowing: not being on the list is not a full guarantee. The list covers plugins that have explicitly declared compatibility or the lack of it. Code added directly to a theme, or a private plugin built to order, declares nothing, and nobody will check it for you.

How to switch safely, step by step (staging, sync, rollback)

The order of operations matters more here than the operation itself. This is how I run it:

  1. A full backup - files and database. Not just the database. The backup has to be recent enough that restoring it costs you minutes, not days.
  2. A copy of the store on a staging environment. You test the switch on a copy, not on the store that is taking orders. On staging you walk the whole path: place a test order, issue an invoice, create a shipment, check the accounting export and every integration you have connected.
  3. Plugin updates before the change, not during it. Compatibility with the new order storage arrived with newer versions. Run those updates as a separate step, following the same safe WooCommerce update checklist, so that if something breaks you know what caused it.
  4. Turn compatibility mode on. In the same settings there is a checkbox labelled Enable compatibility mode (synchronizes orders to the posts table). Compatibility mode keeps order data in the new tables and in the old post tables at the same time. It is slower, because the store writes everything twice, but it is what gives you a way back.
  5. Switch to the new storage and wait for the backfill. WooCommerce does not copy everything in one go - it schedules background actions that move the orders gradually. You do not need to close the store or put it into maintenance mode for that. You do need to wait until those actions finish before you call the job done.
  6. A day of watching. For the first 24 hours you check everything that touches orders: whether new orders reach the list, whether emails go out, whether invoices are issued, whether the warehouse integration sees fresh items.

Rolling back looks the same in reverse: you make sure compatibility mode is on and the sync has completed, and only then select WordPress posts storage (legacy). That is why you do not disable compatibility mode the moment the migration succeeds - while it is on, you have an emergency exit. It is the same logic I apply to every optimization job on an existing store: a change goes in only once I know how to get out of it.

What helps: decide up front how you will know something went wrong, ideally through a number you check daily anyway - the count of orders that reached your warehouse system. If in the morning it matches the count in the store admin, the migration worked.

When it makes sense and what I do differently

Let me start with what I will not promise: a specific speed gain. How much you gain depends on the number of orders, the hosting, the plugins and how bloated the database is. A store with a few hundred orders on cramped shared hosting will not feel a difference, because its problem is not the order tables but everything else - which is what I cover in the piece on why a WooCommerce store runs slow. A store with tens of thousands of orders and an admin order list that takes forever to open is a completely different conversation, and there the change can be felt immediately.

My sequence is this: first I establish whether the store actually slows down on orders or somewhere else. If what hurts the client is the product page rather than the admin, moving order storage fixes nothing and only adds risk. If it is the admin and a sluggish order database, HPOS is the right tool.

The second thing I treat differently from most guides: I do not leave compatibility mode on forever. It often stays switched on “just in case”, and the store spends years writing everything twice, losing exactly the thing it migrated for. Compatibility mode is a lifeboat, not a destination. I take it off after the observation period, once I know nothing is falling back to the old tables.

The third point is new, and worth knowing if you are tackling this now. Until recently there was a sync mechanism working in the other direction too: when some piece of code wrote data straight into the old tables, bypassing WooCommerce, the store could still pull it across. In version 10.7, released on 14 April 2026, WooCommerce disabled that sync-on-read by default and announced it may be removed entirely later. The practical effect: code that somehow got away with it a year ago now fails quietly. If your store carries a plugin or a theme snippet like that, the time for postponing the fix is over - and that applies equally to stores that moved to HPOS long ago.

Summary

HPOS moves orders out of the generic WordPress tables and into dedicated store tables. New stores have had it from the start; older ones sit on the old storage until somebody deliberately switches. The change itself is one setting, but the value of the whole operation lies in what you do around it: a backup, a test on a copy of the store, plugin updates as a separate step, compatibility mode as the way back, and a day of watching.

If you do not know whether your store already runs on it, or which of your plugins would survive the switch - send me the store address and a list of your integrations. I will check which order storage you are on, what is blocking the change and whether it is worth the effort in your case at all.

Frequently asked questions

How do I know whether my store already uses HPOS? In the WooCommerce admin, under the advanced settings, in the features section, you will find a choice between the legacy storage based on WordPress posts and the new high-performance order storage. Whichever is selected is your answer. If the store was created after October 2023 and nobody touched the setting, it most likely already runs on the new tables.

Will I lose old orders during the migration? No. Backfilling data into the new tables copies it rather than moving and deleting it, so the old tables stay in place. That is precisely why going back to the old storage is possible. It does not excuse you from taking a backup first, because the backup protects you from everything else that can go wrong along the way.

Does the store have to be closed during the migration? It does not. WooCommerce schedules the order backfill as background actions, so the store keeps selling throughout. Even so, it is better to pick the quietest hours for the switch itself - not because anything requires it, but because if something does go wrong, it affects fewer customers.

A plugin I use is on the incompatible list. What now? In order: check whether a newer version exists, because compatibility usually arrived with updates. If the plugin is no longer maintained, look for a replacement or commission a fix from a developer - in most cases it is a matter of changing how order data is saved, not rewriting the whole plugin. Until it is resolved, stay on the old storage; forcing the switch with an incompatible plugin is the shortest path to losing order data.


Sitting on this yourself and unsure where to start? I speed up and repair existing sites and stores - Core Web Vitals, outages, the features that are missing. Let’s talk about your project.

§ Let's talk about your project

Your store is slowing down or looks dated, and you do not know where to start?

Describe the scope in two sentences or send a link to your store. I tell you what to fix first, and you get the scope, hours and price in writing - no "from X" pricing.

I reply personally, in writing, with a price and a date. No newsletter.