WordPress wp_ajax_nopriv not working

julie-coderiver picture julie-coderiver · Sep 11, 2013 · Viewed 8.6k times · Source

wp_ajax works perfectly (i.e. when logged in). wp_ajax_nopriv is not working (when not logged in).

I am using wp_localize_script to pass through the admin_url('admin-ajax.php') to the JS as shown here:

add_action( 'wp_enqueue_scripts', 'child_enqueue_scripts' );

/**
 * Enqueue Custom Scripts
 * 
 * @since 1.0.0
 */
function child_enqueue_scripts() { 

    wp_enqueue_script( 'crl-js', CHILD_JS_URL . '/child.js', array('jquery'), '1.0.0', true );

    // Pass some parameters to javascript
    $params = array(
        'wp_admin_ajax_url'  => admin_url("admin-ajax.php"),
    );
    wp_localize_script( 'crl-js', 'childParams', $params ); 
}

The JS is here:

(function($){

child = {
    name: 'child',
    wpAdminAjax: childParams.wp_admin_ajax_url || '',     

    gformAutoPopulate: function() {

        $('.p_location select').change( function(){

            var location = $(this).val(),
                pSelect = $( '.p select' );

            if ( location != "none" ) {

                $.ajax({
                    type:   'POST',
                    url:    child.wpAdminAjax,
                    data:   { 
                        pLocation: location, 
                        action: 'dynamically_update_p_dropdown' 
                    },
                    success: function(data) { 

                        pSelect.empty();
                        var options = $.parseJSON(data); 
                        for( i = 0; i < options.length; i++ ) {
                            pSelect.append( options[i] );
                        }
                        pSelect.removeAttr('disabled');
                    }
                });
            }
        });
    },
    ....
 })(jQuery);

And the AJAX code here is:

add_action( 'wp_ajax_dynamically_update_p_dropdown', 'child_gforms_dynamically_update_p_dropdown' );
add_action( 'wp_ajax_nopriv_dynamically_update_p_dropdown', 'child_gforms_dynamically_update_p_dropdown' );

/**
 * AJAX Call to dynamically update the members dropdown
 * 
 * @since 1.0.0
 * 
 */
function child_gforms_dynamically_update_p_dropdown() {

    if( isset( $_POST['pLocation'] ) ) {       

        $location = esc_html( $_POST['pLocation'] );
        $ps = child_get_ps_by_location( $location );

        $options = array();
        foreach( $ps as $p ) 
        {                          
            $options[] = sprintf( '<option value="%s">%s</option>', esc_attr( $p['id'] ), esc_html( $p['name'] ) );
        }

        echo json_encode( $options );  
        die();
     }
}

SOLVED! I found it. It had nothing to do with the above code. It is simply how I was limiting access to wp-admin for admins only:

add_action( 'admin_init', 'child_limit_backend_to_admin_only' );
/**
 * Redirect logged in user to the home page if they are not an admin
 * 
 * @since 1.0.0
 */
function child_limit_backend_to_admin_only() {

    if ( ! is_admin() ) return;

    // If not the admin, then redirect back to the home page
    if ( ! is_user_logged_in() || ! current_user_can( 'manage_options' ) ) {
        wp_redirect( home_url() ); exit;
    }    

}

As soon as I commented out the hook, bam it worked. Thanks everyone.

Answer

Philip Downer picture Philip Downer · Oct 23, 2013

I had a slightly different usage scenario. I needed to keep users who don't have proper permissions out of the admin area, but still needed to allow these users to make AJAX calls. Here's the function that I used to accomplish this.

add_action( 'admin_init', 'prefix_no_admin_access', 100 );
function prefix_no_admin_access() {
    $redirect = home_url('/');

  if( !is_admin() ) return;

  if( empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest' ) {
     if ( !current_user_can('delete_others_pages') ) {
       wp_redirect($redirect);
       exit;
      } 
  }
}

This additional check makes sure that the request type is AJAX.