wp/wp-includes/class-wp-walker.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
   139 		$this->has_children = ! empty( $children_elements[ $id ] );
   139 		$this->has_children = ! empty( $children_elements[ $id ] );
   140 		if ( isset( $args[0] ) && is_array( $args[0] ) ) {
   140 		if ( isset( $args[0] ) && is_array( $args[0] ) ) {
   141 			$args[0]['has_children'] = $this->has_children; // Back-compat.
   141 			$args[0]['has_children'] = $this->has_children; // Back-compat.
   142 		}
   142 		}
   143 
   143 
   144 		$cb_args = array_merge( array(&$output, $element, $depth), $args);
   144 		$cb_args = array_merge( array( &$output, $element, $depth ), $args );
   145 		call_user_func_array(array($this, 'start_el'), $cb_args);
   145 		call_user_func_array( array( $this, 'start_el' ), $cb_args );
   146 
   146 
   147 		// descend only when the depth is right and there are childrens for this element
   147 		// descend only when the depth is right and there are childrens for this element
   148 		if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
   148 		if ( ( $max_depth == 0 || $max_depth > $depth + 1 ) && isset( $children_elements[ $id ] ) ) {
   149 
   149 
   150 			foreach ( $children_elements[ $id ] as $child ){
   150 			foreach ( $children_elements[ $id ] as $child ) {
   151 
   151 
   152 				if ( !isset($newlevel) ) {
   152 				if ( ! isset( $newlevel ) ) {
   153 					$newlevel = true;
   153 					$newlevel = true;
   154 					//start the child delimiter
   154 					//start the child delimiter
   155 					$cb_args = array_merge( array(&$output, $depth), $args);
   155 					$cb_args = array_merge( array( &$output, $depth ), $args );
   156 					call_user_func_array(array($this, 'start_lvl'), $cb_args);
   156 					call_user_func_array( array( $this, 'start_lvl' ), $cb_args );
   157 				}
   157 				}
   158 				$this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
   158 				$this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
   159 			}
   159 			}
   160 			unset( $children_elements[ $id ] );
   160 			unset( $children_elements[ $id ] );
   161 		}
   161 		}
   162 
   162 
   163 		if ( isset($newlevel) && $newlevel ){
   163 		if ( isset( $newlevel ) && $newlevel ) {
   164 			//end the child delimiter
   164 			//end the child delimiter
   165 			$cb_args = array_merge( array(&$output, $depth), $args);
   165 			$cb_args = array_merge( array( &$output, $depth ), $args );
   166 			call_user_func_array(array($this, 'end_lvl'), $cb_args);
   166 			call_user_func_array( array( $this, 'end_lvl' ), $cb_args );
   167 		}
   167 		}
   168 
   168 
   169 		//end this element
   169 		//end this element
   170 		$cb_args = array_merge( array(&$output, $element, $depth), $args);
   170 		$cb_args = array_merge( array( &$output, $element, $depth ), $args );
   171 		call_user_func_array(array($this, 'end_el'), $cb_args);
   171 		call_user_func_array( array( $this, 'end_el' ), $cb_args );
   172 	}
   172 	}
   173 
   173 
   174 	/**
   174 	/**
   175 	 * Display array of elements hierarchically.
   175 	 * Display array of elements hierarchically.
   176 	 *
   176 	 *
   185 	 * @param array $elements  An array of elements.
   185 	 * @param array $elements  An array of elements.
   186 	 * @param int   $max_depth The maximum hierarchical depth.
   186 	 * @param int   $max_depth The maximum hierarchical depth.
   187 	 * @return string The hierarchical item output.
   187 	 * @return string The hierarchical item output.
   188 	 */
   188 	 */
   189 	public function walk( $elements, $max_depth ) {
   189 	public function walk( $elements, $max_depth ) {
   190 		$args = array_slice(func_get_args(), 2);
   190 		$args   = array_slice( func_get_args(), 2 );
   191 		$output = '';
   191 		$output = '';
   192 
   192 
   193 		//invalid parameter or nothing to walk
   193 		//invalid parameter or nothing to walk
   194 		if ( $max_depth < -1 || empty( $elements ) ) {
   194 		if ( $max_depth < -1 || empty( $elements ) ) {
   195 			return $output;
   195 			return $output;
   198 		$parent_field = $this->db_fields['parent'];
   198 		$parent_field = $this->db_fields['parent'];
   199 
   199 
   200 		// flat display
   200 		// flat display
   201 		if ( -1 == $max_depth ) {
   201 		if ( -1 == $max_depth ) {
   202 			$empty_array = array();
   202 			$empty_array = array();
   203 			foreach ( $elements as $e )
   203 			foreach ( $elements as $e ) {
   204 				$this->display_element( $e, $empty_array, 1, 0, $args, $output );
   204 				$this->display_element( $e, $empty_array, 1, 0, $args, $output );
       
   205 			}
   205 			return $output;
   206 			return $output;
   206 		}
   207 		}
   207 
   208 
   208 		/*
   209 		/*
   209 		 * Need to display in hierarchical order.
   210 		 * Need to display in hierarchical order.
   211 		 * Children_elements is two dimensional array, eg.
   212 		 * Children_elements is two dimensional array, eg.
   212 		 * Children_elements[10][] contains all sub-elements whose parent is 10.
   213 		 * Children_elements[10][] contains all sub-elements whose parent is 10.
   213 		 */
   214 		 */
   214 		$top_level_elements = array();
   215 		$top_level_elements = array();
   215 		$children_elements  = array();
   216 		$children_elements  = array();
   216 		foreach ( $elements as $e) {
   217 		foreach ( $elements as $e ) {
   217 			if ( empty( $e->$parent_field ) )
   218 			if ( empty( $e->$parent_field ) ) {
   218 				$top_level_elements[] = $e;
   219 				$top_level_elements[] = $e;
   219 			else
   220 			} else {
   220 				$children_elements[ $e->$parent_field ][] = $e;
   221 				$children_elements[ $e->$parent_field ][] = $e;
       
   222 			}
   221 		}
   223 		}
   222 
   224 
   223 		/*
   225 		/*
   224 		 * When none of the elements is top level.
   226 		 * When none of the elements is top level.
   225 		 * Assume the first one must be root of the sub elements.
   227 		 * Assume the first one must be root of the sub elements.
   226 		 */
   228 		 */
   227 		if ( empty($top_level_elements) ) {
   229 		if ( empty( $top_level_elements ) ) {
   228 
   230 
   229 			$first = array_slice( $elements, 0, 1 );
   231 			$first = array_slice( $elements, 0, 1 );
   230 			$root = $first[0];
   232 			$root  = $first[0];
   231 
   233 
   232 			$top_level_elements = array();
   234 			$top_level_elements = array();
   233 			$children_elements  = array();
   235 			$children_elements  = array();
   234 			foreach ( $elements as $e) {
   236 			foreach ( $elements as $e ) {
   235 				if ( $root->$parent_field == $e->$parent_field )
   237 				if ( $root->$parent_field == $e->$parent_field ) {
   236 					$top_level_elements[] = $e;
   238 					$top_level_elements[] = $e;
   237 				else
   239 				} else {
   238 					$children_elements[ $e->$parent_field ][] = $e;
   240 					$children_elements[ $e->$parent_field ][] = $e;
   239 			}
   241 				}
   240 		}
   242 			}
   241 
   243 		}
   242 		foreach ( $top_level_elements as $e )
   244 
       
   245 		foreach ( $top_level_elements as $e ) {
   243 			$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
   246 			$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
       
   247 		}
   244 
   248 
   245 		/*
   249 		/*
   246 		 * If we are displaying all levels, and remaining children_elements is not empty,
   250 		 * If we are displaying all levels, and remaining children_elements is not empty,
   247 		 * then we got orphans, which should be displayed regardless.
   251 		 * then we got orphans, which should be displayed regardless.
   248 		 */
   252 		 */
   249 		if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
   253 		if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
   250 			$empty_array = array();
   254 			$empty_array = array();
   251 			foreach ( $children_elements as $orphans )
   255 			foreach ( $children_elements as $orphans ) {
   252 				foreach ( $orphans as $op )
   256 				foreach ( $orphans as $op ) {
   253 					$this->display_element( $op, $empty_array, 1, 0, $args, $output );
   257 					$this->display_element( $op, $empty_array, 1, 0, $args, $output );
   254 		 }
   258 				}
   255 
   259 			}
   256 		 return $output;
   260 		}
       
   261 
       
   262 		return $output;
   257 	}
   263 	}
   258 
   264 
   259 	/**
   265 	/**
   260  	 * paged_walk() - produce a page of nested elements
   266 	 * paged_walk() - produce a page of nested elements
   261  	 *
   267 	 *
   262  	 * Given an array of hierarchical elements, the maximum depth, a specific page number,
   268 	 * Given an array of hierarchical elements, the maximum depth, a specific page number,
   263  	 * and number of elements per page, this function first determines all top level root elements
   269 	 * and number of elements per page, this function first determines all top level root elements
   264  	 * belonging to that page, then lists them and all of their children in hierarchical order.
   270 	 * belonging to that page, then lists them and all of their children in hierarchical order.
   265  	 *
   271 	 *
   266 	 * $max_depth = 0 means display all levels.
   272 	 * $max_depth = 0 means display all levels.
   267 	 * $max_depth > 0 specifies the number of display levels.
   273 	 * $max_depth > 0 specifies the number of display levels.
   268 	 *
   274 	 *
   269  	 * @since 2.7.0
   275 	 * @since 2.7.0
   270 	 *
   276 	 *
   271 	 * @param array $elements
   277 	 * @param array $elements
   272 	 * @param int   $max_depth The maximum hierarchical depth.
   278 	 * @param int   $max_depth The maximum hierarchical depth.
   273 	 * @param int   $page_num The specific page number, beginning with 1.
   279 	 * @param int   $page_num The specific page number, beginning with 1.
   274 	 * @param int   $per_page
   280 	 * @param int   $per_page
   277 	public function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
   283 	public function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
   278 		if ( empty( $elements ) || $max_depth < -1 ) {
   284 		if ( empty( $elements ) || $max_depth < -1 ) {
   279 			return '';
   285 			return '';
   280 		}
   286 		}
   281 
   287 
   282 		$args = array_slice( func_get_args(), 4 );
   288 		$args   = array_slice( func_get_args(), 4 );
   283 		$output = '';
   289 		$output = '';
   284 
   290 
   285 		$parent_field = $this->db_fields['parent'];
   291 		$parent_field = $this->db_fields['parent'];
   286 
   292 
   287 		$count = -1;
   293 		$count = -1;
   288 		if ( -1 == $max_depth )
   294 		if ( -1 == $max_depth ) {
   289 			$total_top = count( $elements );
   295 			$total_top = count( $elements );
   290 		if ( $page_num < 1 || $per_page < 0  ) {
   296 		}
       
   297 		if ( $page_num < 1 || $per_page < 0 ) {
   291 			// No paging
   298 			// No paging
   292 			$paging = false;
   299 			$paging = false;
   293 			$start = 0;
   300 			$start  = 0;
   294 			if ( -1 == $max_depth )
   301 			if ( -1 == $max_depth ) {
   295 				$end = $total_top;
   302 				$end = $total_top;
       
   303 			}
   296 			$this->max_pages = 1;
   304 			$this->max_pages = 1;
   297 		} else {
   305 		} else {
   298 			$paging = true;
   306 			$paging = true;
   299 			$start = ( (int)$page_num - 1 ) * (int)$per_page;
   307 			$start  = ( (int) $page_num - 1 ) * (int) $per_page;
   300 			$end   = $start + $per_page;
   308 			$end    = $start + $per_page;
   301 			if ( -1 == $max_depth )
   309 			if ( -1 == $max_depth ) {
   302 				$this->max_pages = ceil($total_top / $per_page);
   310 				$this->max_pages = ceil( $total_top / $per_page );
       
   311 			}
   303 		}
   312 		}
   304 
   313 
   305 		// flat display
   314 		// flat display
   306 		if ( -1 == $max_depth ) {
   315 		if ( -1 == $max_depth ) {
   307 			if ( !empty($args[0]['reverse_top_level']) ) {
   316 			if ( ! empty( $args[0]['reverse_top_level'] ) ) {
   308 				$elements = array_reverse( $elements );
   317 				$elements = array_reverse( $elements );
   309 				$oldstart = $start;
   318 				$oldstart = $start;
   310 				$start = $total_top - $end;
   319 				$start    = $total_top - $end;
   311 				$end = $total_top - $oldstart;
   320 				$end      = $total_top - $oldstart;
   312 			}
   321 			}
   313 
   322 
   314 			$empty_array = array();
   323 			$empty_array = array();
   315 			foreach ( $elements as $e ) {
   324 			foreach ( $elements as $e ) {
   316 				$count++;
   325 				$count++;
   317 				if ( $count < $start )
   326 				if ( $count < $start ) {
   318 					continue;
   327 					continue;
   319 				if ( $count >= $end )
   328 				}
       
   329 				if ( $count >= $end ) {
   320 					break;
   330 					break;
       
   331 				}
   321 				$this->display_element( $e, $empty_array, 1, 0, $args, $output );
   332 				$this->display_element( $e, $empty_array, 1, 0, $args, $output );
   322 			}
   333 			}
   323 			return $output;
   334 			return $output;
   324 		}
   335 		}
   325 
   336 
   328 		 * Children_elements is two dimensional array, e.g.
   339 		 * Children_elements is two dimensional array, e.g.
   329 		 * $children_elements[10][] contains all sub-elements whose parent is 10.
   340 		 * $children_elements[10][] contains all sub-elements whose parent is 10.
   330 		 */
   341 		 */
   331 		$top_level_elements = array();
   342 		$top_level_elements = array();
   332 		$children_elements  = array();
   343 		$children_elements  = array();
   333 		foreach ( $elements as $e) {
   344 		foreach ( $elements as $e ) {
   334 			if ( 0 == $e->$parent_field )
   345 			if ( 0 == $e->$parent_field ) {
   335 				$top_level_elements[] = $e;
   346 				$top_level_elements[] = $e;
   336 			else
   347 			} else {
   337 				$children_elements[ $e->$parent_field ][] = $e;
   348 				$children_elements[ $e->$parent_field ][] = $e;
       
   349 			}
   338 		}
   350 		}
   339 
   351 
   340 		$total_top = count( $top_level_elements );
   352 		$total_top = count( $top_level_elements );
   341 		if ( $paging )
   353 		if ( $paging ) {
   342 			$this->max_pages = ceil($total_top / $per_page);
   354 			$this->max_pages = ceil( $total_top / $per_page );
   343 		else
   355 		} else {
   344 			$end = $total_top;
   356 			$end = $total_top;
   345 
   357 		}
   346 		if ( !empty($args[0]['reverse_top_level']) ) {
   358 
       
   359 		if ( ! empty( $args[0]['reverse_top_level'] ) ) {
   347 			$top_level_elements = array_reverse( $top_level_elements );
   360 			$top_level_elements = array_reverse( $top_level_elements );
   348 			$oldstart = $start;
   361 			$oldstart           = $start;
   349 			$start = $total_top - $end;
   362 			$start              = $total_top - $end;
   350 			$end = $total_top - $oldstart;
   363 			$end                = $total_top - $oldstart;
   351 		}
   364 		}
   352 		if ( !empty($args[0]['reverse_children']) ) {
   365 		if ( ! empty( $args[0]['reverse_children'] ) ) {
   353 			foreach ( $children_elements as $parent => $children )
   366 			foreach ( $children_elements as $parent => $children ) {
   354 				$children_elements[$parent] = array_reverse( $children );
   367 				$children_elements[ $parent ] = array_reverse( $children );
       
   368 			}
   355 		}
   369 		}
   356 
   370 
   357 		foreach ( $top_level_elements as $e ) {
   371 		foreach ( $top_level_elements as $e ) {
   358 			$count++;
   372 			$count++;
   359 
   373 
   360 			// For the last page, need to unset earlier children in order to keep track of orphans.
   374 			// For the last page, need to unset earlier children in order to keep track of orphans.
   361 			if ( $end >= $total_top && $count < $start )
   375 			if ( $end >= $total_top && $count < $start ) {
   362 					$this->unset_children( $e, $children_elements );
   376 					$this->unset_children( $e, $children_elements );
   363 
   377 			}
   364 			if ( $count < $start )
   378 
       
   379 			if ( $count < $start ) {
   365 				continue;
   380 				continue;
   366 
   381 			}
   367 			if ( $count >= $end )
   382 
       
   383 			if ( $count >= $end ) {
   368 				break;
   384 				break;
       
   385 			}
   369 
   386 
   370 			$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
   387 			$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
   371 		}
   388 		}
   372 
   389 
   373 		if ( $end >= $total_top && count( $children_elements ) > 0 ) {
   390 		if ( $end >= $total_top && count( $children_elements ) > 0 ) {
   374 			$empty_array = array();
   391 			$empty_array = array();
   375 			foreach ( $children_elements as $orphans )
   392 			foreach ( $children_elements as $orphans ) {
   376 				foreach ( $orphans as $op )
   393 				foreach ( $orphans as $op ) {
   377 					$this->display_element( $op, $empty_array, 1, 0, $args, $output );
   394 					$this->display_element( $op, $empty_array, 1, 0, $args, $output );
       
   395 				}
       
   396 			}
   378 		}
   397 		}
   379 
   398 
   380 		return $output;
   399 		return $output;
   381 	}
   400 	}
   382 
   401 
   386 	 * @since 2.7.0
   405 	 * @since 2.7.0
   387 	 *
   406 	 *
   388 	 * @param array $elements Elements to list.
   407 	 * @param array $elements Elements to list.
   389 	 * @return int Number of root elements.
   408 	 * @return int Number of root elements.
   390 	 */
   409 	 */
   391 	public function get_number_of_root_elements( $elements ){
   410 	public function get_number_of_root_elements( $elements ) {
   392 		$num = 0;
   411 		$num          = 0;
   393 		$parent_field = $this->db_fields['parent'];
   412 		$parent_field = $this->db_fields['parent'];
   394 
   413 
   395 		foreach ( $elements as $e) {
   414 		foreach ( $elements as $e ) {
   396 			if ( 0 == $e->$parent_field )
   415 			if ( 0 == $e->$parent_field ) {
   397 				$num++;
   416 				$num++;
       
   417 			}
   398 		}
   418 		}
   399 		return $num;
   419 		return $num;
   400 	}
   420 	}
   401 
   421 
   402 	/**
   422 	/**
   405 	 * @since 2.7.0
   425 	 * @since 2.7.0
   406 	 *
   426 	 *
   407 	 * @param object $e
   427 	 * @param object $e
   408 	 * @param array $children_elements
   428 	 * @param array $children_elements
   409 	 */
   429 	 */
   410 	public function unset_children( $e, &$children_elements ){
   430 	public function unset_children( $e, &$children_elements ) {
   411 		if ( ! $e || ! $children_elements ) {
   431 		if ( ! $e || ! $children_elements ) {
   412 			return;
   432 			return;
   413 		}
   433 		}
   414 
   434 
   415 		$id_field = $this->db_fields['id'];
   435 		$id_field = $this->db_fields['id'];
   416 		$id = $e->$id_field;
   436 		$id       = $e->$id_field;
   417 
   437 
   418 		if ( !empty($children_elements[$id]) && is_array($children_elements[$id]) )
   438 		if ( ! empty( $children_elements[ $id ] ) && is_array( $children_elements[ $id ] ) ) {
   419 			foreach ( (array) $children_elements[$id] as $child )
   439 			foreach ( (array) $children_elements[ $id ] as $child ) {
   420 				$this->unset_children( $child, $children_elements );
   440 				$this->unset_children( $child, $children_elements );
       
   441 			}
       
   442 		}
   421 
   443 
   422 		unset( $children_elements[ $id ] );
   444 		unset( $children_elements[ $id ] );
   423 	}
   445 	}
   424 
   446 
   425 } // Walker
   447 } // Walker