There are three different WooCommerce hooks after payment completed I would like to talk about.

  • woocommerce_pre_payment_complete,
  • woocommerce_payment_complete,
  • woocommerce_payment_complete_order_status_$status;

All of those hooks are fired when an order is either paid or doesn’t require a payment (Cash on Delivery for example). They also apply for custom payment gateways.


The first hook, woocommerce_pre_payment_complete applies at the very beginning and doesn’t depend on order status.

add_action( 'woocommerce_pre_payment_complete', 'rudr_pre_complete' );

function rudr_pre_complete( $order_id ) {
	$order = wc_get_order( $order_id );
	// get the order data and do anything
  • All the code snippets you see in this tutorial you can insert to your current theme functions.php file or create a plugin for that if your theme receives updates.
  • You can get a lot of information from the $order object, like $order->get_items() to get order items or $order->get_payment_method() to get a payment method slug or $order->get_user_id() to get a customer ID.


The next one, woocommerce_payment_complete will be fired only if an order has one of the following order status on-holdpendingfailedcancelled, but please keep in mind that this list of statuses can also be filtered with woocommerce_valid_order_statuses_for_payment_complete.

But before the hook applies, WooCommerce is going to change the order status either to processing or completed, which also can be filtered with woocommerce_payment_complete_order_status.

add_action( 'woocommerce_payment_complete', 'rudr_complete' );

function rudr_complete( $order_id ) {
	$order = wc_get_order( $order_id );
	// do anything


And the last but not least, woocommerce_payment_complete_order_status_$status will be fired for the rest of the order statuses.

add_action( 'woocommerce_payment_complete_order_status_processing', 'rudr_complete_for_status' );
add_action( 'woocommerce_payment_complete_order_status_completed', 'rudr_complete_for_status' );

function rudr_complete_for_status( $order_id ){
	// do anything

When I say “do anything”, I do not actually mean absolutely anything, for example, if you would like to perform a redirect, it is better to be done with template_redirect hook

In some tutorials I also saw woocommerce_payment_complete_order_status and woocommerce_order_status_completed but I think their usage is less correct.