AJAX / Read More: multiple check_ajax_referer() and wp_create_nonce() not working independentely

The problem I’m finding is that I can only get one to work at a time.
Whichever function is added first in the functions.php, that one works
– the other one gets a 403 error for admin-ajax.php.

Yes, because both your PHP functions (or AJAX callbacks) there are hooked to the same AJAX action, which is load_posts_by_ajax:

// #1 AJAX action = load_posts_by_ajax
add_action('wp_ajax_load_posts_by_ajax', 'load_smart_maps_by_ajax_callback');
add_action('wp_ajax_nopriv_load_posts_by_ajax', 'load_smart_maps_by_ajax_callback');

// #2 AJAX action = load_posts_by_ajax
add_action('wp_ajax_load_posts_by_ajax', 'load_strats_by_ajax_callback');
add_action('wp_ajax_nopriv_load_posts_by_ajax', 'load_strats_by_ajax_callback');

And check_ajax_referer() by default exits the page with a 403 (“forbidden”) status, when for example the nonce is not specified or has already expired:

// #1 $_REQUEST['security2'] will be checked for the load_smartmaps_posts nonce action.
check_ajax_referer('load_smartmaps_posts', 'security2');

// #2 $_REQUEST['security'] will be checked for the load_strats_posts nonce action.
check_ajax_referer('load_strats_posts', 'security');

You can send both nonces (although nobody would do that), or you can use the same nonce and same $_REQUEST key (e.g. security), but you’d still get an unexpected results/response.

So if you want a “single function”, you can use a secondary “action”:

  1. PHP part in functions.php:

    // #1 Load More Smart Maps
    // No add_action( 'wp_ajax_...' ) calls here.
    function load_smart_maps_by_ajax_callback() {
        // No need to call check_ajax_referer()
        ...your code here...
    }
    
    
    // #2 Load More Strategic Events
    // No add_action( 'wp_ajax_...' ) calls here.
    function load_strats_by_ajax_callback() {
        // No need to call check_ajax_referer()
        ...your code here...
    }
    
    add_action( 'wp_ajax_load_posts_by_ajax', 'load_posts_by_ajax' );
    add_action( 'wp_ajax_nopriv_load_posts_by_ajax', 'load_posts_by_ajax' );
    function load_posts_by_ajax() {
        check_ajax_referer( 'load_posts_by_ajax', 'security' );
    
        switch ( filter_input( INPUT_POST, 'action2' ) ) {
            case 'load_smartmaps_posts':
                load_smart_maps_by_ajax_callback();
                break;
    
            case 'load_strats_posts':
                load_strats_by_ajax_callback();
                break;
        }
    
        wp_die();
    }
    
  2. JS part — the data object:

    // #1 On click of `.loadmore.smarties`
    var data = {
        'action': 'load_posts_by_ajax',
        'action2': 'load_smartmaps_posts',
        'security': '<?php echo wp_create_nonce( "load_posts_by_ajax" ); ?>', // same nonce
        ...other properties...
    };
    
    // #2 On click of `.loadmore.strats`
    var data = {
        'action': 'load_posts_by_ajax',
        'action2': 'load_strats_posts',
        'security': '<?php echo wp_create_nonce( "load_posts_by_ajax" ); ?>', // same nonce
        ...other properties...
    };
    

But why not hook the callbacks to their own specific AJAX action:

// #1 AJAX action = load_smart_maps_posts_by_ajax
add_action('wp_ajax_load_smart_maps_posts_by_ajax', 'load_smart_maps_by_ajax_callback');
add_action('wp_ajax_nopriv_load_smart_maps_posts_by_ajax', 'load_smart_maps_by_ajax_callback');

// #2 AJAX action = load_strats_posts_by_ajax
add_action('wp_ajax_load_strats_posts_by_ajax', 'load_strats_by_ajax_callback');
add_action('wp_ajax_nopriv_load_strats_posts_by_ajax', 'load_strats_by_ajax_callback');

Leave a Comment