Implementing AJAX Functionality Within WordPress Custom Shortcodes

I’m having trouble with my WordPress AJAX setup

I created a custom shortcode that shows random inspirational messages, but the AJAX part isn’t working correctly. When users click the “Get New Message” button, absolutely nothing happens. The page just sits there doing nothing.

My Current Setup

PHP Handler File

/wp-content/themes/mytheme/js/fetch-message.php

<?php
// require_once('../../../../wp-load.php'); // uncomment if needed

$messages = file($_POST['data_file']);
$random_index = rand(0, count($messages) - 1);

echo '<div class="message-content">' . $messages[$random_index] . '</div>';
?>

Frontend HTML Output

<section id="inspirational-messages">
    <div class="message-content">
        The only way to do great work is to love what you do.<br>
        -- Steve Jobs, Co-founder of Apple Inc.
    </div>
</section>
<button id="fetch-new-message" class="btn-primary" type="button">Get New Message</button>

JavaScript Code

/wp-content/themes/mytheme/js/message-loader.js

function loadNewMessage() {
    var request = jQuery.ajax({
        method: 'POST',
        url: scriptVars.templateURL + 'js/fetch-message.php',
        data: { data_file: scriptVars.messageFile },
        beforeSend: function() {
            showLoader(true, '#inspirational-messages');
        },
        success: function(response) {
            jQuery('#inspirational-messages .message-content').remove();
            jQuery('#inspirational-messages').html(response);
        },
        complete: function() {
            showLoader(false, '#inspirational-messages');
        }
    });
    return request;
}

function showLoader(display, target) {
    if (display) {
        var loaderHTML = '<div class="loading-indicator"><img src="' + scriptVars.templateURL + 'images/spinner.gif" alt="Loading..." /></div>';
        jQuery(target).append(loaderHTML);
    } else {
        jQuery(target + ' .loading-indicator').remove();
    }
}

jQuery('#fetch-new-message').on('click', function(e) {
    e.preventDefault();
    loadNewMessage();
});

Functions.php Integration

function inspirational_message_shortcode($attributes) {
    extract(shortcode_atts(array(
        'source' => get_template_directory_uri() . '/data/messages.txt'
    ), $attributes));
    
    $message_list = file($source);
    $random_pick = rand(0, count($message_list) - 1);
    
    $html_output = '<section id="inspirational-messages"><div class="message-content">' . $message_list[$random_pick] . '</div></section>';
    $html_output .= '<button id="fetch-new-message" class="btn-primary" type="button">Get New Message</button>';
    
    wp_enqueue_script('message-ajax-script');
    wp_localize_script('message-ajax-script', 'scriptVars', array(
        'messageFile' => $source,
        'templateURL' => get_template_directory_uri() . '/'
    ));
    
    return $html_output;
}
add_shortcode('daily_inspiration', 'inspirational_message_shortcode');

function register_message_scripts() {
    if (!is_admin()) {
        wp_register_script(
            'message-ajax-script',
            get_template_directory_uri() . '/js/message-loader.js',
            array('jquery'),
            '1.0.0',
            true
        );
    }
}
add_action('init', 'register_message_scripts');

Can anyone spot what might be preventing the AJAX request from working properly? I’m pretty sure I’m missing something obvious but can’t figure out what it is.

WordPress blocks direct access to standalone PHP files for security - that’s your main problem. Even if it worked, the file can’t access WordPress functions anyway. Had the same issue last year with a custom quote system. Fixed it by switching to WordPress’s AJAX handler instead. Create an AJAX action in functions.php and point your JavaScript to admin-ajax.php. Don’t forget the ‘action’ parameter in your AJAX data - WordPress needs it to route requests properly. Also check if your script’s actually loading. Throw a console.log in your click handler to see if it fires. Sometimes the JavaScript just isn’t loading at all.

you’re bypassing wordpress security by calling a php file directly. use wp_ajax_* actions in functions.php with admin-ajax.php as ur endpoint instead of a custom file.

Your AJAX handler is sitting completely outside WordPress - that’s the problem. You can’t just call PHP files directly in WordPress themes like that. They won’t have access to WordPress functions and you’ll get 404 errors or security blocks.

Here’s what you need to do: Move your PHP code from fetch-message.php into a function in functions.php. Hook it to wp_ajax and wp_ajax_nopriv actions. Then update your JavaScript to hit admin-ajax.php with an action parameter instead.

I ran into this exact same issue when I first started with WordPress AJAX. Once I switched to admin-ajax.php as the endpoint with proper action hooks, everything just worked. The WordPress way looks more complicated at first, but it handles all the security and loading stuff for you automatically.