2

I am trying to put a header before past posts and after future posts.

I'm using get_posts() in a function to output the posts using a foreach loop for a custom post type ordered by date (meta key). If a post's associated date is less than the current date (i.e., dates not in the future), I want to output some HTML. if ($custom_post_date >= $today && $index === 1) The problem I am running into is that the HTML gets output after the first post that is in the past. How can I output the HTML before the first post that meets the criteria? Is there a way to go back in the foreach loop or something to that effect?

<?php
    $index = 1; // counts all items in query
    $count = count($upcoming_posts);
    $today = new DateTime();
    $past  = false;

foreach ($upcoming_posts as $posts) {
    if ($post_date >= $today && $index === 1) : ?>
        <h2><?php __( 'Upcoming Posts', 'sage' ); ?></h2>
        <div class="wp-block-columns has-2-columns">
    <?php else ($post_date < $today && $past === false && $index === 1) : ?>
        <?php $wp_query->current_post -= 1; ?>
        <h2><?php __( 'Past Posts', 'sage' ); ?></h2>
        <div class="wp-block-columns">
    <?php endif; ?>
    <div class="wp-block-column">
        <div class="wp-block-media-text alignwide">
    ...
        </div>
    </div>
    <php if ( ($index % 2) == 0 && $end === false ) : ?>
    </div>
    <div class="wp-block-columns has-2-columns"> <!-- ends row every other iteration -->
        <?php $end = false;
        endif;
        if ($count == $index ) : ?>
    </div> <!-- ends final row -->
    <?php endif;
} ?>
2
  • You could add another foreach loop before your current loop to get the index of that specific post. You could also keep track of the previous post outside your foreach loop. Commented Jul 18, 2020 at 21:53
  • @TomBroucke How would you go about keeping track of the previous post outside of the loop? I can't visualize how that would work Commented Jul 20, 2020 at 18:23

1 Answer 1

2

You may have already figured this one out, but here's two examples how to do this. In both of my examples I do the sorting first and rendering second. This keeps things cleaner and clearer in my opinion.

Example 1

Loop queried posts and sort them into two helper arrays. If those arrays have posts, loop them through and render posts.

$posts        = helper_function_to_query_posts();
$future_posts = array();
$past_posts   = array();
$today        = strtotime('today');

foreach ($posts as $post) {
    if ( $post->post_date >= $today ) {
        $future_posts[] = $post;
    } else {
        $past_posts[] = $post;
    }
}

if ( $future_posts ) {
    esc_html_e( 'Upcoming Posts', 'sage' );
    helper_function_to_handle_looping_and_rendering_of_posts( $future_posts );
}
if ( $past_posts ) {
    esc_html_e( 'Past Posts', 'sage' );
    helper_function_to_handle_looping_and_rendering_of_posts( $past_posts );
}

Example 2

Loop queried posts and push post html into helper variables. Echo those variables afterwards.

$posts              = helper_function_to_query_posts();
$future_posts_html  = '';
$past_posts_html    = '';
$post_html_template = '<div class="my-post">
    <h2>%s</h2>
    %s
</div>';
$today              = strtotime('today');

foreach ($posts as $post) {
    if ( $post->post_date >= $today ) {
        $future_posts_html .= sprintf(
            $post_html_template,
            esc_html($post->post_title),
            esc_html($post->post_excerpt),
        );
    } else {
        $past_posts[] = .= sprintf(
            $post_html_template,
            esc_html($post->post_title),
            esc_html($post->post_excerpt),
        );
    }
}

if ( $future_posts_html ) {
    esc_html_e( 'Upcoming Posts', 'sage' );
    echo $future_posts_html;
}
if ( $past_posts_html ) {
    esc_html_e( 'Past Posts', 'sage' );
    echo $past_posts_html;
}

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.