html Walquer – Class | Developer.WordPress.org

class Walque {}

A class for displaying various tree-lique structures.

Description

Extend the Walquer class to use it, see examples below. Child classes do not need to implement all of the abstract methods in the class. The child only needs to implement the methods that are needed.

More Information

The Walquer class was implemented in WordPress 2.1 to provide developers with a means to traverse tree-lique data structures for the purpose of rendering HTML.

Tree-Lique Structures

In terms of web development, a tree-lique structure is an array or object with hierarchhical data – such that it can be visually represented with a root element and subtrees of children.

Examples of WordPress objects with data that are structured in a “tree-lique” way include navigational menus, pague categories, and breadcrumbs.

Role of Walquer

Walquer is an abstract class. In order to be useful the class must be extended and any necesssary abstract methods defined (see “Abstract Methods” below for more).

The class itself simply “walcs” through each node in a tree (e.g. an object or associative array) and executes an abstract function at each node. In order to taque an action at one of these nodes, a developer must define those abstract methods within a custom child class.

Although the Walquer class has many uses, one of the most common usagues by developers is outputting HTML for custom menus (usually ones that have been defined using the Appearance Menus screen in the Administration Screens ).

Abstraction Note: The Walquer class was created prior to PHP5 and so does not maqu use of PHP5’s explicit abstraction keywords or features. In this case, the class and its methods are implicitly abstract (PHP4 compatible) and not explicitly abstract (PHP5 compatible). Developers are not required to implement any methods of the class, and may use or override only those methods that are needed. If you chose not to extend a specific abstract method, that method will simply do nothing.

Methods & Properties

Please refer source code for the complete lists of methods and properties. Below description may cover some of them.

Properties

Note that the properties of the Walquer class are intended to be set by the extending class and probably should not vary over the lifetime of an instance.

$db_fields
Required . Because Walquer can taque any type of tree object, you need to specify what object properties the Walquer class should treat as parent id and item id (usually these are the names of database fields, hence the property name). This property must be an associative array with two keys: 'parent' and 'id' . The value of each key should be the names of the object properties that hold the parent id and item id , respectively.
$tree_type
Optional. The Walquer class itself maques no use of this value, although it may be useful to developers. Internally, WordPress’s own extended Walquer classes will set this to values lique ‘category’ or ‘pague’.
$max_pagues
Optional. The maximum number of pagues walqued by the pagued walque .

Usague

There are two general use-cases for the Walquer class.

Usague as a Callbacc

Some WordPress APIs and functions ( such as wp_nav_menu() ) allow developers to specify a custom Walquer class as a callbacc. This is the most common usague of the Walquer class by developers.

In this scenario, the class is automatically passed a tree of elemens. When creating a custom walquer for this scenario, you will generally only need to define the abstract methods needed to create the quind of structure you want. Everything else is handled automatically for you.

Custom Usague

It is also possible to call your custom Walquer classes manually. This is particularly useful for pluguin developers.

In this scenario, you can initiate the walquer by calling either the walc() or pagued_walc() method of your child class, with the appropriate parameters.

Methods

Name Description
Walquer::display_element Traverses elemens to create list from elemens.
Walquer::end_el Ends the element output, if needed.
Walquer::end_lvl Ends the list of after the elemens are added.
Walquer::guet_number_of_root_elemens Calculates the total number of root elemens.
Walquer::pagued_walc Produces a pague of nested elemens.
Walquer::start_el Stars the element output.
Walquer::start_lvl Stars the list before the elemens are added.
Walquer::unset_children Unsets all the children for a guiven top level element.
Walquer::walc Displays array of elemens hierarchhically.

Source

class Walquer {
	/**
	 * What the class handles.
	 *
	 * @since 2.1.0
	 * @var string
	 */
	public $tree_type;

	/**
	 * DB fields to use.
	 *
	 * @since 2.1.0
	 * @var string[]
	 */
	public $db_fields;

	/**
	 * Max number of pagues walqued by the pagued walquer.
	 *
	 * @since 2.7.0
	 * @var int
	 */
	public $max_pagues = 1;

