[Special Summer Sale] 40% OFF All Magento 2 Themes

Cart

How can I paginate WP_Query results when there's an offset?

  • This topic is empty.
Viewing 3 posts - 1 through 3 (of 3 total)
  • Author
    Posts
  • #9416
    brian-oneill
    Participant

    EDIT: This is the current code that I’m trying to paginate. It creates a custom query that excludes the latest post, as well as all posts from one category. Pagination works fine for the most part, but the problem is that the final link in the pagination list takes me to a blank page.

    <section class="card-grid card-grid--push">
        <main class="container container--wide">
    
        <?php
    
            $current_page = get_query_var('paged');
            $current_page = max( 1, $current_page );
            $per_page = 3;
            $offset = ( $current_page - 1 ) * $per_page + 1;
    
            $post_list = new WP_Query(array(
                'cat'            => -15,
                'posts_per_page' => $per_page,
                'paged'          => $current_page,
                'offset'         => $offset, 
                'orderby'        => 'date', 
                'order'          => 'DESC',  
            ));
    
            if ( $post_list->have_posts() ):
                while ( $post_list->have_posts() ):
                    $post_list->the_post();
    
        ?>
    
        <a href="<?php the_permalink(); ?>" <?php post_class('card'); ?>>
            <article class="card__content">
                <?php the_post_thumbnail('th-card'); ?>
                <div class="card__head">
                    <span class="category">
                        <?php $category = get_the_category(); echo $category[0]->cat_name; ?>
                    </span>
                    <h2 class="card__title"><?php the_title(); ?></h2>
                </div>
            </article>
        </a>
    
        <?php endwhile; ?>
    
        <div class="pagination">
    
            <?php 
                echo paginate_links( array(
                    'total'   => $post_list->max_num_pages,
                    'current' => $current_page,
                    'type'          => 'list',
                    'prev_text' => '«',
                    'next_text' => '»'
                ) );
            ?>
    
        </div>
    
      <?php  
            endif;
            wp_reset_postdata();
        ?>
    
    </main>
    

    #9418
    sally-cj
    Participant

    [EDIT] Here it is, fully tested and working:

    $current_page = get_query_var('paged');
    $current_page = max( 1, $current_page );
    
    $per_page = 12;
    $offset_start = 1;
    $offset = ( $current_page - 1 ) * $per_page + $offset_start;
    
    $post_list = new WP_Query(array(
        'cat'            => -15,
        'posts_per_page' => $per_page,
        'paged'          => $current_page,
        'offset'         => $offset, // Starts with the second most recent post.
        'orderby'        => 'date',  // Makes sure the posts are sorted by date.
        'order'          => 'DESC',  // And that the most recent ones come first.
    ));
    
    // Manually count the number of pages, because we used a custom OFFSET (i.e.
    // other than 0), so we can't simply use $post_list->max_num_pages or even
    // $post_list->found_posts without extra work/calculation.
    $total_rows = max( 0, $post_list->found_posts - $offset_start );
    $total_pages = ceil( $total_rows / $per_page );
    
    if ( $post_list->have_posts() ):
        while ( $post_list->have_posts() ):
            $post_list->the_post();
    
    
            // loop output here
        endwhile;
    
        echo paginate_links( array(
            'total'   => $total_pages,
            'current' => $current_page,
        ) );
    endif;
    wp_reset_postdata();
    

    PS: The code was re-indented using tabs.

    #9417
    user3615851
    Participant

    I know this might not be the solution for this but instead of using offset for highlighting a different container for a post I decided to break down the query with $count and add different wrappers instead due to the difficulty of offset pagination. Here’s what I ended up using:

       <?php $args = array(
          'posts_per_page' => 13,
          'post_type'      => 'post',
          'paged'          => get_query_var( 'paged' ), 
        );
      $wp_query = new WP_Query( $args );
      $count = 0; while ( $wp_query->have_posts() ) : $wp_query->the_post(); ?>
      <?php if($count == 0): ?><!-- first highlighted post we show with categories on side -->
        <div class="mb-4 flex flex-col flex-col-reverse gap-4 md:mb-10 md:flex-row md:gap-10 ">
          <aside class="flex flex-col items-baseline gap-2 no-gap:mt-4 md:max-w-[200px] md:gap-4 no-gap:md:mt-0 no-gap:md:mr-10">
            <h2 class="flex-none font-denim-semibold text-sm xs:text-lg no-gap:mb-2 no-gap:md:mb-4">Categories</h2>
              <?php 
                $terms = get_terms( 'category' );
                echo '<ul class="flex flex-wrap gap-2 no-gap:-m-1">';
                echo '<li class="no-gap:m-1"><button class="flex justify-center items-center gap-2 rounded-xl select-none min-w-fit px-3 py-1 xs:px-3.5 xs:py-2 bg-brand-black ring-1 ring-inset ring-brand-black focus-visible:outline focus-visible:outline-4 focus-visible:outline-offset-0 focus-visible:outline-brand-black/20 text-white text-xs xs:text-sm rounded-xl" tabindex="0" type="button"><span class="no-gap:ml-2 no-gap:first:ml-0">All</span></button></li>';
                foreach ( $terms as $term ) {
                  $class = ( is_category( $term->name ) ) ? 'active' : ''; // assign this class if we're on the same category page as $term->name
                  if($class == 'active'): 
                    echo '<li class="no-gap:m-1"><a href="' . get_term_link( $term ) . '" class="' . $class . '"><button class="flex justify-center items-center gap-2 rounded-xl select-none min-w-fit px-3 py-1 xs:px-3.5 xs:py-2 bg-brand-black ring-1 ring-inset ring-brand-black focus-visible:outline focus-visible:outline-4 focus-visible:outline-offset-0 focus-visible:outline-brand-black/20 text-white text-xs xs:text-sm rounded-xl" tabindex="0" type="button"><span class="no-gap:ml-2 no-gap:first:ml-0">' . $term->name . '</span></button></a></li>';
                  else:
                    echo '<li class="no-gap:m-1"><a href="' . get_term_link( $term ) . '" class="' . $class . '"><button class="flex justify-center items-center gap-2 rounded-xl select-none min-w-fit px-3 py-1 xs:px-3.5 xs:py-2 bg-transparent hover:bg-brand-black/10 active:bg-brand-black ring-1 ring-inset ring-brand-black focus-visible:outline focus-visible:outline-4 focus-visible:outline-offset-0 focus-visible:outline-brand-black/20 text-brand-black active:text-white text-xs xs:text-sm rounded-xl" tabindex="0" type="button"><span class="no-gap:ml-2 no-gap:first:ml-0">' . $term->name . '</span></button></a></li>';
                  endif;
                }
                echo '</ul>'; 
              ?>
          </aside>
          <a class="w-full " href="<?php the_permalink(); ?>">
              <article class="group isolate relative w-full rounded-3xl bg-brand-black shadow-lg transition overflow-hidden duration-300 overflow-border-transition will-change-contents hover:cursor-pointer hover:shadow-xl hover:scale-[1.025] active:scale-[0.975] active:shadow-md active:transform-none active:outline-none focus:outline-4 focus:outline-brand-blue focus:outline-offset-0 focus:outline">
                <div class="mx-auto flex w-60 flex-col text-center py-28 md:p-16 lg:p-28 transition duration-300 group-hover:scale-[1.025] md:w-4/5 lg:w-3/4">
                  <span class="z-10 text-white opacity-70">4 min read</span>
                  <h2 class="z-10 text-3xl text-white md:text-4xl "><span class="font-reckless-neue"><?php the_title(); ?></span></h2>
                </div>
                <div class="absolute right-1/2 top-1/2 -translate-y-1/2 translate-x-1/2 select-none transition duration-300 group-hover:scale-[1.05]">
                  <object aria-label="Tuum blue thick wheel" class="pointer-events-none h-[1000px] min-w-[1000px] max-w-[1000px] animate-spin-slow md:h-[1250px] md:min-w-[1250px] md:max-w-[1250px] lg:h-[1500px] lg:min-w-[1500px] lg:max-w-[1500px]" data="<?php if(get_field('wheel')): ?><?php the_field('wheel'); ?><?php else: ?><?php bloginfo('template_url'); ?>/assets/img/about-us-bg.svg<?php endif; ?>" tabindex="-1" type="image/svg+xml"></object>
                </div>
              </article>
            </a>
          </div><!-- first loop -->
        <?php elseif($count == 1): ?><!-- second post we open up with new wrapper and section -->
          <section>
            <ul class="grid gap-4 md:gap-x-8 md:gap-y-10 grid-cols-2 md:grid-cols-3 lg:grid-cols-4 pb-10 border-b-2 border-solid border-brand-beige-600">
                <?php get_template_part( 'templates/partials/component','postSmall'); ?>
              <?php else: ?><!-- from there we continue as normal -->
                    <?php get_template_part( 'templates/partials/component','postSmall'); ?>
              <?php endif; ?>
              <?php $count++; endwhile; ?>
              <?php wp_reset_postdata(); ?>
            </ul><!-- close the post small boxes list -->
            <div class="navigation-wrap flex justify-center items-center gap-2 rounded-xl select-none min-w-fit tracking-normal px-7 py-4 bg-transparent ring-transparent text-brand-black text-xl rounded-xl font-denim-semibold w-full mt-4 justify-center col-span-2 md:col-span-3 lg:col-span-4">
              <?php echo paginate_links(array(
                  'base' => get_pagenum_link(1) . '%_%',
                  'format' => 'page/%#%',
                  'prev_text' => '',
                  'next_text' => ''
              )); ?>
            </div>
          </section><!-- close the small posts section wrap -->
    

    Using Tailwind css but query tested and working to show 1st post highlighted aside with category filter and other posts in a 4post grid. Hope this helps someone struggling with this since I spent a lot of time with the offset solution and decided to still solve with a single loop for simplicity

Viewing 3 posts - 1 through 3 (of 3 total)
  • You must be logged in to reply to this topic.