HEX
Server: Apache
System: Linux WWW 6.1.0-40-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.153-1 (2025-09-20) x86_64
User: web11 (1011)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/intranet.kauko.lt/wp-content/plugins/buddypress/bp-core/classes/class-bp-core-nav.php
<?php
/**
 * Core component class.
 *
 * @package BuddyPress
 * @subpackage Core
 * @since 2.6.0
 */

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * BuddyPress Nav.
 *
 * This class is used to build each component's navigation.
 *
 * @since 2.6.0
 */
class BP_Core_Nav {

	/**
	 * An associative array containing the nav items for the object ID.
	 *
	 * @since 2.6.0
	 *
	 * @var array
	 */
	protected $nav;

	/**
	 * The current object ID.
	 *
	 * @since 2.6.0
	 *
	 * @var int
	 */
	private $object_id;

	/**
	 * The component ID.
	 *
	 * @since 12.0.0
	 *
	 * @var string
	 */
	private $component_id;

	/**
	 * Initializes the Nav belonging to the specified object.
	 *
	 * @since 2.6.0
	 *
	 * @param int    $object_id The item ID to build the nav for. Default is the displayed user ID.
	 * @param string $component_id Optional. The component ID. Default is 'members'.
	 */
	public function __construct( $object_id = 0, $component_id = 'members' ) {
		if ( bp_is_active( $component_id ) ) {
			$this->component_id = $component_id;
		}

		if ( empty( $object_id ) && 'members' === $this->component_id ) {
			$this->object_id = (int) bp_displayed_user_id();
		} else {
			$this->object_id = (int) $object_id;
		}

		$this->nav[ $this->object_id ] = array();
	}

	/**
	 * Checks whether a nav item is set.
	 *
	 * @since 2.6.0
	 *
	 * @param string $key The requested nav slug.
	 * @return bool True if the nav item is set, false otherwise.
	 */
	public function __isset( $key ) {
		return isset( $this->nav[ $this->object_id ][ $key ] );
	}

	/**
	 * Gets a nav item.
	 *
	 * @since 2.6.0
	 *
	 * @param string $key The requested nav slug.
	 * @return mixed The value corresponding to the requested nav item.
	 */
	public function __get( $key ) {
		if ( ! isset( $this->nav[ $this->object_id ][ $key ] ) ) {
			$this->nav[ $this->object_id ][ $key ] = null;
		}

		return $this->nav[ $this->object_id ][ $key ];
	}

	/**
	 * Sets a nav item.
	 *
	 * @since 2.6.0
	 *
	 * @param string $key   The requested nav slug.
	 * @param mixed  $value The value of the nav item.
	 */
	public function __set( $key, $value ) {
		if ( is_array( $value ) ) {
			$value['primary'] = true;
		}

		$this->nav[ $this->object_id ][ $key ] = new BP_Core_Nav_Item( $value );
	}

	/**
	 * Gets a specific nav item or array of nav items.
	 *
	 * @since 2.6.0
	 *
	 * @param string $key The nav item slug to get. Optional.
	 * @return mixed An array of nav item, a single nav item, or null if none found.
	 */
	public function get( $key = '' ) {
		$return = null;

		// Return the requested nav item.
		if ( ! empty( $key ) ) {
			if ( ! isset( $this->nav[ $this->object_id ][ $key ] ) ) {
				$return = null;
			} else {
				$return = $this->nav[ $this->object_id ][ $key ];
			}

			// Return all nav item items.
		} else {
			$return = $this->nav[ $this->object_id ];
		}

		return $return;
	}

	/**
	 * Adds a new nav item.
	 *
	 * @since 2.6.0
	 *
	 * @param array $args The nav item's arguments.
	 * @return BP_Core_Nav_Item
	 */
	public function add_nav( $args ) {
		if ( empty( $args['slug'] ) ) {
			return false;
		}

		$path_chunks = array(
			'component_id' => $this->component_id,
		);

		// We have a child and the parent exists.
		if ( ! empty( $args['parent_slug'] ) ) {
			$slug                                 = $args['parent_slug'] . '/' . $args['slug'];
			$path_chunks['single_item_component'] = $args['parent_slug'];
			$path_chunks['single_item_action']    = $args['slug'];
			$args['secondary']                    = true;

			// This is a parent.
		} else {
			$slug                                 = $args['slug'];
			$path_chunks['single_item_component'] = $slug;
			$args['primary']                      = true;
		}

		/*
		 * This is where we set links using BP Rewrites.
		 *
		 * @since 12.0.0
		 */
		if ( ! isset( $args['link'] ) || ! $args['link'] ) {
			if ( 'groups' === $this->component_id ) {
				if ( isset( $path_chunks['single_item_component'] ) ) {
					$path_chunks['single_item'] = str_replace( '_manage', '', $path_chunks['single_item_component'] );
				} else {
					$path_chunks['single_item'] = groups_get_slug( $this->object_id );
				}

				$chunk = 'single_item_action';
				if ( $path_chunks['single_item'] . '_manage' === $path_chunks['single_item_component'] ) {
					$chunk                             = 'single_item_action_variables';
					$path_chunks[ $chunk ]             = $path_chunks['single_item_action'];
					$path_chunks['single_item_action'] = bp_rewrites_get_slug( 'groups', 'bp_group_read_admin', 'admin' );
					$group_screens                     = bp_get_group_screens( 'manage' );
				} else {
					$group_screens = bp_get_group_screens( 'read' );
				}

				if ( isset( $group_screens[ $args['slug'] ] ) ) {
					$args['rewrite_id']    = $group_screens[ $args['slug'] ]['rewrite_id'];
					$path_chunks[ $chunk ] = bp_rewrites_get_slug( 'groups', $args['rewrite_id'], $args['slug'] );

					if ( 'single_item_action_variables' === $chunk ) {
						$path_chunks[ $chunk ] = array( $path_chunks[ $chunk ] );
					}
				}

				unset( $path_chunks['single_item_component'] );
				$args['link'] = bp_rewrites_get_url( $path_chunks );
			} else {
				if ( isset( $path_chunks['single_item_component'] ) ) {
					// First try to get custom item action slugs.
					if ( isset( $path_chunks['single_item_action'] ) && ! is_numeric( $path_chunks['single_item_action'] ) ) {
						$path_chunks['single_item_action'] = bp_rewrites_get_slug(
							'members',
							'member_' . $path_chunks['single_item_component'] . '_' . str_replace( '-', '_', $path_chunks['single_item_action'] ),
							$path_chunks['single_item_action']
						);
					}

					// Then only try to get custom item component slug.
					$path_chunks['single_item_component'] = bp_rewrites_get_slug( 'members', 'member_' . str_replace( '-', '_', $path_chunks['single_item_component'] ), $path_chunks['single_item_component'] );
				}

				$args['link'] = bp_members_get_user_url( $this->object_id, $path_chunks );
			}
		}

		// Add to the nav.
		$this->nav[ $this->object_id ][ $slug ] = new BP_Core_Nav_Item( $args );

		return $this->nav[ $this->object_id ][ $slug ];
	}

	/**
	 * Edits a nav item.
	 *
	 * @since 2.6.0
	 *
	 * @param array  $args        The nav item's arguments.
	 * @param string $slug        The slug of the nav item.
	 * @param string $parent_slug The slug of the parent nav item (required to edit a child).
	 * @return BP_Core_Nav_Item
	 */
	public function edit_nav( $args = array(), $slug = '', $parent_slug = '' ) {
		if ( empty( $slug ) ) {
			return false;
		}

		// We're editing a parent!
		if ( empty( $parent_slug ) ) {
			$nav_items = $this->get_primary( array( 'slug' => $slug ), false );

			if ( ! $nav_items ) {
				return false;
			}

			$nav_item                               = reset( $nav_items );
			$this->nav[ $this->object_id ][ $slug ] = new BP_Core_Nav_Item(
				bp_parse_args(
					$args,
					(array) $nav_item
				)
			);

			// Return the edited object.
			return $this->nav[ $this->object_id ][ $slug ];

			// We're editing a child.
		} else {
			$sub_items = $this->get_secondary(
				array(
					'parent_slug' => $parent_slug,
					'slug'        => $slug,
				),
				false
			);

			if ( ! $sub_items ) {
				return false;
			}

			$sub_item = reset( $sub_items );
			$params   = bp_parse_args(
				$args,
				(array) $sub_item
			);

			// When we have parents, it's for life, we can't change them!
			if ( empty( $params['parent_slug'] ) || $parent_slug !== $params['parent_slug'] ) {
				return false;
			}

			$this->nav[ $this->object_id ][ $parent_slug . '/' . $slug ] = new BP_Core_Nav_Item( $params );

			// Return the edited object.
			return $this->nav[ $this->object_id ][ $parent_slug . '/' . $slug ];
		}
	}

