Adding an action within a function that is being called by add_filter

I am trying to call the function woocommerce_custom_surcharge. I need to call it within the filter for woocommerce_checkout_fields, as I need $fields[‘billing’][‘forhandler_kode’] in my IF statement, and I don’t know how to use it outside the filter. Furthermore, I have tried add_action outside the function, and it works fine there.

My echo is being called, meaning the if statement returns true, so that’s not the issue. For some reason, add_action does not work within my function

add_filter( 'woocommerce_checkout_fields' , 'call_my_add_action' );
function call_my_add_action($fields) {


    if ($fields['billing']['forhandler_kode']) {
         add_action( 'woocommerce_cart_calculate_fees','woocommerce_custom_surcharge' );
         echo "I am being called";
     }



     return $fields;
}

function woocommerce_custom_surcharge() {
        global $woocommerce;

        if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
            return;
        }

        $percentage = -0.1;
        $surcharge = ( $woocommerce->cart->cart_contents_total + $woocommerce->cart->shipping_total ) * $percentage;    
        $woocommerce->cart->add_fee( 'Forhandlerkode Rabat', $surcharge, true, '' );
}

My question is NOT woocommerce specific, as the solution of it can help with a more general understanding of actions and filters. Thank you in advance for any help you can provide!

EDIT:

Perhaps a somewhat hacky solution to this problem (I ended up doing something entirely different so I don’t have the problem anymore, but someone might find this so here goes):

If you HAVE to have an hook fired again, without changing when it is called or using jQuery, you can simply use do_action

With my code above, I got the hook to fire again like so:

if ($fields['billing']['forhandler_kode']) {
     add_action( 'woocommerce_cart_calculate_fees','woocommerce_custom_surcharge' );
     do_action('woocommerce_cart_calculate_fees');
     echo "I am being called";
 }

HOWEVER, PLEASE NOTE

This works, but it is, as Otto pointed out, a silly way to do it. A better solution is simply calling the function like so:

if ($fields['billing']['forhandler_kode']) {
         woocommerce_custom_surcharge();
         echo "I am being called";
     }

1 Answer
1

The answer when the question is about hooks is always either: timing, priority, or both.

Consider the following code:

add_action( 'shutdown', 'wpse_258451_shutdown' );
function wpse_258451_shutdown() {
  add_action( 'init', 'wpse_258451_init' );
}
function wpse_258451_init() {
  wp_die( 'I will never be called.' );
}

It should be obvious that the function wpse_258451_init() will never be called. This is because init is fired only once per page request and that is very near the beginning of the request. Further, shutdown is fired only once per page request and that is very near the end of the request.

What exactly happens in our code? WordPress gets to the first add_action() and adds a callback to the shutdown hook tag. WordPress fires off all sort of hooks before finally getting to the end of the request and firing shutdown. At priority 10, the default, WordPress will attempt to call the callback, which is the function wpse_258451_shutdown().

Inside the wpse_258451_shutdown() function, we add another action. This time to init with the callback of wpse_258451_init(). This gets added on to the global $wp_filter just fine. However, because we’re already past init and shutting down the request, this callback never fires.

How does this relate to your question?

If “I am being called” is being echoed but your action does not appear to be firing, then there are only two possible reasons.

  1. The hook has already fired and does not fire again on this request
  2. The hook isn’t fired at all on this request

How can I determine the timing of hooks

The following will echo every hook ( action and filter ) that is fired during a request.

add_filter( 'all', function( $a ) { 
  echo $a . "\\n";
  return $a; 
}, 10, 1 );

Another option would be to use Query Monitor by John Blackbourn.

Leave a Comment