0

I'm looking for a way on how to display only a few posts on a first page of my archive. This is my archive template — page-archive.php, which I am using as a template to display all my posts/recipes:

<?php
get_header('archive');  ?>

<div id="primary" class="content-area blog-archive col-md-9">
  <main id="main" class="site-main">
    <div class="breadcrumbs-block"><?php
    if ( function_exists('yoast_breadcrumb') ) {
      yoast_breadcrumb( '<p id="breadcrumbs">','</p>' );
    }
    ?>
      </div>
    <?php query_posts('post_type=post&post_status=publish&posts_per_page=24&paged='. get_query_var('paged')); ?>
       <?php if( have_posts() ): ?>
<div class="row all-recipes-block">
        <?php while( have_posts() ): the_post(); ?>
          <article id="post-<?php the_ID(); ?>" <?php post_class('col-md-4'); ?>>
            <?php if ( has_post_thumbnail() ) : ?>
              <a class="post-teaser" href="<?php the_permalink() ?>" title="<?php the_title(); ?>">
                <div class="thumbnail-block"><?php the_post_thumbnail('regular-post-thumbnail'); ?></div>
                <div class="title-block"><span class="h3 title-for-widget"><?php the_title(); ?></span></div>
              </a>
            <?php endif; ?>
          </article>
        <?php endwhile; ?>
      </div>
      <div class="pagination-block row">
              <?php numeric_posts_nav(); ?>
      </div>
         <?php else: ?>
      <div id="post-404" class="noposts">
            <p><?php _e('None found.','example'); ?></p>
      </div><!-- /#post-404 -->
     <?php endif; wp_reset_query(); ?>
  </main>
</div>
<?php
get_footer();

Currently I have 24 posts per page and pagination, and I would love to show only 12 posts on the first page!

This is my post navigation function:

// numeric posts navigation

function numeric_posts_nav() {

    if( is_singular() )
        return;

    global $wp_query;

    /** Stop execution if there's only 1 page */
    if( $wp_query->max_num_pages <= 1 )
        return;

    $paged = get_query_var( 'paged' ) ? absint( get_query_var( 'paged' ) ) : 1;
    $max   = intval( $wp_query->max_num_pages );

    /** Add current page to the array */
    if ( $paged >= 1 )
        $links[] = $paged;

    /** Add the pages around the current page to the array */
    if ( $paged >= 3 ) {
        $links[] = $paged - 1;
        $links[] = $paged - 2;
    }

    if ( ( $paged + 2 ) <= $max ) {
        $links[] = $paged + 2;
        $links[] = $paged + 1;
    }

    echo '<div class="pagination-navigation col-md-12"><ul class="d-flex justify-content-center">' . "\n";

Please help!

Thank you in advance!

9
  • 1
    You should not call query_posts() in your template. Use the pre_get_posts hook instead to modify the main query's arguments like posts_per_page. And by "archive template", are you referring to the archive.php file?
    – Sally CJ
    Commented Jan 26, 2022 at 4:39
  • Hi Sally CJ, this is page-archive.php. I am using as a template to display all my posts/recipes. Commented Jan 26, 2022 at 7:09
  • So you have a Page (post type page) with the slug archive, right? Can you add that detail and the ones in your previous comment to your post along with the code for the numeric_posts_nav() function?
    – Sally CJ
    Commented Jan 26, 2022 at 10:32
  • Hey Sally CJ, i posted the code for numeric_posts_nav() function, but i have no idea how to use pre_get_posts vs query_posts(), can you please explain to me like i am 10 year old:)) What function should i use in function.php? Or i use snippet plugin, and how i call it in my case in my page template (i posted above). Sorry i know a lot about CSS and HTML, but when it comes to PHP, i have no idea, man:) Commented Jan 26, 2022 at 23:48
  • 1
    Thank you Sally CJ, it worked! Thanks to you! ...And I learned something too:))) You ROCK! Commented Jan 28, 2022 at 18:05

2 Answers 2

1

This is my archive template — page-archive.php, which I am using as a template to display all my posts/recipes

So if you're using a Page (post of the page type) with a custom/specific Page Template, then you should create a secondary query and loop for retrieving and displaying your recipes/posts.

But even with a default archive template such as the archive.php file, you should not use query_posts() in the template!

