3

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
    there is nothing I hate more than people starting to argue why their off-topic question is not off-topic in the question itself :( most likely you add the action too late – Mark Kaplun Mar 1 '17 at 13:57
  • Don't understand why this is off topic? If he had substituted the three letters "woo" with "foo" then we'd be ok with the question (?). I'd try to un-nest the add_action from inside the add_filter called function; put logic in the called function to determine if it should execute or not, instead. – C C Mar 1 '17 at 14:40
  • @MarkKaplun I started off because I felt that some people might see it as off-topic, when really, it's not, it's generally applicable. And C C, I'll look into that, although my biggest problem with doing that is not being able to use $fields['billing']['forhandler_kode']. I think I might have found another solution however, which I will look into tomorrow :) Thanks for the comments. – Kristoffer M Mar 1 '17 at 15:02
  • I'd recommend refactoring your code so that it doesn't appear to be specific to woocommerce. – Nathan Johnson Mar 1 '17 at 17:14
  • Your edit shows that you don't understand what actions or possibly functions are. Why not just call your function directly? Adding an action and immediately doing the same action is somewhat silly, no? – Otto Mar 2 '17 at 10:01
3

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.

| improve this answer | |
  • Thank you! Very helpful information, I'll be sure to have this bookmarked for future use. – Kristoffer M Mar 2 '17 at 9:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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