3

Update: Thank you for the answer but after implementing this code it's breaking the theme/site. I'm sure it's me but here's my functions.php file:

// Custom posts for homepage
function get_featured_one() { /* returns post #1 */ }
function get_featured_two() { /* returns posts #2 and #3 */ }

add_action( 'pre_get_posts', function( $query ) {
    if ( ! $query->is_main_query() || is_admin() )
        return;

    if ( is_front_page() ) {
        $featured_one = get_featured_one();
        $featured_two = get_featured_two();

        $exclude = array_merge( wp_list_pluck( $featured_one->posts , 'ID' ), wp_list_plugk( $featured_two->posts, 'ID' ) );
        $query->set( 'post__not_in', $exclude );
    }
});

function get_featured_one() {
    return new WP_Query( array(
        'ignore_sticky_posts' => true,
        'posts_per_page' => 1,
    ) );
}

function get_featured_two() {
    return new WP_Query( array(
        'ignore_sticky_posts' => true,
        'tag' => 'featured',
        'posts_per_page' => 2,
    ) );
}

This is my header file containing the latest post:

<section class="header-latest-post">    
    <?php if ( is_front_page() && ! is_paged() ) :
        $latest = get_featured_one();
        while ( $latest->have_post() ) : $latest->the_post();
            get_template_part('content',get_post_format());
        endwhile;
    endif; ?>
</section>
<!-- End latest post -->

And this is the code for the two latest posts and standard loop on the homepage:

<!-- Start two featured posts -->
<section class="two-feat-posts">
    <?php if ( is_front_page() && ! is_paged() ) :
    $latest = get_featured_two();
    while ( $latest->have_post() ) : $latest->the_post();
        get_template_part('content',get_post_format());
    endwhile;
    endif; ?>
</section>
<!-- End two featured posts -->

<h4 class="main-title">Previous episodes</h4>

<!-- Start standard loop -->
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
    <?php get_template_part('content',get_post_format()); ?>
<?php endwhile; endif; ?>
<!-- End standard loop -->

Any more help would be hugely appreciated :)


I've been coding up a theme and have run into a pickle which I've half-solved but have hit a wall.

Essentially what I'm trying to achieve is this:

  1. The latest post (post 1) to be displayed in the header area of the homepage
  2. Two featured posts (posts 2 and 3) each 50% width
  3. Then the remaining posts in a list of 10 (posts 4 to 13)

I have the main loop displaying the ten posts which also offsets the latest post (as the latest is in the top area of the site):

<?php

        $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
        $args = array (
            'post_type' => 'post',
            'posts_per_page' => '10',
            'paged' => $paged
        );

        $mainLoop = new WP_Query( $args );

        if( $mainLoop->have_posts() ) :

        while( $mainLoop->have_posts() ) : $mainLoop->the_post(); ?>

    <?php get_template_part( 'content', get_post_format() ); ?>

    <?php endwhile;

        the_posts_pagination( array(
            'mid_size'  => 2,
            'prev_text' => __( 'Previous', 'textdomain' ),
            'next_text' => __( 'Next', 'textdomain' ),
        ) );

        wp_reset_postdata();

        else : get_template_part( 'content', 'none' );

        endif;

    ?>

Here's the code for the latest post in the header:

<?php
            $args = array (
                'post_type' => 'post',
                'posts_per_page' => '1'
            );

            $latestPost = new WP_Query( $args );

            if( $latestPost->have_posts() ):

            while( $latestPost->have_posts() ): $latestPost->the_post();

                 get_template_part('content',get_post_format());

             endwhile;

            endif;

            wp_reset_postdata();
        ?>

The problem I ran into was the pagination. It was showing the same posts on every page so I implemented this fix from the codex. This did the trick with both the pagination and the offset but now the latest post in the header is also offsetting by one and not displaying the latest post.

I've not coded the two featured posts as yet so I could use some advice with those too (is it ok to have 3 custom loops on one page?).

Thanks.

2
  • Spelling pluck as plugk could be a problem. Aug 6 '16 at 15:41
  • @AndyMacaulay-Brook - I noticed that after pasting it in here. After I corrected it, it made no difference. Aug 8 '16 at 6:54
1

Since you're not displaying a different amount of posts on the front page and on the paged pages for your main query, you don't really need to mess around with the offset. All you need is to exclude the three posts you've already shown from your query, which you can do with the pre_get_posts action:

function get_featured_one() { /* returns your post #1 */ }
function get_featured_two() { /* returns your posts #2 and #3 */ }

add_action( 'pre_get_posts', function( $query ) {
    if ( ! $query->is_main_query() || is_admin() )
        return;

    if ( is_front_page() ) {
        $featured_one = get_featured_one();
        $featured_two = get_featured_two();

        $exclude = array_merge( wp_list_pluck( $featured_one->posts , 'ID' ), wp_list_plugk( $featured_two->posts, 'ID' ) );
        $query->set( 'post__not_in', $exclude );
    }
});

Then in your template files just get rid of your $mainLoop, because WordPress already does that query long before it reaches your template file, so there's no need to run one again. All you need is to display your latest post in your header:

<?php if ( is_front_page() && ! is_paged() ) : ?>
    <?php $latest = get_featured_one(); ?>
    <?php while ( $latest->have_post() ) : $latest->the_post(); ?>
        <!-- Output stuff here. -->
    <?php endwhile; ?>
<?php endif; ?>

And same thing but get_featured_two() for your archive/front-page/index template for your two 50/50 posts. After that, the (actual) main loop will take care of everything else. So this is your order:

  • $latest->have_posts()
  • $featured->have_posts()
  • have_posts()

For paged pages you'll probably want to leave out the $featured output, but still keep those posts excluded from the main query, since you've already shown them on your front page. Also including them in your main query will change the total number of posts returned by the main query (on paged pages), and will break pagination.

Both get_featured_* functions have to return a WP_Query object:

function get_featured_one() {
    return new WP_Query( array(
        'ignore_sticky_posts' => true,
        'posts_per_page' => 1,
    ) );
}

function get_featured_two() {
    return new WP_Query( array(
        'ignore_sticky_posts' => true,
        'tag' => 'featured',
        'posts_per_page' => 2,
    ) );
}

They can also probably use some static caching to improve performance, but only if you're absolutely sure that calling them several times in a single request must result in the exact same output (i.e. never used in a switch_to_blog() context).

It will probably also be a good idea to exclude the post returned in _one() from _two() because a post can probably be both featured and latest.

I did something similar although a bit more complex in my Semicolon theme. It's trickier because the amount of posts has to stay the same regardless of whether featured posts are stuck to the top, hence the offset magic. But the idea is very similar.

Hope that helps.

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.