0

I am working in a WordPress plugin. I need help in below AJAX code.

// On change division 
    $('body').on( 'change', '.division', function() {
        $.ajax({
            type: "POST",
            url:localData.statesurl,   //http://localhost/wordpress/wp-admin/admin-ajax.php
            data:{
                division: $(this).val(),  // I am getting value here.
                action: 'division_to_district_ajax'  //Do you need anything here ?
            },
            success:function(rss){
                console.log(rss);
                $('.district').empty();
                var $opt = '';  
                $.each( JSON.parse(rss), function(key, value) {
                    $opt += '<option value="'+key+'">'+value+'</option>';
                });
                $('.district').append($opt);
            },
            error: function (jqXHR, textStatus, errorThrown) { 
                   console.log(errorThrown);  // Bad Request
            },
            dataType: "json",
            cache: false,
            contentType: "application/json"
        });         
    });

From above code I am getting Bad Request in console.

I am attaching some screenshots of Network tab.

enter image description here

enter image description here

enter image description here

  • 1
    where did you add action division_to_dustrict_ajax function?? – Chetan Vaghela Mar 4 at 11:29
  • 1
    What’s the code for handling the request? Have you looked at other questions about this error? The solution is always the same. – Jacob Peattie Mar 4 at 11:30
  • 1
    Did you add this code : function idonate_division_to_district_ajax() { if( isset( $_POST['division'] ) ){ echo json_encode( $_POST['division']); die(); } } add_action('wp_ajax_division_to_district_ajax', 'idonate_division_to_district_ajax' ); // executed when logged in add_action('wp_ajax_nopriv_division_to_district_ajax', 'idonate_division_to_district_ajax' ); // executed when logged out – Chetan Vaghela Mar 4 at 11:35
  • 1
    Is there a reason you used a legacy Admin AJAX endpoint instead of a modern REST API endpoint to do your AJAX calls? – Tom J Nowell Mar 4 at 11:42
  • 1
    Thanks @ChetanVaghela, your solution is working. Thanks. – Foysal Mar 4 at 13:37
2

The problem is that it's sending JSON request headers, the old legacy Admin AJAX API doesn't understand this. As a result these are the cause of the bad request:

            dataType: "json",
            contentType: "application/json"

Your endpoint might be able to handle that input, but WP's admin AJAX handler can't, so it never knows which action to fire in the first place.

You have 2 options:

  • Remove these and adjust your AJAX handler accordingly
  • Switch to the modern REST API and get a proper endpoint URL that happily accepts JSON and returns JSON, and even encodes/validates/sanitises for you if told what to expect

Some additional notes:

  • $('body').on( 'change', '.division' is quite a broad event handler, I'd recommend limiting it down from the entire body tag to something more specific
  • There's no checking of the response to make sure it is what you think it is, the code just goes straight into JSON.parse
  • If no values are found or returned there's nothing to indicate that's what happened

But more importantly:

A Major Security Hole In The Code

Building up a HTML string by joining variables up together in JS then appending it is awful for security. It's one of the worst things code can do in javascript short of eval'ing code. Use DOM node construction instead and deal with DOM nodes, never HTML strings. Consider this a omgbbq high level priority fix. $( '<option>', { value: key, text: value } ) is what the code should be appending, it's much faster and safer.

Here's a secure version, the browser will automatically escape and sanitise the keys and make sure no malicious HTML gets snuck in:

const data = JSON.parse( rss );
const options = data.map( function ( key, value ) {
        return jQuery( '<option>', {
            value: key,
            text: value
        } );
} );
jQuery('.district').append( options );

It's also a little faster as the browser doesn't need to parse the HTML, and you don't have to worry about broken HTML markup either. Notice the data variable, we can now wrap it in an if statement and change behaviour if JSON parsing failed, or it doesn't contain what we expected it to. Never create HTML by joining up strings and variables, it's a major security issue, it's slow, and it's unnecessary.

| improve this answer | |

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.