Im trying to create a very basic AJAX script that shows a random post title, just so I at least know I can get AJAX to work.
But I keep getting a 400 error in the Chrome console.
I've been checking my admin-ajax.php URL is correct and have also tried specifying it absolutely, but still no luck
I've tried both GET and POST and neither seem to work
Im building this locally on MAMP, could that be related to my issues?
Here is my template file:
<?php
/* Template Name: Page AJAX */
get_header();
?>
<div class="container-fluid">
<div class="row">
<div class="col-8 offset-2">
<div id="result"></div>
<button id="load_data">Load Random Post Title</button>
</div>
</div>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('#load_data').click(function() {
var data = {
action: 'load_random_post_title',
security: '<?php echo wp_create_nonce("load_random_post_title_nonce"); ?>' // Add nonce for security
};
$.ajax({
url: '<?php echo admin_url("admin-ajax.php"); ?>', // Ensure correct URL
type: 'POST',
data: data,
success: function(response) {
$('#result').html(response); // Display the random post title
},
error: function(xhr, status, error) {
console.error('AJAX error:', status, error); // Log any error
}
});
});
});
</script>
<?php get_footer(); ?>
And here is from functions.php
// AJAX
function handle_random_post_title_request()
{
// Verify nonce for security
if (
!isset($_POST['security']) ||
!wp_verify_nonce($_POST['security'], 'load_random_post_title_nonce')
) {
wp_die('Permission Denied: Nonce verification failed.');
}
// Get a random post
$args = array(
'posts_per_page' => 1, // Get one post
'orderby' => 'rand', // Order by random
'post_type' => 'post', // Post type is 'post'
'post_status' => 'publish' // Only published posts
);
$random_post = get_posts($args);
if ($random_post) {
// Output the title of the random post
echo esc_html($random_post[0]->post_title);
} else {
echo 'No posts found.';
}
wp_die(); // Always call wp_die() to end AJAX requests properly
}
// Hook the AJAX request (both for logged-in and non-logged-in users)
add_action('wp_ajax_load_random_post_title', 'handle_random_post_title_request');
add_action('wp_ajax_nopriv_load_random_post_title', 'handle_random_post_title_request');
Im trying to create a very basic AJAX script that shows a random post title, just so I at least know I can get AJAX to work.
But I keep getting a 400 error in the Chrome console.
I've been checking my admin-ajax.php URL is correct and have also tried specifying it absolutely, but still no luck
I've tried both GET and POST and neither seem to work
Im building this locally on MAMP, could that be related to my issues?
Here is my template file:
<?php
/* Template Name: Page AJAX */
get_header();
?>
<div class="container-fluid">
<div class="row">
<div class="col-8 offset-2">
<div id="result"></div>
<button id="load_data">Load Random Post Title</button>
</div>
</div>
</div>
<script type="text/javascript">
jQuery(document).ready(function($) {
$('#load_data').click(function() {
var data = {
action: 'load_random_post_title',
security: '<?php echo wp_create_nonce("load_random_post_title_nonce"); ?>' // Add nonce for security
};
$.ajax({
url: '<?php echo admin_url("admin-ajax.php"); ?>', // Ensure correct URL
type: 'POST',
data: data,
success: function(response) {
$('#result').html(response); // Display the random post title
},
error: function(xhr, status, error) {
console.error('AJAX error:', status, error); // Log any error
}
});
});
});
</script>
<?php get_footer(); ?>
And here is from functions.php
// AJAX
function handle_random_post_title_request()
{
// Verify nonce for security
if (
!isset($_POST['security']) ||
!wp_verify_nonce($_POST['security'], 'load_random_post_title_nonce')
) {
wp_die('Permission Denied: Nonce verification failed.');
}
// Get a random post
$args = array(
'posts_per_page' => 1, // Get one post
'orderby' => 'rand', // Order by random
'post_type' => 'post', // Post type is 'post'
'post_status' => 'publish' // Only published posts
);
$random_post = get_posts($args);
if ($random_post) {
// Output the title of the random post
echo esc_html($random_post[0]->post_title);
} else {
echo 'No posts found.';
}
wp_die(); // Always call wp_die() to end AJAX requests properly
}
// Hook the AJAX request (both for logged-in and non-logged-in users)
add_action('wp_ajax_load_random_post_title', 'handle_random_post_title_request');
add_action('wp_ajax_nopriv_load_random_post_title', 'handle_random_post_title_request');
You're getting a HTTP 400 because there is no ajax handler for load_random_post_title
. This is because the only place that handler exists is when that template page is being displayed, and since that never happens on an AJAX request it will never be found. As a result the legacy ajax handler returns 0
with a HTTP code of 400.
Instead, you should move those AJAX handlers to a place that always runs, not a theme template. E.g. a plugin or functions.php
Alternatively instead of using the old AJAX API, instead consider using the new API by registering a REST API endpoint. This gives you a pretty URL, human readable error messages, and built in validation/authentication/sanitizing options that would need to be built from scratch if using admin-ajax.php
here is a proposal with an API endpoint and javascript code in a external file.
add_action("rest_api_init", function (\WP_REST_Server $wp_rest_server) {
register_rest_route(
"MY_PLUGIN"
, "random_post"
, [
"methods" => WP_REST_Server::READABLE, // "GET"
"permission_callback" => fn (\WP_REST_Request $request) => TRUE,
"callback" => function (\WP_REST_Request $req) {
$response = [
"code" => "not_found",
];
// Get a random post
$args = [
'posts_per_page' => 1, // Get one post
'orderby' => 'rand', // Order by random
'post_type' => 'post', // Post type is 'post'
'post_status' => 'publish', // Only published posts
];
$random_posts = get_posts($args);
if (isset($random_posts[0])) {
$post = $random_posts[0];
$response["code"] = "found";
$response["title"] = $post->post_title;
$response["permalink"] = get_permalink($post);
}
return $response;
},
]
);
}, 10, 1);
wp_enqueue_script(
"MY_PLUGIN/load_random_post_title"
, "load_random_post_title.js"
, ["wp-api"] // to retrieve api root in javascript variable wpApiSettings
, "1" // script version
);
?>
<div id="result"></div>
<button id="load_data">Load Random Post Title</button>
<?php
"use strict";
document.addEventListener("DOMContentLoaded", e => {
document.getElementById("load_data").addEventListener("click", e => {
fetch(`${wpApiSettings["root"]}MY_PLUGIN/random_post`)
.then(r => r.json())
.then(json => {
const result = document.getElementById("result");
if ( "undefined" === typeof json["code"]
|| "found" !== json["code"]
) {
result["textContent"] = `No posts found.`;
} else {
const post_link = document.createElement("a");
post_link["textContent"] = json["title"];
post_link.setAttribute("href", json["permalink"]);
result.replaceChildren(post_link);
}
})
.catch(error => console.error(error))
;
});
});