diff --git src/bp-core/bp-core-buddybar.php src/bp-core/bp-core-buddybar.php
index 9f1ffb0..e0a8ae4 100644
--- src/bp-core/bp-core-buddybar.php
+++ src/bp-core/bp-core-buddybar.php
@@ -13,9 +13,9 @@
defined( 'ABSPATH' ) || exit;
/**
- * Add an item to the main BuddyPress navigation array.
+ * Add an item to the primary navigation of the specified component.
*
- * @since 1.1.0
+ * @since 2.6.0
*
* @param array|string $args {
* Array describing the new nav item.
@@ -32,9 +32,14 @@ defined( 'ABSPATH' ) || exit;
* @type bool|string $default_subnav_slug Optional. The slug of the default subnav item to select when the nav
* item is clicked.
* }
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
* @return bool|null Returns false on failure.
*/
-function bp_core_new_nav_item( $args = '' ) {
+
+function bp_core_add_nav_item( $args, $component = 'members' ) {
+ if ( ! bp_is_active( $component ) ) {
+ return;
+ }
$defaults = array(
'name' => false, // Display name for the nav item.
@@ -49,22 +54,36 @@ function bp_core_new_nav_item( $args = '' ) {
$r = wp_parse_args( $args, $defaults );
- // First, add the nav item link to the bp_nav array.
- $created = bp_core_create_nav_link( $r );
+ // First, add the nav item link to the primary nav for the component.
+ $nav_item = bp_core_create_nav_link( $r );
+
+ /**
+ * Fires after a link is added to the main BuddyPress navigation array.
+ *
+ * @since 2.4.0
+ *
+ * @param array $r Parsed arguments for the nav item.
+ * @param array $args Originally passed in arguments for the nav item.
+ * @param array $defaults Default arguments for a nav item.
+ */
+ do_action( 'bp_core_create_nav_link', $r, $args, $defaults );
// To mimic the existing behavior, if bp_core_create_nav_link()
// returns false, we make an early exit and don't attempt to register
// the screen function.
- if ( false === $created ) {
+ if ( false === $nav_item ) {
return false;
}
// Then, hook the screen function for the added nav item.
- $hooked = bp_core_register_nav_screen_function( $r );
+ $hooked = bp_core_register_nav_screen_function( $nav_item );
if ( false === $hooked ){
return false;
}
+ // Add the item to the nav
+ buddypress()->{$component}->nav->add_nav( $nav_item );
+
/**
* Fires after adding an item to the main BuddyPress navigation array.
* Note that, when possible, the more specific action hooks
@@ -132,7 +151,7 @@ function bp_core_create_nav_link( $args = '' ) {
$r['item_css_id'] = $r['slug'];
}
- $bp->bp_nav[$r['slug']] = array(
+ return array(
'name' => $r['name'],
'slug' => $r['slug'],
'link' => trailingslashit( bp_loggedin_user_domain() . $r['slug'] ),
@@ -142,17 +161,6 @@ function bp_core_create_nav_link( $args = '' ) {
'screen_function' => &$r['screen_function'],
'default_subnav_slug' => $r['default_subnav_slug']
);
-
- /**
- * Fires after a link is added to the main BuddyPress navigation array.
- *
- * @since 2.4.0
- *
- * @param array $r Parsed arguments for the nav item.
- * @param array $args Originally passed in arguments for the nav item.
- * @param array $defaults Default arguments for a nav item.
- */
- do_action( 'bp_core_create_nav_link', $r, $args, $defaults );
}
/**
@@ -290,20 +298,33 @@ function bp_core_new_nav_default( $args = '' ) {
$r = wp_parse_args( $args, $defaults );
- if ( $function = $bp->bp_nav[$r['parent_slug']]['screen_function'] ) {
+ // This is specific to Members, it's not available in Groups.
+ $parent_nav = $bp->members->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false );
+
+ if ( ! $parent_nav ) {
+ return ;
+ }
+
+ $parent_nav = reset( $parent_nav );
+
+ if ( ! empty( $parent_nav->screen_function ) ) {
// Remove our screen hook if screen function is callable.
- if ( is_callable( $function ) ) {
- remove_action( 'bp_screens', $function, 3 );
+ if ( is_callable( $parent_nav->screen_function ) ) {
+ remove_action( 'bp_screens', $parent_nav->screen_function, 3 );
}
}
- $bp->bp_nav[$r['parent_slug']]['screen_function'] = &$r['screen_function'];
+ // Edit the screen function for the parent nav
+ $bp->members->nav->edit_nav( array(
+ 'screen_function' => &$r['screen_function'],
+ 'default_subnav_slug' => $r['subnav_slug'],
+ ), $parent_nav->slug );
- if ( bp_is_current_component( $r['parent_slug'] ) ) {
+ if ( bp_is_current_component( $parent_nav->slug ) ) {
// The only way to tell whether to set the subnav is to peek at the unfiltered_uri
// Find the component.
- $component_uri_key = array_search( $r['parent_slug'], $bp->unfiltered_uri );
+ $component_uri_key = array_search( $parent_nav->slug, $bp->unfiltered_uri );
if ( false !== $component_uri_key ) {
if ( ! empty( $bp->unfiltered_uri[$component_uri_key + 1] ) ) {
@@ -339,47 +360,9 @@ function bp_core_new_nav_default( $args = '' ) {
}
/**
- * Sort the navigation menu items.
- *
- * The sorting is split into a separate function because it can only happen
- * after all plugins have had a chance to register their navigation items.
- *
- * @since 1.0.0
- *
- * @return bool|null Returns false on failure.
- */
-function bp_core_sort_nav_items() {
- $bp = buddypress();
-
- if ( empty( $bp->bp_nav ) || ! is_array( $bp->bp_nav ) ) {
- return false;
- }
-
- $temp = array();
-
- foreach ( (array) $bp->bp_nav as $slug => $nav_item ) {
- if ( empty( $temp[$nav_item['position']] ) ) {
- $temp[$nav_item['position']] = $nav_item;
- } else {
- // Increase numbers here to fit new items in.
- do {
- $nav_item['position']++;
- } while ( ! empty( $temp[$nav_item['position']] ) );
-
- $temp[$nav_item['position']] = $nav_item;
- }
- }
-
- ksort( $temp );
- $bp->bp_nav = &$temp;
-}
-add_action( 'wp_head', 'bp_core_sort_nav_items' );
-add_action( 'admin_head', 'bp_core_sort_nav_items' );
-
-/**
- * Add a subnav item to the BuddyPress navigation.
+ * Add an item to secondary navigation of the specified component.
*
- * @since 1.1.0
+ * @since 2.6.0
*
* @param array|string $args {
* Array describing the new subnav item.
@@ -403,22 +386,26 @@ add_action( 'admin_head', 'bp_core_sort_nav_items' );
* @type bool $show_in_admin_bar Optional. Whether the nav item should be added into the group's "Edit"
* Admin Bar menu for group admins. Default: false.
* }
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
* @return bool|null Returns false on failure.
*/
-function bp_core_new_subnav_item( $args = '' ) {
+function bp_core_add_subnav_item( $args, $component = 'members' ) {
+ if ( ! bp_is_active( $component ) ) {
+ return;
+ }
// First, add the subnav item link to the bp_options_nav array.
- $created = bp_core_create_subnav_link( $args );
+ $subnav_item = bp_core_create_subnav_link( $args, $component );
// To mimic the existing behavior, if bp_core_create_subnav_link()
// returns false, we make an early exit and don't attempt to register
// the screen function.
- if ( false === $created ) {
+ if ( false === $subnav_item ) {
return false;
}
// Then, hook the screen function for the added subnav item.
- $hooked = bp_core_register_subnav_screen_function( $args );
+ $hooked = bp_core_register_subnav_screen_function( $subnav_item, $component );
if ( false === $hooked ) {
return false;
}
@@ -428,6 +415,7 @@ function bp_core_new_subnav_item( $args = '' ) {
* Add a subnav link to the BuddyPress navigation.
*
* @since 2.4.0
+ * @since 2.6.0 Adds the $component parameter.
*
* @param array|string $args {
* Array describing the new subnav item.
@@ -455,9 +443,10 @@ function bp_core_new_subnav_item( $args = '' ) {
* the group's "Edit" Admin Bar menu for group admins.
* Default: false.
* }
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
* @return bool|null Returns false on failure.
*/
-function bp_core_create_subnav_link( $args = '' ) {
+function bp_core_create_subnav_link( $args = '', $component = 'members' ) {
$bp = buddypress();
$r = wp_parse_args( $args, array(
@@ -483,8 +472,10 @@ function bp_core_create_subnav_link( $args = '' ) {
if ( empty( $r['link'] ) ) {
$r['link'] = trailingslashit( $r['parent_url'] . $r['slug'] );
+ $parent_nav = $bp->{$component}->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false );
+
// If this sub item is the default for its parent, skip the slug.
- if ( ! empty( $bp->bp_nav[$r['parent_slug']]['default_subnav_slug'] ) && $r['slug'] == $bp->bp_nav[$r['parent_slug']]['default_subnav_slug'] ) {
+ if ( ! empty( $parent_nav->default_subnav_slug ) && $r['slug'] === $parent_nav->default_subnav_slug ) {
$r['link'] = trailingslashit( $r['parent_url'] );
}
}
@@ -502,6 +493,7 @@ function bp_core_create_subnav_link( $args = '' ) {
'name' => $r['name'],
'link' => $r['link'],
'slug' => $r['slug'],
+ 'parent_slug' => $r['parent_slug'],
'css_id' => $r['item_css_id'],
'position' => $r['position'],
'user_has_access' => $r['user_has_access'],
@@ -510,13 +502,16 @@ function bp_core_create_subnav_link( $args = '' ) {
'show_in_admin_bar' => (bool) $r['show_in_admin_bar'],
);
- $bp->bp_options_nav[$r['parent_slug']][$r['slug']] = $subnav_item;
+ buddypress()->{$component}->nav->add_nav( $subnav_item );
+
+ return $subnav_item;
}
/**
* Register a screen function, whether or not a related subnav link exists.
*
* @since 2.4.0
+ * @since 2.6.0 Adds the $component parameter.
*
* @param array|string $args {
* Array describing the new subnav item.
@@ -541,9 +536,10 @@ function bp_core_create_subnav_link( $args = '' ) {
* the group's "Edit" Admin Bar menu for group admins.
* Default: false.
* }
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
* @return bool|null Returns false on failure.
*/
-function bp_core_register_subnav_screen_function( $args = '' ) {
+function bp_core_register_subnav_screen_function( $args = '', $component = 'members' ) {
$bp = buddypress();
$r = wp_parse_args( $args, array(
@@ -568,7 +564,7 @@ function bp_core_register_subnav_screen_function( $args = '' ) {
* (b) there is no current_action (ie, this is the default subnav for the parent nav)
* and this subnav item is the default for the parent item (which we check by
* comparing this subnav item's screen function with the screen function of the
- * parent nav item in $bp->bp_nav). This condition only arises when viewing a
+ * parent nav item in the component's primary nav). This condition only arises when viewing a
* user, since groups should always have an action set.
*/
@@ -577,15 +573,17 @@ function bp_core_register_subnav_screen_function( $args = '' ) {
return;
}
+ $parent_nav = $bp->{$component}->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false );
+
// If we *do* meet condition (2), then the added subnav item is currently being requested.
- if ( ( bp_current_action() && bp_is_current_action( $r['slug'] ) ) || ( bp_is_user() && ! bp_current_action() && ( $r['screen_function'] == $bp->bp_nav[$r['parent_slug']]['screen_function'] ) ) ) {
+ if ( ( bp_current_action() && bp_is_current_action( $r['slug'] ) ) || ( bp_is_user() && ! bp_current_action() && ( $r['screen_function'] == $parent_nav->screen_function ) ) ) {
// If this is for site admins only and the user is not one, don't create the subnav item.
if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) {
return false;
}
- $hooked = bp_core_maybe_hook_new_subnav_screen_function( $r );
+ $hooked = bp_core_maybe_hook_new_subnav_screen_function( $r, $component );
// If redirect args have been returned, perform the redirect now.
if ( ! empty( $hooked['status'] ) && 'failure' === $hooked['status'] && isset( $hooked['redirect_args'] ) ) {
@@ -598,11 +596,13 @@ function bp_core_register_subnav_screen_function( $args = '' ) {
* For a given subnav item, either hook the screen function or generate redirect arguments, as necessary.
*
* @since 2.1.0
+ * @since 2.6.0 Adds the $component parameter.
*
- * @param array $subnav_item The subnav array added to bp_options_nav in `bp_core_new_subnav_item()`.
+ * @param array $subnav_item The subnav array added to the secondary navigation of the component in `bp_core_add_subnav_item()`.
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
* @return array
*/
-function bp_core_maybe_hook_new_subnav_screen_function( $subnav_item ) {
+function bp_core_maybe_hook_new_subnav_screen_function( $subnav_item, $component = 'members' ) {
$retval = array(
'status' => '',
);
@@ -645,10 +645,12 @@ function bp_core_maybe_hook_new_subnav_screen_function( $subnav_item ) {
// redirect URL.
} elseif ( bp_is_user() ) {
+ $parent_nav_default = $bp->{$component}->nav->get_primary( array( 'slug' => $bp->default_component ), false );
+
// Redirect to the displayed user's default
// component, as long as that component is
// publicly accessible.
- if ( bp_is_my_profile() || ! empty( $bp->bp_nav[ $bp->default_component ]['show_for_displayed_user'] ) ) {
+ if ( bp_is_my_profile() || ! empty( $parent_nav_default->show_for_displayed_user ) ) {
$message = __( 'You do not have access to this page.', 'buddypress' );
$redirect_to = bp_displayed_user_domain();
@@ -691,58 +693,32 @@ function bp_core_maybe_hook_new_subnav_screen_function( $subnav_item ) {
}
/**
- * Sort all subnavigation arrays.
+ * Check whether a given nav item has subnav items.
*
- * @since 1.1.0
+ * @since 1.5.0
+ * @since 2.6.0 Adds the $component parameter.
*
- * @return bool|null Returns false on failure.
+ * @param string $nav_item The slug of the top-level nav item whose subnav items you're checking.
+ * Default: the current component slug.
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
+ * @return bool $has_subnav True if the nav item is found and has subnav items; false otherwise.
*/
-function bp_core_sort_subnav_items() {
+function bp_nav_item_has_subnav( $nav_item = '', $component = 'members' ) {
$bp = buddypress();
- if ( empty( $bp->bp_options_nav ) || !is_array( $bp->bp_options_nav ) )
+ if ( ! isset( $bp->{$component}->nav ) ) {
return false;
+ }
- foreach ( (array) $bp->bp_options_nav as $parent_slug => $subnav_items ) {
- if ( !is_array( $subnav_items ) )
- continue;
-
- foreach ( (array) $subnav_items as $subnav_item ) {
- if ( empty( $temp[$subnav_item['position']]) )
- $temp[$subnav_item['position']] = $subnav_item;
- else {
- // Increase numbers here to fit new items in.
- do {
- $subnav_item['position']++;
- } while ( !empty( $temp[$subnav_item['position']] ) );
+ if ( ! $nav_item ) {
+ $nav_item = bp_current_component();
- $temp[$subnav_item['position']] = $subnav_item;
- }
+ if ( bp_is_group() ) {
+ $nav_item = bp_current_item();
}
- ksort( $temp );
- $bp->bp_options_nav[$parent_slug] = &$temp;
- unset( $temp );
}
-}
-add_action( 'wp_head', 'bp_core_sort_subnav_items' );
-add_action( 'admin_head', 'bp_core_sort_subnav_items' );
-
-/**
- * Check whether a given nav item has subnav items.
- *
- * @since 1.5.0
- *
- * @param string $nav_item The slug of the top-level nav item whose subnav items you're checking.
- * Default: the current component slug.
- * @return bool $has_subnav True if the nav item is found and has subnav items; false otherwise.
- */
-function bp_nav_item_has_subnav( $nav_item = '' ) {
- $bp = buddypress();
-
- if ( !$nav_item )
- $nav_item = bp_current_component();
- $has_subnav = isset( $bp->bp_options_nav[$nav_item] ) && count( $bp->bp_options_nav[$nav_item] ) > 0;
+ $has_subnav = (bool) $bp->{$component}->nav->get_secondary( array( 'parent_slug' => $nav_item ), false );
/**
* Filters whether or not a given nav item has subnav items.
@@ -756,75 +732,95 @@ function bp_nav_item_has_subnav( $nav_item = '' ) {
}
/**
- * Remove a nav item from the navigation array.
+ * Deletes an item from the primary navigation of the specified component.
*
- * @since 1.0.0
+ * @since 2.6.0
*
- * @param int $parent_id The slug of the parent navigation item.
- * @return bool Returns false on failure, ie if the nav item can't be found.
+ * @param string $slug The slug of the primary navigation item.
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
+ * @return bool Returns false on failure, True on success.
*/
-function bp_core_remove_nav_item( $parent_id ) {
+function bp_core_delete_nav_item( $slug, $component = 'members' ) {
$bp = buddypress();
- // Unset subnav items for this nav item.
- if ( isset( $bp->bp_options_nav[$parent_id] ) && is_array( $bp->bp_options_nav[$parent_id] ) ) {
- foreach( (array) $bp->bp_options_nav[$parent_id] as $subnav_item ) {
- bp_core_remove_subnav_item( $parent_id, $subnav_item['slug'] );
- }
+ if ( ! isset( $bp->{$component}->nav ) ) {
+ return false;
}
- if ( empty( $bp->bp_nav[ $parent_id ] ) )
+ $screen_functions = $bp->{$component}->nav->delete_nav( $slug );
+
+ if ( ! is_array( $screen_functions ) ) {
return false;
+ }
- if ( $function = $bp->bp_nav[$parent_id]['screen_function'] ) {
+ foreach ( $screen_functions as $screen_function ) {
// Remove our screen hook if screen function is callable.
- if ( is_callable( $function ) ) {
- remove_action( 'bp_screens', $function, 3 );
+ if ( is_callable( $screen_function ) ) {
+ remove_action( 'bp_screens', $screen_function, 3 );
}
}
- unset( $bp->bp_nav[$parent_id] );
+ return true;
}
/**
- * Remove a subnav item from the navigation array.
+ * Deletes an item from the secondary navigation of the specified component.
*
- * @since 1.0.0
+ * @since 2.6.0
*
- * @param string $parent_id The slug of the parent navigation item.
- * @param string $slug The slug of the subnav item to be removed.
+ * @param string $slug The slug of the secondary item to be removed.
+ * @param string $parent_slug The slug of the primary navigation item.
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
+ * @return bool Returns false on failure, True on success.
*/
-function bp_core_remove_subnav_item( $parent_id, $slug ) {
+function bp_core_delete_subnav_item( $slug, $parent_slug, $component = 'members' ) {
$bp = buddypress();
- $screen_function = isset( $bp->bp_options_nav[$parent_id][$slug]['screen_function'] )
- ? $bp->bp_options_nav[$parent_id][$slug]['screen_function']
- : false;
+ if ( ! isset( $bp->{$component}->nav ) ) {
+ return false;
+ }
- if ( ! empty( $screen_function ) ) {
- // Remove our screen hook if screen function is callable.
- if ( is_callable( $screen_function ) ) {
- remove_action( 'bp_screens', $screen_function, 3 );
- }
+ $screen_functions = $bp->{$component}->nav->delete_nav( $slug, $parent_slug );
+
+ if ( ! is_array( $screen_functions ) ) {
+ return false;
}
- unset( $bp->bp_options_nav[$parent_id][$slug] );
+ $screen_function = reset( $screen_functions );
- if ( isset( $bp->bp_options_nav[$parent_id] ) && !count( $bp->bp_options_nav[$parent_id] ) )
- unset($bp->bp_options_nav[$parent_id]);
+ // Remove our screen hook if screen function is callable.
+ if ( is_callable( $screen_function ) ) {
+ remove_action( 'bp_screens', $screen_function, 3 );
+ }
+
+ return true;
}
/**
* Clear all subnav items from a specific nav item.
*
* @since 1.0.0
+ * @since 2.6.0 Adds the $component parameter.
*
* @param string $parent_slug The slug of the parent navigation item.
+ * @param string $component The component the navigation is attached to. Defaults to 'members'.
*/
-function bp_core_reset_subnav_items( $parent_slug ) {
+function bp_core_reset_subnav_items( $parent_slug, $component = 'members' ) {
$bp = buddypress();
- unset( $bp->bp_options_nav[$parent_slug] );
+ if ( ! isset( $bp->{$component}->nav ) ) {
+ return;
+ }
+
+ $subnav_items = $bp->{$component}->nav->get_secondary( array( 'parent_slug' => $parent_slug ), false );
+
+ if ( ! $subnav_items ) {
+ return;
+ }
+
+ foreach( $subnav_items as $subnav_item ) {
+ $bp->{$component}->nav->delete_nav( $subnav_item->slug, $parent_slug );
+ }
}
diff --git src/bp-core/bp-core-catchuri.php src/bp-core/bp-core-catchuri.php
index e78f67b..6b35960 100644
--- src/bp-core/bp-core-catchuri.php
+++ src/bp-core/bp-core-catchuri.php
@@ -684,7 +684,7 @@ add_action( 'login_form_bpnoaccess', 'bp_core_no_access_wp_login_error' );
*
* @see BP_Members_Component::setup_globals() where
* $bp->canonical_stack['base_url'] and ['component'] may be set.
- * @see bp_core_new_nav_item() where $bp->canonical_stack['action'] may be set.
+ * @see bp_core_add_nav_item() where $bp->canonical_stack['action'] may be set.
* @uses bp_get_canonical_url()
* @uses bp_get_requested_url()
*/
diff --git src/bp-core/bp-core-classes.php src/bp-core/bp-core-classes.php
index bebf4ed..bb886d0 100644
--- src/bp-core/bp-core-classes.php
+++ src/bp-core/bp-core-classes.php
@@ -30,3 +30,5 @@ require dirname( __FILE__ ) . '/classes/class-bp-email-recipient.php';
require dirname( __FILE__ ) . '/classes/class-bp-email.php';
require dirname( __FILE__ ) . '/classes/class-bp-email-delivery.php';
require dirname( __FILE__ ) . '/classes/class-bp-phpmailer.php';
+require dirname( __FILE__ ) . '/classes/class-bp-core-nav.php';
+require dirname( __FILE__ ) . '/classes/class-bp-core-backcompat-nav.php';
diff --git src/bp-core/bp-core-functions.php src/bp-core/bp-core-functions.php
index 702d0dd..ea81687 100644
--- src/bp-core/bp-core-functions.php
+++ src/bp-core/bp-core-functions.php
@@ -2443,15 +2443,12 @@ function bp_nav_menu_get_loggedin_pages() {
return buddypress()->wp_nav_menu_items->loggedin;
}
- // Pull up a list of items registered in BP's top-level nav array.
- $bp_menu_items = buddypress()->bp_nav;
-
- // Alphabetize.
- $bp_menu_items = bp_alpha_sort_by_key( $bp_menu_items, 'name' );
+ // Pull up a list of items registered in BP's primary nav for the member.
+ $bp_menu_items = buddypress()->members->nav->get_primary();
// Some BP nav menu items will not be represented in bp_nav, because
// they are not real BP components. We add them manually here.
- $bp_menu_items[] = array(
+ $bp_menu_items[] = (object) array(
'name' => __( 'Log Out', 'buddypress' ),
'slug' => 'logout',
'link' => wp_logout_url(),
@@ -2467,18 +2464,18 @@ function bp_nav_menu_get_loggedin_pages() {
foreach ( $bp_menu_items as $bp_item ) {
// Remove number.
- $item_name = _bp_strip_spans_from_title( $bp_item['name'] );
+ $item_name = _bp_strip_spans_from_title( $bp_item->name );
- $page_args[ $bp_item['slug'] ] = (object) array(
+ $page_args[ $bp_item->slug ] = (object) array(
'ID' => -1,
'post_title' => $item_name,
'post_author' => 0,
'post_date' => 0,
- 'post_excerpt' => $bp_item['slug'],
+ 'post_excerpt' => $bp_item->slug,
'post_type' => 'page',
'post_status' => 'publish',
'comment_status' => 'closed',
- 'guid' => $bp_item['link']
+ 'guid' => $bp_item->link
);
}
@@ -2575,7 +2572,7 @@ function bp_nav_menu_get_loggedout_pages() {
* @since 1.9.0
*
* @param string $slug The slug of the nav item: login, register, or one of the
- * slugs from buddypress()->bp_nav.
+ * slugs from the members navigation.
* @return string $nav_item_url The URL generated for the current user.
*/
function bp_nav_menu_get_item_url( $slug ) {
diff --git src/bp-core/bp-core-template.php src/bp-core/bp-core-template.php
index 1f2c5e9..48fd117 100644
--- src/bp-core/bp-core-template.php
+++ src/bp-core/bp-core-template.php
@@ -13,7 +13,7 @@ defined( 'ABSPATH' ) || exit;
/**
* Output the "options nav", the secondary-level single item navigation menu.
*
- * Uses the $bp->bp_options_nav global to render out the sub navigation for the
+ * Uses the component's nav global to render out the sub navigation for the
* current component. Each component adds to its sub navigation array within
* its own setup_nav() function.
*
@@ -40,35 +40,54 @@ function bp_get_options_nav( $parent_slug = '' ) {
$component_index = !empty( $bp->displayed_user ) ? bp_current_component() : bp_get_root_slug( bp_current_component() );
$selected_item = bp_current_action();
+ /**
+ * Use the members Nav
+ */
if ( ! bp_is_single_item() ) {
- if ( !isset( $bp->bp_options_nav[$component_index] ) || count( $bp->bp_options_nav[$component_index] ) < 1 ) {
+ // Set the parent slug if not provided
+ if ( empty( $parent_slug ) ) {
+ $parent_slug = $component_index;
+ }
+
+ $secondary_nav_items = $bp->members->nav->get_secondary( array( 'parent_slug' => $parent_slug ) );
+
+ if ( ! $secondary_nav_items ) {
return false;
- } else {
- $the_index = $component_index;
}
+
+ /**
+ * Try to use the component's Nav for the single item.
+ */
} else {
$current_item = bp_current_item();
+ $single_item_component = bp_current_component();
+ // Adjust the selected nav item for the current single item if needed
if ( ! empty( $parent_slug ) ) {
$current_item = $parent_slug;
$selected_item = bp_action_variable( 0 );
}
- if ( !isset( $bp->bp_options_nav[$current_item] ) || count( $bp->bp_options_nav[$current_item] ) < 1 ) {
- return false;
+ // The nav is not defined by the parent component, try to look in the members one
+ if ( ! isset( $bp->{$single_item_component}->nav ) ) {
+ $secondary_nav_items = $bp->members->nav->get_secondary( array( 'parent_slug' => $current_item ) );
} else {
- $the_index = $current_item;
+ $secondary_nav_items = $bp->{$single_item_component}->nav->get_secondary( array( 'parent_slug' => $current_item ) );
+ }
+
+ if ( ! $secondary_nav_items ) {
+ return false;
}
}
// Loop through each navigation item.
- foreach ( (array) $bp->bp_options_nav[$the_index] as $subnav_item ) {
- if ( empty( $subnav_item['user_has_access'] ) ) {
+ foreach ( $secondary_nav_items as $subnav_item ) {
+ if ( empty( $subnav_item->user_has_access ) ) {
continue;
}
// If the current action or an action variable matches the nav item id, then add a highlight CSS class.
- if ( $subnav_item['slug'] == $selected_item ) {
+ if ( $subnav_item->slug === $selected_item ) {
$selected = ' class="current selected"';
} else {
$selected = '';
@@ -88,7 +107,7 @@ function bp_get_options_nav( $parent_slug = '' ) {
* @param array $subnav_item Submenu array item being displayed.
* @param string $selected_item Current action.
*/
- echo apply_filters( 'bp_get_options_nav_' . $subnav_item['css_id'], '
' . $subnav_item['name'] . '', $subnav_item, $selected_item );
+ echo apply_filters( 'bp_get_options_nav_' . $subnav_item->css_id, '' . $subnav_item->name . '', $subnav_item, $selected_item );
}
}
@@ -3010,24 +3029,36 @@ function bp_get_title_parts( $seplocation = 'right' ) {
// Set empty subnav name.
$component_subnav_name = '';
+ if ( ! empty( $bp->members->nav ) ) {
+ $primary_nav_item = $bp->members->nav->get_primary( array( 'slug' => $component_id ), false );
+ $primary_nav_item = reset( $primary_nav_item );
+ }
+
// Use the component nav name.
- if ( ! empty( $bp->bp_nav[$component_id] ) ) {
- $component_name = _bp_strip_spans_from_title( $bp->bp_nav[ $component_id ]['name'] );
+ if ( ! empty( $primary_nav_item->name ) ) {
+ $component_name = _bp_strip_spans_from_title( $primary_nav_item->name );
// Fall back on the component ID.
} elseif ( ! empty( $bp->{$component_id}->id ) ) {
$component_name = ucwords( $bp->{$component_id}->id );
}
- // Append action name if we're on a member component sub-page.
- if ( ! empty( $bp->bp_options_nav[ $component_id ] ) && ! empty( $bp->canonical_stack['action'] ) ) {
- $component_subnav_name = wp_filter_object_list( $bp->bp_options_nav[ $component_id ], array( 'slug' => bp_current_action() ), 'and', 'name' );
+ if ( ! empty( $bp->members->nav ) ) {
+ $secondary_nav_item = $bp->members->nav->get_secondary( array(
+ 'parent_slug' => $component_id,
+ 'slug' => bp_current_action()
+ ), false );
- if ( ! empty( $component_subnav_name ) ) {
- $component_subnav_name = array_shift( $component_subnav_name );
+ if ( $secondary_nav_item ) {
+ $secondary_nav_item = reset( $secondary_nav_item );
}
}
+ // Append action name if we're on a member component sub-page.
+ if ( ! empty( $secondary_nav_item->name ) && ! empty( $bp->canonical_stack['action'] ) ) {
+ $component_subnav_name = $secondary_nav_item->name;
+ }
+
// If on the user profile's landing page, just use the fullname.
if ( bp_is_current_component( $bp->default_component ) && ( bp_get_requested_url() === bp_displayed_user_domain() ) ) {
$bp_title_parts[] = $displayed_user_name;
@@ -3045,14 +3076,28 @@ function bp_get_title_parts( $seplocation = 'right' ) {
}
}
- // A single group.
- } elseif ( bp_is_active( 'groups' ) && ! empty( $bp->groups->current_group ) && ! empty( $bp->bp_options_nav[ $bp->groups->current_group->slug ] ) ) {
- $subnav = isset( $bp->bp_options_nav[ $bp->groups->current_group->slug ][ bp_current_action() ]['name'] ) ? $bp->bp_options_nav[ $bp->groups->current_group->slug ][ bp_current_action() ]['name'] : '';
- $bp_title_parts = array( $bp->bp_options_title, $subnav );
-
- // A single item from a component other than groups.
+ // A single item from a component other than members.
} elseif ( bp_is_single_item() ) {
- $bp_title_parts = array( $bp->bp_options_title, $bp->bp_options_nav[ bp_current_item() ][ bp_current_action() ]['name'] );
+ $component_id = bp_current_component();
+
+ if ( ! empty( $bp->{$component_id}->nav ) ) {
+ $secondary_nav_item = $bp->{$component_id}->nav->get_secondary( array(
+ 'parent_slug' => bp_current_item(),
+ 'slug' => bp_current_action()
+ ), false );
+
+ if ( $secondary_nav_item ) {
+ $secondary_nav_item = reset( $secondary_nav_item );
+ }
+ }
+
+ $single_item_subnav = '';
+
+ if ( ! empty( $secondary_nav_item->name ) ) {
+ $single_item_subnav = $secondary_nav_item->name;
+ }
+
+ $bp_title_parts = array( $bp->bp_options_title, $single_item_subnav );
// An index or directory.
} elseif ( bp_is_directory() ) {
@@ -3428,79 +3473,57 @@ function _bp_nav_menu_sort( $a, $b ) {
* Get the items registered in the primary and secondary BuddyPress navigation menus.
*
* @since 1.7.0
+ * @since 2.6.0 Add the component parameter to be able to get the menu items for any single item
*
* @return array A multidimensional array of all navigation items.
*/
-function bp_get_nav_menu_items() {
- $menus = $selected_menus = array();
-
- // Get the second level menus.
- foreach ( (array) buddypress()->bp_options_nav as $parent_menu => $sub_menus ) {
-
- // The root menu's ID is "xprofile", but the Profile submenus are using "profile". See BP_Core::setup_nav().
- if ( 'profile' === $parent_menu ) {
- $parent_menu = 'xprofile';
- }
+function bp_get_nav_menu_items( $component = 'members' ) {
+ $bp = buddypress();
+ $menus = array();
- // Sort the items in this menu's navigation by their position property.
- $second_level_menus = (array) $sub_menus;
- usort( $second_level_menus, '_bp_nav_menu_sort' );
-
- // Iterate through the second level menus.
- foreach( $second_level_menus as $sub_nav ) {
-
- // Skip items we don't have access to.
- if ( empty( $sub_nav['user_has_access'] ) ) {
- continue;
- }
-
- // Add this menu.
- $menu = new stdClass;
- $menu->class = array( 'menu-child' );
- $menu->css_id = $sub_nav['css_id'];
- $menu->link = $sub_nav['link'];
- $menu->name = $sub_nav['name'];
- $menu->parent = $parent_menu; // Associate this sub nav with a top-level menu.
-
- // If we're viewing this item's screen, record that we need to mark its parent menu to be selected.
- if ( $sub_nav['slug'] == bp_current_action() ) {
- $menu->class[] = 'current-menu-item';
- $selected_menus[] = $parent_menu;
- }
-
- $menus[] = $menu;
- }
+ if ( ! isset( $bp->{$component}->nav ) ) {
+ return $menus;
}
- // Get the top-level menu parts (Friends, Groups, etc) and sort by their position property.
- $top_level_menus = (array) buddypress()->bp_nav;
- usort( $top_level_menus, '_bp_nav_menu_sort' );
-
- // Iterate through the top-level menus.
- foreach ( $top_level_menus as $nav ) {
-
- // Skip items marked as user-specific if you're not on your own profile.
- if ( empty( $nav['show_for_displayed_user'] ) && ! bp_core_can_edit_settings() ) {
- continue;
- }
-
+ // Get the item nav and build the menus
+ foreach ( $bp->{$component}->nav->get_item_nav() as $nav_menu ) {
// Get the correct menu link. See https://buddypress.trac.wordpress.org/ticket/4624.
- $link = bp_loggedin_user_domain() ? str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $nav['link'] ) : trailingslashit( bp_displayed_user_domain() . $nav['link'] );
+ $link = bp_loggedin_user_domain() ? str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $nav_menu->link ) : trailingslashit( bp_displayed_user_domain() . $nav_menu->link );
// Add this menu.
$menu = new stdClass;
$menu->class = array( 'menu-parent' );
- $menu->css_id = $nav['css_id'];
- $menu->link = $link;
- $menu->name = $nav['name'];
+ $menu->css_id = $nav_menu->css_id;
+ $menu->link = $nav_menu->link;
+ $menu->name = $nav_menu->name;
$menu->parent = 0;
- // Check if we need to mark this menu as selected.
- if ( in_array( $nav['css_id'], $selected_menus ) ) {
- $menu->class[] = 'current-menu-parent';
+ if ( ! empty( $nav_menu->children ) ) {
+ $submenus = array();
+
+ foreach( $nav_menu->children as $sub_menu ) {
+ $submenu = new stdClass;
+ $submenu->class = array( 'menu-child' );
+ $submenu->css_id = $sub_menu->css_id;
+ $submenu->link = $sub_menu->link;
+ $submenu->name = $sub_menu->name;
+ $submenu->parent = $nav_menu->slug;
+
+ // If we're viewing this item's screen, record that we need to mark its parent menu to be selected.
+ if ( $sub_menu->slug == bp_current_action() ) {
+ $menu->class[] = 'current-menu-parent';
+ $submenu->class[] = 'current-menu-item';
+ }
+
+ $submenus[] = $submenu;
+ }
}
$menus[] = $menu;
+
+ if ( ! empty( $submenus ) ) {
+ $menus = array_merge( $menus, $submenus );
+ }
}
/**
diff --git src/bp-core/classes/class-bp-component.php src/bp-core/classes/class-bp-component.php
index 8a53680..5fdab1d 100644
--- src/bp-core/classes/class-bp-component.php
+++ src/bp-core/classes/class-bp-component.php
@@ -473,28 +473,30 @@ class BP_Component {
* Set up component navigation.
*
* @since 1.5.0
+ * @since 2.6.0 Use bp_core_add_nav_item() instead of bp_core_new_nav_item() (deprecated)
+ * Use bp_core_add_subnav_item() instead of bp_core_new_subnav_item() (deprecated)
*
- * @see bp_core_new_nav_item() For a description of the $main_nav
+ * @see bp_core_add_nav_item() For a description of the $main_nav
* parameter formatting.
- * @see bp_core_new_subnav_item() For a description of how each item
+ * @see bp_core_add_subnav_item() For a description of how each item
* in the $sub_nav parameter array should be formatted.
*
- * @param array $main_nav Optional. Passed directly to bp_core_new_nav_item().
+ * @param array $main_nav Optional. Passed directly to bp_core_add_nav_item().
* See that function for a description.
* @param array $sub_nav Optional. Multidimensional array, each item in
- * which is passed to bp_core_new_subnav_item(). See that
+ * which is passed to bp_core_add_subnav_item(). See that
* function for a description.
*/
public function setup_nav( $main_nav = array(), $sub_nav = array() ) {
// No sub nav items without a main nav item.
if ( !empty( $main_nav ) ) {
- bp_core_new_nav_item( $main_nav );
+ bp_core_add_nav_item( $main_nav, 'members' );
// Sub nav items are not required.
if ( !empty( $sub_nav ) ) {
foreach( (array) $sub_nav as $nav ) {
- bp_core_new_subnav_item( $nav );
+ bp_core_add_subnav_item( $nav, 'members' );
}
}
}
diff --git src/bp-core/classes/class-bp-core-backcompat-nav.php src/bp-core/classes/class-bp-core-backcompat-nav.php
index e69de29..784dae3 100644
--- src/bp-core/classes/class-bp-core-backcompat-nav.php
+++ src/bp-core/classes/class-bp-core-backcompat-nav.php
@@ -0,0 +1,243 @@
+bp_nav global
+ *
+ * @since 2.6.0
+ */
+class BP_Core_BackCompat_Nav implements ArrayAccess {
+ public $backcompat_nav;
+
+ public function __construct( $backcompat_nav = array() ) {
+ foreach ( $backcompat_nav as $key => $value ) {
+ $this->backcompat_nav[ $key ] = $value;
+ }
+ }
+
+ public function offsetSet( $offset, $value ) {
+ $bp = buddypress();
+
+ if ( is_array( $value ) ) {
+ $value = new self( $value );
+ }
+
+ if ( $offset !== null ) {
+ // Set the backcompat_nav
+ $this->backcompat_nav[ $offset ] = $value;
+
+ _doing_it_wrong(
+ 'buddypress()->bp_nav',
+ __( 'These globals should not be used directly and are deprecated. Please use the BuddyPress nav functions instead.', 'buddypress' ),
+ '2.6.0'
+ );
+
+ // This should never be the case!
+ if ( ! isset( $bp->members->nav ) ) {
+ return;
+ }
+
+ // The primary nav already exists and the user is trying to edit it.
+ if ( ! empty( $this->backcompat_nav['slug'] ) ) {
+ $primary_nav = $bp->members->nav->get_primary( array( 'slug' => $this->backcompat_nav['slug'] ), false );
+
+ // Primary nav item exists, so edit it!
+ if ( ! empty( $primary_nav ) ) {
+ $primary_nav = reset( $primary_nav );
+ $bp->members->nav->edit_nav( (array) $this->backcompat_nav, $primary_nav->slug );
+ }
+
+ // Check if it's a complete new nav item and create it if needed.
+ } else if ( ! empty( $value->backcompat_nav ) && isset( $value['slug'] ) ) {
+ // Add the new nav
+ $bp->members->nav->add_nav( $value->backcompat_nav );
+ }
+ }
+ }
+
+ public function get_nav( $offset ) {
+ $bp = buddypress();
+
+ if ( isset( $bp->members->nav ) ) {
+ $primary_nav = $bp->members->nav->get_primary( array( 'slug' => $offset ), false );
+ $nav = array();
+
+ if ( empty( $primary_nav ) ) {
+ return $nav;
+ }
+
+ foreach( $primary_nav as $item ) {
+ $nav[ $item->slug ] = (array) $item;
+ }
+
+ return $nav;
+ }
+ }
+
+ public function offsetGet( $offset ) {
+ if ( ! isset( $this->backcompat_nav[ $offset ] ) ) {
+ $this->backcompat_nav[ $offset ] = new self;
+
+ if ( empty( $this->backcompat_nav[ $offset ]->backcompat_nav ) ) {
+ $nav = $this->get_nav( $offset );
+
+ if ( ! empty( $nav[ $offset ] ) ) {
+ $this->backcompat_nav[ $offset ] = new self( $nav[ $offset ] );
+ }
+ }
+ }
+
+ _doing_it_wrong(
+ 'buddypress()->bp_nav',
+ __( 'These globals should not be used directly and are deprecated. Please use the BuddyPress nav functions instead.', 'buddypress' ),
+ '2.6.0'
+ );
+
+ return $this->backcompat_nav[ $offset ];
+ }
+
+ public function offsetExists( $offset ) {
+ return isset( $this->backcompat_nav[ $offset ] );
+ }
+
+ public function offsetUnset( $offset ) {
+ unset( $this->backcompat_nav );
+ }
+}
+
+/**
+ * BuddyPress BackCompat Options Nav.
+ *
+ * This class is used to provide Backward compatibility
+ * in case people are directly accessing the buddypress()->bp_options_nav global
+ *
+ * @since 2.6.0
+ */
+class BP_Core_BackCompat_Options_Nav extends BP_Core_BackCompat_Nav {
+
+ public function get_parent_slug( $subnav, $offset ) {
+ $parent_slug = false;
+
+ if ( ! is_array( $subnav ) || empty( $subnav['slug'] ) ) {
+ return $parent_slug;
+ }
+
+ if ( ! empty( $subnav['parent_slug'] ) ) {
+ $parent_slug = $subnav['parent_slug'];
+
+ /**
+ * Unfortunately the parent slug is not part of the args
+ * when a bp_options_nav item is first created, So we need to parse the url to find it.
+ */
+ } else {
+ $s = str_replace( array( bp_get_members_slug(), $offset ), '', parse_url( $subnav['link'], PHP_URL_PATH ) );
+ $s = explode( '/', trim( $s, '/' ) );
+
+ if ( ! empty( $s[1] ) ) {
+ $parent_slug = $s[1];
+ }
+ }
+
+ return $parent_slug;
+ }
+
+ public function get_component( $parent_slug ) {
+ $component = 'members';
+
+ if ( bp_is_group() && $parent_slug === groups_get_current_group()->slug ) {
+ $component = 'groups';
+ }
+
+ return $component;
+ }
+
+ public function offsetSet( $offset, $value ) {
+ $bp = buddypress();
+
+ if ( is_array( $value ) ) {
+ $value = new self( $value );
+ }
+
+ if ( $offset !== null ) {
+ // Set the backcompat_nav
+ $this->backcompat_nav[ $offset ] = $value;
+
+ _doing_it_wrong(
+ 'buddypress()->bp_options_nav',
+ __( 'These globals should not be used directly and are deprecated. Please use the BuddyPress nav functions instead.', 'buddypress' ),
+ '2.6.0'
+ );
+
+ // This should never be the case!
+ if ( ! isset( $bp->members->nav ) ) {
+ return;
+ }
+
+ // The secondary nav already exists and the user is trying to edit it.
+ if ( ! empty( $this->backcompat_nav['slug'] ) ) {
+ $parent_slug = $this->get_parent_slug( $this->backcompat_nav, $offset );
+
+ $secondary_nav = $bp->{$this->get_component( $parent_slug )}->nav->get_secondary( array(
+ 'parent_slug' => $parent_slug,
+ 'slug' => $this->backcompat_nav['slug']
+ ), false );
+
+ // Primary nav item exists, so edit it!
+ if ( ! empty( $secondary_nav ) ) {
+ $secondary_nav = reset( $secondary_nav );
+ $bp->{$this->get_component( $parent_slug )}->nav->edit_nav( (array) $this->backcompat_nav, $secondary_nav->slug, $secondary_nav->parent_slug );
+ }
+ } else if ( ! empty( $value->backcompat_nav ) && isset( $value['slug'] ) ) {
+ $parent_slug = $this->get_parent_slug( $value->backcompat_nav, $offset );
+
+ if ( $parent_slug ) {
+ $value->backcompat_nav['parent_slug'] = $parent_slug;
+ $bp->{$this->get_component( $parent_slug )}->nav->add_nav( $value->backcompat_nav );
+ }
+ }
+ }
+ }
+
+ public function offsetGet( $offset ) {
+ $bp = buddypress();
+
+ if ( isset( $bp->members->nav ) ) {
+ $nav_items = $bp->members->nav->get();
+
+ if ( bp_is_group() ) {
+ $nav_items = array_merge( $nav_items, $bp->groups->nav->get_secondary( array( 'parent_slug' => groups_get_current_group()->slug ), false ) );
+ }
+
+ foreach ( $nav_items as $nav_item ) {
+ if ( ! empty( $nav_item->secondary ) ) {
+ $this->backcompat_nav[ $nav_item->slug ] = new self( (array) $nav_item );
+ $this->backcompat_nav[ $nav_item->parent_slug ] = new self( $this->backcompat_nav[ $nav_item->slug ] );
+ }
+ }
+ }
+
+ if ( ! isset( $this->backcompat_nav[ $offset ] ) ) {
+ $this->backcompat_nav[ $offset ] = new self;
+ }
+
+ _doing_it_wrong(
+ 'buddypress()->bp_options_nav',
+ __( 'These globals should not be used directly and are deprecated. Please use the BuddyPress nav functions instead.', 'buddypress' ),
+ '2.6.0'
+ );
+
+ return $this->backcompat_nav[ $offset ];
+ }
+}
diff --git src/bp-core/classes/class-bp-core-nav.php src/bp-core/classes/class-bp-core-nav.php
index e69de29..8528aac 100644
--- src/bp-core/classes/class-bp-core-nav.php
+++ src/bp-core/classes/class-bp-core-nav.php
@@ -0,0 +1,392 @@
+item_id = (int) bp_displayed_user_id();
+ } else {
+ $this->item_id = (int) $item_id;
+ }
+
+ $this->nav[ $this->item_id ] = array();
+ }
+
+ /**
+ * Checks if 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->item_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->item_id ][ $key ] ) ) {
+ $this->nav[ $this->item_id ][ $key ] = null;
+ }
+
+ return $this->nav[ $this->item_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->item_id ][ $key ] = (object) $value;
+ }
+
+ /**
+ * Gets a specific Raw Item Nav or all items.
+ *
+ * @since 2.6.0
+ *
+ * @param string $key The nav item slug to get. Optional.
+ * @return mixed An array of nav item(s), null if not found.
+ */
+ public function get( $key = '' ) {
+ $return = null;
+
+ // Return the requested nav item attribute
+ if ( ! empty( $key ) ) {
+ if ( ! isset( $this->nav[ $this->item_id ][ $key ] ) ) {
+ $return = null;
+ } else {
+ $return = $this->nav[ $this->item_id ][ $key ];
+ }
+
+ // Return all nav item attributes
+ } else {
+ $return = $this->nav[ $this->item_id ];
+ }
+
+ return $return;
+ }
+
+ /**
+ * Adds a new nav item.
+ *
+ * @since 2.6.0
+ *
+ * @param array $args The nav item's arguments.
+ */
+ public function add_nav( $args ) {
+ if ( empty( $args['slug'] ) ) {
+ return false;
+ }
+
+ // We have a child and the parent exists
+ if ( ! empty( $args['parent_slug'] ) ) {
+ $slug = $args['parent_slug'] . '/' . $args['slug'];
+ $args['secondary'] = true;
+
+ // This is a parent
+ } else {
+ $slug = $args['slug'];
+ $args['primary'] = true;
+ }
+
+ // Add to the nav
+ $this->nav[ $this->item_id ][ $slug ] = (object ) $args;
+ }
+
+ /**
+ * 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).
+ */
+ 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->item_id ][ $slug ] = (object) wp_parse_args( $args, (array) $nav_item );
+
+ // Return the edited object
+ return $this->nav[ $this->item_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 = wp_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->item_id ][ $parent_slug . '/' . $slug ] = (object) $params;
+
+ // Return the edited object
+ return $this->nav[ $this->item_id ][ $parent_slug . '/' . $slug ];
+ }
+ }
+
+ /**
+ * Unset an item or a subitem of the nav.
+ *
+ * @since 2.6.0
+ *
+ * @param string $key The slug of the main item.
+ * @param string $sub_key The slug of the sub item.
+ */
+ public function delete_nav( $slug, $parent_slug = '' ) {
+ 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->item_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->item_id ][ $nav_item->slug . '/' . $sub_item->slug ] );
+ }
+ }
+
+ // Delete the parent
+ unset( $this->nav[ $this->item_id ][ $nav_item->slug ] );
+
+ // Return the deleted item's screen functions
+ return array_unique( $screen_functions );
+ }
+ }
+
+ /**
+ * Sorts a list of nav items.
+ *
+ * @since 2.6.0
+ *
+ * @param array $items The nav item's to sort.
+ */
+ 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 += 1;
+ } while ( in_array( $position, $sorted_keys ) );
+ }
+
+ $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.
+ * @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 = wp_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->item_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.
+ * @param bool $sort True to sort the nav items. False otherwise.
+ * @return array The list of secondary objects nav
+ */
+ public function get_secondary( $args = array(), $sort = true ) {
+ $params = wp_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->item_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 objects nav
+ */
+ 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;
+ }
+}
diff --git src/bp-core/deprecated/2.6.php src/bp-core/deprecated/2.6.php
index acc5e23..3c289b2 100644
--- src/bp-core/deprecated/2.6.php
+++ src/bp-core/deprecated/2.6.php
@@ -21,3 +21,141 @@ function bp_core_print_generation_time() {
groups->nav ) ) {
+
+ if ( $bp->groups->nav->get_primary( array( 'slug' => $parent_id ) ) ) {
+ return bp_core_delete_nav_item( $parent_id, 'groups' );
+ }
+ }
+
+ return bp_core_delete_nav_item( $parent_id );
+}
+
+/**
+ * Remove a subnav item from the navigation array.
+ *
+ * @since 1.0.0
+ * @deprecated 2.6.0
+ *
+ * @param string $parent_id The slug of the parent navigation item.
+ * @param string $slug The slug of the subnav item to be removed.
+ */
+function bp_core_remove_subnav_item( $parent_id, $slug ) {
+ $bp = buddypress();
+
+ _deprecated_function( __FUNCTION__, '2.6', 'bp_core_delete_subnav_item()' );
+
+ if ( bp_is_active( 'groups' ) && isset( $bp->groups->nav ) ) {
+
+ if ( $bp->groups->nav->get_primary( array( 'slug' => $parent_id ) ) ) {
+ return bp_core_delete_subnav_item( $slug, $parent_id, 'groups' );
+ }
+ }
+
+ return bp_core_delete_subnav_item( $slug, $parent_id );
+}
diff --git src/bp-groups/bp-groups-adminbar.php src/bp-groups/bp-groups-adminbar.php
index f27f74e..6cef4b5 100644
--- src/bp-groups/bp-groups-adminbar.php
+++ src/bp-groups/bp-groups-adminbar.php
@@ -47,15 +47,15 @@ function bp_groups_group_admin_menu() {
) );
// Index of the Manage tabs parent slug.
- $nav_index = $bp->groups->current_group->slug . '_manage';
+ $secondary_nav_items = $bp->groups->nav->get_secondary( array( 'parent_slug' => $bp->groups->current_group->slug . '_manage' ) );
// Check if current group has Manage tabs.
- if ( empty( $bp->bp_options_nav[ $nav_index ] ) ) {
+ if ( ! $secondary_nav_items ) {
return;
}
// Build the Group Admin menus.
- foreach ( $bp->bp_options_nav[ $nav_index ] as $menu ) {
+ foreach ( $secondary_nav_items as $menu ) {
/**
* Should we add the current manage link in the Group's "Edit" Admin Bar menu ?
*
@@ -63,19 +63,19 @@ function bp_groups_group_admin_menu() {
* to also add the link to the "edit screen" of their group component. To do so, set the
* the 'show_in_admin_bar' argument of your edit screen to true
*/
- if ( $menu['show_in_admin_bar'] ) {
- $title = sprintf( _x( 'Edit Group %s', 'Group WP Admin Bar manage links', 'buddypress' ), $menu['name'] );
+ if ( $menu->show_in_admin_bar ) {
+ $title = sprintf( _x( 'Edit Group %s', 'Group WP Admin Bar manage links', 'buddypress' ), $menu->name );
// Title is specific for delete.
- if ( 'delete-group' == $menu['slug'] ) {
- $title = sprintf( _x( '%s Group', 'Group WP Admin Bar delete link', 'buddypress' ), $menu['name'] );
+ if ( 'delete-group' == $menu->slug ) {
+ $title = sprintf( _x( '%s Group', 'Group WP Admin Bar delete link', 'buddypress' ), $menu->name );
}
$wp_admin_bar->add_menu( array(
'parent' => $bp->group_admin_menu_id,
- 'id' => $menu['slug'],
+ 'id' => $menu->slug,
'title' => $title,
- 'href' => bp_get_groups_action_link( 'admin/' . $menu['slug'] )
+ 'href' => bp_get_groups_action_link( 'admin/' . $menu->slug )
) );
}
}
diff --git src/bp-groups/classes/class-bp-group-extension.php src/bp-groups/classes/class-bp-group-extension.php
index 5709b0b..7209401 100644
--- src/bp-groups/classes/class-bp-group-extension.php
+++ src/bp-groups/classes/class-bp-group-extension.php
@@ -737,7 +737,7 @@ class BP_Group_Extension {
'screen_function' => array( &$this, '_display_hook' ),
'user_has_access' => $user_can_see_nav_item,
'no_access_url' => $group_permalink,
- ) );
+ ), 'groups' );
}
// If the user can visit the screen, we register it.
@@ -752,7 +752,7 @@ class BP_Group_Extension {
'screen_function' => array( &$this, '_display_hook' ),
'user_has_access' => $user_can_visit,
'no_access_url' => $group_permalink,
- ) );
+ ), 'groups' );
// When we are viewing the extension display page, set the title and options title.
if ( bp_is_current_action( $this->slug ) ) {
@@ -967,7 +967,7 @@ class BP_Group_Extension {
}
// Add the tab to the manage navigation.
- bp_core_new_subnav_item( $subnav_args );
+ bp_core_add_subnav_item( $subnav_args, 'groups' );
// Catch the edit screen and forward it to the plugin template.
if ( bp_is_groups_component() && bp_is_current_action( 'admin' ) && bp_is_action_variable( $screen['slug'], 0 ) ) {
diff --git src/bp-groups/classes/class-bp-groups-component.php src/bp-groups/classes/class-bp-groups-component.php
index 355ab8c..145051d 100644
--- src/bp-groups/classes/class-bp-groups-component.php
+++ src/bp-groups/classes/class-bp-groups-component.php
@@ -253,6 +253,15 @@ class BP_Groups_Component extends BP_Component {
// Check once if the current group has a custom front template.
$this->current_group->front_template = bp_groups_get_front_template( $this->current_group );
+ /**
+ * Since 2.6.0 The Groups single items are using their own navigation to avoid slug
+ * collisions with the displayed user options nav (buddypress()->bp_options_nav)
+ * and for more flexibility in future releases.
+ */
+
+ // Set the Group's Primary Nav
+ $this->nav = new BP_Core_Nav( $this->current_group->id );
+
// Set current_group to 0 to prevent debug errors.
} else {
$this->current_group = 0;
@@ -496,15 +505,20 @@ class BP_Groups_Component extends BP_Component {
// Reset sub nav.
$sub_nav = array();
- // Add 'Groups' to the main navigation.
- $main_nav = array(
+ /**
+ * Set the Current Group's main navigation
+ *
+ * Since 2.6.0 it's now using its own navigation by passing the
+ * component's id as the second argument of bp_core_add_nav_item()
+ */
+ bp_core_add_nav_item( array(
'name' => __( 'Memberships', 'buddypress' ),
'slug' => $this->current_group->slug,
'position' => -1, // Do not show in BuddyBar.
'screen_function' => 'groups_screen_group_home',
'default_subnav_slug' => $this->default_extension,
'item_css_id' => $this->id
- );
+ ), 'groups' );
$group_link = bp_get_group_permalink( $this->current_group );
@@ -675,7 +689,15 @@ class BP_Groups_Component extends BP_Component {
), $default_params );
}
- parent::setup_nav( $main_nav, $sub_nav );
+ foreach( $sub_nav as $nav ) {
+ /**
+ * Set the Current Group's sub navigation
+ *
+ * Since 2.6.0 it's now using its own sub navigation by passing it
+ * as the second argument of bp_core_add_subnav_item()
+ */
+ bp_core_add_subnav_item( $nav, 'groups' );
+ }
}
if ( isset( $this->current_group->user_has_access ) ) {
diff --git src/bp-loader.php src/bp-loader.php
index 4a744c4..3ee25b6 100644
--- src/bp-loader.php
+++ src/bp-loader.php
@@ -72,7 +72,7 @@ class BuddyPress {
/**
* @var array The canonical URI stack.
* @see bp_redirect_canonical()
- * @see bp_core_new_nav_item()
+ * @see bp_core_add_nav_item()
*/
public $canonical_stack = array();
diff --git src/bp-members/bp-members-template.php src/bp-members/bp-members-template.php
index bffd155..038ec06 100644
--- src/bp-members/bp-members-template.php
+++ src/bp-members/bp-members-template.php
@@ -1290,12 +1290,12 @@ function bp_get_loggedin_user_nav() {
$bp = buddypress();
// Loop through each navigation item.
- foreach( (array) $bp->bp_nav as $nav_item ) {
+ foreach( (array) $bp->members->nav->get_primary() as $nav_item ) {
$selected = '';
// If the current component matches the nav item id, then add a highlight CSS class.
- if ( !bp_is_directory() && !empty( $bp->active_components[bp_current_component()] ) && $bp->active_components[bp_current_component()] == $nav_item['css_id'] ) {
+ if ( !bp_is_directory() && !empty( $bp->active_components[bp_current_component()] ) && $bp->active_components[bp_current_component()] == $nav_item->css_id ) {
$selected = ' class="current selected"';
}
@@ -1307,7 +1307,7 @@ function bp_get_loggedin_user_nav() {
$selected = '';
if ( bp_is_active( 'friends' ) ) {
- if ( $nav_item['css_id'] == $bp->friends->id ) {
+ if ( $nav_item->css_id == $bp->friends->id ) {
if ( friends_check_friendship( bp_loggedin_user_id(), bp_displayed_user_id() ) ) {
$selected = ' class="current selected"';
}
@@ -1316,7 +1316,7 @@ function bp_get_loggedin_user_nav() {
}
// Echo out the final list item.
- echo apply_filters_ref_array( 'bp_get_loggedin_user_nav_' . $nav_item['css_id'], array( '' . $nav_item['name'] . '', &$nav_item ) );
+ echo apply_filters_ref_array( 'bp_get_loggedin_user_nav_' . $nav_item->css_id, array( '' . $nav_item->name . '', &$nav_item ) );
}
// Always add a log out list item to the end of the navigation.
@@ -1333,19 +1333,20 @@ function bp_get_loggedin_user_nav() {
function bp_get_displayed_user_nav() {
$bp = buddypress();
- foreach ( (array) $bp->bp_nav as $user_nav_item ) {
- if ( empty( $user_nav_item['show_for_displayed_user'] ) && !bp_is_my_profile() )
+ foreach ( $bp->members->nav->get_primary() as $user_nav_item ) {
+ if ( empty( $user_nav_item->show_for_displayed_user ) && ! bp_is_my_profile() ) {
continue;
+ }
$selected = '';
- if ( bp_is_current_component( $user_nav_item['slug'] ) ) {
+ if ( bp_is_current_component( $user_nav_item->slug ) ) {
$selected = ' class="current selected"';
}
if ( bp_loggedin_user_domain() ) {
- $link = str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $user_nav_item['link'] );
+ $link = str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $user_nav_item->link );
} else {
- $link = trailingslashit( bp_displayed_user_domain() . $user_nav_item['link'] );
+ $link = trailingslashit( bp_displayed_user_domain() . $user_nav_item->link );
}
/**
@@ -1359,7 +1360,7 @@ function bp_get_displayed_user_nav() {
* @param array $user_nav_item Array holding parts used to construct tab list item.
* Passed by reference.
*/
- echo apply_filters_ref_array( 'bp_get_displayed_user_nav_' . $user_nav_item['css_id'], array( '' . $user_nav_item['name'] . '', &$user_nav_item ) );
+ echo apply_filters_ref_array( 'bp_get_displayed_user_nav_' . $user_nav_item->css_id, array( '' . $user_nav_item->name . '', &$user_nav_item ) );
}
}
diff --git src/bp-members/classes/class-bp-members-component.php src/bp-members/classes/class-bp-members-component.php
index 92a2c85..ee77fc9 100644
--- src/bp-members/classes/class-bp-members-component.php
+++ src/bp-members/classes/class-bp-members-component.php
@@ -150,6 +150,13 @@ class BP_Members_Component extends BP_Component {
// The domain for the user currently being displayed.
$bp->displayed_user->domain = bp_core_get_user_domain( bp_displayed_user_id() );
+ // Backward compatibility for the Displayed User Nav
+ $bp->bp_nav = new BP_Core_BackCompat_Nav();
+ $bp->bp_options_nav = new BP_Core_BackCompat_Options_Nav();
+
+ // Set the Nav for the members component
+ $this->nav = new BP_Core_Nav();
+
/** Signup ***********************************************************
*/
diff --git src/bp-messages/bp-messages-screens.php src/bp-messages/bp-messages-screens.php
index 2be4937..0e92210 100644
--- src/bp-messages/bp-messages-screens.php
+++ src/bp-messages/bp-messages-screens.php
@@ -132,7 +132,10 @@ function messages_screen_conversation() {
$class = ( 0 === $count ) ? 'no-count' : 'count';
$nav_name = sprintf( __( 'Messages %s', 'buddypress' ), esc_attr( $class ), bp_core_number_format( $count ) );
- $bp->bp_nav[ $bp->messages->slug ]['name'] = $nav_name;
+ // Edit the Navigation name.
+ $bp->members->nav->edit_nav( array(
+ 'name' => $nav_name,
+ ), $bp->messages->slug );
/**
* Fires right before the loading of the Messages view screen template file.
diff --git src/bp-settings/bp-settings-actions.php src/bp-settings/bp-settings-actions.php
index f377ff6..6a68868 100644
--- src/bp-settings/bp-settings-actions.php
+++ src/bp-settings/bp-settings-actions.php
@@ -488,7 +488,7 @@ add_action( 'bp_actions', 'bp_settings_verify_email_change' );
*/
function bp_settings_remove_email_subnav() {
if ( ! has_action( 'bp_notification_settings' ) ) {
- bp_core_remove_subnav_item( BP_SETTINGS_SLUG, 'notifications' );
+ bp_core_delete_subnav_item( 'notifications', BP_SETTINGS_SLUG );
}
}
add_action( 'bp_actions', 'bp_settings_remove_email_subnav' );
diff --git src/bp-xprofile/classes/class-bp-xprofile-component.php src/bp-xprofile/classes/class-bp-xprofile-component.php
index a07929b..326465d 100644
--- src/bp-xprofile/classes/class-bp-xprofile-component.php
+++ src/bp-xprofile/classes/class-bp-xprofile-component.php
@@ -287,7 +287,7 @@ class BP_XProfile_Component extends BP_Component {
// Get the settings slug.
$settings_slug = bp_get_settings_slug();
- bp_core_new_subnav_item( array(
+ bp_core_add_subnav_item( array(
'name' => _x( 'Profile Visibility', 'Profile settings sub nav', 'buddypress' ),
'slug' => 'profile',
'parent_url' => trailingslashit( $user_domain . $settings_slug ),
@@ -295,7 +295,7 @@ class BP_XProfile_Component extends BP_Component {
'screen_function' => 'bp_xprofile_screen_settings',
'position' => 30,
'user_has_access' => bp_core_can_edit_settings()
- ) );
+ ), 'members' );
}
/**