I have process_ipn
method that runs on init
action hook. Looks like it is fired after PayPal returns to merchant. Under this method, I could find out the payment status such as completed
, pending
, failed
from PayPal. And, save it to the database.
update_user_meta( $user_id, 'status', 'completed' );
I am redirecting back to login page from PayPal’s return to merchant with added user_id
and form_id
in return url. I used the login_message
filter to override message depending upon payment status.
add_filter( 'login_message', array( $this,'custom_login_message' ) );
public function custom_login_message() {
$return = base64_decode ( $_GET['wdb_return'] );
$return = explode( '&', $return );
$return = explode( '=', $return[1] );
$user_id = isset( $return[1] ) ? $return[1] : -1;
if( 'completed' === get_user_meta( $user_id, 'status', true ) ) {
return print_notice( __( 'Payment Completed. Now login.','wdp' ) );
} else {
return print_notice( __( 'Payment Failed','wdp' ) );
}
}
The return to merchant will return to login page. The problem the status is updated too late after the login page appears. So, Payment Failed
appears if I click on return to merchant instantly after payment. If I waited a few minutes after payment and then return to merchant, It’s okay.
Note that $user_id
is grabbed from return url from PayPal and is valid.
What could be the solution?
Thanks!
If I understand your question, the race condition you describe between WordPress knowing the transaction was “complete” and the user returning to your site is the problem.
Regarding a potential solution, what about changing the way you’re approaching this such that this race condition is accepted as a real possibility rather than something that you can avoid? You do mention one of the possible Paypal status is “pending”…
Its been years since I’ve worked with Paypal, but I recall the IPN feed can sometimes lag for quite a while.
Suppose you use ajax: you could show the login page with a conditional box, or you could use an interstitial ‘transaction processing’ page that redirects to the login. Your process could thank your customer, show a throbber animation, and explain that you’re processing the transaction / waiting for payment confirmation from Paypal.
Your page can keep polling WordPress and when the user’s meta status
is “complete” you can update the user and show them the login form, and if it “failed” you can handle accordingly.
I’m not sure if you’re setting the Paypal “pending” status in the user meta, but regardless an easy way to trigger this case is by checking for the presence of the user_id
and form_id
in the request from Paypal.
In cases where IPN is updated quick and/or the user pauses before returning to your site, the ‘payment success’ case could already work seamlessly as you desire: no need to show any throbbers or anything like that.
I think ajax is the best approach. A continuous poll every couple seconds might sound like you’re generating a lot of requests, but I doubt you will have scores of users waiting to find out their transaction outcome at any one time. If you do, congratulations, you’re making lots of money 🙂
WordPress also has a Heartbeat API but the fastest this can poll is 15 seconds. Web Sockets is another approach but is probably overkill and introduces its own complexities.
Here is a tutorial that covers an example implementation: https://premium.wpmudev.org/blog/using-ajax-with-wordpress/
For a docs reference: https://developer.wordpress.org/plugins/javascript/ajax/
To have javascript check continuously every few seconds, see setInterval()
and setTimeout()
, references: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval and there’s always: https://www.w3schools.com/js/js_timing.asp
Good luck!