A beta guide to WooCommerce Order Fulfillments
We’re excited to announce the beta release of WooCommerce Order Fulfillments, a new core feature that helps merchants track shipments, manage partial fulfillments, and share shipping updates with customers.
This system combines a user-friendly interface for store owners and a robust API for developers, enabling programmatic control and extension.
What are fulfillments?
A fulfillment represents the process of shipping items from an order. Each fulfillment may include:
- Items – products and quantities shipped.
- Status – Draft (prepared) or Fulfilled (shipped).
- Shipping Information – carrier, tracking number, tracking URL.
- Metadata – custom shipment details.
Orders can have multiple fulfillments, making split or partial shipments simple and trackable.
Guide for store owners
Accessing fulfillments
- Orders list – use the Fulfillment button in the “Fulfillment” column.
- Order details page – open the fulfillments panel.
Creating a fulfillment
- Select which items to ship.
- Add tracking information (choose from 70+ providers or enter manually).
- Choose whether to Save as Draft (no customer notification) or Fulfill (customer is notified).
Managing fulfillments
- Edit – update details or add tracking (customers can be notified if desired).
- Delete – remove incorrect fulfillments. If it was marked fulfilled, customers may receive a cancellation email.
Fulfillment statuses
- Draft – shipment prepared but not sent; no customer emails.
- Fulfilled – shipment sent; customer notified by default.
- Order-level status – calculated automatically:
- No Fulfillments
- Partially Fulfilled
- Fulfilled
- No Fulfillments
3rd-party extensions can add custom statuses.
Customer notifications
- Customers can receive emails for new, updated, or canceled fulfillments.
- Emails include shipment details, items, and tracking links.
- Drafts never trigger notifications.
Automatic fulfillment of digital items
Automatic fulfillment of digital items can all be changed via the settings screen. The following settings are dynamic:
- Downloadable items are auto-fulfilled by default.
- Virtual items can be set to auto-fulfill.
- In mixed orders, digital items are fulfilled automatically while physical items remain pending.
Guide for developers
REST API reference
The fulfillments system provides a comprehensive REST API under the /wc/v3/orders/{order_id}/fulfillments namespace. Refer to the Fulfillments REST API doc for more information.
Available hooks and filters
Refer to Fulfillment Hooks for detailed information.
Architecture
- Core classes – Fulfillment, FulfillmentsManager, FulfillmentsDataStore.
- REST API – /wc/v3/orders/{order_id}/fulfillments.
- React UI – with state in order/fulfillments data store.
Here are examples using PHP and React to help you extend and customize the feature:
PHP example
$fulfillment = new Fulfillment();
$fulfillment->set_entity_type( WC_Order::class );
$fulfillment->set_entity_id( 123 );
$fulfillment->set_status( 'fulfilled' );
$fulfillment->set_items( [ [ 'item_id' => 456, 'qty' => 2 ] ] );
$fulfillment->add_meta_data( '_tracking_number', '1Z999AA1234567890' );
$fulfillment->save();
JS example (frontend)
import { useSelect, useDispatch } from '@wordpress/data';
function MyComponent( { orderId } ) {
const { fulfillments, isLoading } = useSelect( ( select ) => ({
fulfillments: select( 'order/fulfillments' ).readFulfillments( orderId ),
isLoading: select( 'order/fulfillments' ).isLoading( orderId ),
}));
const { saveFulfillment } = useDispatch( 'order/fulfillments' );
}
Extensibility
Order Fulfillments does allow for extensibility, particularly with the ability to:
- Extend fulfillment statuses.
- Override notification behavior.
Below is an example of extending your choice of a shipping provider:
Add a Custom Shipping Provider
class MyCustomShippingProvider extends AbstractShippingProvider {
public function get_key(): string {
return 'my_custom_provider';
}
public function get_name(): string {
return 'My Custom Provider';
}
public function try_parse_tracking_number( string $tracking_number, string $shipping_from, string $shipping_to ): ?array {
// Custom tracking number validation logic
if ( $this->validate_tracking_format( $tracking_number ) ) {
return array(
'url' => "https://mycarrier.com/track/{$tracking_number}",
'ambiguity_score' => 100,
);
}
return null;
}
private function validate_tracking_format( string $tracking_number ): bool {
// Your validation logic here
return preg_match( '/^MC[0-9]{10}$/', $tracking_number );
}
}
// Attach your custom shipping provider
add_filter( 'woocommerce_fulfillment_shipping_providers', function( $providers ) {
$providers['my_custom_shipping_provider'] = MyCustomShippingProvider::class;
return $providers;
});
Best practices
For store owners
- Keep tracking numbers updated.
- Use partial fulfillments for multi-package shipments.
- Always verify carrier details before saving.
For developers
- Validate fulfillment data before saving.
- Wrap API calls in try/catch for error handling.
- Respect user permissions.
- Use batch operations for performance in bulk updates.
Troubleshooting
- Fulfillment not saving? Check permissions, order ID, and data format.
- Tracking not recognized? Verify format or enter provider manually.
- No notifications sent? Ensure the “Notify Customer” toggle is on and WooCommerce email settings are correct.
Try it out
Order Fulfillments feature is available starting with WooCommerce 10.2. To enable the beta:
wp option update woocommerce_feature_fulfillments_enabled yes
Once enabled, the Fulfillment status column will appear in the Orders screen.
NOTE: A UI toggle to enable/disable this feature will be available in future releases.
Share Your Feedback
We’d love to hear how it works for you!
- Join the GitHub Discussion
- Drop by the WooCommerce Community Slack, channel #developer-chat
Not in Slack yet? Join here.
Special thanks to @tpaksu for the original guide that shaped this release.
Leave a Reply