How to setup Shipment Tracking in WooCommerce

  • Add shipment tracking information to your orders
  • Provide customers with an easy way to track their shipment
  • Integrates with major shipping providers and softwares

If you need a way to easily add shipment tracking details to orders in your WooCommerce store, then we’ve got the solution for you.

In this tutorial, we’ll show you how to set up Shipment Tracking on your WooCommerce store. Shipment Tracking is an easy way to allow customers to track their shipments.

It costs just $49 a year and supports over 15 of the world’s major shipping providers out of the box. Yes, that includes USPS, FedEx, UPS, and DHL. See the full shipping provider list.

The plugin also integrates with 3rd party tools like ShipStation, Shippo, ShippingEasy and others.

For example, let’s say you want to use ShipStation and are trying to figure out how to connect with your WooCommerce store. When a new shipment is created in ShipStation it will sync the tracking number back to WooCommerce and also update the order in WooCommerce from Processing to Completed. You will not have to manually add the tracking number for each shipment. I also recommend turning off the notification email in ShipStation that sends to your customers. How come? The Completed Order email in WooCommerce will include the tracking number. Just make sure you are using the free ShipStation plugin and the Shipment Tracking plugin and everything will be integrated.

If you are more of a visual learner, see the video below that goes over how to do this! I also have another video at the bottom of the post that may be helpful as well!

Let’s jump into it!

How to setup Shipment Tracking in WooCommerce

The first step is to purchase the Shipment Tracking plugin.

Next, download the .zip file and navigate to your WordPress dashboard.

Then, go to Plugins, add a new plugin, and upload the .zip file.

Finally, activate the plugin. If you navigate to the WooCommerce Orders page in your WooCommerce backend, you will see that the Shipment Tracking column has been added.

How to add a tracking number to an order

If you use ShipStation, Shippo, ShippingEasy or another shipping platform they will automatically integrate with the Shipment Tracking plugin. For example, if a shipment is created in ShipStation it will automatically send the tracking number to WooCommerce and update the Order Status from Processing to Completed and send out the Completed Order email with the tracking number. However, if you are curious how to manually add a tracking number here is how to do so.

– Go to WooCommerce > Orders and click on an order.

– Next, in the top righthand corner, click Add Tracking Number.

– Then, add the Provider and Tracking Number.

– Finally, click Save Tracking.

Finally, if you want to let your customer know that their order has been shipped and provide an email notification with their tracking URL, simply update the order status from Processing to Completed.

This will trigger the Completed Order Email to send to the customer with your branding and includes a tracking number that is linked to USPS, FedEx, UPS, or whatever you use as your shipping provider.

Here is an example:

In addition, your customer will also be able to see their tracking number on the My Account page.

For example:

Pretty cool eh!?

How can you automate this process further?

If you use a plugin such as ShippingEasy or ShipStation to print off your labels, these shipping tools will automatically POST back to your WooCommerce store with the tracking number.

Here is how the process works:

  1. Customer orders a product on your store
  2. Orders that are “processing” will be exported to ShipStation or ShippingEasy
  3. Store manager prints off label and ships product to the customer
  4. ShippingEasy or ShipStation POST back to your WooCommerce store and updates order status to “completed”
  5. Automated email goes out to the customer that their shipment is on their way with tracking code available on the email

How to add shipment tracking from custom order meta

You are trying to integrate a 3rd party integration (like DEAR Inventory) with the WooCommerce Shipment Tracking plugin.

However, the issue is that the _wc_shipment_tracking_items order meta is in an array.

I CANNOT specify the field name when it’s inside an array.

Thus, we have to do a workaround!

First, add the following fields to your order meta data:

  • _tracking_number
  • _tracking_provider
  • _date_shipped

This will show up as order meta data in your WooCommerce Order, but not yet inside the meta key _wc_shipment_tracking_items.

woocommerce-shipment-tracking-dear-inventory-integration

Next, add this snippet to your functions.php file:

function auf_order_status_completed($order_id) {

    if (class_exists('WC_Shipment_Tracking')) {

    	if (function_exists('wc_st_add_tracking_number')) {

    		$tracking_number = get_post_meta($order_id, '_tracking_number', true);
    		$carrier = get_post_meta($order_id, '_tracking_provider', true);
    		$timestamp = get_post_meta($order_id, '_date_shipped', true);
    		
			wc_st_add_tracking_number($order_id, $tracking_number, $carrier, $timestamp);

		}
    }
}

