Using a PostQuery in your Template
Code
No more tb.get_posts() ! You can do a Timber PostQuery inside your Timber Posts Modules from now on. Added in Toolbox 1.2.3 Make sure to update your Toolbox version before using the PostQuery function
Previously, when doing a query inside the Timber Posts module you needed to use tb.get_posts(), but had to fetch a seperate Timber Post Object to get access to all Timber Objects:
{% set args = { post_type: 'my_post_type' } %}
{% set posts = tb.get_posts( args ) %}
{% for item in posts %}
{# reset the WP Post Object-item as a Timber Post-item #}
{% set item = Post( item.ID ) %}
<h3>{{item.title}}</h3>
<div>{{item.preview(50)}}</div>
{% endfor %}
This is quite useful and easy to use, and of course this will still do in most cases. But since Toolbox 1.2.3 there is an alternative that returns Timber Post Objects by default and also brings useful features like pagination.
Let’s showcase how easy it now is to create a paginated result container. For this we will use the Twig template below as a basis.
{% set args = { post_type: 'code', posts_per_page: 4 } %}
{% set posts = PostQuery( args ) %}
<div class="uk-child-width-1-2@s the-posts" uk-grid>
{% for item in posts %}
<div>
<div class="uk-card uk-card-default uk-card-body">
<h3>{{item.title}}</h3>
<div>{{item.preview(50)}}</div>
</div>
</div>
{% endfor %}
</div>
<div class="uk-margin-top">
{% for item in posts.pagination.pages %}
<a href="javascript:void(0);"
class="load-more pagination-item{{ item.current ? ' current' }}"
data-args="{{ args|json_encode|e( 'html' )}}"
data-page="{{item.name}}">
{{- item.name -}}
</a>
{% endfor %}
</div>
And this should give you a result similar to this one (using this site’s ‘code’ CPT):
HTMX Requests
Creating a custom taxonomy filter
Adding Global Twig Variables
Tabs by month
Adding a WP AJAX action hook
As you can see in the pagination code, we are using our base args
(arguments for the query) and our page
to set data-attributes on the links. We will be passing these to our AJAX call later using some javascript. For now, let’s concentrate on the PHP to add a WP AJAX action hook. We’ll be adding a generic function so we can use any Twig template we want for a custom call.
<?php
add_action( 'wp_ajax_twig-load-more' , 'ajax_twig_load_more_callback' );
add_action( 'wp_ajax_nopriv_twig-load-more' , 'ajax_twig_load_more_callback' );
/**
* WP AJAX action callback
*/
function ajax_twig_load_more_callback() {
render_twig_template( 'twig-load-more-demo.twig' );
}
/**
* Callback to render a Twig template
* @return [type] [description]
*/
function render_twig_template( $templatename ) {
//if ( !is_user_logged_in() ) wp_die();
DEFINE( 'DOING_AJAX' , true );
$data = \Timber::get_context();
// buffer output
ob_start();
// Use try to prevent failure
try {
// render $twig template with numberposts and offset as variables
\Timber::render( $templatename , $data );
} catch( Exception $e ) {
if ( apply_filters( 'toolbox/twig_error_debug' , true ) ) echo '[ error handling twig template ] ' . $e->getMessage();
}
// echo result
echo ob_get_clean();
// wp_die() because we want it to end here
wp_die();
}
The load_more_twig function
The render_twig_template
function is added so we can call any Twig template that we have registered. It takes a variable called $templatename
, which is the path and filename to that Twig template.
The ajax_twig_load_more_callback function
The ajax_twig_load_more_callback
function is the callback that is getting executed when the wp_ajax action ‘twig-load-more’ is being called using the /wp-admin/admin-ajax.php?action={action}
call.
To sum things up, when the call is being performed, it will execute the function/callback ajax_twig_load_more_callback()
, which in turn will execute render_twig_template( 'twig-load-more-demo.twig' )
. This should render the template results back to the script calling it.
Adding javascript to perform the request
In order to perform the request, we will add a bit of javascript to our layout. The following javascript will listen to clicks on the DOM elements with a .load-more
class attached to it. We’ve used this class for our pagination links.
When any of the pagination links is clicked, it uses $.ajax
to request our WP AJAX action ‘twig-load-more’ and passes in our link’s data-args
and data-page
attributes as data variables. We’ll use these to lign up our Twig request with our original call.
When the call receives the rendered template, it will replace the contents of the element with a class of .the-posts
with it.
(function($) {
$( '.load-more' ).on( 'click' , function() {
// remove the current class from any load-more item
$( '.load-more' ).each( function( index ){ $(this).removeClass( 'current' ); } )
$this = $(this);
// add current class
$this.addClass( 'current' );
$.ajax( {
method: 'POST',
url: '/wp-admin/admin-ajax.php?action=twig-load-more',
data: {
args: $this.data( 'args' ),
page: $this.data( 'page' ),
}
} ).done( function( data ) {
$( '.the-posts' ).html( data );
});
});
})(jQuery);
Adding our Twig template for paginated results
Now all that remains is adding the Twig template that will render our paginated call. For this we will add it to our Twig Templates CPT.
Make sure that the slug for the template is ‘twig-load-more-demo’, so that our template will be called correctly.
{# filename: twig-load-more-demo.twig #}
{% set args = request.post.args|merge( { paged: request.post.page , post_status: 'publish' } ) %}
{% set posts = PostQuery( args ) %}
{% for item in posts %}
<div>
<div class="uk-card uk-card-default uk-card-body">
<h3>{{item.title}}</h3>
<div>{{item.preview(50)}}</div>
</div>
</div>
{% endfor %}
Notice that here, we are using the Timber request
object that was added using the Timber::get_context()
function in our PHP, to access any post data. We are merging the args, which we passed to our call, with our page
number and a post_status
so that we are sure that only published posts are showing.
Because we are replacing the content inside our .the-posts element only, we only render the elements, and not the surrounding container.
Beaverplugins
Web ninja with PHP/CSS/JS and Wordpress skills. Also stand-in server administrator, father of four kids and husband to a beautiful wife.Always spends too much time figuring out ways to do simple things even quicker. So that you can benefit.