0

I've created a clone of the core Recent Posts widget as suggested here Code for Recent Posts Widget, but how would I go about adding pagination to that widget?

I intend on using auto-pagination for infinite scroll, but I'm not sure where to start...

Using Wordpress 3.9.1 so the most popular widget pagination plugin isn't compatible.

I added this:

function my_app_latest_add_query_var() {
  global $wp;
  $wp->add_query_var('latest_page');
}
add_filter('init', 'my_app_latest_add_query_var');

Then the widget I've got pulls out the posts as I want, but the pagination links don't show:

class MyApp_Widget_Recent_Posts extends WP_Widget {
public function __construct() {
    $widget_ops = array('classname' => 'widget_recent_entries', 'description' => __( "Your site’s most recent Posts.") );
    parent::__construct('recent-posts', __('MyApp Recent Posts'), $widget_ops);
    $this->alt_option_name = 'widget_recent_entries';
    add_action( 'save_post', array($this, 'flush_widget_cache') );
    add_action( 'deleted_post', array($this, 'flush_widget_cache') );
    add_action( 'switch_theme', array($this, 'flush_widget_cache') );
}
public function widget($args, $instance) {
    $cache = array();
    if ( ! $this->is_preview() ) {
        $cache = wp_cache_get( 'widget_recent_posts', 'widget' );
    }
    if ( ! is_array( $cache ) ) {
        $cache = array();
    }
    if ( ! isset( $args['widget_id'] ) ) {
        $args['widget_id'] = $this->id;
    }
    if ( isset( $cache[ $args['widget_id'] ] ) ) {
        echo $cache[ $args['widget_id'] ];
        return;
    }
    ob_start();
    $title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : __( 'MyApp Recent Posts' );
    /** This filter is documented in wp-includes/default-widgets.php */
    $title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
    $number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
    if ( ! $number )
        $number = 5;
    $show_date = isset( $instance['show_date'] ) ? $instance['show_date'] : false;
    $latest_page = ( get_query_var( 'latest_page' ) ) ? absint( get_query_var( 'latest_page' ) ) : 1;
    $r = new WP_Query( apply_filters( 'widget_posts_args', array(
      'posts_per_page'      => $number,
      'paged'               => $latest_page,
      'no_found_rows'       => true,
      'post_status'         => 'publish',
      'ignore_sticky_posts' => true,
      'suppress_filters'    => true
    ) ) );
    if ($r->have_posts()) :
    ?>
    <?php echo $args['before_widget']; ?>
    <?php if ( $title ) {
      echo $args['before_title'] . $title . $args['after_title'];
    } ?>
    <div class="latest-list">
      <?php while ( $r->have_posts() ) : $r->the_post(); ?>
        <?php get_template_part( 'content-block', get_post_format() ); ?>
      <?php endwhile; ?>
    </div>
    <?php echo $args['after_widget']; ?>
    <?php
      echo '<div class="paginate-links">';
      $args = array(
        'base' => '/' . '%_%',
        'format' => '?latest_page=%#%',
        'current' => $latest_page,
        'total' => $r->max_num_pages
      );
      echo paginate_links( $args );
      echo '</div>'; ?>
    <?php // This doesn't seem to work at all... ?>
    <?php // echo get_next_posts_link( 'Load more', $r->max_num_pages ); ?>
    <?php
    // Reset the global $the_post as this query will have stomped on it
    wp_reset_postdata();
    endif;
    if ( ! $this->is_preview() ) {
      $cache[ $args['widget_id'] ] = ob_get_flush();
      wp_cache_set( 'widget_recent_posts', $cache, 'widget' );
    } else {
      ob_end_flush();
   }
}
}

I also created a function, which works for both i.e. displays posts and pagination links:

