Search code examples
ajaxwordpresstwigtimber

Reload .twig template with AJAX


I am using https://github.com/gmrchk/swup in combination with Twig/Timber. It works great, however, I have realised that none of my if clauses work whenever I get to a new page, since SWUP can't read the if arguments from my twig files. (it is a JS library to load pages dynamically)

For example:

{% if fn('is_single') %}
<div class="progress"></div>
{% endif %}

wouldn't load at all when I initially load the page on a not single-post page.

My idea was to re-render header.twig (where the above mentioned if clause is) with an AJAX call.

The AJAX call looks like that:

function swupReplaceHeader() {
    jQuery.ajax({
        type: "POST",
        url: "/wp-admin/admin-ajax.php",
        data: {
            action: 'spx_replace_header',
        },
        success: function (output) {
            console.log(output);
        }
    });
}

swupReplaceHeader();
document.addEventListener('swup:clickLink', swupReplaceHeader);

It is wrapped inside an event listener that fires every time I click on a link.

The WP function looks like that:

add_action('wp_ajax_spx_replace_header', 'spx_replace_header');
add_action('wp_ajax_nopriv_spx_replace_header', 'spx_replace_header');
function spx_replace_header()
{
    $context = Timber::get_context();
    Timber::render('templates/header.twig', $context);
    wp_send_json_success(['AJAX is working']);
}

I added the send JSON message to test if my AJAX call is working.

Now, whenever I test the AJAX call without the Timber code it is working, but when I add the two Timber lines to the function, nothing happens - not even the JSON message appears. I tried Timber::compile as well without any luck.

I hope someone can help me..

Best, Dennis


Solution

  • Answer posted by aj-adl on Github:

    Hey Dennis,

    You're making a call to wp-admin/admin-ajax.php, so conditionals like is_ajax() will return true but is_single() will definitely not.

    Remember that PHP shuts down at the end of each request, discarding state etc, so the call to the admin-ajax.php script is a completely isolated process from the one that's delivered the initial markup for the page, and doesn't know what page it's being called from etc

    For this reason, you'd want to pass in any data you'd need for conditionals, probably as a query string parameter.

    PHP:

    add_action('wp_ajax_nopriv_spx_replace_header', 'spx_replace_header');
    
    function spx_safe_get_string( $key )
    {
        if ( ! isset( $_GET[ $key ] ) ) return '';
       return sanitize_text_field( $_GET[ $key ] );
    }
    
    function spx_replace_header()
    {
        $context = Timber::get_context();
        // Set this in the context, so we can access it in our twig file easily
        $context[ 'type' ] = spx_safe_get( 'my_page_type' );
        Timber::render('templates/header.twig', $context);
    }
    

    JS:

    window.addEventListener('load', function() {
        jQuery.ajax({
            type: "POST",
            url: "/wp-admin/admin-ajax.php",
            data: {
                action: 'spx_replace_header',
                my_page_type: 'single',
            },
            success: function (data) {
                console.log(data);
            }
        });
    })
    

    Twig:

    {% embed "objects/header.twig" with {'hamburger': 'hamburger--spring'} %}
    {% endembed %}
    
    {% if type == 'single' %}
        <div class="progress"></div>
    {% endif %}
    
    {% embed "objects/header.twig" with {'id': '--sticky', 'hamburger': 'hamburger--spring'} %}
    {% endembed %}