Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save oneblackcrayon/5163492d4e70b38741940ab5f8430118 to your computer and use it in GitHub Desktop.
Save oneblackcrayon/5163492d4e70b38741940ab5f8430118 to your computer and use it in GitHub Desktop.
Using two loops on a home.php with pagination on the second loop.

Wordpress - Using two loops on a home.php with pagination on the second loop notes & examples

Problem

I have a layout where I need to show the most recent post in a different layout/design component and remaining posts, needed to have a separate layout/design. I also wanted to use pagination to show other posts instead of infinite scrolling because I do not prefer infinite scrolling. Using the count modulus was not going to be a viable option due to how the design needed to be implemented but I think it could work for someone with experience in PHP. When using the offset in the loop, it was changing on pagination so each page after the first page had different recent post.

This was troublesome but I think I have a solid working solution for having multiple loops it works for my needs.

I separated my loops by using the first loop as the standard (have-posts) loop and the second loop ($custom_query).

The issue was firstly, getting the offset to only work on the second loop ($custom_query).

I achieved this by finding code examples of using the pre_get_posts and found_posts functions to target only the home.php and not the main query. All of this was new to me, but I believe if you read over the code and visit the links in the code, you can start to understand (depending on your PHP level) what WordPress wants you to do to make this happen. (Run on sentence much? lol).

The next goal was to get the pagination to work without being failing. By failing I am referring to how in previous attemps, the pagination would not find additional posts based on the secondary query and just show previous content. That is where the $wp_query hack in the content-home.php works. Also, I found by putting the // Pagination code found in content-home.php file after the wp_reset_postdata() call, and resetting the $wp_query hack after the paginate_links function got the pagination to work as expected. Which is, pagination generates page links that show additional content from the secondary query/loop.

PLEASE FORK!

I am still learning PHP and WordPress and I know all of this code could be rewritten to be more performant: less database calls, smaller code size, .etc. So please, fork & modify and share. It makes us all better developers.

