Advertisement
TheDeadMedic

WordPress Walker Paged Threaded

Jun 25th, 2011
407
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 6.59 KB | None | 0 0
  1. /**
  2.  * Implements threaded awareness for {@see paged_walk()}.
  3.  *
  4.  * @link http://wordpress.stackexchange.com/questions/20506
  5.  * @uses Walker
  6.  */
  7. class Walker_Paged_Threaded extends Walker
  8. {
  9.     /**
  10.      * Get total number of children for an element, recursively working down
  11.      * the tree if neccessary.
  12.      *
  13.      * @param int $ID The element ID
  14.      * @param array $child_elements All children, indexed by parent ID
  15.      * @return int
  16.      */
  17.     function get_total_children( $ID, $child_elements = array() )
  18.     {
  19.         if ( empty( $ID ) || empty( $child_elements[ $ID ] ) )
  20.             return 0;
  21.  
  22.         $count = count( $child_elements[ $ID ] );
  23.         $id_field = $this->db_fields['id'];
  24.  
  25.         // iterate over children and recursively call if they themselves have children
  26.         foreach ( $child_elements[ $ID ] as $child ) {
  27.             if ( ! empty( $child_elements[ $child->$id_field ] ) )
  28.                 $count = $count + $this->get_total_children( $child->$id_field, $child_elements );
  29.         }
  30.  
  31.         return $count;
  32.     }
  33.  
  34.     /**
  35.      * Separate elements into two buckets: top level and children elements.
  36.      *
  37.      * Children elements is a two dimensional array, indexed by parent ID.
  38.      *
  39.      * @param array $elements
  40.      * @return array $top_elements, $child_elements
  41.      */
  42.     function get_top_and_child_elements( $elements )
  43.     {
  44.         $parent_field = $this->db_fields['parent'];
  45.  
  46.         $top_elements =
  47.         $child_elements = array();
  48.  
  49.         foreach ( $elements as $e ) {
  50.             if ( 0 == $e->$parent_field )
  51.                 $top_elements[] = $e;
  52.             else
  53.                 $child_elements[ $e->$parent_field ][] = $e;
  54.         }
  55.  
  56.         return array( $top_elements, $child_elements );
  57.     }
  58.  
  59.     /**
  60.      * This does not actually return the total number of root elements!
  61.      *
  62.      * It's a trick so that {@see get_comment_pages_count()} calculates the
  63.      * correct number of pages.
  64.      *
  65.      * Will break if you start passing custom 'per_page' arguments about.
  66.      */
  67.     function get_number_of_root_elements( $elements )
  68.     {
  69.         $per_page = ( int ) get_query_var( 'comments_per_page' );
  70.  
  71.         if ( 0 === $per_page )
  72.             $per_page = ( int ) get_option( 'comments_per_page' );
  73.  
  74.         if ( 0 === $per_page )
  75.             $per_page = 1;
  76.  
  77.         list( $top_elements, $child_elements ) = $this->get_top_and_child_elements( $elements );
  78.         $page_starts = $this->get_element_page_starts( $per_page, $top_elements, $child_elements );
  79.  
  80.         return count( $page_starts ) * $per_page;
  81.     }
  82.  
  83.     /**
  84.      * Get the page start indexes for $top_elements.
  85.      *
  86.      * @param array $top_elements
  87.      * @param array $top_elements
  88.      * @return array Page numbers and their starting $top_elements key
  89.      */
  90.     function get_element_page_starts( $per_page, $top_elements, $child_elements )
  91.     {
  92.         $id_field = $this->db_fields['id'];
  93.         $page_starts = array( 1 => 0 );
  94.         $stack_count = 0;
  95.  
  96.         foreach ( $top_elements as $k => $e ) {
  97.  
  98.             // add *this* and ALL children to the count stack
  99.             $stack_count = ++$stack_count + $this->get_total_children( $e->$id_field, $child_elements );
  100.  
  101.             if ( $stack_count < $per_page )
  102.                 continue; // keep-a-counting
  103.  
  104.             // hit maximum for the page, start a new one with next element
  105.             if ( isset( $top_elements[$k + 1] ) )
  106.                 $page_starts[] = $k + 1;
  107.  
  108.             $stack_count = 0; // reset stack
  109.         }
  110.  
  111.         return $page_starts;
  112.     }
  113.  
  114.     /**
  115.      * paged_walk() - as {@see Walker_Comment::paged_walk()}, but accounting for
  116.      * threading in pagination.
  117.      *
  118.      * @see Walker_Comment::paged_walk()
  119.      *
  120.      * @param int $max_depth = 0 means display all levels; $max_depth > 0 specifies the number of display levels.
  121.      * @param int $page_num the specific page number, beginning with 1.
  122.      * @return XHTML of the specified page of elements
  123.      */
  124.     function paged_walk( $elements, $max_depth, $page_num, $per_page )
  125.     {
  126.         /* sanity check */
  127.         if ( empty( $elements ) || $max_depth < -1 )
  128.             return '';
  129.  
  130.         $args = array_slice( func_get_args(), 4 );
  131.         $output = '';
  132.  
  133.         $id_field = $this->db_fields['id'];
  134.         $parent_field = $this->db_fields['parent'];
  135.  
  136.         $count = -1;
  137.         if ( -1 == $max_depth )
  138.             $total_top = count( $elements );
  139.         if ( $page_num < 1 || $per_page < 0 ) {
  140.             // No paging
  141.             $paging = false;
  142.             $start = 0;
  143.             if ( -1 == $max_depth )
  144.                 $end = $total_top;
  145.             $this->max_pages = 1;
  146.         } else {
  147.             $paging = true;
  148.             $start = ( ( int )$page_num - 1 ) * ( int )$per_page;
  149.             $end = $start + $per_page;
  150.             if ( -1 == $max_depth )
  151.                 $this->max_pages = ceil( $total_top / $per_page );
  152.         }
  153.  
  154.         // flat display
  155.         if ( -1 == $max_depth ) {
  156.             if ( ! empty( $args[0]['reverse_top_level'] ) ) {
  157.                 $elements = array_reverse( $elements );
  158.                 $oldstart = $start;
  159.                 $start = $total_top - $end;
  160.                 $end = $total_top - $oldstart;
  161.             }
  162.  
  163.             $empty_array = array();
  164.             foreach ( $elements as $e ) {
  165.                 $count++;
  166.                 if ( $count < $start )
  167.                     continue;
  168.                 if ( $count >= $end )
  169.                     break;
  170.                 $this->display_element( $e, $empty_array, 1, 0, $args, $output );
  171.             }
  172.             return $output;
  173.         }
  174.  
  175.         list( $top_elements, $child_elements ) = $this->get_top_and_child_elements( $elements );
  176.         $total_top = count( $top_elements );
  177.  
  178.         // check we actually need paging
  179.         if ( $paging && count( $elements ) > $per_page ) {
  180.             $page_starts = $this->get_element_page_starts( $per_page, $top_elements, $child_elements );
  181.             $this->max_pages = count( $page_starts );
  182.  
  183.             if ( isset( $page_starts[$page_num] ) ) { // valid page
  184.                 $start = $page_starts[$page_num];
  185.  
  186.                 // set end to start key for next page
  187.                 if ( isset( $page_starts[$page_num + 1] ) )
  188.                     $end = $page_starts[$page_num + 1];
  189.  
  190.                 // no next page, end is last key + 1
  191.                 else
  192.                     $end = $total_top;
  193.  
  194.             } else { // invalid page number - void indexes
  195.                 $start = $total_top;
  196.                 $end = $start + $per_page;
  197.             }
  198.  
  199.         // no paging
  200.         } else {
  201.             $start = 0;
  202.             $end = $total_top;
  203.         }
  204.  
  205.         if ( ! empty( $args[0]['reverse_top_level'] ) )
  206.             $top_elements = array_reverse( $top_elements );
  207.  
  208.         if ( ! empty( $args[0]['reverse_children'] ) ) {
  209.             foreach ( $child_elements as $parent => $children )
  210.                 $child_elements[$parent] = array_reverse( $children );
  211.         }
  212.  
  213.         foreach ( $top_elements as $k => $e ) {
  214.             //for the last page, need to unset earlier children in order to keep track of orphans
  215.             if ( $end >= $total_top && $k < $start )
  216.                 $this->unset_children( $e, $child_elements );
  217.  
  218.             if ( $k < $start )
  219.                 continue;
  220.  
  221.             if ( $k >= $end )
  222.                 break;
  223.  
  224.             $this->display_element( $e, $child_elements, $max_depth, 0, $args, $output );
  225.         }
  226.  
  227.         if ( $end >= $total_top && count( $child_elements ) > 0 ) {
  228.             $empty_array = array();
  229.             foreach ( $child_elements as $orphans )
  230.                 foreach ( $orphans as $op )
  231.                     $this->display_element( $op, $empty_array, 1, 0, $args, $output );
  232.         }
  233.  
  234.         return $output;
  235.     }
  236. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement