Avoiding action Being Triggered Twice in woocommerce_thankyou hook

3.6k views Asked by At

I am using the woocommerce action below to call a custom function, but for some reason it's being triggered twice on every order. Does anyone know why this could be or how to fix it so that it only calls once per order?

add_action( 'woocommerce_thankyou', 'parent_referral_for_all', 10, 1 );

function parent_referral_for_all( $order_id ) {
  ....
}

UPDATE

I thought the action was being triggered twice but I'm not so sure now. I'm using this action to add another referral inside the affiliatewp plugin, which is adding twice, yet my echo of "Thank You" only appears once.

Everything is working as intended except that the referral (and it's associated order note) are being added twice.

Any help would be greatly appreciated.

That full function:

function parent_referral_for_all( $order_id ) {

//Direct referral
$existing = affiliate_wp()->referrals->get_by( 'reference', $order_id );
$affiliate_id = $existing->affiliate_id;

    //Total amount
    if( ! empty( $existing->products ) ) {
        $productsarr = maybe_unserialize( maybe_unserialize( $existing->products ) );
        foreach( $productsarr as $productarr ) {
            $bigamount = $productarr['price'];
        }
    }

    //Parent amount
    $parentamount = $bigamount * .1;
    $affiliate_id = $existing->affiliate_id;
    $user_info = get_userdata( affwp_get_affiliate_user_id( $existing->affiliate_id ) );
    $parentprovider = $user_info->referral;
    //Affiliate id by username
    $userparent = get_user_by('login',$parentprovider);
    $thisid = affwp_get_affiliate_id($userparent->ID);

            $args = array(
                'amount'       => $parentamount,
                'reference'    => $order_id,
                'description'  => $existing->description,
                'campaign'     => $existing->campaign,
                'affiliate_id' => $thisid,
                'visit_id'     => $existing->visit_id,
                'products'     => $existing->products,
                'status'       => 'unpaid',
                'context'      => $existing->context
            );

    $referral_id2 = affiliate_wp()->referrals->add( $args );
    echo "Thank you!";

         if($referral_id2){
                //Add the order note
                $order = apply_filters( 'affwp_get_woocommerce_order', new WC_Order( $order_id ) );
                $order->add_order_note( sprintf( __( 'Referral #%d for %s recorded for %s', 'affiliate-wp' ), $referral_id2, $parentamount, $parentamount ) );
         }

}
add_action( 'woocommerce_thankyou', 'parent_referral_for_all', 10, 1 );
2

There are 2 answers

0
LoicTheAztec On BEST ANSWER

To avoid this repetition, you couldadd a custom post meta data to the current order, once your "another" referral has been added the first time.

So your code will be:

function parent_referral_for_all( $order_id ) {

    ## HERE goes the condition to avoid the repetition
    $referral_done = get_post_meta( $order_id, '_referral_done', true );
    if( empty($referral_done) ) {

        //Direct referral
        $existing = affiliate_wp()->referrals->get_by( 'reference', $order_id );
        $affiliate_id = $existing->affiliate_id;

        //Total amount
        if( ! empty( $existing->products ) ) {
            $productsarr = maybe_unserialize( maybe_unserialize( $existing->products ) );
            foreach( $productsarr as $productarr ) {
                $bigamount = $productarr['price'];
            }
        }

        //Parent amount
        $parentamount = $bigamount * .1;
        $affiliate_id = $existing->affiliate_id;
        $user_info = get_userdata( affwp_get_affiliate_user_id( $existing->affiliate_id ) );
        $parentprovider = $user_info->referral;
        //Affiliate id by username
        $userparent = get_user_by('login',$parentprovider);
        $thisid = affwp_get_affiliate_id($userparent->ID);

        $args = array(
            'amount'       => $parentamount,
            'reference'    => $order_id,
            'description'  => $existing->description,
            'campaign'     => $existing->campaign,
            'affiliate_id' => $thisid,
            'visit_id'     => $existing->visit_id,
            'products'     => $existing->products,
            'status'       => 'unpaid',
            'context'      => $existing->context
        );

        $referral_id2 = affiliate_wp()->referrals->add( $args );
        echo "Thank you!";

        if($referral_id2){
            //Add the order note
            $order = apply_filters( 'affwp_get_woocommerce_order', new WC_Order( $order_id ) );
            $order->add_order_note( sprintf( __( 'Referral #%d for %s recorded for %s', 'affiliate-wp' ), $referral_id2, $parentamount, $parentamount ) );

            ## HERE you Create/update your custom post meta data to avoid repetition
            update_post_meta( $order_id, '_referral_done', 'yes' )
        }
    }
}
add_action( 'woocommerce_thankyou', 'parent_referral_for_all', 10, 1 );

I hope this will help.

1
Web Assembler On

You can check for the existence of the _thankyou_action_done post_meta key like so:

<?php
/**
 * Allow code execution only once when the hook is fired.
 *
 * @param int $order_id The Woocommerce order ID.
 * @return void
 */
function so41284646_trigger_thankyou_once( $order_id ) {
    
    if ( ! get_post_meta( $order_id, '_thankyou_action_done', true ) ) {
        // Your code here.
    }
}
add_action( 'woocommerce_thankyou', 'so41284646_trigger_thankyou_once', 10, 1 );