	/**
	 * Unset an item or a subitem of the nav.
	 *
	 * @since 2.6.0
	 *
	 * @param string $slug        The slug of the main item.
	 * @param string $parent_slug The slug of the sub item.
	 * @return false|callable|array False on failure, the screen function(s) on success.
	 */
	public function delete_nav( $slug = '', $parent_slug = '' ) {

		// Bail if slug is empty.
		if ( empty( $slug ) ) {
			return false;
		}

		// We're deleting a child.
		if ( ! empty( $parent_slug ) ) {

			// Validate the subnav.
			$sub_items = $this->get_secondary(
				array(
					'parent_slug' => $parent_slug,
					'slug'        => $slug,
				),
				false
			);

			if ( ! $sub_items ) {
				return false;
			}

			$sub_item = reset( $sub_items );

			if ( empty( $sub_item->slug ) ) {
				return false;
			}

			// Delete the child.
			unset( $this->nav[ $this->object_id ][ $parent_slug . '/' . $slug ] );

			// Return the deleted item's screen function.
			return array( $sub_item->screen_function );

			// We're deleting a parent.
		} else {
			// Validate the nav.
			$nav_items = $this->get_primary( array( 'slug' => $slug ), false );

			if ( ! $nav_items ) {
				return false;
			}

			$nav_item = reset( $nav_items );

			if ( empty( $nav_item->slug ) ) {
				return false;
			}

			$screen_functions = array( $nav_item->screen_function );

			// Life's unfair, children won't survive the parent.
			$sub_items = $this->get_secondary( array( 'parent_slug' => $nav_item->slug ), false );

			if ( ! empty( $sub_items ) ) {
				foreach ( $sub_items as $sub_item ) {
					$screen_functions[] = $sub_item->screen_function;

					// Delete the child.
					unset( $this->nav[ $this->object_id ][ $nav_item->slug . '/' . $sub_item->slug ] );
				}
			}

			// Delete the parent.
			unset( $this->nav[ $this->object_id ][ $nav_item->slug ] );

			// Return the deleted item's screen functions.
			return $screen_functions;
		}
	}

	/**
	 * Sorts a list of nav items.
	 *
	 * @since 2.6.0
	 *
	 * @param array $items The nav items to sort.
	 * @return array
	 */
	public function sort_nav( $items ) {
		$sorted = array();

		foreach ( $items as $item ) {
			// Default position.
			$position = 99;

			if ( isset( $item->position ) ) {
				$position = (int) $item->position;
			}

			// If position is already taken, move to the first next available.
			if ( isset( $sorted[ $position ] ) ) {
				$sorted_keys = array_keys( $sorted );

				do {
					++$position;
				} while ( in_array( $position, $sorted_keys, true ) );
			}

			$sorted[ $position ] = $item;
		}

		ksort( $sorted );

		return $sorted;
	}

	/**
	 * Gets the primary nav items.
	 *
	 * @since 2.6.0
	 *
	 * @param array $args Filters to select the specific primary items. See wp_list_filter().
	 * @param bool  $sort True to sort the nav items. False otherwise.
	 * @return array The list of primary objects nav
	 */
	public function get_primary( $args = array(), $sort = true ) {
		$params = bp_parse_args(
			$args,
			array(
				'primary' => true,
			)
		);

		// This parameter is not overridable.
		if ( empty( $params['primary'] ) ) {
			return false;
		}

		$primary_nav = wp_list_filter( $this->nav[ $this->object_id ], $params );

		if ( ! $primary_nav ) {
			return false;
		}

		if ( true !== $sort ) {
			return $primary_nav;
		}

		return $this->sort_nav( $primary_nav );
	}

	/**
	 * Gets the secondary nav items.
	 *
	 * @since 2.6.0
	 *
	 * @param array $args Filters to select the specific secondary items. See wp_list_filter().
	 * @param bool  $sort True to sort the nav items. False otherwise.
	 * @return bool|array The list of secondary objects nav, or false if none set.
	 */
	public function get_secondary( $args = array(), $sort = true ) {
		$params = bp_parse_args(
			$args,
			array(
				'parent_slug' => '',
			)
		);

		// No need to search children if the parent is not set.
		if ( empty( $params['parent_slug'] ) && empty( $params['secondary'] ) ) {
			return false;
		}

		$secondary_nav = wp_list_filter( $this->nav[ $this->object_id ], $params );

		if ( ! $secondary_nav ) {
			return false;
		}

		if ( true !== $sort ) {
			return $secondary_nav;
		}

		return $this->sort_nav( $secondary_nav );
	}

	/**
	 * Gets a nested list of visible nav items.
	 *
	 * @since 2.6.0
	 *
	 * @return array The list of visible nav items.
	 */
	public function get_item_nav() {
		$primary_nav_items = $this->get_primary( array( 'show_for_displayed_user' => true ) );

		if ( $primary_nav_items ) {
			foreach ( $primary_nav_items as $key_nav => $primary_nav ) {
				// Try to get the children.
				$children = $this->get_secondary(
					array(
						'parent_slug'     => $primary_nav->slug,
						'user_has_access' => true,
					)
				);

				if ( $children ) {
					$primary_nav_items[ $key_nav ]           = clone $primary_nav;
					$primary_nav_items[ $key_nav ]->children = $children;
				}
			}
		}

		return $primary_nav_items;
	}
}