Skip to content

Modified Infinite Scroll

josualeonard edited this page Feb 25, 2013 · 2 revisions

Here's how the changes to original infinite-scroll from jetpack are made:

Add new custom option

case 'posts_args' :
$settings[ $key ] = $value;

Add new custom option called posts_args to the default option. This option will be useful to add custom configuration to load custom posts.

Get last post date and time

Since we are going to load a custom post, the date and time for default posts will not be available and the plugin would not run. So we have to tell infinite-scroll plugin the date of the last post from the custom post. Modification made on the action_template_redirect() function.

Only run the plugin if it's a custom post with option posts_args filled

// Force set time for custom arguments
if(self::$settings['posts_args']){

Create array to store all of our custom posts, including comment

  $infinity_posts = array();

Check the post type

  $post_type = self::$settings['posts_args']['post_type'];

If it's a post type 'comment', then we load all comments and make it look like a post. This will be useful for a review.

  if((is_array($post_type) && in_array('comment', $post_type) || !is_array($post_type) && $post_type=='comment')){
    $args = (self::$settings['posts_args']['comment_args'])?self::$settings['posts_args']['comment_args']:array(
      'orderby' => 'modified',
      'order'   => 'DESC'
    );
    $args['number'] = -1; // To load all comments
    $comments = get_comments($args);
    if(count($comments)>0) {
      foreach($comments as $comment){
        $post = new StdClass();
        $post->ID = intval($comment->comment_ID);
        $post->post_title = $comment->comment_author;
        $post->post_type = 'comment';
        $post->post_date_gmt = $comment->comment_date_gmt;
        $post->post_modified_gmt = $comment->comment_date_gmt;
        $post->post_status = ($comment->comment_approved==1)?'approved':'pending';
        array_push($infinity_posts, $post);
      }
    }
  }

If it's a post, just load the post

  $args = self::$settings['posts_args'];
  $args['posts_per_page'] = -1; // To load all posts
  $loop = new WP_Query($args);
  $posts = $loop->posts;
  if(count($posts)>0) {
    foreach($posts as $post){
      array_push($infinity_posts, $post);
    }
  }

Get the last modified date of last post/comment

  if(count($infinity_posts>0)){
    $last_post = end($infinity_posts);
    self::$the_time = $last_post->post_modified_gmt;
  }
}

Move spinner to separate file

Spinner.js is moved to separate file and only loaded if spinner is not queued yet.

Cleanup scripts and styles param

The infinite-scroll plugin adds javascript array variables for the configurations on page. There are two unused parameters that is also included: scripts and styles. If this is included, then every time the infinite-scroll running, it's causes the plugin add long query parameter on the url. We should remove this if using custom post, we don't want to affect the original plugin functionality. Modification takes place on action_wp_head() function.

// Remove the scripts and styles parameters for custom post infinite-scroll
if(self::$settings['posts_args']){
  unset($js_settings['scripts']);
  unset($js_settings['styles']);
}

Querying and load template

Last part of modification is for the querying and loading template.

Adds custom variable to check if this custom posts contains comments.

$custom_fetch_with_comments = false;

I the post type is custom

if(self::get_settings()->posts_args){

For default custom post configuration, replace current query_vars with our customized posts_args

  $wp_the_query->query_vars = self::get_settings()->posts_args;

Check if there is a custom post with type 'comment'

  $post_type = self::get_settings()->posts_args['post_type'];
  if((is_array($post_type) && in_array('comment', $post_type) || !is_array($post_type) && $post_type=='comment')){
    $custom_fetch_with_comments = true;
  }
}

Then load the posts content and create our customized $wp_query variable

/*
 * Modify a little bit, if the args has post type comment,
 * but please preserve original plugin functionality
 */
if(self::get_settings()->posts_args){
  $infinity_posts = array();

If it has post type comments

  if($custom_fetch_with_comments){
    $args = (self::$settings['posts_args']['comment_args'])?self::$settings['posts_args']['comment_args']:array(
      'orderby' => 'modified',
      'order'   => 'DESC'
    );
    $args['number'] = null; // Load all comments
    $comments = get_comments($args);
    /*
     * Make comments as posts
     */
    if(count($comments)>0) {
      foreach($comments as $comment){
        $post = new StdClass();
        $post->ID = intval($comment->comment_ID);
        $post->post_title = $comment->comment_author;
        $post->post_type = 'comment';
        $post->post_date_gmt = $comment->comment_date_gmt;
        $post->post_modified_gmt = $comment->comment_date_gmt;
        $post->post_status = ($comment->comment_approved==1)?'approved':'pending';
        array_push($infinity_posts, $post);
      }
    }
  }

Load the default custom posts

  $args = self::$settings['posts_args'];
  $args['posts_per_page'] = -1; // To load all posts
  $loop = new WP_Query($args);
  $posts = $loop->posts;
  if(count($posts)>0) {
    foreach($posts as $post){
      array_push($infinity_posts, $post);
    }
  }

Sort and filter posts so it's only show specified number of posts.

  $loaded_posts = array();
  $per_page = self::$settings['posts_args']['posts_per_page'];
  if(count($infinity_posts)>0){
    function isort($a,$b) {
      return strcmp($a->post_modified_gmt, $b->post_modified_gmt)<0;
    }
    usort($infinity_posts, "isort");
    for($i=$page*$per_page;$i<($page*$per_page)+$per_page && $i<count($infinity_posts);$i++){
      array_push($loaded_posts, $infinity_posts[$i]);
    }
  }

Now, since we modify the post loading function and not using actual wp_query anymore, we should mimic the original $wp_query content.

  /*
   * Resemble the actual $wp_query content
   */
  $loop->post_count    = count($loaded_posts);
  $loop->current_post  = -1; // To load all posts
  $loop->found_posts   = count($infinity_posts);
  $loop->max_num_pages = round(count($infinity_posts)/$per_page);
  $loop->posts         = $loaded_posts;

Set it as new $wp_query

  $wp_query = $loop;
}

Usage

The usage of this modified infinite-scroll can be seen on Tb_Showroom class.

/**
 * Add theme support for infinity scroll for showroom
 *
 * @return void
 */
function showroom_infinite_scroll_init() {
  if(in_array(current_page(), array('dashboard'))){
    // Custom arguments for custom post, needed to get last post time
    // and rendering get_template_part
    $per_page = 10;
    $args = array(
      'orderby'		     => 'modified',
      'order'			     => 'DESC',
      'post_type'		   => array('showroom', 'leads', 'comment'),
      'post_status'	   => 'publish',
      'posts_per_page' => $per_page,
      // Infinite scroll with custom action, comment as post
      'comment_args'   => array(
        'orderby'    => 'modified',
        'order'      => 'DESC',
        'number'     => $per_page
      )
    );
    add_theme_support('infinite-scroll', array(
      'posts_args' => $args, // Add custom arguments into infinite scroll
      'container'  => 'activities-container', // Use current class
      'render'     => array(&$this, 'showroom_infinite_scroll_render'), // Render with custom function
      'wrapper'    => false, // Do not use wrapper
      'footer'     => false  // Do not use footer
    ));
  }
}

And use this custom render function:

/**
 * Function to load showroom list, used in infinite scroll.
 * This function is custom function for replacing the infinite scroll render
 */
function showroom_infinite_scroll_render() {
  global $wp_query;
  $loop = $wp_query;
  if ( $loop->have_posts() ) {
    while( $loop->have_posts() ) : $loop->the_post();
      get_template_part( TOOLBOX_TEMPLATES . '/list','showroom'));
    endwhile;
  }
}

And the modified plugin should be working nicely.