WooCommerce guides

Add a Retry Payment Button to WooCommerce Failed-Order Emails

A focused PHP example that adds WooCommerce’s secure order-pay link to an eligible customer failed-order email, plus the limits to test before using it.

Practical guidance from Ecom Plugin Co.

WooCommerce failed-order email with a clear retry-payment button

When a WooCommerce payment fails, the customer may receive an email without an obvious next step. This example adds WooCommerce’s own order-pay URL to the Customer failed order email, but only while the order still needs payment.

The code is intentionally small and fixed. It is useful when a developer can maintain the integration and test every active payment gateway. If you want editable copy, a settings screen and a supported implementation tested across current WooCommerce email formats, compare the snippet with Payment Rescue CTA.

Before you start: enable WooCommerce’s Customer failed order email. Add custom code as a small plugin or through a snippet manager, not directly to a parent theme. Back up the site and test on staging first.

The failed-order payment-link snippet

<?php
/**
 * Add an order-pay CTA to eligible WooCommerce customer failed-order emails.
 */
add_action(
	'woocommerce_email_order_details',
	static function ( $order, $sent_to_admin, $plain_text, $email ) {
		if (
			$sent_to_admin
			|| ! $order instanceof WC_Order
			|| ! $email instanceof WC_Email
			|| 'customer_failed_order' !== $email->id
			|| ! $order->needs_payment()
			|| 0 >= (float) $order->get_total()
			|| '' === trim( (string) $order->get_order_key() )
			|| false === is_email( (string) $order->get_billing_email() )
		) {
			return;
		}

		$payment_url = (string) $order->get_checkout_payment_url( false );

		if ( '' === trim( $payment_url ) ) {
			return;
		}

		$supporting_text = 'Your order still needs payment. You can try again using the link below.';
		$button_label    = 'Try payment again';

		if ( $plain_text ) {
			echo "\n" . $supporting_text . "\n";
			echo $button_label . ': ' . esc_url_raw( $payment_url ) . "\n\n";
			return;
		}

		printf(
			'<div style="margin:0 0 24px;"><p style="margin:0 0 16px;">%1$s</p><p style="margin:0;"><a href="%2$s" style="background:#1d2327;border-radius:3px;color:#fff;display:inline-block;font-weight:600;padding:12px 20px;text-decoration:none;">%3$s</a></p></div>',
			esc_html( $supporting_text ),
			esc_url( $payment_url ),
			esc_html( $button_label )
		);
	},
	5,
	4
);

What the code checks

  • It runs only for the customer-facing failed-order email, never the administrator notification.
  • It requires a real WooCommerce order that still needs payment, has a positive total, an order key and a valid billing email.
  • It asks WooCommerce for the protected checkout payment URL rather than building a URL manually.
  • It produces a button for HTML email and a readable raw URL for plain-text email.

The link opens WooCommerce’s order-pay flow. Depending on whether the order belongs to a registered customer or a guest, WooCommerce may require login or billing-email verification before showing payment details. Do not remove those checks merely to make testing easier.

How to test it safely

  1. Create a staging order with the same gateway and checkout type used by the live store.
  2. Move it through a genuine failed-payment path and confirm that exactly one Customer failed order email is generated.
  3. Open both HTML and plain-text versions. Confirm that the URL uses the store’s HTTPS origin and leads to the expected order-pay screen.
  4. Complete payment, then regenerate or preview the email and confirm that the action is no longer eligible once the order does not need payment.
  5. Repeat for guest and account-owned orders, and for every gateway customers can use to retry.

Snippet versus a maintained plugin

DIY snippetPayment Rescue CTA
Hard-coded English copyEditable button label and supporting text
The merchant maintains the PHPDedicated updateable plugin
Manual email compatibility testingTested HTML, plain-text and block-email paths
No settings screenFocused settings screen
No click trackingAlso avoids click tracking and order writes

Do not run this example together with Payment Rescue CTA: both use the same email area and customers may see two payment actions. The snippet also does not diagnose gateway errors, prevent failed orders, retry a charge automatically or decide whether a customer should be contacted.

Frequently asked questions

Does the link bypass WooCommerce security?

No. The snippet requests the standard order-pay URL. WooCommerce still applies the account, order-key and guest email-verification rules relevant to that order.

Will the original payment gateway always work on retry?

No. The order-pay screen provides another route to payment, but gateway availability, stored payment methods and the reason for the original failure still matter. Test the actual gateways used by the store.

Is this an abandoned-cart system?

No. It changes an existing transactional email for an order WooCommerce already marked failed. It does not monitor carts, send campaigns or schedule follow-ups.

For configurable production use, review Payment Rescue CTA and its exact compatibility notes. You can also browse more tested examples in WooCommerce snippets or continue with the failed-order diagnosis guide.