1

I've been struggling to create a Load More button on a WP project. Basically, I use the Admin Ajax at our disposal when using WordPress. I also use the fetch API to communicate with it, via my load-more.js file.

The magic should happen when I click on my id-ed p28-load-more button, defined in my archive file. The sent request contains 3 parameters : action, current_page and query. They are filled correctly, with the variables I defined in the wp_localize_script function (assets.php). But the response is 0 with a message in console "Bad Request 400". No error available in the log file of my WP setup.

error from development tool firefox

I tested so many things in 2 weeks, I can't seem to find the solution.

Here's my load-more.js file :

    $(document).ready(function () {
        let ajaxurl = p28_query_params.ajaxurl;

        $('#p28-load-more').click(function () {

            const data = {
                action: 'p28_load_more',
                current_page: p28_query_params.current_page,
                query: p28_query_params.query
            };

            fetch(ajaxurl,
                {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'x-www-form-urlencoded',
                        'Cache-Control': 'no-cache'
                    },
                    body: new URLSearchParams(data),
                })
                .then(response => response.json())
                .then(response => {
                    if (!response.success) {

                        console.log('Erreur dans la réponse : ' + response);
                        return;
                    }
                    if (response) {
                        $('div#p28-load-more').text('CHARGER ENCORE');

                        $('div#p28-load-more-results').append(response);

                        p28_query_params.current_page++;

                        $('div.p28-load-more-msg').html('<p class="p28-small-text">' + p28_query_params.posts_count + ' sur ' + p28_query_params.found_posts + '</p>');

                        if (p28_query_params.current_page == p28_query_params.max_pages) {
                            $('div#p28-load-more').hide();
                        }
                    } else {
                        $('div#p28-load-more').hide();
                    }
                }).catch(function (err) {
                    console.warn('Erreur lors de l&apos;envoi : ', err);
                });
        });


})(jQuery);

My load-more.php file (included in functions.php) - I tried to move the code directly in functions.php, didn't work) :

<?php

add_action('wp_ajax_p28_load_more', 'p28_load_more');
add_action('wp_ajax_nopriv_p28_load_more', 'p28_load_more');

function p28_load_more()
{
    echo 'OK';
    die();
}


The assets.php file (also included in functions.php, my load-more.js file is correctly included when I go to the website so I don't think the issue is here) :


<?php

function page28_register_assets()
{
    // Déclarer jQuery
    wp_enqueue_script('jquery');

    // Déclarer le JS
    wp_enqueue_script(
        'app',
        get_template_directory_uri() . '/dist/js/app.js',
        array('jquery'),
        '1.0',
        true

    );


    // Déclarer le fichier CSS à un autre emplacement
    wp_enqueue_style(
        'style',
        get_template_directory_uri() . '/dist/css/style.css',
        array(),
        '1.0'
    );
}

add_action('wp_enqueue_scripts', 'page28_register_assets');



function p28_login_logo()
{
    wp_enqueue_style(
        'custom-login',
        get_template_directory_uri() . '/dist/css/custom-login.css',
        array('login')
    );
}

add_action('login_enqueue_scripts', 'p28_login_logo');


function p28_load_and_filter()
{

    global $wp_query;

    wp_register_script('p28_load_more_filter', get_stylesheet_directory_uri() . '/dist/js/load-more.js', array('jquery'));

    wp_localize_script('p28_load_more_filter', 'p28_query_params', array(
        'ajaxurl' => admin_url('admin-ajax.php'),
        'query' => json_encode($wp_query->query_vars),
        'found_posts' => $wp_query->found_posts,
        'posts_count' => $wp_query->post_count,
        'current_page' => $wp_query->query_vars['paged'] ? $wp_query->query_vars['paged'] : 1,
        'max_pages' => $wp_query->max_num_pages
    ));

    wp_enqueue_script('p28_load_more_filter');
}
add_action('wp_enqueue_scripts', 'p28_load_and_filter');

My functions.php

// Déclaration des styles et animations

require_once get_template_directory() . '/src/server/assets.php';

// Déclaration des CPT

require_once get_template_directory() . '/src/server/post-types.php';

include get_template_directory() . '/src/server/load-more.php';
include get_template_directory() . '/src/server/filter.php';


//Enlever le switcher de langage sur la page de login

add_filter('login_display_language_dropdown', '__return_false');

// Modifier Wp_Query post type pour la pagination des oeuvres

add_action('pre_get_posts', 'post_type_oeuvre', 1, 1);
function post_type_oeuvre($query)
{
    if (is_post_type_archive('oeuvre') && $query->is_main_query()) {
        $query->set('posts_per_page', 8);
    }
}

Could you please tell me if you see something I missed ? What's wrong with my code ?

10
  • the old admin ajax returns a 0 and this HTTP request when you try to query it with an action that doesn't exist, or when your AJAX request is missing an action field. However, it's much easier to use the modern REST API which aside from giving you a pretty permalink URL to make your AJAX request to, it won't respond with a 0 when you make a mistake, it has human readable error messages. Is there a specific reason you chose to use the legacy admin-ajax.php API for AJAX? Did you check your PHP error log?
    – Tom J Nowell
    Commented Jul 8 at 13:00
  • also note the .html etc and any other jQuery methods that try to build HTML using raw strings like this: '<p>' + variable + '</p>' can be extremely insecure/dangerous! You should build HTML in JS using DOM node construction instead, e.g. jQuery( 'p', { text: variable } )
    – Tom J Nowell
    Commented Jul 8 at 13:02
  • I also see that you've decided to add your parameters as URL parameters, but you've chosen to POST which doesn't make sense, I'd take a look at this question and its answer wordpress.stackexchange.com/questions/382129/…
    – Tom J Nowell
    Commented Jul 8 at 13:05
  • Hi @TomJNowell and thank you for answering me ! Here is my answers to your questions : 1-1. The reason why I chose to use Admin Ajax is because I followed a tutorial. 1-2. No error in my PHP logs, unfortunately :'( 2. Thank you for your the advice, I am new to coding so I'll take your advice into account 3. I thought POST method was the good one to use to "hide" the parameters from the displayed URL. I learnt it was better for security purpose, isn't it ? Commented Jul 8 at 13:22
  • if you're using POST then you wouldn't want to put the parameters in the URL ( aka GET ), so in PHP it'll see it's a POST request, look in $_POST and find nothing because of the way you put your parameters in. The problem here is improper use of fetch. Also given that your request handles no personal or sensitive information there is no issue with using GET to get things.
    – Tom J Nowell
    Commented Jul 8 at 13:27

1 Answer 1

0

You're using an invalid Content-Type header.

x-www-form-urlencoded isn't a valid content-type.
The correct content type is application/x-www-form-urlencoded.

Essentially, the web server doesn't know how to handle the content type you're giving it to parse the parameters. This is why the request is failing with a 400 because WP is not getting anything in the POST body, including the action.

You may not need to provide this header at all though as it seems to be the default value.

Not the answer you're looking for? Browse other questions tagged or ask your own question.