Hook AJAX in Wordpress

2019-01-12 08:17发布

问题:

I have been delving into the world of Javascript and AJAX. I am super close, but for some reason I do not think I am hooking into wordpress ajax functions right. I have poured through the docs and this and think it is 99% there.

Is what this app does is there is a list of items. Each one with a + button. Clicking the button pops up a confirm box, and if confirmed grabs the needed data to pass to the php. The php adds the item into mysql with wpdb->insert. It also does some changes if you buy.

The js works all the way up to the call, grabbing the right values etc. Testing the php separately works as well if I hard code the values it is supposed to grab from POST. So I KNOW both pieces run, I just can't get the js to call the ajax api right. Can someone please take a look at this and let me know how to hook these together so the ajax call actually runs the php?

Here is the code.

<?php 
add_action( 'admin_footer', 'addItemAJAX_javascript' );

function addItemAJAX_javascript() {
    $adminAJAX =  admin_url('admin-ajax.php'); 
?>
<script type="text/javascript" language="JavaScript">

  $(function() {
    $( "input[name=btnAddItem]" )  
      .button()
      .click(function( event ) {
        event.preventDefault();
        var confirmAction = confirm('Are you sure you want to add this item to your character?');
        if (confirmAction==true) {
    // build data for AJAX call
            var cID = $('#hdnCharID').val();
            cID = cID*1;
            var charMoney = $('#hdnCharMoney').val();
            var thisValue = $(this).val();
            var iID = $(this).prev('input[id="hdnItemID"]').val()
            iID = iID*1;
    //Add or Buy Item
            if (thisValue != "+") {
                var buy = 1;
            }
            else {
                var buy = 0;
                }
            var ajaxurl = <?php echo json_encode($adminAJAX); ?>;
            console.log('cID = ' + cID);
            console.log('charMoney = ' + charMoney);
            console.log('thisValue = ' + thisValue);
            console.log('iID = ' + iID);        
            console.log('buy = ' + buy);        
            console.log('ajaxurl = ' + ajaxurl);                
            var data = {
                        action: 'addItemAJAX',
                        charID: cID,
                        itemID: iID,
                        buyItem: buy
            };
            console.log('data = ' + data);
            console.log(data);

    //WP ajax call
            $.post(ajaxurl, data, function(response) {
            alert('Got this from the server: ' + response);
            });
        }
        else {
            console.log('add item aborted');
        }
      });
  });
</script>
<?php 

}; 

addItemAJAX_javascript();

// PHP SIDE OF AJAX - Handeling Request  //// AJAX PROCESSING /////////////////////////////////
add_action('wp_ajax_addItemAJAX', 'addItemAJAX_callback');

function addItemAJAX_callback() {
    global $wpdb;
    $charID = intval($_POST['charID']);
    $itemID = intval($_POST['itemID']);
    $buyItem = intval($_POST['buyItem']);

//  //get item details
    $getItemDetailsSQL = "
    Select
      fyxt_wp_db_fatcow.fyxt_items.idfyxt_items,
      fyxt_wp_db_fatcow.fyxt_items.fyxt_item_name,
      fyxt_wp_db_fatcow.fyxt_items.fyxt_item_description,
      fyxt_wp_db_fatcow.fyxt_items.fyxt_item_cost,
      fyxt_wp_db_fatcow.fyxt_items.fyxt_item_weight
    From
      fyxt_wp_db_fatcow.fyxt_items
    Where
      fyxt_wp_db_fatcow.fyxt_items.idfyxt_items = $itemID";
    $getItemDetailsResults = $wpdb->get_row($getItemDetailsSQL);

    $iID = $getItemDetailsResults->idfyxt_items;
    $iName = $getItemDetailsResults->fyxt_item_name;
    $iDesc = $getItemDetailsResults->fyxt_item_description;
    $iCost = $getItemDetailsResults->fyxt_item_cost;
    $iWeight = $getItemDetailsResults->fyxt_item_weight; 

    $charItemTable = fyxt_char_items;
    $wpdb->insert(
                  $charItemTable,
                  array (
                          idfyxt_item => $iID,
                          idfyxt_character => $charID,
                          item_name => $iName,
                          item_desc => $iDesc,
                          item_cost => $iCost,
                          item_weight => $iWeight,
                          item_quant => 1,
                          equip => 0,
                          carried => 1
                        )
                  );
    $wpdb->print_error();                                               
    $newItemAdded = $wpdb->insert_id;

    //remove cash if item is bought
    if ($buyItem == 1 ) {
        $curCharMoneySQL = 
        "Select
          fyxt_wp_db_fatcow.fyxt_characters.char_money
        From
          fyxt_wp_db_fatcow.fyxt_characters
        Where
          fyxt_wp_db_fatcow.fyxt_characters.idfyxt_character = $charID";
        $curCharCash = $wpdb->get_var($curCharMoneySQL);
        $wpdb->print_error(); 

        $newCash = $curCharCash - $iCost;

        $changeCashSQL = "
        UPDATE fyxt_characters
        SET 
            char_money = $newCash
        WHERE
            idfyxt_character = $charID";
        $changeCash = $wpdb->query($changeCashSQL);
        $wpdb->print_error(); 
    }

    $debugArray = Array();
    array_push($debugArray,$charID, $itemID, $buyItem, $getItemDetailsSQL, $getItemDetailsResults,$newItemAdded, $newCash);
    echo $debugArray ;  

    die();
}

?>

I am pretty sure it is 1 (or 2) of 2 things. I am not sure if I am hooking these functions to wordpress right. Or there might be issues with nested functions I have for the jQuery button. I doubt it is number 2 though because it seems to work... I just get a 0 back from the server without any database activity. Here is what the log says.


