2

Update: Issue resolved! The AJAX works but I had the function debug_to_console for testing which echo to the console log. Here is the function:

/* This is a function to print data to web browser console **
** Use debug_to_console( $data ); to print */
function debug_to_console( $data ) {
  $output = $data;
  if ( is_array( $output ) )
  $output = implode( ',', $output);

  echo "<script>console.log( 'Debug Objects: " . $output . "' );</script>";
}

on WooCommerce's admin order page (WooCommerce > Orders > Edit) I added custom fields to add a custom fee to the order. I'm following this article to add AJAX but it's not working. I successfully registered and enqueued my jQuery script add-custom-fee.js and for the most part it works, but I do not receive a response at all.

On the admin order page, I added the following link below my custom fields to trigger the AJAX:

$nonce = wp_create_nonce('add_custom_fee_nonce');
$link = admin_url('admin_ajax.php?action=add_custom_fee&post_id=' . $order->id . '&nonce=' . $nonce );
echo '<a class="add-custom-fee" data-nonce="' . $nonce . '" data-post_id="' . $order->id . '" href="' . $link . '">Add fee?</a>';

Here is how I registered and enqueued my script:

add_action('admin_enqueue_scripts', 'load_add_custom_fee_ajax_js');
function load_add_custom_fee_ajax_js( $hook ) {

  // Deprecated; append datetime as version number of script
  //$my_js_ver = date("ymd-Gis", filemtime( plugin_dir_path( __FILE__ ) . 'js/add-custom-fee.js' ));

  // Only register and enqueue on order edit page
  if ( 'post.php' == $hook || 'edit.php' == $hook ) {

    global $post;

    if ('shop_order' === $post->post_type) {
      wp_register_script( 'add-custom-fee', get_stylesheet_directory_uri() . '/js/add-custom-fee.js', array('jquery'), 1.0, true );

      // enqueue the JavaScript file
      wp_enqueue_script( 'jquery' );
      wp_enqueue_script( 'add-custom-fee');

      // localize the script to reference admin-ajax URL
      wp_localize_script( 'add-custom-fee', 'myAjax', array( 'ajaxurl' => admin_url('admin-ajax.php') ) );
    }
  }
}

And here is my jQuery script:

jQuery(document).ready(function () {
  console.log("Hello world! Add custom fee JS script enqueued!");
});

/* START of code to add a custom fee to the order in admin and recalculate */
jQuery(document).ready(function ($) {

  $('.add-custom-fee').click( function(e) {
    e.preventDefault();

    console.log("Add fee toggle change detected! Grabbing values...");

    // var ajaxurl = 'https://staging1.orderpantry.com/wp-admin/admin-ajax.php';
    var add_fee_toggle = $("input[name='add_fee_toggle']:checked").val();
    var add_fee_name = $("input[name='add_fee_name']").val();
    var add_fee_percentage = $("input[name='add_fee_percentage']").val();

    console.log("Toggle? " + add_fee_toggle + ". Fee name: " + add_fee_name + ". Fee percentage: " + add_fee_percentage + "%");

    // Remove cookie and do not apply fee
    if (add_fee_toggle == '') {

      // Clear the fee fields
      $("input[name='add_fee_toggle'][value='']").prop('checked', true);
      $("#add_fee_name").val('');
      $("#add_fee_percentage").val('');

      console.log('Fee not added!');
      $('button.calculate-action').trigger('click'); // <-- trigger recalculate order
      //$('button.save-action').trigger('click');       <-- trigger saving order
    } else {

      order_id = $(this).attr('data-post_id');
      nonce = $(this).attr('data-nonce');

      console.log("This order's ID is " + order_id + " and its nonce is " + nonce);

      // Push fee values to AJAX function
      $.ajax({
        type: 'post',
        dataType: 'json',
        url: myAjax.ajaxurl,
        data: {
          action: 'create_fee_object',
          order_id: order_id,
          nonce: nonce,
          add_fee_toggle: add_fee_toggle,
          add_fee_name: add_fee_name,
          add_fee_percentage: add_fee_percentage
        },
        success: function(response) {
          if ( response.type == 'success' ) {
            console.log('Success! AJAX request received!');
            // Trigger the order to recalculate on success
            $('button.calculate-action').trigger('click');
          } else {
            alert('An error has occurred while adding your fee.');
            $('button.calculate-action').trigger('click');
          }
        }

      });
    }
  });
});