add_action('woocommerce_order_status_completed', 'auf_order_status_completed', 10, 1 );

This snippet updates the _wc_shipment_tracking_items order meta when the Order is shipped, based on your custom fields you defined.

Let me know if this snippet works for you!

How to return real-time rates to customers during Checkout?

If you want to return real time rates to your customers during the Checkout process, USPS, UPS, and FedEx have separate plugins for that.

Customizations

To further improve the experience with the Shipment Tracking plugin, you’ll want your customers to be able to access their tracking info directly from the frontend of your site’s My Account page.

Let’s look at how to set this up so your customers can see the Track Shipment link next to their Orders.

First, edit your active WordPress theme via SFTP or SSH. I use FileZilla.

Next, create a ‘woocommerce’ folder inside your active WordPress theme if you have not already. This will allow you to override core WooCommerce files.

Then, inside the /woocommerce/ folder, create another folder titled ‘myaccount’.

Next, open up the file inside your /woocommerce/myaccount/ folder called orders.php.

Edit your current orders.php file and search for the following snippet on lines 56 and 57:

// Search for this line of code in your orders.php file
<?php elseif ( 'order-status' === $column_id ) : ?>
	<?php echo esc_html( wc_get_order_status_name( $order->get_status() ) ); ?>

Replace with this snippet below:

// replace with the following code below in your orders.php file
<?php elseif ('order-status' === $column_id) :

	$status = $order->get_status();
	$column_output = "";

	// show tracking link
	if ($status == 'completed' && class_exists('WC_Shipment_Tracking_Actions')) {

		$st_actions = WC_Shipment_Tracking_Actions::get_instance();

		if ($tracking_items = $st_actions->get_tracking_items($order->get_id(), true)) {

			foreach ($tracking_items as $tracking_item) {

				if ($tracking_item['formatted_tracking_link'] !== '') {

					$column_output = sprintf("<a href='%s' target='_blank'>%s</a>",
						$tracking_item['formatted_tracking_link'], __('Track Shipment', 'bdl'));

					break;
				}
			}
		}
	}

	if (empty($column_output))
		$column_output = esc_html(wc_get_order_status_name($status));

	echo $column_output; ?>

If you would rather just replace the entire orders.php file, copy the code below and replace it.

<?php
/**
 * Orders
 *
 * Shows orders on the account page.
 */

defined( 'ABSPATH' ) || exit;

do_action( 'woocommerce_before_account_orders', $has_orders ); ?>