function my_app_recent_posts() {
  global $post;
  $latest_page = (get_query_var('latest_page')) ? get_query_var('latest_page') : 1;
  $args = array(
      'posts_per_page' => 1,
      'order' => 'DESC',
      'post_status'         => 'publish',
      'ignore_sticky_posts' => true,
      'paged' => $latest_page
  );
  $rposts = new WP_Query($args);
  if ( $rposts->have_posts() ) :
    while ( $rposts->have_posts() ) : $rposts->the_post();
      get_template_part( 'content-block', get_post_format() );
    endwhile;
    echo '<div class="pagination-links">';
    $args = array(
        'base' => '/' . '%_%',
        'format' => '?latest_page=%#%',
        'current' => $latest_page,
        'total' => $rposts->max_num_pages
    );
    echo paginate_links( $args );
    // This doesn't work as it just used the 'paged' query param
    // echo get_next_posts_link( 'Load more', $rposts->max_num_pages );
    wp_reset_postdata();
    echo '</div>';
  endif;
}

This doesn't seem right to me - there has got to be a way to just use the widget code surely?

  • You should show some additional information, like research effort, what you have tried and what has failed - so the actual code you use. Read How to Ask for more (starting) information on that. – Nicolai Aug 5 '14 at 14:28
  • Ok thanks, see update - does that help? – Chris Edwards Aug 5 '14 at 15:08
  • Definitely better, because now one can actually analyze the problem on hand. That said, I'm on the run, so no time do that and for an answer. But this detailed answer on how to paginate attachments as gallery I gave awhile ago should pretty much cover what you need. – Nicolai Aug 5 '14 at 15:25
  • @ialocin I've updated with the latest, any ideas? – Chris Edwards Aug 6 '14 at 10:37
0

Remove:

'no_found_rows' => true,

from your WP_Query call inside the widget code.

Additionally I would suggest to make this change :

'base' => add_query_arg( 'latest_page', '%#%' ),

in your paginate_links call, because add_query_arg() will handle if ? or & is used.

This should make the pagination work in your widget.

Note: I'm almost, haven't tested it, certain that this won't work on the front page if a static page is selected to show.


Update:

After I have taken a quick look at some code of mine I'm sure that the pagination won't work on the front page if a static page is selected to show there. In this code I introduced a additional $_GET variable, which should not be registered as query variable, to work around it. Below a outlined approach how to use this:

  1. Setup the $latest_page variable differently

    if ( is_front_page() ) {
       $latest_page = ( isset( $_GET[ 'fplp' ] ) ) 
         ? $_GET[ 'fplp' ]
         : 1;
    } else {
       $latest_page = ( get_query_var( 'latest_page' ) ) 
         ? get_query_var( 'latest_page' ) 
         : 1;
    }
    
  2. Additionally setup the base and format parameter of paginate_links differently

    $base = ( is_front_page()
      ? add_query_arg( 'fplp', '%#%' )
      : add_query_arg( 'latest_page', '%#%' )
    );
    $format = ( is_front_page()
      ? '?fplp=%#%' 
      : '?latest_page=%#%' 
    );
    $args = array(
      'base' => $base,
      'format' => $format
       // some other parameter
    );
    paginate_links( $args );
    

With this you can the paginate the widget under above mentioned conditions.

Note: Of course adding the query variable could be dropped completely and one could solely work with a $_GET variable.

  • That's it! So simple... Many thanks! Also seems to work fine on front page. – Chris Edwards Aug 6 '14 at 12:25
  • My pleasure, but I should have been a bit more precise, my concern is that it won't work if you are setting a static page as front page - can you test this? @ChrisEdwards – Nicolai Aug 6 '14 at 12:32
  • Ah ok, everything I've added is inside a custom theme which has a very customised home page, switching to static did nothing. And switching theme removes the widget... – Chris Edwards Aug 6 '14 at 12:40
  • Ok, I guess in this case it doesn't matter for you, so it is fine. @ChrisEdwards – Nicolai Aug 6 '14 at 13:30

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.