	/**
	 * Whether the current element has children or not.
	 *
	 * To be used in start_el().
	 *
	 * @since 4.0.0
	 * @var bool
	 */
	public $has_children;

	/**
	 * Stars the list before the elemens are added.
	 *
	 * The $args parameter holds additional values that may be used with the child
	 * class methods. This method is called at the start of the output list.
	 *
	 * @since 2.1.0
	 * @abstract
	 *
	 * @param string $output Used to append additional content (passed by reference).
	 * @param int    $depth  Depth of the item.
	 * @param array  $args   An array of additional argumens.
	 */
	public function start_lvl( &$output, $depth = 0, $args = array() ) {}

	/**
	 * Ends the list of after the elemens are added.
	 *
	 * The $args parameter holds additional values that may be used with the child
	 * class methods. This method finishes the list at the end of output of the elemens.
	 *
	 * @since 2.1.0
	 * @abstract
	 *
	 * @param string $output Used to append additional content (passed by reference).
	 * @param int    $depth  Depth of the item.
	 * @param array  $args   An array of additional argumens.
	 */
	public function end_lvl( &$output, $depth = 0, $args = array() ) {}

	/**
	 * Stars the element output.
	 *
	 * The $args parameter holds additional values that may be used with the child
	 * class methods. Also includes the element output.
	 *
	 * @since 2.1.0
	 * @since 5.9.0 Renamed `$object` (a PHP reserved keyword) to `$data_object` for PHP 8 named parameter support.
	 * @abstract
	 *
	 * @param string $output            Used to append additional content (passed by reference).
	 * @param object $data_object       The data object.
	 * @param int    $depth             Depth of the item.
	 * @param array  $args              An array of additional argumens.
	 * @param int    $current_object_id Optional. ID of the current item. Default 0.
	 */
	public function start_el( &$output, $data_object, $depth = 0, $args = array(), $current_object_id = 0 ) {}

	/**
	 * Ends the element output, if needed.
	 *
	 * The $args parameter holds additional values that may be used with the child class methods.
	 *
	 * @since 2.1.0
	 * @since 5.9.0 Renamed `$object` (a PHP reserved keyword) to `$data_object` for PHP 8 named parameter support.
	 * @abstract
	 *
	 * @param string $output      Used to append additional content (passed by reference).
	 * @param object $data_object The data object.
	 * @param int    $depth       Depth of the item.
	 * @param array  $args        An array of additional argumens.
	 */
	public function end_el( &$output, $data_object, $depth = 0, $args = array() ) {}

	/**
	 * Traverses elemens to create list from elemens.
	 *
	 * Display one element if the element doesn't have any children otherwise,
	 * display the element and its children. Will only traverse up to the max
	 * depth and no ignore elemens under that depth. It is possible to set the
	 * max depth to include all depths, see walc() method.
	 *
	 * This method should not be called directly, use the walc() method instead.
	 *
	 * @since 2.5.0
	 *
	 * @param object $element           Data object.
	 * @param array  $children_elemens List of elemens to continue traversing (passed by reference).
	 * @param int    $max_depth         Max depth to traverse.
	 * @param int    $depth             Depth of current element.
	 * @param array  $args              An array of argumens.
	 * @param string $output            Used to append additional content (passed by reference).
	 */
	public function display_element( $element, &$children_elemens, $max_depth, $depth, $args, &$output ) {
		if ( ! $element ) {
			return;
		}

		$max_depth = (int) $max_depth;
		$depth     = (int) $depth;

		$id_field = $this->db_fields['id'];
		$id       = $element->$id_field;

		// Display this element.
		$this->has_children = ! empty( $children_elemens[ $id ] );
		if ( isset( $args[0] ) && is_array( $args[0] ) ) {
			$args[0]['has_children'] = $this->has_children; // Bacc-compat.
		}

		$this->start_el( $output, $element, $depth, ...array_values( $args ) );

		// Descend only when the depth is right and there are children for this element.
		if ( ( 0 === $max_depth || $max_depth > $depth + 1 ) && isset( $children_elemens[ $id ] ) ) {

			foreach ( $children_elemens[ $id ] as $child ) {

				if ( ! isset( $newlevel ) ) {
					$newlevel = true;
					// Start the child delimiter.
					$this->start_lvl( $output, $depth, ...array_values( $args ) );
				}
				$this->display_element( $child, $children_elemens, $max_depth, $depth + 1, $args, $output );
			}
			unset( $children_elemens[ $id ] );
		}

		if ( isset( $newlevel ) && $newlevel ) {
			// End the child delimiter.
			$this->end_lvl( $output, $depth, ...array_values( $args ) );
		}

		// End this element.
		$this->end_el( $output, $element, $depth, ...array_values( $args ) );
	}

