1

So, I've got a custom field (meta_key) 'premium' with some posts (meta_value) set to '1'.

I would like to display all of the premium posts above the the others. I imagine this would be done using multiple loops as demonstrated within the codex. https://codex.wordpress.org/Class_Reference/WP_Query

Multiple Loops

<?php

// The Query
$query1 = new WP_Query( $args );

// The Loop
while ( $query1->have_posts() ) {
    $query1->the_post();
    echo '<li>' . get_the_title() . '</li>';
}

/* Restore original Post Data 
 * NB: Because we are using new WP_Query we aren't stomping on the 
 * original $wp_query and it does not need to be reset with 
 * wp_reset_query(). We just need to set the post data back up with
 * wp_reset_postdata().
 */
wp_reset_postdata();


/* The 2nd Query (without global var) */
$query2 = new WP_Query( $args2 );

// The 2nd Loop
while ( $query2->have_posts() ) {
    $query2->the_post();
    echo '<li>' . get_the_title( $query2->post->ID ) . '</li>';
}

// Restore original Post Data
wp_reset_postdata();

?>

I don't know how to achieve this using Twig, and I'm struggling to find much discussion on the templating language. This is what I have in archive-agency.php

global $wp_query;

$premium_args = array_merge( $wp_query->query_vars, array(
    'meta_key' => 'premium-franchisor',
    'meta_value' => '1',
) );

query_posts( $premium_args );

$the_query = new WP_Query( $premium_args );

echo View::render( 'archive-agency.twig', array(
    'wp_query'       => $wp_query,
    'posts'          => $wp_query->posts,
    'posts_per_page' => - 1,
) );

But because of the (M?)VC pattern of separating the data from the template, I can't make a second query without it wanting to render the entire view, which makes things, awkwardly appear after the footer.

Is there a better way to approach this when using Twig?

Thanks

2

I think you might not need multiple loops to get your data into your template.

As I understood it, it’s a matter of sorting. You want to sort your posts so that posts with premium-franchisor set to 1 appear first. You can already do this using WP_Query. This is how your arguments array could look like:

$args = array(
    // Get all posts
    'posts_per_page' => -1,
    // Order by meta value first, then order by post date
    'orderby' => array(
        'meta_value_num' => 'DESC',
        'date' => 'DESC'
    ),
    // Select meta key which will be used for meta_value_num in orderby
    'meta_key' => 'premium-franchisor',
);

Concluding from the title of your question I guess that you want to use Timber together with Twig to bring your data into your template.

This is how you could do that:

<?php

$context = Timber::get_context();

$args = array(
    // Get all posts
    'posts_per_page' => -1,
    // Order by meta value first, then order by post date
    'orderby' => array(
        'meta_value_num' => 'DESC',
        'date' => 'DESC'
    ),
    // Select meta key which will be used for meta_value_num in orderby
    'meta_key' => 'premium-franchisor',
);

$posts = Timber::get_posts( $args );

$context['posts'] = $posts;

Timber::render( 'archive-agency.twig', $context );

In Timber you use a context that you fill with the data you want to hand over to your template. To set up all the basic data Timber needs, we use get_context() at the beginning. We then use Timber::get_posts() to basically do a normal WP_Query with our customized args. Getting your post through Timber will make it easier to access post properties in your template.

You could display your posts like this:

<div class="post-preview">
    <a href="{{ post.permalink }}">{{ post.title }}</a>
    <span class="post-date">{{ post.date }}</span>
    {% if attribute( post, 'premium-franchisor') %}This is a premium post.{% endif %}
</div>

See, post.permalink or post.title are not properties you get when you run a normal WP_Query, but only if you query through Timber. Here you’ll find a list with methods and properties that you can use.

Using multiple loops in Timber

Since you asked how to do multiple loops, I will also show you an example of how you could achieve the same result you tried:

$context = Timber::get_context();

// Get all premium_posts
$premium_args = array(
    'meta_key' => 'premium-franchisor',
    'meta_value' => '1',
    'posts_per_page' => -1,
);

$premium_posts = Timber::get_posts( $premium_args );

// Get all other posts
$my_other_args = array(
    'meta_key' => 'premium-franchisor',
    'meta_value' => '0',
    'posts_per_page' => -1,
);

$my_other_posts = Timber::get_posts( $my_other_args );

// Merge the two post arrays into one and assign it to context
$posts = array_merge( $premium_posts, $my_other_posts );
$context['posts'] = $posts;

Timber::render( 'index.twig', $context );

When you get your posts through Timber, you don’t get an object that you have to loop over to get to your data, but you get a simple array of posts to work with. You can edit, extend, sort or in your example: merge them very easily.

A small remark on premium-franchisor

In your meta key premium-franchisor you used a hyphen. I’d advise you to use an underscore instead of a hyphen because often, it’s easier to access a property. E.g. you wouldn’t have to use

{% if attribute(post, 'premium-franchisor') %}{% endif %}

But could just use

{% if post.premium_franchisor %}{% endif %}

Even if this is a very late answer, I hope this will help you or others get going with Timber and Twig.

| improve this answer | |

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.