<?php if ( $has_orders ) : ?>

	<table class="woocommerce-orders-table woocommerce-MyAccount-orders shop_table shop_table_responsive my_account_orders account-orders-table">
		<thead>
			<tr>
				<?php foreach ( wc_get_account_orders_columns() as $column_id => $column_name ) : ?>
					<th class="woocommerce-orders-table__header woocommerce-orders-table__header-<?php echo esc_attr( $column_id ); ?>"><span class="nobr"><?php echo esc_html( $column_name ); ?></span></th>
				<?php endforeach; ?>
			</tr>
		</thead>

		<tbody>
			<?php
			foreach ( $customer_orders->orders as $customer_order ) {
				$order      = wc_get_order( $customer_order ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
				$item_count = $order->get_item_count() - $order->get_item_count_refunded();
				?>
				<tr class="woocommerce-orders-table__row woocommerce-orders-table__row--status-<?php echo esc_attr( $order->get_status() ); ?> order">
					<?php foreach ( wc_get_account_orders_columns() as $column_id => $column_name ) : ?>
						<td class="woocommerce-orders-table__cell woocommerce-orders-table__cell-<?php echo esc_attr( $column_id ); ?>" data-title="<?php echo esc_attr( $column_name ); ?>">
							<?php if ( has_action( 'woocommerce_my_account_my_orders_column_' . $column_id ) ) : ?>
								<?php do_action( 'woocommerce_my_account_my_orders_column_' . $column_id, $order ); ?>

							<?php elseif ( 'order-number' === $column_id ) : ?>
								<a href="<?php echo esc_url( $order->get_view_order_url() ); ?>">
									<?php echo esc_html( _x( '#', 'hash before order number', 'woocommerce' ) . $order->get_order_number() ); ?>
								</a>

							<?php elseif ( 'order-date' === $column_id ) : ?>
								<time datetime="<?php echo esc_attr( $order->get_date_created()->date( 'c' ) ); ?>"><?php echo esc_html( wc_format_datetime( $order->get_date_created() ) ); ?></time>

							<?php elseif ('order-status' === $column_id) :

								$status = $order->get_status();
								$column_output = "";

								// show tracking link
								if ($status == 'completed' && class_exists('WC_Shipment_Tracking_Actions')) {

									$st_actions = WC_Shipment_Tracking_Actions::get_instance();

									if ($tracking_items = $st_actions->get_tracking_items($order->get_id(), true)) {

										foreach ($tracking_items as $tracking_item) {

											if ($tracking_item['formatted_tracking_link'] !== '') {

												$column_output = sprintf("<a href='%s' target='_blank'>%s</a>",
													$tracking_item['formatted_tracking_link'], __('Track Shipment', 'bdl'));

												break;
											}
										}
									}
								}

								if (empty($column_output))
									$column_output = esc_html(wc_get_order_status_name($status));

								echo $column_output; ?>

							<?php elseif ( 'order-total' === $column_id ) : ?>
								<?php
								/* translators: 1: formatted order total 2: total order items */
								echo wp_kses_post( sprintf( _n( '%1$s for %2$s item', '%1$s for %2$s items', $item_count, 'woocommerce' ), $order->get_formatted_order_total(), $item_count ) );
								?>

							<?php elseif ( 'order-actions' === $column_id ) : ?>
								<?php
								$actions = wc_get_account_orders_actions( $order );

								if ( ! empty( $actions ) ) {
									foreach ( $actions as $key => $action ) { // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
										echo '<a href="' . esc_url( $action['url'] ) . '" class="woocommerce-button button ' . sanitize_html_class( $key ) . '">' . esc_html( $action['name'] ) . '</a>';
									}
								}
								?>
							<?php endif; ?>
						</td>
					<?php endforeach; ?>
				</tr>
				<?php
			}
			?>
		</tbody>
	</table>

	<?php do_action( 'woocommerce_before_account_orders_pagination' ); ?>

	<?php if ( 1 < $customer_orders->max_num_pages ) : ?>
		<div class="woocommerce-pagination woocommerce-pagination--without-numbers woocommerce-Pagination">
			<?php if ( 1 !== $current_page ) : ?>
				<a class="woocommerce-button woocommerce-button--previous woocommerce-Button woocommerce-Button--previous button" href="<?php echo esc_url( wc_get_endpoint_url( 'orders', $current_page - 1 ) ); ?>"><?php esc_html_e( 'Previous', 'woocommerce' ); ?></a>
			<?php endif; ?>

			<?php if ( intval( $customer_orders->max_num_pages ) !== $current_page ) : ?>
				<a class="woocommerce-button woocommerce-button--next woocommerce-Button woocommerce-Button--next button" href="<?php echo esc_url( wc_get_endpoint_url( 'orders', $current_page + 1 ) ); ?>"><?php esc_html_e( 'Next', 'woocommerce' ); ?></a>
			<?php endif; ?>
		</div>
	<?php endif; ?>

<?php else : ?>
	<div class="woocommerce-message woocommerce-message--info woocommerce-Message woocommerce-Message--info woocommerce-info">
		<a class="woocommerce-Button button" href="<?php echo esc_url( apply_filters( 'woocommerce_return_to_shop_redirect', wc_get_page_permalink( 'shop' ) ) ); ?>">
			<?php esc_html_e( 'Go to the shop', 'woocommerce' ); ?>
		</a>
		<?php esc_html_e( 'No order has been made yet.', 'woocommerce' ); ?>
	</div>
<?php endif; ?>

<?php do_action( 'woocommerce_after_account_orders', $has_orders ); ?>

Video Tutorials

Summary

The WooCommerce Shipment Tracking plugin is an easy-to-use plugin if you need a solid way to allow your customers to track their shipments.

You can use this plugin to allow your customers to track their order with the world’s major shipping providers, ensuring your brand remains linked in their minds to a high-quality and professional delivery service.

Additional Resources

Simon Gondeck

I’m a big fan of WordPress + WooCommerce (especially WooCommerce Subscriptions). Check out my YouTube channel.

21 thoughts on “How to setup Shipment Tracking in WooCommerce”

  1. I drop ship through a company for some orders and need to manually add tracking. My “shipment tracking” box is empty, with not button to add tracking information. Thoughts on why? Does something need updated? Thank you!

    Reply
  2. So I am using ShipStation and they report the tracking number in the order notes as soon as I buy a label.

    I am using Orders Tracking for WooCommerce, but the tracking number is never found because it is in the notes. So I don’t need that plugin if I use the one you recommend WooCommerce Shipment Tracking?

    also, I had a shipment delivered earlier this week on Tuesday. But ShipStation still shows it as Shipped. So, how will it ever get updated to completed on my store?

    do I have to manually watch and mark them? That will be tough because we are opening the store world wide, one country per week until we have every country we are opening finished.
    I don’t want to have to do this manually. I already have to process every order manually, the orders are started as “pending verification” then I have to verify them and mark them as “Approved”. Then I can go to ShipStation and manually buy the label and download it. Then I have to email it over to our warehouse.

    That is pain enough, I wish I could automate 100% of it.
    I mean, at most I would only want to verify payments then wish the rest could be automated. Because even just verifying payments could be a huge job, when this site takes off. We are the only company using Affiliates for these products, outside of Amazon…

    and the products are needed by everyone, so if someone can afford them, I’m sure we are going to be selling TONS.
    They help make a cleaner environment, make engines run more efficiently, save on gas mileage and protect the engines. But they are not just for Engines, they have products for just about everything. Homes, Small Engines, Transmissions, Power Steering and even weapons!

    So I need to automate as much of this as I can.
    So, can I delete Orders Tracking for WooCommerce if I am using WooCommerce Shipment Tracking?

    Reply
  3. Finally someone with a similar problem to me. I’m importing with WP All Import but when the function executes the tracking details return blank. The tracking is created, the complete status is triggered and the email sent but my information in the meta fields does not populate the array. Have you experienced anything like this? It’s doing my head in!

    Reply
  4. Hi Simon, thanks for putting this together! Do you know if PirateShip also automatically feeds the tracking number into Shipment Tracking? Currently, the PirateShip support page only talks about adding the tracking number as an Order Note or Customer Note. Is there a way to grab this and feed it in automatically into Shipment Tracking?

    Reply
    • Hey there! Pirate Ship does not feed the tracking number into Shipment Tracking. Try reaching out to their support team to see if they can make this happen with their integration.

      Reply
  5. Hi

    10% of our sales are for temporarily out of stock items. Most orders with out of stock items also include in-stock items, so we’ve got the challenge of tracking what items have and haven’t shipped in an order.

    We use shipstation and its nicely integrated into our Woo setup.

    curious about a configuration of the the integration, even if another plugin is required, that would allow us to track unshipped, ordered items.

    Thanks in advance.

    Reply
  6. Any way to link Pirateship with this plugin? Pirateship currently integrates with Woocommerce by sending the shipment tracking number via customer note. But of course, this does not update the tracking number in the plugin. Thanks for any help

    Reply
    • Hey Max, try reaching out to Pirate Ship to see if they can add this integration with the Shipment Tracking plugin.

      Reply
  7. Hello Simon,

    I already integrated woocomerce store to shipstation

    So second step is set up shipment tracking?

    thanks

    Reply
    • yes that is correct! ShipStation will automatically integrate with WooCommerce Shipment Tracking. Let me know if you have any issues.

      Reply
  8. Hi Simon,

    The verbiage in the different sections confused me a little. Are you saying that with the Shipment Tracking and Shipstation plugins, It can automatically inject the tracking number into the Completed Order email sent from woocommerce?

    Reply
  9. Thanks for sharing this! I have this plug-in but we get the tracking info and order status updates via a REST API not DEAR. At the moment the plug-in isn’t automatically sourcing the tracking numbers, while it used to. Would you be able to help me with a solution please?

    Reply
  10. Unfortunately the code does not work.
    I know the template is being overwritten, because I can force a blank page if I delete all the code, but the inclusion does not create a new column for tracking.

    Reply
  11. Just so I understand this correctly. The code you added doesn’t add a tracking number to the “completed order” email notice correct? It’s just for the user inside their my account page. Correct? So there’s no way of using a snippet to add it to the notice. We have to use a plugin?

    Thanks

    Reply
  12. Hi Simon, thanks for the tutorial. I have the plugin setup but curious how I can copy and override the orders.php file in my theme. I am stuck on how to do this. Any insight?

    Reply

Leave a Comment