Syntax to get the Nth item in a list of custom post types?

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

Solutions Collecting From Web of "Syntax to get the Nth item in a list of custom post types?"

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 );

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();