• Resolved jlanpheer

    (@jlanpheer)


    I’m trying to do something fairly simple (or so i THOUGHT), with the problem being that I can’t isolate what the actual error is. Very simply, i have created a plugin which displays a form where i am soliciting the user to upload a csv file. Upon submitting the form an ajax call assembles everything and calls a function which simply displays the contents in an HTML table (so far). The problem is that i get a “POST 404 (not found)”. I can’t figure out what i am missing here, i’ve watched some tutorials, followed the examples, etc…..

    <div id="file-upload-form" style="display: none;">
    <form id="csv-form" enctype="multipart/form-data">
    <label for="csv_file">CSV File Name:</label>
    <input type="file" id="csv_file" name="csv_file" accept=".csv">
    <button type="button" id="upload-csv">Upload</button>
    </form>
    </div>
    <div id="csv-table"></div>

    My AJAX call:

    $('#upload-csv').on('click', function () {
    alert('Doing the right thing');
    const fileInput = $('#csv_file')[0].files[0];
    if (!fileInput) {
    alert('Please select a CSV file.');
    return;
    }

    var ajaxurl = "<?php echo admin_url('admin-ajax.php'); ?>";
    const formData = new FormData();
    formData.append('csv_file', fileInput);
    formData.append('action', 'process_csv');
    alert(formData);

    $.ajax({
    //url: ajax_new_obj.ajax_url,
    url: ajaxurl,
    type: 'post',
    data: formData,
    processData: false,
    contentType: false,
    success: function (response) {
    if (response.success) {
    $('#csv-table').html(response.data);
    } else {
    alert(response.data);
    }
    },
    error: function (data, status) {
    console.log(data, status);
    alert('An error occurred while loading this payroll file. Please check the file format and try again.');
    }
    });
    });
    });

    And finally, my receiving function. I do know that many times you can get the ‘Bad Request’ error if you don’t add the appropriate actions, which i have added here. This is my code handler, which never executes due to the POST 404 Not Found error.

    // Handle AJAX request to process CSV
    add_action('wp_ajax_process_csv_file', 'process_csv_file');
    add_action('wp_ajax_nopriv_process_csv_file', 'process_csv_file');
    function process_csv_file() {
    if ( ! wp_verify_nonce( $_POST['nonce'], 'ajax-nonce' ) ) {
    die ( 'You do not have permission to access this routine - nonce violation.'); // Die if invalid Nonce
    }
    if (!empty($_FILES['csv_file']['tmp_name'])) {
    $file = $_FILES['csv_file']['tmp_name'];
    $csv_data = array_map('str_getcsv', file($file));
    $html = '<table border="1">';
    $html .= '<tr><th>Customer Name</th><th>Date</th></tr>';
    foreach ($csv_data as $index => $row) {
    if ($index === 0) continue; // Skip header row
    $html .= '<tr><td>' . esc_html($row[0]) . '</td><td>' . esc_html($row[1]) . '</td></tr>';
    }
    $html .= '</table>';
    wp_send_json_success($html);
    } else {
    wp_send_json_error('No file uploaded.');
    }
    }

    I had originally set up the ajax url in my plugin’s root file like this:

     
    function load_admin_assets() {

    wp_enqueue_script('ajax-new', plugins_url('/js/ajax-new.js', __FILE__), array('jquery'), null, true);
    wp_localize_script('ajax-new', 'ajax_new_obj', array('ajax_url' => admin_url('admin-ajax.php'),
    'baseUrl' => esc_url( home_url() ),
    'nonce' => wp_create_nonce('ajax-nonce')));
    }
    add_action('admin_enqueue_scripts', 'load_admin_assets');

    That didn’t work either, so i went to the above approach of hard-coding the ajax url into the code, no love was returned. I’ve swapped in/out most every argument, including nonce that i can think to try and still, no love was returned. I’ve also removed the nonce references completely, thinking that might be the root of it. No such luck…. Can anyone help with some knowledge as far as what I can do to track down the source of the problem? The ‘404 Not Found’ error is VERY vague and i lack some knowledge in how to dig deeper. Thanks and cheers!

