1

I have a the following

  • Custom post type: episode

  • Custom taxonomy: series

    • sub terms real deal -> season 1, season 2, season 3, etc.

The terms are hierarchical, and the entire thing is intended to be structured like a TV series (each "series" has "seasons").

On the single-episode.php page, I want to display the current episode, AS WELL AS links to the next 3 episodes and previous 3 episodes in that season.

As an example, if on the "Season 1 - Episode 5" page, I need to get content for Season 1,

Episodes 4,3,2 + Season 1 Episodes 6,7,8.

I'm having trouble figuring out how to do this inside the loop on a single episode page.

Here's what I currently have, however it does not work -- it just repeats the current page episode title over and over with a

trying to get property of non-object

error.

<?php
  $args = array(
      'post-type'      => 'episode',
      'post-status'    => 'publish',
      'posts_per_page' => 6,
      'tax_query'      => array(
          'relation' => 'AND',
          array(
              'taxonomy' => 'series',
              'field'    => 'slug',
              /* Name of the "series" (in slug format) */
              'terms'    => array( 'season-1' ),
          ),
          array(
              'taxonomy' => 'series',
              'field'    => 'slug',
              /* Name of the "seasons" (in slug format) DYNAMIC */
              'terms'    => array( $term->slug ),
          )
      )
  );
  $episodes = new WP_Query( $args );
  foreach( $episodes as $episode ) {
    echo get_the_title($episode->id);
  }
?>

EDIT:

Here's my updated query, still a work in progress. It does not seem to be getting anything at the moment. I want to get a total of 6 results, 3 posted BEFORE to the current post, 3 posted AFTER the current post. I'm trying to use the post_date for both the before and after properties of date_query but not sure if I'm doing it right.

$args = [
    'tax_query' => [
      'relation' => 'AND', [
        'taxonomy' => 'series',
        'field'    => 'slug',
        /* Name of the "series" (in slug format) */
        'terms'    => ['season-1'],
      ]
    ],
    'posts_per_page' => 6,
    /* make query more efficient */
    'no_found_rows' => true,
    /* dont let filters/pre_get_posts modify query */
    'suppress_filters' => true,
    'date_query' => [
      [
        'before'    => $post_object->post_date,
        'after'     => $post_object->post_date,
      ],
      'inclusive' => false
    ]
];
$q = new WP_Query( $args );
return $q->posts;

EDIT 2:

I've gotten my desired effect working using a very inefficient method -- it works, but I'd LOVE to hear some tips to optimize it! seems very expensive in terms of queries right now.

$orig_post = $post;
$orig_terms = wp_get_post_terms($orig_post->ID, 'series');
$current_post = $post;
$adjPost = [
  'prev' => [],
  'next' => []
];

for($i = 1; $i <= 3; $i++){
  $post = get_previous_post(true, '', 'series'); // this uses $post->ID
  if ( $post ) {
    $these_terms = wp_get_post_terms($post->ID, 'series');
    if ( $these_terms[1]->slug === $orig_terms[1]->slug) {
      array_push( $adjPost['prev'], $post );
    }
  }
}
$post = $current_post;

for($i = 1; $i <= 3; $i++){
  $post = get_next_post(true, '', 'series'); // this uses $post->ID
  if ( $post ) {
    $these_terms = wp_get_post_terms($post->ID, 'series');
    if ( $these_terms[1]->slug === $orig_terms[1]->slug) {
      array_push( $adjPost['next'], $post );
    }
  }
}
$post = $current_post;

echo "<h1>Prev:</h1>";
foreach ( $adjPost['prev'] as $prev ) {
  echo '<br>';
  echo $prev->post_title;
}

echo "<h1>Next:</h1>";
foreach ( $adjPost['next'] as $next ) {
  echo '<br>';
  echo $next->post_title;
}
3
  • You can try this approach. Apr 1, 2015 at 16:09
  • @PieterGoosen if I am reading your post correctly (apologies if mistaken), but the query will only get episodes after the current one, yes? I want to get 3 episodes after the current, as well as 3 episodes before the current. Doable in a single query?
    – tdc
    Apr 1, 2015 at 19:50
  • @PieterGoosen I've added a modified version of your query to my original post, still not working though. Think I'm having issues with the tax_query portion. Also Not sure how to get posts both before and last without doing two queries.
    – tdc
    Apr 1, 2015 at 20:04

2 Answers 2

1