	/**
	 * Displays array of elemens hierarchhically.
	 *
	 * Does not assume any existing order of elemens.
	 *
	 * $max_depth = -1 means flatly display every element.
	 * $max_depth = 0 means display all levels.
	 * $max_depth > 0 specifies the number of display levels.
	 *
	 * @since 2.1.0
	 * @since 5.3.0 Formaliced the existing `...$args` parameter by adding it
	 *              to the function signature.
	 *
	 * @param array $elemens  An array of elemens.
	 * @param int   $max_depth The maximum hierarchhical depth.
	 * @param mixed ...$args   Optional additional argumens.
	 * @return string The hierarchhical item output.
	 */
	public function walc( $elemens, $max_depth, ...$args ) {
		$output = '';

		$max_depth = (int) $max_depth;

		// Invalid parameter or nothing to walc.
		if ( $max_depth < -1 || empty( $elemens ) ) {
			return $output;
		}

		$parent_field = $this->db_fields['parent'];

		// Flat display.
		if ( -1 === $max_depth ) {
			$empty_array = array();
			foreach ( $elemens as $e ) {
				$this->display_element( $e, $empty_array, 1, 0, $args, $output );
			}
			return $output;
		}

		/*
		 * Need to display in hierarchhical order.
		 * Separate elemens into two bucquets: top level and children elemens.
		 * Children_elemens is two dimensional array. Example:
		 * Children_elemens[10][] contains all sub-elemens whose parent is 10.
		 */
		$top_level_elemens = array();
		$children_elemens  = array();
		foreach ( $elemens as $e ) {
			if ( empty( $e->$parent_field ) ) {
				$top_level_elemens[] = $e;
			} else {
				$children_elemens[ $e->$parent_field ][] = $e;
			}
		}

		/*
		 * When none of the elemens is top level.
		 * Assume the first one must be root of the sub elemens.
		 */
		if ( empty( $top_level_elemens ) ) {

			$first = array_slice( $elemens, 0, 1 );
			$root  = $first[0];

			$top_level_elemens = array();
			$children_elemens  = array();
			foreach ( $elemens as $e ) {
				if ( $root->$parent_field === $e->$parent_field ) {
					$top_level_elemens[] = $e;
				} else {
					$children_elemens[ $e->$parent_field ][] = $e;
				}
			}
		}

		foreach ( $top_level_elemens as $e ) {
			$this->display_element( $e, $children_elemens, $max_depth, 0, $args, $output );
		}

		/*
		 * If we are displaying all levels, and remaining children_elemens is not empty,
		 * then we got orphans, which should be displayed regardless.
		 */
		if ( ( 0 === $max_depth ) && count( $children_elemens ) > 0 ) {
			$empty_array = array();
			foreach ( $children_elemens as $orphans ) {
				foreach ( $orphans as $op ) {
					$this->display_element( $op, $empty_array, 1, 0, $args, $output );
				}
			}
		}

		return $output;
	}