Viewing 3 replies - 1 through 3 (of 3 total)
  • Thread Starter jlanpheer

    (@jlanpheer)

    Just to provide a bit more info, if i replace the ‘url’ parameter with this, i instead get the error: POST 400 (Bad Request). As in:

    $.ajax({
    url: ajax_new_obj.ajax_url,
    type: 'post',
    data: formData,
    processData: false,
    contentType: false,
    success: function (response) {
    if (response.success) {
    $('#csv-table').html(response.data);
    } else {
    alert(response.data);
    }
    },
    error: function (data, status) {
    console.log(data, status);
    alert('An error occurred while loading this payroll file. Please check the file format and try again.');
    }
    });
    });

    The issue causing the 404 (Not Found) or 400 (Bad Request) errors in your AJAX request likely stems from two main areas:

    1. Action Name Mismatch
    2. Missing or Invalid Nonce Handling

    Below, I’ll walk you through the problems, fixes, and improvements to ensure this works. Problem 1: Action Name Mismatch

    In your AJAX handler, you have:

    add_action('wp_ajax_process_csv_file', 'process_csv_file');
    add_action('wp_ajax_nopriv_process_csv_file', 'process_csv_file');

    But in the AJAX request, you append the action as 'process_csv':

    formData.append('action', 'process_csv');

    The action names must match.
    The 'action' parameter you send via AJAX corresponds to the wp_ajax_{action} hook in WordPress. Fix: Align Action Names

    Choose one consistent action name for both the request and the server hook. Update the JavaScript:

    formData.append('action', 'process_csv_file'); // Match the action name

    Keep the hooks as-is in PHP:

    add_action('wp_ajax_process_csv_file', 'process_csv_file');
    add_action('wp_ajax_nopriv_process_csv_file', 'process_csv_file');

    This ensures the WordPress hook system recognizes the AJAX action. Problem 2: Nonce Validation Failure

    In your PHP function, you validate a nonce:

    if ( ! wp_verify_nonce( $_POST['nonce'], 'ajax-nonce' ) ) {
        die('You do not have permission to access this routine - nonce violation.');
    }

    However, you’re not actually sending the nonce in the FormData object:

    const formData = new FormData();
    formData.append('csv_file', fileInput);
    formData.append('action', 'process_csv_file');

    Fix: Pass the Nonce to Your AJAX Request

    Since you localized the script to include a nonce (ajax_new_obj.nonce), append it to the form data:

    formData.append('nonce', ajax_new_obj.nonce); // Add nonce to FormData

    Corrected JavaScript (Full Code)

    Here is the corrected AJAX call:

    $('#upload-csv').on('click', function () {
        alert('Preparing to upload file...');
        const fileInput = $('#csv_file')[0].files[0];
        if (!fileInput) {
            alert('Please select a CSV file.');
            return;
        }
    
        var ajaxurl = ajax_new_obj.ajax_url; // Use localized AJAX URL
        const formData = new FormData();
        formData.append('csv_file', fileInput);
        formData.append('action', 'process_csv_file'); // Match the PHP hook action name
        formData.append('nonce', ajax_new_obj.nonce); // Pass the nonce
    
        $.ajax({
            url: ajaxurl,
            type: 'POST',
            data: formData,
            processData: false,
            contentType: false,
            success: function (response) {
                if (response.success) {
                    $('#csv-table').html(response.data);
                } else {
                    alert('Error: ' + response.data);
                }
            },
            error: function (jqXHR, status, error) {
                console.log(jqXHR, status, error);
                alert('An error occurred. Check the console for details.');
            }
        });
    });

    Verifying the Script Localization

    Ensure your script localization works as expected in PHP. Here’s the relevant function:

    function load_admin_assets() {
        wp_enqueue_script('ajax-new', plugins_url('/js/ajax-new.js', __FILE__), array('jquery'), null, true);
        wp_localize_script('ajax-new', 'ajax_new_obj', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce'    => wp_create_nonce('ajax-nonce')
        ));
    }
    add_action('admin_enqueue_scripts', 'load_admin_assets');

    Check the front-end source code of your page. You should see ajax_new_obj defined like this:

    <script type="text/javascript">
    var ajax_new_obj = {
        "ajax_url": "https://your-site.com/wp-admin/admin-ajax.php",
        "nonce": "random_nonce_value"
    };
    </script>

    If the ajax_url or nonce is missing or incorrect, there’s likely an issue with your wp_localize_script function. Final PHP Handler

    Ensure the PHP handler remains unchanged except for matching the action name. The nonce is now validated correctly:

    add_action('wp_ajax_process_csv_file', 'process_csv_file');
    add_action('wp_ajax_nopriv_process_csv_file', 'process_csv_file');
    
    function process_csv_file() {
        // Verify nonce
        if ( ! isset($_POST['nonce']) || ! wp_verify_nonce($_POST['nonce'], 'ajax-nonce') ) {
            wp_send_json_error('Nonce validation failed.');
        }
    
        // Process CSV file
        if (!empty($_FILES['csv_file']['tmp_name'])) {
            $file = $_FILES['csv_file']['tmp_name'];
            $csv_data = array_map('str_getcsv', file($file));
            $html = '<table border="1"><tr><th>Customer Name</th><th>Date</th></tr>';
    
            foreach ($csv_data as $index => $row) {
                if ($index === 0) continue; // Skip header row
                $html .= '<tr><td>' . esc_html($row[0]) . '</td><td>' . esc_html($row[1]) . '</td></tr>';
            }
    
            $html .= '</table>';
            wp_send_json_success($html);
        } else {
            wp_send_json_error('No file uploaded.');
        }
    }

    Debugging Tips

    1. Check Console Output:
      Open the browser’s developer tools (F12 or right-click > Inspect > Console) and see the exact request details.
    2. Test Nonce Issues:
      Temporarily disable the nonce verification to confirm if it’s the root of the problem. If it works without nonce, the issue is nonce generation or passing.
    3. Inspect Network Tab:
      Check the Network tab in developer tools for the actual AJAX request, the POST data sent, and the response.
    4. Clear Cache:
      Clear browser, server, and plugin caches to ensure changes take effect.

    By fixing the action name mismatch and ensuring the nonce is passed, your AJAX file upload should work smoothly. Let me know if you run into further issues! 😊

    Thread Starter jlanpheer

    (@jlanpheer)

    Thank you Seyyed for your kind and detailed response! It was very helpful!

    First, i realized about 10 minutes after i posted this that the name of my function and the name in the ‘action’ parameter were not the same, i had made that mistake after creating several incarnations of this function, trying slightly different things. However, correcting that did not solve the problem.

    What DID solve it was handling the nonce parameter correctly. I did not know that if you localized the script that the nonce argument should be included INSIDE the ‘data’ array that is passed. Every example i had seen had showed it as a separate parameter. Doing so fixed the problem straight away. I don’t know why i didn’t think to try that, but your suggestion makes sense and solved my problem. I’m not quite sure why other parameters in the call are not also included in the passed ‘data’ array (e.g. processData, contentType etc…) but i will have to study that.

    Thank you again for your help and i am marking this as ‘resolved’. Take good care of yourself and your loved ones!

Viewing 3 replies - 1 through 3 (of 3 total)
  • You must be logged in to reply to this topic.