5

Due to the setup of my template (and layout), I need to be able to place 4 different posts in 4 different divs.

For example, my structure would be like this

<div>Post 1</div>
<div>
    <div>Post 2</div>
    <div>
        <div>Post 3</div>
        <div>Post 4</div>
    </div>
</div>

But I'm having some trouble getting this to work, I use get_posts to get the 4 latest posts.

$posts = get_posts(array(
    'post_type' => 'post',
    'post_count' => 4
));  

And then I try to display my post

<?php setup_postdata($posts[0]); ?>
<?php get_template_part( 'template-parts/post-thumbnail' ); ?>
<?php wp_reset_postdata(); ?>

In template-parts/post-thumbnail.php I'm trying to display the title and permalink, but it's always showing the title and link of the current page. Never of the actual post.

4 Answers 4

7

Your problem is that the variable passed to setup_postdata() must be the global $post variable, like this:

// Reference global $post variable.
global $post;

// Get posts.
$posts = get_posts(array(
    'post_type' => 'post',
    'post_count' => 4
));  

// Set global post variable to first post.
$post = $posts[0];

// Setup post data.
setup_postdata( $post );

// Output template part.
get_template_part( 'template-parts/post-thumbnail' );

// Reset post data.
wp_reset_postdata();

Now normal template functions, like the_post_thumbnail() inside the template part will reference the correct post.

2
  • 1
    Aha, that as it. I didn't realise it had to be specifically called $post, thanks!
    – woutr_be
    Commented Jul 21, 2017 at 7:56
  • 1
    Yeah it's pretty weird. I've definitely tripped over this many times before. Also make sure to use global $post so that you're using the global post variable. Commented Jul 21, 2017 at 7:58
4

Other than messing with the globals, you can write a custom loop that requires absolutely no extra work to make your template part work. For example:

$args = array(
    'post_type' => 'post',
    'posts_per_page' => 4
);

$my_query = new WP_Query($args);
if ($my_query->have_posts()){
    while ($my_query->have_posts()){
        $my_query->the_post(); // This is where the post's data is set up
        get_template_part( 'template-parts/post-thumbnail' );
    }
}

Done. You don't need to set up post's data for each post in the loop.

By the way get_posts() itself uses a WP_Query() to fetch the posts, but the difference is that it doesn't set up the post's data for you, and it needs to be reset after the loop.

2
  • Sure, but due to my structure, I couldn't do this. Unless you can point me in the right direction to get it to work with that.
    – woutr_be
    Commented Jul 21, 2017 at 10:34
  • 1
    @woutr_be you can do the same thing by replacing get_posts with $query = new WP_Query($args) and replacing setup_postdata() with $query->the_post(). The while loop isn't strictly necessary, each call to $query->the_post() will populate the internal vars with the next post's data.
    – Milo
    Commented Jul 21, 2017 at 16:46
3

$posts wouldn't be available within context of post-thumbnail.php if you're using get_template_part(), so it will use the post ID found for the current page. You should use locate_template() to make the variable available, which is what get_template_part uses internally, like this:

<?php $posts = get_posts( array( 'post_type' => 'post', 'post_count' => 4 ) ); ?>

<?php foreach ( $posts as $post ) : setup_postdata( $post ); ?>
    <?php locate_template( 'page-templates/post-thumbnail.php', true, false ); ?>
<?php endforeach; wp_reset_postdata(); ?>

Then you would be able to have whatever you have in the page-templates/post-thumbnail.php template with the correct post data:

<div>
    <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</div>
2
  • locate_template isn't necessary. Template tags and the global post variable will be available in the template part if setup_postdata() is used correctly. OP's problem is that the variable passed to setup_postdata() must be called $post. Commented Jul 21, 2017 at 7:49
  • 1
    Interesting - I seem to recall having issues with get_template_part in the past, I just tested out your example and it works great, thanks for sharing!
    – Tim Elsass
    Commented Jul 21, 2017 at 8:48
2

Take it to your provinces

<?php foreach ($posts as $post) : setup_postdata( $post ); ?>
    <div>
        <a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
    </div>
<?php endforeach; wp_reset_postdata(); ?>

wp_reset_postdata is important to reset a current query's result.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.