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.
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):
Creating a custom taxonomy filter
Using a PostQuery in your Template
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.
/**
* Callback to render a Twig template
* @return [type] [description]
*/
function load_more_twig( $twig ) {
//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( $twig , $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();
}
/**
* WP AJAX action callback
*/
function twig_load_more() {
load_more_twig( 'twig-load-more-demo.twig' );
}
add_action( 'wp_ajax_twig-load-more' , 'twig_load_more' );
add_action( 'wp_ajax_nopriv_twig-load-more' , 'twig_load_more' );
The load_more_twig function
The load_more_twig
function is added so we can call any Twig template that we have registered. It takes a variable called $twig
, which is the path and filename to that Twig template.
The twig_load_more function
The twig_load_more
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. You can see that being added on the last two lines.
To sum things up, when the call is being performed, it will execute the function/callback twig_load_more()
, which in turn will execute load_more_twig( '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.
{% 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.