And here's why: (bold and italic formatting was added by me)

This function will completely override the main query and isn’t intended for use by plugins or themes. Its overly-simplistic approach to modifying the main query can be problematic and should be avoided wherever possible. In most cases, there are better, more performant options for modifying the main query such as via the ‘pre_get_posts’ action within WP_Query.

It should be noted that using this to replace the main query on a page can increase page loading times, in worst case scenarios more than doubling the amount of work needed or more. While easy to use, the function is also prone to confusion and problems later on. See the note further below on caveats for details.

— See https://developer.wordpress.org/reference/functions/query_posts/ for the caveats mentioned above and other details.

And here's how can you convert your query_posts() code to using a secondary query/WP_Query and loop instead:

  1. Replace the <?php query_posts('post_type=post&post_status=publish&posts_per_page=24&paged='. get_query_var('paged')); ?> with this:

    <?php
    // you could also do $query = new WP_Query( 'your args here' ), but I thought
    // using array is better or more readable :)
    $query = new WP_Query( array(
        'post_type'      => 'post',
        'post_status'    => 'publish',
        'posts_per_page' => 24,
        'paged'          => get_query_var( 'paged' ),
    ) );
    ?>
    
  2. Replace the have_posts() with $query->have_posts(), and the the_post() with $query->the_post(). I.e. Use the $query variable created above.

  3. And finally, replace the wp_reset_query() with wp_reset_postdata().

Now, as for displaying only a few posts on the first page, i.e. different than your posts_per_page value..