cID = 112 ?charID=112:538
charMoney = 9990 ?charID=112:539
thisValue = + ?charID=112:540
iID = 664 ?charID=112:541
buy = 0 ?charID=112:542
ajaxurl = http://localhost/nnnnnnnn.com/wp-admin/admin-ajax.php ?charID=112:543
data = [object Object] ?charID=112:550
Object {action: "addItemAJAX", charID: 112, itemID: 664, buyItem: 0} ?charID=112:551
XHR finished loading: "http://localhost/nnnnnnnn.com/wp-admin/admin-ajax.php". jquery-1.9.1.js:8526
send jquery-1.9.1.js:8526
jQuery.extend.ajax jquery-1.9.1.js:7978
jQuery.(anonymous function) jquery-1.9.1.js:7614
(anonymous function) ?charID=112:554
jQuery.event.dispatch jquery-1.9.1.js:3074
elemData.handle

Thank you very much for all of the help and suggestions!

回答1:

First of all you need to add hooks in proper way

// For the users that are not logged in
add_action( 'wp_ajax_nopriv_addItemAJAX', 'addItemAJAX_callback' );  

// For the users that are  logged in:  
add_action( 'wp_ajax_addItemAJAX', 'addItemAJAX_callback' );

// ajax handler
function addItemAJAX_callback()
{
    // code goes here
    // since $debugArray is an array, so 
    die(json_encode($debugArray)); // last line
}

One hook will work when user is logged in and another will work when user is not logged in (for any user). If you are making ajax request for logged in users then, wp_ajax_nopriv_ hook is required.

Keep your js/ajax code in a separate file in yourthemefolder/js/myAjaxScript.js and also keep following code in your functions.php file

add_action('wp_enqueue_scripts', 'my_load_scripts');
function my_load_scripts()
{
    // for pluggin, you may use "plugin_dir_url( __FILE__ )"
    wp_enqueue_script( 'my_ajax-script', get_stylesheet_directory_uri() . '/js/myAjaxScript.js', array('jquery') );

    // Following code will let you use "ajaxObj.ajax_url" to get the
    //  ajax url (admin-ajax.php) in your my_ajax_scriptjs file
    wp_localize_script(
        'my_ajax-script', 'ajaxObj', array( 'ajax_url' => admin_url( 'admin-ajax.php' )                
    ));
}

In your my_ajax_script.js file, you may code like this

var data = {
     action: 'addItemAJAX_callback',
     // ...
};
$.getJson(ajaxObj.ajax_url, data, function(response) {
     // response is an object
     // ...
});

Alos remember, when using ajax from admin panel, you don't need to use wp_localize_script, since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php.



回答2:

I won't go through your code as it seems a bit hard to replicate (see SSCCE for this matter). But I'll outline how to work with Ajax and WordPress (from How to Use AJAX in a WordPress Shortcode?):

1) Enqueue and localize the JavaScript file.

Instead of enqueueing, we could print directly in the head or footer, but it's not good practice. And the localization will pass PHP values to JS in a clean fashion.
I'm assuming you're working with a theme, otherwise change get_stylesheet_directory_uri() to plugins_url().

add_action( 'wp_enqueue_scripts', 'enqueue_so_19721859' );

function enqueue_so_19721859() 
{
    # jQuery will be loaded as a dependency
    ## DO NOT use other version than the one bundled with WP
    ### Things will BREAK if you do so
    wp_enqueue_script( 
        'my-handler',
        get_stylesheet_directory_uri() . '/js/ajax.js',
        array( 'jquery' )
    );
    # Here we send PHP values to JS
    wp_localize_script( 
        'my-handler', 
        'my_handler',
        array( 
            'ajaxurl'      => admin_url( 'admin-ajax.php' ),
            'ajaxnonce'   => wp_create_nonce( 'my_ajax_validation' ) // <--- Security!
        ) 
    );
}

2) Ajax for logged and non-logged users

You gotta add a public Ajax callback too with no_priv_:

add_action('wp_ajax_addItemAJAX', 'addItemAJAX_callback');
add_action('wp_ajax_no_priv_addItemAJAX', 'addItemAJAX_callback');

3) Ajax Callback and Response

The Ajax callback has security checks and uses wp_send_json_* to handle the response:

function addItemAJAX_callback()
{
    check_ajax_referer( 'my_ajax_validation', 'security' );
    $my_thing = something();
    if( !$my_thing )
        wp_send_json_error( array( 'error' => __( 'Could not retrieve a post.' ) ) );
    else
        wp_send_json_success( $my_thing );
}

4) Finally, the script

It's essential to wrap all jQuery with noConflict mode.
You can pass whatever info you need through the localized object my_handler. We check 3 things from the response:

  • total failure: couldn't reach the callback or didn't pass security
  • partial failure: the callback was reached but returned json_error
  • success: proceed with your thing
jQuery( document ).ready( function( $ ) { 
     var data = {
         action: 'addItemAJAX_callback',
         security: my_handler.ajaxnonce
     };

    $( '#my-submit' ).click( function(e) {
        e.preventDefault();
        $.post( 
            my_handler.ajaxurl, 
            data,                   
            function( response ) {
                // ERROR HANDLING
                if( !response.success ) {
                    // No data came back, maybe a security error
                    if( !response.data )
                        $( '#my-answer' ).html( 'AJAX ERROR: no response' );
                    else
                        $( '#my-answer' ).html( response.data.error );
                }
                else
                    $( '#my-answer' ).html( response.data );
            }
        ); 
    });
});