<?php
/**
* This could be written much better (performant & detailed) so please fork and update.
*/
/**
* The main template file
*
* This is the most generic template file in a WordPress theme
* and one of the two required files for a theme (the other being style.css).
* It is used to display a page when nothing more specific matches a query.
* E.g., it puts together the home page when no home.php file exists.
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*
* @package The_Factory_Two
*/
get_header();
?>
<main id="primary" class="site-main content">
<?php
/**
* This is the template file for the first loop with only the recent post.
* We will have to make updates if we need to have a sticky post.
*/
get_template_part( 'template-parts/content-home-recent-post' );
/**
* Second loop with pagination
*/
get_template_part( 'template-parts/content-home' );
?>
</main><!-- #main -->
<?php
get_footer();
<?php
/**
* This could be written much better (performant & detailed) so please fork and update.
*/
/**
* Manipulate the Pre Get Posts and Found Posts for Loops on home.php
* @link: https://codex.wordpress.org/Making_Custom_Queries_using_Offset_and_Pagination#Offset_.26_Manual_Pagination
*/
function homepage_secondary_loop_query_offset( &$query ) {
//Before anything else, make sure this is the right query...
if ( ! $query->is_home() ) {
return;
}
//First, define your desired offset...
$offset = 1;
//Next, determine how many posts per page you want (we'll use WordPress's settings)
$ppp = get_option('posts_per_page');
//Next, detect and handle pagination...
// Added !$query->is_main_query() to stop from working on main query (have_posts)
if ( $query->is_paged && !$query->is_main_query() ) {
//Manually determine page query offset (offset + current page (minus one) x posts per page)
$page_offset = $offset + ( ($query->query_vars['paged']-1) * $ppp );
//Apply adjust page offset
$query->set('offset', $page_offset );
}
elseif( !$query->is_main_query() ) {
//This is the first page. Just use the offset...
$query->set('offset',$offset);
}
}
add_action( 'pre_get_posts', 'homepage_secondary_loop_query_offset', 1 );
function homepage_secondary_loop_adjust_offset_pagination( $found_posts, $query ) {
//Define our offset again...
$offset = 1;
// Ensure we're modifying the right query object...
// Added !$query->is_main_query() to stop from working on main query (have_posts)
// The right query object is the one with the most posts rendering ($custom_query)
if ( $query->is_home() && !$query->is_main_query() ) {
//Reduce WordPress's found_posts count by the offset...
return $found_posts - $offset;
}
return $found_posts;
}
add_filter( 'found_posts', 'homepage_secondary_loop_adjust_offset_pagination', 1, 2 );
function main_homepage_query( &$query ) {
// Override the offset in the previous pre_get_posts & found_posts
$offset = 0;
// Modifying the main query on the home.php by setting paramaters
if ( $query->is_main_query() && ! is_admin() && $query->is_home() ) {
// @link: https://stackoverflow.com/questions/21628487/exclude-only-latest-post-of-a-category-in-wordpress-main-loop-using-pre-get-post#answer-21629006
$latest_post = wp_get_recent_posts( array( 'numberposts' => 1 ) );
$query->set( 'posts_per_page', '1' );
$query->set( 'order', 'DESC' );
$query->set( 'orderby', 'date' );
// @link: https://stackoverflow.com/questions/21628487/exclude-only-latest-post-of-a-category-in-wordpress-main-loop-using-pre-get-post#answer-29171366
$query->set('post_is', array($latest_post[0]['ID']) );
// Telling this pre_get_posts to not have an offset
$query->set('offset',$offset);
return $found_posts - $offset;
}
}
add_action( 'pre_get_posts', 'main_homepage_query', 1 );
<?php
/**
* Using Bulma CSS Framework
*/
/**
* Template part for displaying content in the home.php file
* This is the loop that only shows one post.
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*
* @package textdomain
*/
?>
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<div class="section has-background-warning">
<div class="container is-fullhd">
<div class="columns is-centered is-multiline">
<?php if ( ( function_exists('has_post_thumbnail') ) && ( has_post_thumbnail() ) ): ?>
<div class="column">
<figure class="image block">
<?php the_post_thumbnail('large', array( 'alt' => the_title_attribute( array( 'echo' => false, )),)); ?>
</figure>
</div><!-- /.column -->
<?php endif; ?>
<div class="column">
<?php if ( 'post' === get_post_type() ) : ?>
<div class="entry-meta block">
<p class="level is-justify-content-flex-start">
<?php $categories = get_the_category();
if ( ! empty( $categories ) ) {
echo '<span class="level-left tags has-text-weight-bold is-uppercase mb-0 mr-5">';
echo '<a class="tag is-brand-red is-medium is-rounded is-uppercase has-text-weight-bold mb-0" href="' . esc_url( get_category_link( $categories[0]->term_id ) ) . '">';
echo esc_html( $categories[0]->name ) ;
echo '</a>';
echo '</span>';
} ;?>
<span class="level-left is-size-6">
<span class="level-item"><?php textdomain_posted_on(); ?></span>
</span>
</p>
</div><!-- /.block -->
<?php endif; ?>
<div class="block">
<?php
if ( is_singular() ) :
the_title( '<h2 class="title is-spaced has-text-weight-semibold">', '</h2>' );
else :
the_title( '<h2 class="title is-spaced has-text-weight-semibold"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
endif; ?>
</div><!-- /.block -->
<div class="entry-content block content">
<?php
if ($counter === 1) {
echo '<p class="subtitle">' .excerpt(). '</p>';
} else {
echo '<p class="">' .excerpt(). '</p>';
}
?>
</div><!-- /.entry-content content -->
</div><!-- /.column -->
</div><!-- /.columns -->
</div><!-- /.container -->
</div><!-- /.section has-background-warning -->
<?php endwhile;
endif;
wp_reset_postdata(); ?>
<?php
/**
* Template part for displaying content in the home.php file
*
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/
*
* @package textdomain
*/
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$custom_query_args = array(
'post_type' => 'post',
'posts_per_page' => get_option('posts_per_page'),
'paged' => $paged,
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'order' => 'DESC',
'orderby' => 'date'
);
global $wp_query;
$custom_query = new WP_Query( $custom_query_args );
$temp_query = $wp_query;
$wp_query = NULL;
$wp_query = $custom_query;
if( $wp_query->have_posts() ): ?>
<div class="section">
<div class="container is-fullhd">
<div class="columns is-centered is-multiline">
<?php while ( $custom_query->have_posts() ) : $custom_query->the_post(); ?>
<article id="post-<?php the_ID(); ?>" class="column is-4">
<div class="card is-flex is-flex-direction-column" style="height: 100%;">
<header class="entry-header block mb-auto">
<?php if ( ( function_exists('has_post_thumbnail') ) && ( has_post_thumbnail() ) ): ?>
<figure class="image block">
<?php the_post_thumbnail('large', array( 'alt' => the_title_attribute( array( 'echo' => false, )),)); ?>
</figure>
<?php endif; ?>
<?php if ( 'post' === get_post_type() ) : ?>
<div class="entry-meta block">
<p class="level is-justify-content-flex-start">
<?php $categories = get_the_category();
if ( ! empty( $categories ) ) {
echo '<span class="level-left tags has-text-weight-bold is-uppercase mb-0 mr-5">';
echo '<a class="tag is-brand-red is-medium is-rounded is-uppercase has-text-weight-bold mb-0" href="' . esc_url( get_category_link( $categories[0]->term_id ) ) . '">';
echo esc_html( $categories[0]->name ) ;
echo '</a>';
echo '</span>';
} ;?>
<span class="level-left is-size-6">
<span class="level-item"><?php textdomain_posted_on(); ?></span>
</span>
</p>
</div><!-- /.block -->
<?php endif; ?>
<div class="block">
<?php
if ( is_singular() ) :
the_title( '<h2 class="title is-spaced has-text-weight-semibold">', '</h2>' );
else :
the_title( '<h2 class="title is-spaced has-text-weight-semibold"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h2>' );
endif; ?>
</div><!-- /.block -->
</header><!-- /.entry-header -->
<div class="entry-content block content mt-auto">
<?php
# echo excerpt(25);
if ($counter === 1) {
echo '<p class="subtitle">' .excerpt(50). '</p>';
} else {
echo '<p class="">' .excerpt(15). '</p>';
}
?>
</div><!-- /.entry-content content -->
</div><!-- /.card -->
</article><!-- /.column -->
<?php endwhile; ?>
</div><!-- /.columns-->
</div><!-- /.container -->
</div><!-- /.section -->
<?php endif;
wp_reset_postdata();
// Pagination
global $wp_query;
$big = 999999999; // need an unlikely integer
$translated = __( 'Page', 'the_factory_2' );
$pagination = paginate_links( array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'format' => '?paged=%#%',
'type' => 'array', //instead of 'list'
'total' => $wp_query->max_num_pages,
'current' => max( 1, get_query_var('paged') ),
'before_page_number' => '<span class="screen-reader-text">'.$translated.' </span>',
'prev_next' => false,
'end_size' => 1,
'mid_size' => 1,
));
if ( ! empty( $pagination ) ) :
echo '<div class="section"><div class="container is-narrow">';
echo '<nav class="pagination is-centered is-align-content-center has-background-transparent" role="navigation" aria-label="pagination">';
# previous_posts_link( 'Newer Posts', $custom_query->max_num_pages );
# next_posts_link( 'Older Posts', $custom_query->max_num_pages );
?>
<ul class="pagination-list m-auto">
<?php foreach ( $pagination as $key => $page_link ) : ?>
<li class="pagination-link m-2 <?php if ( strpos( $page_link, 'current' ) !== false ) { echo 'is-current'; } ?>"><?php echo $page_link ?></li>
<?php endforeach ?>
</ul>
<?php
echo '</nav><!-- /.pagination -->';
echo '</div><!-- /.container --></div><!-- /.section -->';
endif;
$wp_query = NULL;
$wp_query = $temp_query;
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment