5

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!

4
  • 1
    "I can get the $user_id from $_GET method." But are you? You're not in the code you've posted. The code you've posted has no way of knowing which user to get the meta for. Commented Aug 2, 2018 at 2:42
  • @JacobPeattie Yes, I could get. I could catch the return url by PayPal for this. I have now edited the question. Commented Aug 2, 2018 at 2:48
  • Could you show us the code of your "process_ipn" function? How do you find out the payment status?
    – user141080
    Commented Aug 2, 2018 at 15:12
  • @user141080 It is adapted from here.github.com/easydigitaldownloads/Easy-Digital-Downloads/blob/… Commented Aug 2, 2018 at 15:33

3 Answers 3

2
+50

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!

0

sleep() function can be used to delay the execution.

add_filter( 'login_message', array( $this,'custom_login_message' ) );

public function custom_login_message() {
        sleep(5);

        $return =  base64_decode ( $_GET['wdb_return'] );
        $return = explode( '&', $return );
        $return = explode( '=', $return[1] );           
        $user_id = isset( $return[1] ) ? $return[1] : -1;
        .
        .

Now, the notice is 'Payment Completed. Now login.' on successful payment. Because the execution is delayed in reponse to PayPal's delayed process. However I think I need more genuine answer.

0

Another native Wordpress way is to use the WP_Cron scheduling. Consider wp_schedule_event() and wp_unschedule_event() fuction, which runs under your hooks of login. Each time user will ask the page the Cron will check remote status and update your database on success. In the last case, you can do unscheduling of the event and show to your user an appropriate message or a page.

Pros of the solution: * the client doesn't repeatedly send ajax requests * no need to know JS, just assign your existing function to another hook and add a few more easy logic. * use of native Wordpress features

Cons of the solution: * if you have a large traffic on the website, consider using another CRON-library instead Wordpress

links: https://codex.wordpress.org/Function_Reference/wp_schedule_event https://code.tutsplus.com/articles/insights-into-wp-cron-an-introduction-to-scheduling-tasks-in-wordpress--wp-23119

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.