Automatically Log In Customer From WooCommerce Invoice

When sending manual payment invoices to WooCommerce customers, there will be a link that can be used to pay for the order. It will take the customer directly to the payment page where they can pay. Easy peasy, right?

The trouble comes in when customers have difficulty logging in so they can pay. The order is tied to the account so if the user is logged into another account or can’t figure out how to log in, they won’t be able to pay. I’ve seen customers try to register a new account and further complicate the situation.

Here’s a possible way around this. It’s a small script that will log the user into the account on the order when the payment URL is clicked. WooCommerce has an action (before_woocommerce_pay) we can hook into right before the checks are made to see if the order can be paid for. We can use some of these same checks to make sure the order is valid and the key matches. Here’s the snippet:

/**
 * Logs a logged out customer in when they click the payment link in the email.
 *
 * @throws Exception When the order can't be paid for.
 */
function ijab_auto_login():void {
	if ( is_wc_endpoint_url( 'order-pay' ) ) {
		global $wp;
		$order_id = intval( str_replace( 'checkout/order-pay/', '', $wp->request ) );
		$order_id = absint( $order_id );

		// Pay for existing order.
		if ( isset( $_GET['pay_for_order'], $_GET['key'] ) && $order_id ) { // WPCS: input var ok, CSRF ok.
			try {
				$order_key = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : ''; // WPCS: input var ok, CSRF ok.
				$order     = wc_get_order( $order_id );

				// Order or payment link is invalid.
				if ( ! $order || $order->get_id() !== $order_id || ! hash_equals( $order->get_order_key(), $order_key ) ) {
					throw new Exception( __( 'Sorry, this order is invalid and cannot be paid for.', 'woocommerce' ) );
				}

				if ( ! current_user_can( 'pay_for_order', $order_id ) ) {
					$customer_id = $order->get_customer_id();
					wp_clear_auth_cookie();
					wp_set_current_user( $customer_id );
					wp_set_auth_cookie( $customer_id );
				}
			} catch ( Exception $e ) {
				wc_add_notice( $e->getMessage(), 'error' );
			}
		}
	}
}
add_action( 'before_woocommerce_pay', 'ijab_auto_login' );

For security, WooCommerce generates a “key” for each order. This is passed in the payment URL. The script verifies that the key is valid for the order number. Only if these match what is saved in the database will the user be logged in.

This does provide a way to log customers in without having to sign in to pay. Do be aware that this will allow anyone with the payment URL to log into the account for that order. It would be quite difficult to guess the combination of order number and order key.

If you have any questions, please let me know in the comments.


Leave a Reply

Discover more from Just A Bill

Subscribe now to keep reading and get access to the full archive.

Continue reading