The proper solution would be to use an offset, like so:

  1. Replace the snippet in step 1 above with this, or use this instead of that snippet:

    <?php
    // Define the number of posts per page.
    $per_page  = 12; // for the 1st page
    $per_page2 = 24; // for page 2, 3, etc.
    
    // Get the current page number.
    $paged     = max( 1, get_query_var( 'paged' ) );
    // This is used as the posts_per_page value.
    $per_page3 = ( $paged > 1 ) ? $per_page2 : $per_page;
    
    // Calculate the offset.
    $offset = ( $paged - 1 ) * $per_page2;
    $diff   = $per_page2 - $per_page;
    $minus  = ( $paged > 1 ) ? $diff : 0;
    
    $query = new WP_Query( array(
        'post_type'      => 'post',
        'post_status'    => 'publish',
        'posts_per_page' => $per_page3,
        'offset'         => $offset - $minus,
    ) );
    
    // Recalculate the total number of pages.
    $query->max_num_pages = ceil(
        ( $query->found_posts + $diff ) /
        max( $per_page, $per_page2 )
    );
    ?>
    
  2. Replace the <?php numeric_posts_nav(); ?> with <?php numeric_posts_nav( $query ); ?>.

  3. Edit your pagination function — replace this part (which is lines 775 - 787 here):

    function numeric_posts_nav() {
    
        if( is_singular() )
            return;
    
        global $wp_query;
    
        /** Stop execution if there's only 1 page */
        if( $wp_query->max_num_pages <= 1 )
            return;
    
        $paged = get_query_var( 'paged' ) ? absint( get_query_var( 'paged' ) ) : 1;
        $max   = intval( $wp_query->max_num_pages );
    

    with this:

    function numeric_posts_nav( WP_Query $query = null ) {
    
        global $wp_query;
    
        if ( ! $query ) {
            $query =& $wp_query;
        }
    
        if( $query->is_singular() || $query->max_num_pages <= 1 ) {
            return;
        }
    
        $paged = get_query_var( 'paged' ) ? absint( get_query_var( 'paged' ) ) : 1;
        $max   = intval( $query->max_num_pages );
    

That's all and now check if it works for you! :)

0

let's say you want to keep your html, its possible to put this in the function and save this function in functions.php

function showPosts($postsToShow){
  if( have_posts() ): ?>
    <div class="row all-recipes-block"><?php
      $countPosts = 0;
      while( have_posts() && $countPosts < $postsToShow): the_post(); ?>
        <article id="post-<?php the_ID(); ?>" <?php post_class('col-md-4'); ?>> <?php
          if ( has_post_thumbnail() ) : ?>
            <a class="post-teaser" href="<?php the_permalink() ?>" title="<?php the_title(); ?>">
            <div class="thumbnail-block"><?php the_post_thumbnail('regular-post-thumbnail'); ?></div>
            <div class="title-block"><span class="h3 title-for-widget"><?php the_title(); ?></span></div>
            </a> <?php
          endif; ?>
        </article> <?php
      $countPosts += 1;
      endwhile; ?>
    </div>
    <div class="pagination-block row">
            <?php numeric_posts_nav(); ?>
    </div>
       <?php else: ?>
    <div id="post-404" class="noposts">
          <p><?php _e('None found.','example'); ?></p>
    </div><!-- /#post-404 --><?php 
  endif; wp_reset_query();
}

Now you just need to call this function showPosts(6); in your front page, this means with your html something like this

get_header('archive');  ?>
<div id="primary" class="content-area blog-archive col-md-9">
  <main id="main" class="site-main">
    <div class="breadcrumbs-block"><?php
    if ( function_exists('yoast_breadcrumb') ) {
      yoast_breadcrumb( '<p id="breadcrumbs">','</p>' );
    }
    ?>
      </div>
    <?php query_posts('post_type=post&post_status=publish&posts_per_page=24&paged='. get_query_var('paged')); ?>
    <?php showPosts(6); ?>
  </main>
</div>
<?php
get_footer();

let me know!

Have notice only now that this isnt the front-page but the archive.php, so if still doesnt give the desire outcome, its because the archive.php is the one responsible for the posts loop by category or by tag or year or month. So if still doesnt work remove the above changes and strangely enough or not copy and paste your code below to the index.php

$postsToShow = 6;
get_header('archive');  ?>
<div id="primary" class="content-area blog-archive col-md-9">
  <main id="main" class="site-main">
    <div class="breadcrumbs-block"><?php
    if ( function_exists('yoast_breadcrumb') ) {
      yoast_breadcrumb( '<p id="breadcrumbs">','</p>' );
    }
    ?>
      </div>
    <?php query_posts('post_type=post&post_status=publish&posts_per_page=24&paged='. get_query_var('paged')); ?>
       <?php if( have_posts() ): ?>
<div class="row all-recipes-block"><?php
        $countPosts = 0;
        while( have_posts() && $countPosts < $postsToShow): the_post(); ?>
          <article id="post-<?php the_ID(); ?>" <?php post_class('col-md-4'); ?>> <?php
          if ( has_post_thumbnail() ) : ?>
            <a class="post-teaser" href="<?php the_permalink() ?>" title="<?php the_title(); ?>">
            <div class="thumbnail-block"><?php the_post_thumbnail('regular-post-thumbnail'); ?></div>
            <div class="title-block"><span class="h3 title-for-widget"><?php the_title(); ?></span></div>
            </a> <?php
          endif; ?>
          </article> <?php
          $countPosts += 1;
        endwhile; ?>
      </div>
      <div class="pagination-block row">
              <?php numeric_posts_nav(); ?>
      </div>
         <?php else: ?>
      <div id="post-404" class="noposts">
            <p><?php _e('None found.','example'); ?></p>
      </div><!-- /#post-404 -->
     <?php endif; wp_reset_query(); ?>
  </main>
</div>
<?php
get_footer();

Now should be like a charm!

I'm creating a website with pages, shop and blog, and to achive the same has you are doing this is the tree I found out, I dont seem to find this in the internet or in the wp library. here it goes

#### posts files ####
all the articles    index.php
single article      single.php
all the articles with some query(year, month, tag, category...) archive.php

it seems strange to do this in the index.php and the single.php, but it is how it works for me.

4
  • Yes Tiago it works, but it's showing 6 posts on every page, i need 6 posts only on a first page of the archive:) Commented Jan 26, 2022 at 7:21
  • I had edit the enteire answer, the solution is the same but in a different way, this time in a function for the functions.php and should be called in the php page file. if a function is not possible to inplement, this can be done in a shortcode also. this should work Commented Jan 26, 2022 at 12:10
  • Another thing, this is the archive.php file, this is the file responsible to make always the loop of the posts by category or by tag. if the above doesnt result is because of this. strange enough, to make what you want work, you must paste the last answer in your index.php Commented Jan 26, 2022 at 12:14
  • Sorry Tiago, doesn't work for me, showing 6 posts on every page...:( Commented Jan 26, 2022 at 23:50

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.