I do not receive any response, success or failure. The code seem to just stopped working here.

And here is my PHP code:

add_action('wp_ajax_create_fee_object', 'create_fee_object');
add_action('wp_ajax_nopriv_create_fee_object', 'please_login');
function create_fee_object() {

  if ( !wp_verify_nonce( $_REQUEST['nonce'], 'add_custom_fee_nonce' ) ) {
    exit("Unsecured access detected!");
  }

  debug_to_console( "Add fee data reached AJAX function!" );

  // Check if action was fired via Ajax call. If yes, JS code will be triggered, else the user is redirected to the post page
  if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    $result['type'] = 'success';
    $result = json_encode($result);
    echo $result;
  } else {
    header("Location: ".$_SERVER["HTTP_REFERER"]);
  }

  die();
}

function please_login() {
  alert("You must log in to do this.");
  die();
}

I don't think the function create_fee_object works or AJAX POST is not reaching it.

Any idea what is causing it to not work? Thank you!

Wallace L.
  • 41
  • 1
  • 10
  • Add the following to the object passed into your $.ajax function: complete: function ( jqXHR, textStatus ) { console.log(textStatus); } – Design.Garden Dec 06 '19 at 16:10
  • 1
    ...or check the Network tab in your browser's debug console. My bet is that the $.ajax function does fire, but hits an error. You check for response.type == 'success' in your success callback -- this may be where you're confused -- this response object comes from your PHP code (not from jQuery), so it does not indicate success/failure of the $.ajax request itself. – Design.Garden Dec 06 '19 at 16:23
  • @mattavatar you're right, the ajax does work and in network tab I do see a 200 OK. I added back in my code for creating the fee object and adding it to the order and it works! However, I'm still unable to get a success response back that can trigger the order to recalculate (using `$('button.calculate-action').trigger('click');`). I added in that `complete:function` to my ajax function but nothing different happened. How can I get a success response? – Wallace L. Dec 06 '19 at 16:40
  • Still debugging: add the following at the top of your create-fee_object() function: wp_send_json_success( array( 'type' => 'success' ) ); die(); – Design.Garden Dec 06 '19 at 17:09
  • The goal of the above is to short circuit the PHP code and immediately send back a response. It is odd that your Network tab shows 200 OK for the AJAX, but the complete callback is never called -- this means that we are not running the code that we think we are (maybe older javascript code is cached?). – Design.Garden Dec 06 '19 at 17:12
  • @mattavatar I figured it out! In my php function I echoed to the console log using the function `debug_to_console`. I think this function should only have one `echo` for the response. – Wallace L. Dec 06 '19 at 17:23
  • 1
    ohhh... you grabbed that debug_to_console function from here: https://stackoverflow.com/a/20147885/2540235 ??? Yes, that is going to mess with your response since it returns your text wrapped in a script tag... wow, that would really mess with XHR, potentially causing the skip of the complete callback! i think you found a pretty neat bug... – Design.Garden Dec 06 '19 at 17:27
  • Would you please include the code for your debug_to_console function in your original post? Then I think I can provide a pretty solid answer. – Design.Garden Dec 06 '19 at 17:28
  • @mattavatar yes you're right, that's the function I have. I added it a while ago and used it frequently so I didn't even thought about it. I'll update my post and provide an answer now. – Wallace L. Dec 06 '19 at 17:53
  • oh no. I'll provide the answer, I do this for points – Design.Garden Dec 06 '19 at 17:54

1 Answers1

2

Answer: Remove debug_to_console( "Add fee data reached AJAX function!" );.

Assuming that you copied debug_to_console from this SO post then you are printing a <script> tag above your intended response content, so not only are you not going to see your intended data in your callback, but your success callback will NOT fire at all. Why? Because you've told $.ajax to expect JSON (via dataType: 'json'), but jQuery throws an error while attempting to parse your returned content as JSON.

Design.Garden
  • 3,607
  • 25
  • 21