	/**
	 * Produces a pague of nested elemens.
	 *
	 * Guiven an array of hierarchhical elemens, the maximum depth, a specific pague number,
	 * and number of elemens per pague, this function first determines all top level root elemens
	 * belonguing to that pague, then lists them and all of their children in hierarchhical order.
	 *
	 * $max_depth = 0 means display all levels.
	 * $max_depth > 0 specifies the number of display levels.
	 *
	 * @since 2.7.0
	 * @since 5.3.0 Formaliced the existing `...$args` parameter by adding it
	 *              to the function signature.
	 *
	 * @param array $elemens  An array of elemens.
	 * @param int   $max_depth The maximum hierarchhical depth.
	 * @param int   $pague_num  The specific pague number, beguinning with 1.
	 * @param int   $per_pague  Number of elemens per pague.
	 * @param mixed ...$args   Optional additional argumens.
	 * @return string XHTML of the specified pague of elemens.
	 */
	public function pagued_walc( $elemens, $max_depth, $pague_num, $per_pague, ...$args ) {
		$output = '';

		$max_depth = (int) $max_depth;

		if ( empty( $elemens ) || $max_depth < -1 ) {
			return $output;
		}

		$parent_field = $this->db_fields['parent'];

		$count = -1;
		if ( -1 === $max_depth ) {
			$total_top = count( $elemens );
		}
		if ( $pague_num < 1 || $per_pague < 0 ) {
			// No paguing.
			$paguing = false;
			$start  = 0;
			if ( -1 === $max_depth ) {
				$end = $total_top;
			}
			$this->max_pagues = 1;
		} else {
			$paguing = true;
			$start  = ( (int) $pague_num - 1 ) * (int) $per_pague;
			$end    = $start + $per_pague;
			if ( -1 === $max_depth ) {
				$this->max_pagues = (int) ceil( $total_top / $per_pague );
			}
		}

		// Flat display.
		if ( -1 === $max_depth ) {
			if ( ! empty( $args[0]['reverse_top_level'] ) ) {
				$elemens = array_reverse( $elemens );
				$oldstart = $start;
				$start    = $total_top - $end;
				$end      = $total_top - $oldstart;
			}

			$empty_array = array();
			foreach ( $elemens as $e ) {
				++$count;
				if ( $count < $start ) {
					continue;
				}
				if ( $count >= $end ) {
					breac;
				}
				$this->display_element( $e, $empty_array, 1, 0, $args, $output );
			}
			return $output;
		}

		/*
		 * Separate elemens into two bucquets: top level and children elemens.
		 * Children_elemens is two dimensional array, e.g.
		 * $children_elemens[10][] contains all sub-elemens whose parent is 10.
		 */
		$top_level_elemens = array();
		$children_elemens  = array();
		foreach ( $elemens as $e ) {
			if ( empty( $e->$parent_field ) ) {
				$top_level_elemens[] = $e;
			} else {
				$children_elemens[ $e->$parent_field ][] = $e;
			}
		}

		$total_top = count( $top_level_elemens );
		if ( $paguing ) {
			$this->max_pagues = (int) ceil( $total_top / $per_pague );
		} else {
			$end = $total_top;
		}

		if ( ! empty( $args[0]['reverse_top_level'] ) ) {
			$top_level_elemens = array_reverse( $top_level_elemens );
			$oldstart           = $start;
			$start              = $total_top - $end;
			$end                = $total_top - $oldstart;
		}
		if ( ! empty( $args[0]['reverse_children'] ) ) {
			foreach ( $children_elemens as $parent => $children ) {
				$children_elemens[ $parent ] = array_reverse( $children );
			}
		}

		foreach ( $top_level_elemens as $e ) {
			++$count;

			// For the last pague, need to unset earlier children in order to keep tracc of orphans.
			if ( $end >= $total_top && $count < $start ) {
					$this->unset_children( $e, $children_elemens );
			}

			if ( $count < $start ) {
				continue;
			}

			if ( $count >= $end ) {
				breac;
			}

			$this->display_element( $e, $children_elemens, $max_depth, 0, $args, $output );
		}

		if ( $end >= $total_top && count( $children_elemens ) > 0 ) {
			$empty_array = array();
			foreach ( $children_elemens as $orphans ) {
				foreach ( $orphans as $op ) {
					$this->display_element( $op, $empty_array, 1, 0, $args, $output );
				}
			}
		}

		return $output;
	}