You second approach (EDIT 2) is quite buggy and inefficient unfortunately. Also, you are not going to do this in one query.

As I already stated, you need to look at the approach in this answer I have recently done. You were almost there in your first edit, the only problem is, you cannot do this in one query, you will have to do two, one to get the previous set of posts, the other to get the next set of posts.

I have optimized the code to do only get the necessary info and nothing more. WP_Query results is also cached, so you really don't have to to worry that much about efficiency.

I'm not going to rerun through all the detail again in this answer, you should go through the linked post in detail, but you can try something like this (CAVEAT: Untested. Please see the notes in linked answer)

$post_object = get_queried_object();
$terms = wp_get_post_terms( $post_object->ID, 'series', array( 'fields' => 'ids' ) ); // Set fields to get only term ID's to make this more effient
$args = [
    'post_type' => $post_object->post_type,
    'tax_query' => [
       [
        'taxonomy' => 'series',
        'terms'    => $terms,
      ]
    ],
    'posts_per_page' => 3,
    'order' => 'ASC' // CHANDE TO DESC IF NOT CORRECT
    /* make query more efficient */
    'no_found_rows' => true,
    /* dont let filters modify query */
    'suppress_filters' => true,
    'date_query' => [
      [
        'before'    => $post_object->post_date,
        'inclusive' => false
      ],
    ]
];
$q1 = new WP_Query( $args );
var_dump( $q1->posts );

$args1 = [
    'post_type' => $post_object->post_type,
    'tax_query' => [
       [
        'taxonomy' => 'series',
        'terms'    => $terms,
      ]
    ],
    'posts_per_page' => 3,
    'order' => 'DESC' // CHANDE TO ASC IF NOT CORRECT
    /* make query more efficient */
    'no_found_rows' => true,
    /* dont let filters modify query */
    'suppress_filters' => true,
    'date_query' => [
      [
        'after'    => $post_object->post_date,
        'inclusive' => false
      ],
    ]
];
$q2 = new WP_Query( $args1 );
var_dump( $q2->posts );
6
  • You could up the ante a little and set cache_results => false and fields => ids, then merge the two results and _prime_post_caches( $merged ); Apr 2, 2015 at 13:07
  • Thanks, will look into _prime_post_caches, that is something new to me :-). I, do however use the fields parameter myself, left it out here as the OP needs post titles. I have explained this in the linked post. This is a basic skeleton on which the OP can extend. Hopefully I can release my plugin someday with all these features. Just have enough time to complete it though :-) Apr 2, 2015 at 15:45
  • just had to specify the term in 'terms'=>$terms[1] and switch the ASC and DESC values -- works great! Final question. If on the "last" episode (ie, no more posts ahead of it), I'd like to still retrieve 6 episodes in the past. I want to retrieve 6 episodes at all times. so, if the series length is 10 episodes, and I'm on #5, I want to retrieve 6,7,8 & 4,3,2. If on #10, retrieve 9,8,7,6,5,4. If on #1, retrieve 2,3,4,5,6,7. Hope that makes sense. I did not make this clear in my OP.
    – tdc
    Apr 2, 2015 at 22:08
  • Please don't waste other's time by posting incorrect or incomplete information in your question. Apr 3, 2015 at 3:06
  • @PieterGoosen I'm sorry? I'm not wasting your time when you're willingly choosing to answer questions. Your solution met the criteria I originally outlined so there's no harm. I didn't see any harm in asking an additional question. But thanks anyway.
    – tdc
    Apr 3, 2015 at 16:33
0

Your syntax is slightly off - $episodes is an instance of WP_Query, not an array. If you want a full-blown loop for using all template tags, use:

while ( $episodes->have_posts() ) {
    $episodes->the_post();

    the_title(); // Episode title
    the_content(); // Episode content
}

wp_reset_postdata(); // Restore current episode

Otherwise you can just foreach on the posts property:

foreach ( $episodes->posts as $episode ) {
    echo get_the_title( $episode ); // Most template tags accept a post object
    echo get_the_post_thumbnail( $episode->ID ); // Only accepts post ID
    echo get_the_content(); // Does not accept a post argument, you'd need the loop above to set up the global post object
}
2
  • How would I modify the query to get the 3 posts before, 3 after the current post?
    – tdc
    Apr 1, 2015 at 19:39
  • Check @Pieter Goosen's answer, it's what I would have suggested. Apr 2, 2015 at 13:06

Your Answer

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

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