How to offset posts in the Genesis framework without losing pagination

Today I encountered a challenging problem. I wanted to know how to offset posts in the Genesis Framework without losing pagination. Immediately, I was surprised that there wasn’t a built-in function or Genesis Loop array value to accomplish this. As you may have found, there are a couple articles available but none were Genesis-specific. Luckily, between the WordPress codex, some of Bill Erickson’s writings on custom post loops and lots of trial and error, I was able to create an efficient, working solution, which I’ll share below.

The Goal

Create a paginated blog with a featured post outside the main loop.

My client, Chicago-based professional commercial photographer Matthew Bowie, was implementing a newly designed blog template with a full-width featured post across the header of the site and all other posts listed below and paginated. The PSD mock-up design is below:

End-goal example mock-up design
Full width post showing latest post. Secondary custom loop with pagination, offset by one post (using Genesis Framework).

The Problem

Declaring an “offset” post in the WordPress query can break pagination. For some folks, the “Next Page” link delivers a 404 error. For me, the same posts were duplicating or repeating on the next pages. The posts that were delivered were indeed offset, but only on the first page.

The Approach

Before I share how I solved this problem, I need to thank the WordPress team for their painstaking efforts in creating such a well-documented codex; taking time to review the following article will prove very helpful:

Creating a custom Genesis loop, like David Wang describes, didn’t work once you attempted to offset the post; in the end a custom Genesis loop ended up not being necessary.

Designing a completely new homepage template for Genesis, such as Carrie Dils writes about, might have worked, but it felt like a lot of extra code, with no promise of being able to manage pagination after I had built the homepage.

Bill Erickson’s post on writing custom WordPress queries was interesting, but I was really hesitant to step away from the Genesis Loop for fear of losing the power of Genesis’ built-in hooks and functions within the loop.

The Solution

In the end, always go back to the documentation. The WordPress codex outlined the problem and how to fix it. Although, because it wasn’t specifically written for Genesis, there was a small gap to leap before arriving at the finished product.

Building the featured post was the easy part. We added a widget area and used the Genesis Featured Posts widget to pull in the latest post. Simple. Done.

Customizing the rest of the blog loop was the tricky part, because every time we added “offset” to the loop, pagination would break.

The WordPress Codex describes using the pre_get_posts hook to modify the WP query before it runs. Skipping the Offset Using pre_get_posts section of the codex, because the code example didn’t solve the pagination issue (but was very educational), I copied the following two sections under Offset & Manual Pagination into functions.php in my theme folder.

function myprefix_query_offset(&$query) {

//Before anything else, make sure this is the right query...
if ( ! $query->is_posts_page ) {
	return;
}

$offset = 10 ;

//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...
if ( $query->is_paged ) {

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

}
else {

	//This is the first page. Just use the offset...
	$query->set('offset',$offset);

}
}
add_action('pre_get_posts', 'myprefix_query_offset', 1 );

add_filter('found_posts', 'myprefix_adjust_offset_pagination', 1, 2 );
function myprefix_adjust_offset_pagination($found_posts, $query) {

    //Define our offset again...
    $offset = 10;

    //Ensure we're modifying the right query object...
    if ( $query->is_posts_page ) {
        //Reduce WordPress's found_posts count by the offset... 
        return $found_posts - $offset;
    }
    return $found_posts;
}

Their example of code says:

if ( ! $query->is_posts_page ) {
        return;
}

…but this code wasn’t hitting my page. Someone much smarter than me would understand why, but I believe this is because of how the Genesis loop was writing their own custom WP query. For whatever reason, my child theme template, which was simply based off the Genesis Framework, was not identifying the homepage and subsequent paginated pages as pages of posts, so the rest of the code that the WordPress codex provided was not being applied.

Changing this section to:

if ( ! $query->is_main_query() ) {
	return;
}

solved the problem for me. This code says, “if this is not the main query, then disregard this function just operate as usual. Otherwise, do all of the code that follows.”

That one slight change was all that was necessary to fix the problem for me. The posts were offset and the “next page” of pagination automatically calculated how many posts needed to be offset (my desired number of offset posts and the previously displayed number of posts).

The final step was simply to adjust the number of offset posts to my liking. 10 offset posts was too much because I only needed to offset the one featured post at the top of my page. So I changed the two references of $offset = 10; to $offset = 1;.

In Summary

This is the final code I used:

function myprefix_query_offset(&$query) {

//Before anything else, make sure this is the right query...
if ( ! $query->is_main_query() ) {
	return;
}

$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...
if ( $query->is_paged ) {

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

}
else {

	//This is the first page. Just use the offset...
	$query->set('offset',$offset);

}
}
add_action('pre_get_posts', 'myprefix_query_offset', 1 );

add_filter('found_posts', 'myprefix_adjust_offset_pagination', 1, 2 );
function myprefix_adjust_offset_pagination($found_posts, $query) {

    //Define our offset again...
    $offset = 1;

    //Ensure we're modifying the right query object...
    if ( $query->is_posts_page ) {
        //Reduce WordPress's found_posts count by the offset... 
        return $found_posts - $offset;
    }
    return $found_posts;
}

That’s all! I hope this helped. Feel free to add questions or comments below. I’m learning alongside you all, but would be glad to help in any way I can.

Additional Resources
Ultimately, these articles didn’t solve my problem, but they did help expand my understanding of WordPress pagination, Genesis Custom Loops, pre_get_posts and query_posts.

If you’re interested in purchasing the Genesis Framework, do us a favor and use our affiliate code to support more helpful posts like this one.