0

I am doing a simple page that would work a single page inside Wordpress using Ajax. So to do this, I create a template page with a short-code in it.

But the thing is that I really can't do ajax work in that page and I search in Internet for something similar, but I keep seeing only related to plugins not to single page.

Can anybody know why this code is not working?

The code is inside /wp-content/themes/<theme_name>/rede-template.php

<?php /* Template Name: rede-template */ ?>
<?php get_header(); ?>
<?php
//require_once(get_template_directory() . '/includes/shortcodes/rede-page.php');

add_action('wp_ajax_ajax_action', 'handle_ajax_request');
add_action('wp_ajax_nopriv_ajax_action', 'handle_ajax_request');

function handle_ajax_request(){
    echo "oi";
    wp_die();
}

function rede_page_function() 
{
    $form = "<button id='mybutton'>Click Here</button>";

    echo $form;
}

add_shortcode('rede-page', 'rede_page_function');

echo do_shortcode('[rede-page]')
?>
<script>
jQuery('#mybutton').click(function(e){
    e.preventDefault();

    var data = {action: "ajax_action"};

    jQuery.post("<?php echo admin_url( 'admin-ajax.php' ); ?>", data, function(response){
        console.log(response);
        return false;   
    });
});
</script>
<?php
get_footer(); 

The error is "POST https://localhost/planoamap/wp-admin/admin-ajax.php 400 (Bad Request)"

4
  • 1
    You can't put AJAX handlers in template files, nor should you register shortcodes in template files, that code will only run in the request that displays your template, so it won't exist in the AJAX handler. It needs to go in a plugin or functions.php – Tom J Nowell Apr 15 at 13:57
  • 2
    Also shortcodes can't echo they need to return their content, or you'll run into bugs and issues, but in this example there's no point registering a shortcode, just call rede_page_function(); directly – Tom J Nowell Apr 15 at 13:58
  • Thanks @TomJNowell. In my code, what I need to do is add this part in functions.php ``` add_action('wp_ajax_ajax_action', 'handle_ajax_request'); add_action('wp_ajax_nopriv_ajax_action', 'handle_ajax_request'); ``` But is it possible to point that handle_ajax_request to a different file? For example I leave handle_ajax_request in rede-template.php? – Marcos Felipe Donadeli Gonalez Apr 15 at 17:06
  • you should never make an AJAX request to a PHP file in your theme. AJAX requests in WordPress should go to either the admin AJAX endpoint, or a REST API endpoint. Making direct requests to PHP files in a theme or plugin is extreme bad practice and has security consequences. The same is true of forms. – Tom J Nowell Apr 15 at 19:00
1

As Tom J Nowell noted in the comments, your setup is bit wonky, which is why it won't work. You need to add the ajax actions and register the shortcode earlier - i.e in a custom plugin or in the theme functions.php. This is related to how WordPress handles requests and in which order it loads and does things - the action reference on Codex sheds some light on this.

You could for example structure your theme in the following way to split the code into more managable parts. I've found that it easier to remember and understand what you were thinking at the time of writing the code, when it is smaller pieces instead of putting everything in one long file.

// theme structure
your-theme
    style.css
    index.php
    rede-template.php
    functions.php
    /assets
        scripts.js
    /inc
        shortcodes.php
        ajax.php

If you set up your theme like this, then you need to require/include the partial files in subdirectories in the functions.php file. And as a personal preference I put scripts in a separate js file, which I then enqueue on the wp_enqueue_scripts action - this can also be done in functions.php.

// functions.php
<?php
// include theme files
add_action('after_setup_theme', 'your_theme_files', 1);
function your_theme_files() {
    $path = get_template_directory();
    require_once $path . '/inc/shortcodes.php';
    require_once $path . '/inc/ajax.php';
}

// load assets
add_action('wp_enqueue_scripts', 'your_theme_assets');
function your_theme_assets() {
    $url = get_template_directory_uri();
    // enqueue scripts
    wp_enqueue_script( 'your-theme', $url . '/assets/scripts.js', array('jquery'), '1.0.0', true );
    // localize admin ajax url to be used in script
    wp_localize_script(
        'your-theme', 
        'yourTheme', 
        array(
            'ajaxUrl' => admin_url( 'admin-ajax.php' )
        )
    );
}

Then just add the ajax action, shortcode registering, and the script in their respective files.

// inc/ajax.php
<?php
add_action('wp_ajax_ajax_action', 'handle_ajax_request');
add_action('wp_ajax_nopriv_ajax_action', 'handle_ajax_request');

function handle_ajax_request(){
    echo "oi";
    wp_die();

    // you could also use wp_send_json(), 
    // wp_send_json_error(), 
    // or wp_send_json_success() here
}

// inc/shortcodes.php
<?php
add_shortcode('rede-page', 'rede_page_function');
function rede_page_function($atts, $content = null) {
    $output = '<div>some html</div>';
    // shortcode should return, not echo, its output
    return $output;
}

If you need to add other ajax functions or shortcode, just put their code to the above files along the first ones.

// assets/scripts.js
jQuery('#mybutton').click(function(e){
    e.preventDefault();

    var data = {action: "ajax_action"};

    // get admin ajax url from the localized variable
    jQuery.post(yourTheme.ajaxUrl, data, function(response){
        console.log(response);
        return false;   
    });
});

The same goes with scripts, add other javascript / jquery you need, to the same scripts file. (And if you want to get really fancy, you could use gulp, webpack, etc. to build the enqueued scripts file from partial script files - i.e. concat all scripts to one file, run them through Babel, and minify the file.)

Also, you could consider adding the required html elements directly to your page template instead of getting it from a shortcode. Or call the shortcode callback directly on the template. Or add the Loop and let users add shortcodes, and whatever content they want, to the page using the editor.

// rede-template.php
<?php 
/* Template Name: rede-template */

get_header();
?>

<div id="some-wrapper">

    <button id="myButton">Add button directly to the template</button>

    <?php
        // or with the shortcode callback
        // do_shortcode not strictly required here
        $args = array(
            // 'some' => 'parameter',
        );
        echo rede_page_function($args);

        // or use the Loop and let the user add shortcodes to the page content
        while ( have_posts() ) {
            the_post(); 
            // the_content takes care of rendering shortcodes
            the_content();
        }
    ?>
    
</div>

<?php get_footer();
1
  • Thanks very much for the detailed answer! Really appreciate and understand how to put all this code into work and it works perfectly for my case – Marcos Felipe Donadeli Gonalez Apr 16 at 0:45

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.