High order volume is one of the best problems a store can have, but it can really slow down your site’s performance. That’s why our team’s main focus this year (and going into 2017) is performance and scalability.

We’ve put in motion a plan spanning several releases to help us tackle scalability head on, and you can read some of our discussions about orders in particular in this issue.

The first step, and something we’ve invested a lot of time in for WooCommerce 2.7, is abstracting the way we store and retrieve WC data. Why? Because right now we have no knowledge of how developers write data to the database for things like orders and products. A developer can use update_post_meta  calls, direct database writes with the $wpdb class, or the REST API as some examples. If we want to optimize where this data is stored, we first need to ensure developers use a single method of sending this data.

Retrieving data is also fragmented at present. You can use get_posts, $wpdb, WP_Query… all of which require you to know what type of data you’re trying to query.

Ideally, developers should not need to know or care about where and how their data gets stored. Be it meta data, or term data, it should not matter. This is why we’re abstracting everything.

What is CRUD?

CRUD is an abbreviation of the 4 basic operations you can do to a database or resource – Create, Read, Update, Delete.

The benefits:

  • We define the structured data for each resource.
  • We control the flow of data, and any validation needed.
  • As a developer, you don’t need to know the internals of the data you’re working with, just the names.
  • Once abstracted, the data can be moved elsewhere e.g. custom tables, without affecting existing code.
  • We can use the same code for updating things in admin as we do in the REST API and CLIs – everything is unified.
  • Less code = less change to malfunction and more unit test coverage.

Which resources will have a CRUD system in place?

We’re implementing CRUD in:

  • Products (in progress)
  • Customers
  • Orders
  • Order items
  • Coupons

These are the main types of data in WooCommerce and are currently each a custom post type, except for customers which are users and user meta.

Admin won’t be the only part of WooCommerce using the new CRUD operations – our REST API will too. This will make it all easier to maintain and more testable.

In addition, we’re working on making our CLI use the REST API, so again, this consolidates our code base and makes everything much more maintainable.

Examples of using the CRUD

Let’s take an existing example. I want to update an order’s address. With the current code base I’d end up doing something like the following:

$order_id = 100;
update_post_meta( $order_id, '_billing_first_name', 'Fred' );
update_post_meta( $order_id, '_billing_last_name', 'Flintstone' );

I need to know the post ID, the meta keys for each field, and I need to handle all validation myself.

Now the CRUD example:

$order = wc_get_order( 100 );
$order->set_billing_first_name( 'Fred );
$order->set_billing_last_name( 'Flintstone' );
$order->save();

I know an order has a billing first and last name property, but I don’t need to know that it’s post meta, nor that the keys are _billing_first_name and _billing_last_name. If those keys changed in the future, this code would be unaffected.

Getting data from the database follows a similar pattern. Old:

$order_id = 100;
$billing_name = get_post_meta( $order_id, '_billing_first_name', true ) . ' ' . get_post_meta( $order_id, '_billing_last_name', true );

New:

$order = wc_get_order( 100 );
$billing_name = $order->get_billing_first_name() . ' ' . $order->get_billing_last_name();

Where possible, the CRUD classes should handle mostly data reads and writes. Anything template related, such as getting HTML, should be moved to a template function. This is also something we’re working on in 2.7.

Examples of querying resources

Because we intend to move the data to a custom table in the future, it’s important that we offer a way to query the data without going through WordPress itself. Again, the developer should not need to know that orders are a custom post type named shop_order – this is irrelevant.

$customer_orders = get_posts( array(
    'numberposts' => 10,
    'meta_key'    => '_customer_user',
    'meta_value'  => get_current_user_id(),
    'post_type'   => wc_get_order_types( 'view-orders' ),
    'post_status' => array_keys( wc_get_order_statuses() )
) );

vs.

$customer_orders = wc_get_orders( array( 
    'customer' => get_current_user_id(), 
    'limit'    => 10,
) );

How will this affect existing plugins?

If you do anything with product, customer, orders, and coupons, you will be affected in some way. Even if you do a simple update meta call. This won’t break immediately, but your code will not be future proof. As soon as the schema changes in another update, your code will fail.

Helping out and testing

2.7 is scheduled for the new year. We will be releasing the first beta within the next month.

Orders, customers and coupons are all found in the master branch on Github here.

Products are still being built. Progress can be tracked in this PR.

It is very important, especially if you’re a plugin developer, that you get involved and start testing these classes as soon as possible. If you do anything with orders/products/customers, you need to be aware of the changes,  and if you need further changes or spot issues let us know as soon as possible. 

Feedback, code review, and PRs/contribution are welcome and encouraged on Github. We’d like to thank the developers working on this with us in advance. This will improve WooCommerce for everyone in the long run, so as a community let’s make it happen!