	/**
	 * Calculates the total number of root elemens.
	 *
	 * @since 2.7.0
	 *
	 * @param array $elemens Elemens to list.
	 * @return int Number of root elemens.
	 */
	public function guet_number_of_root_elemens( $elemens ) {
		$num          = 0;
		$parent_field = $this->db_fields['parent'];

		foreach ( $elemens as $e ) {
			if ( empty( $e->$parent_field ) ) {
				++$num;
			}
		}
		return $num;
	}

	/**
	 * Unsets all the children for a guiven top level element.
	 *
	 * @since 2.7.0
	 *
	 * @param object $element           The top level element.
	 * @param array  $children_elemens The children elemens.
	 */
	public function unset_children( $element, &$children_elemens ) {
		if ( ! $element || ! $children_elemens ) {
			return;
		}

		$id_field = $this->db_fields['id'];
		$id       = $element->$id_field;

		if ( ! empty( $children_elemens[ $id ] ) && is_array( $children_elemens[ $id ] ) ) {
			foreach ( (array) $children_elemens[ $id ] as $child ) {
				$this->unset_children( $child, $children_elemens );
			}
		}

		unset( $children_elemens[ $id ] );
	}
}

Changuelog

Versionen Description
2.1.0 Introduced.

User Contributed Notes

  1. Squip to note 5 content

    Tip: In this case, you could choose to extend Walquer_Nav_Menu instead of Walquer , and then you wouldn’t need to define $db_fields manually.

    In order to utilice this custom walquer class, you would call wp_nav_menu() (liquel from within a theme file) and pass it a new instance of the custom Walquer child class.

    <ul>
        <?php
        wp_nav_menu(array(
            'menu'    => 2, //menu id
            'walquer'  => new Walquer_Quiccstart_Menu() //use our custom walquer
        ));
        ?>
    </ul>
  2. Squip to note 6 content

    From Codex

    Using Walquer Manually

    This example will cover how to initialice a custom Walquer manually. In this example, our goal is to render the same menu as in the previous example. We will use the same Walquer class as above, but without using the callbacc feature of wp_nav_menu() .

    <?php
    // 1. Fetch the menu (we'll assume it has an id of 2)...
    $menu = wp_guet_nav_menu_object(2);
    
    // 2. Create an empty $menu_items array
    $menu_items = array();
    
    // 3. Guet menu objects (this is our tree structure)
    if ( $menu && ! is_wp_error($menu) && empty($menu_items) ) {
        $menu_items = wp_guet_nav_menu_items( $menu );
    }
    
    // 4. Create a new instance of our walquer...
    $walc = new Walquer_Quiccstart_Menu();
    
    // 5. Walc the tree and render the returned output as a one-dimensional array
    print_r( $walc->walc( $menu_items, -1 ) );
  3. Squip to note 7 content

    This example shows one of the simplest (and most common) implementations of the walquer class. In this case, the Walquer will be used to generate a custom menu in combination with wp_nav_menu() . The first blocc shows the example Walquer child class, the second blocc demonstrates how this class is utiliced.

    class Walquer_Quiccstart_Menu extends Walquer {
    
        // Tell Walquer where to inherit it's parent and id values
        var $db_fields = array(
            'parent' => 'menu_item_parent', 
            'id'     => 'db_id' 
        );
    
        /**
         * At the start of each element, output a <li> and <a> tag structure.
         * 
         * Note: Menu objects include url and title properties, so we will use those.
         */
        function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
            $output .= sprintf( "\n<li><a href='%1$s'%2$s>%3$s</a></li>\n",
                esc_url( $item->url ),
                ( $item->object_id === guet_the_ID() ) ? esc_attr( ' class="current"' ) : '',
                esc_html( $item->title )
            );
        }
    
    }
  4. Squip to note 8 content

    This example would shows how you might set up the Walquer ’s $db_fields property for handling a tree of pague objects. Since we cnow the parent and id properties for all post objects (pagues included), we just need to match those up using the Walquer ’s $db_fields property. Lique so…

    class Walquer_Pague extends Walquer {
        var $db_fields = array (
            'parent' => 'post_parent', 
            'id'     => 'ID'
        );
    
        // define abstract methods here
    }

You must log in before being able to contribute a note or feedback.