/df_home/static/test/portalbkd/wp-includes/class-wp-walker.php

https://gitlab.com/darmawan.fatria/df-skp-2014 · PHP · 416 lines · 185 code · 57 blank · 174 comment · 56 complexity · 9ca7ed9f12d357238927dd01868a806d MD5 · raw file

  1. <?php
  2. /**
  3. * A class for displaying various tree-like structures.
  4. *
  5. * Extend the Walker class to use it, see examples below. Child classes
  6. * do not need to implement all of the abstract methods in the class. The child
  7. * only needs to implement the methods that are needed.
  8. *
  9. * @since 2.1.0
  10. *
  11. * @package WordPress
  12. * @abstract
  13. */
  14. class Walker {
  15. /**
  16. * What the class handles.
  17. *
  18. * @since 2.1.0
  19. * @access public
  20. * @var string
  21. */
  22. public $tree_type;
  23. /**
  24. * DB fields to use.
  25. *
  26. * @since 2.1.0
  27. * @var array
  28. */
  29. public $db_fields;
  30. /**
  31. * Max number of pages walked by the paged walker
  32. *
  33. * @since 2.7.0
  34. * @var int
  35. */
  36. public $max_pages = 1;
  37. /**
  38. * Whether the current element has children or not.
  39. *
  40. * To be used in start_el().
  41. *
  42. * @since 4.0.0
  43. * @var bool
  44. */
  45. public $has_children;
  46. /**
  47. * Starts the list before the elements are added.
  48. *
  49. * The $args parameter holds additional values that may be used with the child
  50. * class methods. This method is called at the start of the output list.
  51. *
  52. * @since 2.1.0
  53. * @abstract
  54. *
  55. * @param string $output Passed by reference. Used to append additional content.
  56. * @param int $depth Depth of the item.
  57. * @param array $args An array of additional arguments.
  58. */
  59. public function start_lvl( &$output, $depth = 0, $args = array() ) {}
  60. /**
  61. * Ends the list of after the elements are added.
  62. *
  63. * The $args parameter holds additional values that may be used with the child
  64. * class methods. This method finishes the list at the end of output of the elements.
  65. *
  66. * @since 2.1.0
  67. * @abstract
  68. *
  69. * @param string $output Passed by reference. Used to append additional content.
  70. * @param int $depth Depth of the item.
  71. * @param array $args An array of additional arguments.
  72. */
  73. public function end_lvl( &$output, $depth = 0, $args = array() ) {}
  74. /**
  75. * Start the element output.
  76. *
  77. * The $args parameter holds additional values that may be used with the child
  78. * class methods. Includes the element output also.
  79. *
  80. * @since 2.1.0
  81. * @abstract
  82. *
  83. * @param string $output Passed by reference. Used to append additional content.
  84. * @param object $object The data object.
  85. * @param int $depth Depth of the item.
  86. * @param array $args An array of additional arguments.
  87. * @param int $current_object_id ID of the current item.
  88. */
  89. public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {}
  90. /**
  91. * Ends the element output, if needed.
  92. *
  93. * The $args parameter holds additional values that may be used with the child class methods.
  94. *
  95. * @since 2.1.0
  96. * @abstract
  97. *
  98. * @param string $output Passed by reference. Used to append additional content.
  99. * @param object $object The data object.
  100. * @param int $depth Depth of the item.
  101. * @param array $args An array of additional arguments.
  102. */
  103. public function end_el( &$output, $object, $depth = 0, $args = array() ) {}
  104. /**
  105. * Traverse elements to create list from elements.
  106. *
  107. * Display one element if the element doesn't have any children otherwise,
  108. * display the element and its children. Will only traverse up to the max
  109. * depth and no ignore elements under that depth. It is possible to set the
  110. * max depth to include all depths, see walk() method.
  111. *
  112. * This method should not be called directly, use the walk() method instead.
  113. *
  114. * @since 2.5.0
  115. *
  116. * @param object $element Data object.
  117. * @param array $children_elements List of elements to continue traversing.
  118. * @param int $max_depth Max depth to traverse.
  119. * @param int $depth Depth of current element.
  120. * @param array $args An array of arguments.
  121. * @param string $output Passed by reference. Used to append additional content.
  122. * @return null Null on failure with no changes to parameters.
  123. */
  124. public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
  125. if ( !$element )
  126. return;
  127. $id_field = $this->db_fields['id'];
  128. $id = $element->$id_field;
  129. //display this element
  130. $this->has_children = ! empty( $children_elements[ $id ] );
  131. if ( isset( $args[0] ) && is_array( $args[0] ) ) {
  132. $args[0]['has_children'] = $this->has_children; // Backwards compatibility.
  133. }
  134. $cb_args = array_merge( array(&$output, $element, $depth), $args);
  135. call_user_func_array(array($this, 'start_el'), $cb_args);
  136. // descend only when the depth is right and there are childrens for this element
  137. if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
  138. foreach( $children_elements[ $id ] as $child ){
  139. if ( !isset($newlevel) ) {
  140. $newlevel = true;
  141. //start the child delimiter
  142. $cb_args = array_merge( array(&$output, $depth), $args);
  143. call_user_func_array(array($this, 'start_lvl'), $cb_args);
  144. }
  145. $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
  146. }
  147. unset( $children_elements[ $id ] );
  148. }
  149. if ( isset($newlevel) && $newlevel ){
  150. //end the child delimiter
  151. $cb_args = array_merge( array(&$output, $depth), $args);
  152. call_user_func_array(array($this, 'end_lvl'), $cb_args);
  153. }
  154. //end this element
  155. $cb_args = array_merge( array(&$output, $element, $depth), $args);
  156. call_user_func_array(array($this, 'end_el'), $cb_args);
  157. }
  158. /**
  159. * Display array of elements hierarchically.
  160. *
  161. * Does not assume any existing order of elements.
  162. *
  163. * $max_depth = -1 means flatly display every element.
  164. * $max_depth = 0 means display all levels.
  165. * $max_depth > 0 specifies the number of display levels.
  166. *
  167. * @since 2.1.0
  168. *
  169. * @param array $elements An array of elements.
  170. * @param int $max_depth The maximum hierarchical depth.
  171. * @return string The hierarchical item output.
  172. */
  173. public function walk( $elements, $max_depth) {
  174. $args = array_slice(func_get_args(), 2);
  175. $output = '';
  176. if ($max_depth < -1) //invalid parameter
  177. return $output;
  178. if (empty($elements)) //nothing to walk
  179. return $output;
  180. $parent_field = $this->db_fields['parent'];
  181. // flat display
  182. if ( -1 == $max_depth ) {
  183. $empty_array = array();
  184. foreach ( $elements as $e )
  185. $this->display_element( $e, $empty_array, 1, 0, $args, $output );
  186. return $output;
  187. }
  188. /*
  189. * Need to display in hierarchical order.
  190. * Separate elements into two buckets: top level and children elements.
  191. * Children_elements is two dimensional array, eg.
  192. * Children_elements[10][] contains all sub-elements whose parent is 10.
  193. */
  194. $top_level_elements = array();
  195. $children_elements = array();
  196. foreach ( $elements as $e) {
  197. if ( 0 == $e->$parent_field )
  198. $top_level_elements[] = $e;
  199. else
  200. $children_elements[ $e->$parent_field ][] = $e;
  201. }
  202. /*
  203. * When none of the elements is top level.
  204. * Assume the first one must be root of the sub elements.
  205. */
  206. if ( empty($top_level_elements) ) {
  207. $first = array_slice( $elements, 0, 1 );
  208. $root = $first[0];
  209. $top_level_elements = array();
  210. $children_elements = array();
  211. foreach ( $elements as $e) {
  212. if ( $root->$parent_field == $e->$parent_field )
  213. $top_level_elements[] = $e;
  214. else
  215. $children_elements[ $e->$parent_field ][] = $e;
  216. }
  217. }
  218. foreach ( $top_level_elements as $e )
  219. $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
  220. /*
  221. * If we are displaying all levels, and remaining children_elements is not empty,
  222. * then we got orphans, which should be displayed regardless.
  223. */
  224. if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
  225. $empty_array = array();
  226. foreach ( $children_elements as $orphans )
  227. foreach( $orphans as $op )
  228. $this->display_element( $op, $empty_array, 1, 0, $args, $output );
  229. }
  230. return $output;
  231. }
  232. /**
  233. * paged_walk() - produce a page of nested elements
  234. *
  235. * Given an array of hierarchical elements, the maximum depth, a specific page number,
  236. * and number of elements per page, this function first determines all top level root elements
  237. * belonging to that page, then lists them and all of their children in hierarchical order.
  238. *
  239. * $max_depth = 0 means display all levels.
  240. * $max_depth > 0 specifies the number of display levels.
  241. *
  242. * @since 2.7.0
  243. *
  244. * @param int $max_depth The maximum hierarchical depth.
  245. * @param int $page_num The specific page number, beginning with 1.
  246. * @return string XHTML of the specified page of elements
  247. */
  248. public function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
  249. /* sanity check */
  250. if ( empty($elements) || $max_depth < -1 )
  251. return '';
  252. $args = array_slice( func_get_args(), 4 );
  253. $output = '';
  254. $parent_field = $this->db_fields['parent'];
  255. $count = -1;
  256. if ( -1 == $max_depth )
  257. $total_top = count( $elements );
  258. if ( $page_num < 1 || $per_page < 0 ) {
  259. // No paging
  260. $paging = false;
  261. $start = 0;
  262. if ( -1 == $max_depth )
  263. $end = $total_top;
  264. $this->max_pages = 1;
  265. } else {
  266. $paging = true;
  267. $start = ( (int)$page_num - 1 ) * (int)$per_page;
  268. $end = $start + $per_page;
  269. if ( -1 == $max_depth )
  270. $this->max_pages = ceil($total_top / $per_page);
  271. }
  272. // flat display
  273. if ( -1 == $max_depth ) {
  274. if ( !empty($args[0]['reverse_top_level']) ) {
  275. $elements = array_reverse( $elements );
  276. $oldstart = $start;
  277. $start = $total_top - $end;
  278. $end = $total_top - $oldstart;
  279. }
  280. $empty_array = array();
  281. foreach ( $elements as $e ) {
  282. $count++;
  283. if ( $count < $start )
  284. continue;
  285. if ( $count >= $end )
  286. break;
  287. $this->display_element( $e, $empty_array, 1, 0, $args, $output );
  288. }
  289. return $output;
  290. }
  291. /*
  292. * Separate elements into two buckets: top level and children elements.
  293. * Children_elements is two dimensional array, e.g.
  294. * $children_elements[10][] contains all sub-elements whose parent is 10.
  295. */
  296. $top_level_elements = array();
  297. $children_elements = array();
  298. foreach ( $elements as $e) {
  299. if ( 0 == $e->$parent_field )
  300. $top_level_elements[] = $e;
  301. else
  302. $children_elements[ $e->$parent_field ][] = $e;
  303. }
  304. $total_top = count( $top_level_elements );
  305. if ( $paging )
  306. $this->max_pages = ceil($total_top / $per_page);
  307. else
  308. $end = $total_top;
  309. if ( !empty($args[0]['reverse_top_level']) ) {
  310. $top_level_elements = array_reverse( $top_level_elements );
  311. $oldstart = $start;
  312. $start = $total_top - $end;
  313. $end = $total_top - $oldstart;
  314. }
  315. if ( !empty($args[0]['reverse_children']) ) {
  316. foreach ( $children_elements as $parent => $children )
  317. $children_elements[$parent] = array_reverse( $children );
  318. }
  319. foreach ( $top_level_elements as $e ) {
  320. $count++;
  321. // For the last page, need to unset earlier children in order to keep track of orphans.
  322. if ( $end >= $total_top && $count < $start )
  323. $this->unset_children( $e, $children_elements );
  324. if ( $count < $start )
  325. continue;
  326. if ( $count >= $end )
  327. break;
  328. $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
  329. }
  330. if ( $end >= $total_top && count( $children_elements ) > 0 ) {
  331. $empty_array = array();
  332. foreach ( $children_elements as $orphans )
  333. foreach( $orphans as $op )
  334. $this->display_element( $op, $empty_array, 1, 0, $args, $output );
  335. }
  336. return $output;
  337. }
  338. public function get_number_of_root_elements( $elements ){
  339. $num = 0;
  340. $parent_field = $this->db_fields['parent'];
  341. foreach ( $elements as $e) {
  342. if ( 0 == $e->$parent_field )
  343. $num++;
  344. }
  345. return $num;
  346. }
  347. // Unset all the children for a given top level element.
  348. public function unset_children( $e, &$children_elements ){
  349. if ( !$e || !$children_elements )
  350. return;
  351. $id_field = $this->db_fields['id'];
  352. $id = $e->$id_field;
  353. if ( !empty($children_elements[$id]) && is_array($children_elements[$id]) )
  354. foreach ( (array) $children_elements[$id] as $child )
  355. $this->unset_children( $child, $children_elements );
  356. if ( isset($children_elements[$id]) )
  357. unset( $children_elements[$id] );
  358. }
  359. } // Walker