3

We have a custom post type testimonial and want to show the 1st, 2nd and 3rd in various bespoke locations on the page.

Here's how we would do it if we just wanted to loop over testimonials and show them one after another (this works):

<?php
$args = array('post_type' => 'testimonial');
$testimonials = new WP_Query( $args );
    while( $testimonials->have_posts() ) {
    $testimonials->the_post();
?>
    <li>
        <?php echo get_the_content(); ?>
    </li>

<?php }?>

But to show only the first or only the third or the Nth? Here's what we've got so far (to obtain the first), it's obviously wrong:

$args = array('post_type' => 'testimonial');
$testimonials = new WP_Query( $args );   
$testimonial1 =$testimonials[0]->the_post;
echo $testimonial1->the_content;

We get an error saying:

Fatal error: Cannot use object of type WP_Query as array

7

Make use of an offset to skip the first 2 posts if you need the third post only, and then set you posts_per_page to 1 to get only that specific post

You can try something like this in your arguments

$args = array(
    'post_type' => 'testimonial',
    'offset' => 2,
    'posts_per_page' => 1
);
$testimonials = new WP_Query( $args );
    while( $testimonials->have_posts() ) {
    $testimonials->the_post();
?>
    <li>
        <?php the_content(); ?>
    </li>

<?php }
wp_reset_postdata(); ?>

EDIT

Before I start, a few notes on your code and my edited code. (I have edited my original code to show a normal loop).

  • You don't need to use echo get_the_content(). You can just use the_content() directly

  • Remember to reset your postdata after the loop with wp_reset_postdata().

As requested in comments, here is the alternative syntax where you don't use the loop. Also, a note or two first:

  • With this alternative syntax, you cannot use the template tags as they will not be available

You need to work with the WP_Post objects directly and use filters as described in the link

  • You don't need to reset postdata as you are not altering the globals

You can try

$args = array(
    'post_type' => 'testimonial',
    'offset' => 2,
    'posts_per_page' => 1
);
$testimonials = new WP_Query( $args );

//Displays the title
echo apply_filters( 'the_title', $testimonials->posts[0]->post_title );

//Displays the content
echo apply_filters( 'the_content', $testimonials->posts[0]->post_content );
6
  • thanks for answering. i considered something like that but it seemed inelegant. so is yours the best and only way to do it?
    – hawbsl
    Jan 20 '15 at 13:06
  • There is no other native way to do this if you need something this specifc. And it is the quickest way as well. The only other method would be to get a list of posts and then use normal php to get the desired post from the returned array of posts, but this is much slower that the method in my answer. Simply skipping posts is also not an option, as it is much slower Jan 20 '15 at 13:14
  • ok, so do i still need a while loop?
    – hawbsl
    Jan 20 '15 at 13:17
  • For easyness, yes. Or you can access the post by $testimonials->posts[0] Jan 20 '15 at 13:21
  • Pieter thanks for all the help ... what would a little bit more of the syntax look like for $testimonials->posts[0]? i've tried it and then tried to echo out the content but got nothing showing
    – hawbsl
    Jan 20 '15 at 13:31
4

You could use the current_post property and the rewind_posts() method of the WP_Query class, to target the relevant post objects.

You could try playing with the following example (untested):

if( $testimonials->post_count >= 3 )
{
    // First post:
    $nr = 1;
    if( isset( $testimonials->posts[$nr-1] ) )
    {
        $testimonials->rewind_posts();
        $testimonials->current_post = $nr - 2;
        $testimonials->the_post();
        the_title();
    }

    // Third post:
    $nr = 3;
    if( isset( $testimonials->posts[$nr-1] ) )
    {
        $testimonials->rewind_posts();
        $testimonials->current_post = $nr - 2;
        $testimonials->the_post();
        the_title();
    }

    // Second post:
    $nr = 2;
    if( isset( $testimonials->posts[$nr-1] ) )
    {
        $testimonials->rewind_posts();
        $testimonials->current_post = $nr - 2;
        $testimonials->the_post();
        the_title();
    }  

    wp_reset_postdata();
}    

You could also use it like this, with your current while loops:

$testimonials = new WP_Query( $args );

// First post:
$nr = 1; 
while( $testimonials->have_posts() && ( $nr - 2 ) === $testimonials->current_post ) {
    $testimonials->the_post();
    // ...
}

// Third post:
$nr = 3;
$testimonials->rewind_posts();
while( $testimonials->have_posts() && ( $nr - 2 ) === $testimonials->current_post ) {
    $testimonials->the_post();
    // ...
}

// Second post:
$nr = 2;
$testimonials->rewind_posts();
while( $testimonials->have_posts() && ( $nr - 2 ) === $testimonials->current_post ) {
    $testimonials->the_post();
    // ...
}

wp_reset_postdata();   
1
  • 1
    Cool method if you need to randomly pic posts within the same query. Little bit to much if you need one post :-) Jan 20 '15 at 13:24

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.