Skip to:
Content

Changeset 10745


Ignore:
Timestamp:
05/12/16 17:19:06 (15 months ago)
Author:
boonebgorges
Message:

Introduce new API for BuddyPress navigation.

The new BP_Core_Nav overhauls the way that BuddyPress registers, stores, and
renders navigation items. Navigations are now component-specific, eliminating
the potential for confusion and conflict between navigation items with similar
names in different components, and opening the possibility of generating navs
for separate objects of the same type on a single pageload.

The new nav API replaces the old bp_nav and bp_options_nav system, which
dates from the earliest days of BuddyPress. These global properties were
responsible for handling nav and subnav across all of BP's components. The data
structure of bp_nav and bp_options_nav was simultaneously too opaque (in the
sense of being difficult to approach for developers and not having a complete
interface for programmatic modification) and too transparent (forcing devs to
manipulate the global arrays directly in order to customize navigation). The
new system eliminates most of these problems, by removing direct access to the
underlying navigation data, while providing a full-fledged API for accessing
and modifying that data.

An abstraction layer provides backward compatibility for most legacy uses of
bp_nav and bp_options_nav. Plugins that read data from the globals, modify
the data (eg $bp->bp_nav['foo']['name'] = 'Bar'), and unset nav items via
bp_nav and bp_options_nav should all continue to work as before. Anyone
accessing the globals in this way will see a _doing_it_wrong() notice. This
backward compatibility layer requires SPL (Standard PHP Library), which means
that it will not be enabled on certain configurations running PHP 5.2.x. (SPL
cannot be disabled in PHP 5.3+, and is on by default for earlier versions.)

The new system breaks backward compatibility in a number of small ways. Our
research suggests that these breaks will affect very few customizations, but
we list them here for posterity:

  • Some array functions, such as sort(), will no longer work to modify the nav globals.
  • Subnav items added to nonexistent parents can no longer be successfully registered. Previously, they could be loaded into the global, but were never displayed on the front end.
  • Manual management of group navigation items previously worked by passing the group slug as the parent_slug parameter to the bp_core_*_subnav_item() functions. The new API requires specifying a $component ('members', 'groups') when accessing nav items. To provide compatibility with legacy use - where $component was not required - we make some educated guesses about whether a nav item is "meant" to be attached to a group. This could result in unpredictable behavior in cases where a group slug clashes with a Members navigation item. This has always been broken - see #5103 - but may break in different ways after this changeset.

Props imath, boonebgorges, r-a-y.
Fixes #5103. Fixes #6534.

Location:
trunk
Files:
5 added
1 deleted
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bp-core/bp-core-buddybar.php

    r10497 r10745  
    1414 
    1515/** 
    16  * Add an item to the main BuddyPress navigation array. 
     16 * Add an item to the primary navigation of the specified component. 
    1717 * 
    1818 * @since 1.1.0 
     19 * @since 2.6.0 Introduced the `$component` parameter. 
     20 * 
     21 * @param array|string $args { 
     22 *     Array describing the new nav item. 
     23 *     @type string      $name                    Display name for the nav item. 
     24 *     @type string      $slug                    Unique URL slug for the nav item. 
     25 *     @type bool|string $item_css_id             Optional. 'id' attribute for the nav item. Default: the value of `$slug`. 
     26 *     @type bool        $show_for_displayed_user Optional. Whether the nav item should be visible when viewing a 
     27 *                                                member profile other than your own. Default: true. 
     28 *     @type bool        $site_admin_only         Optional. Whether the nav item should be visible only to site admins 
     29 *                                                (those with the 'bp_moderate' cap). Default: false. 
     30 *     @type int         $position                Optional. Numerical index specifying where the item should appear in 
     31 *                                                the nav array. Default: 99. 
     32 *     @type callable    $screen_function         The callback function that will run when the nav item is clicked. 
     33 *     @type bool|string $default_subnav_slug     Optional. The slug of the default subnav item to select when the nav 
     34 *                                                item is clicked. 
     35 * } 
     36 * @param string $component The component the navigation is attached to. Defaults to 'members'. 
     37 * @return bool|null Returns false on failure. 
     38 */ 
     39function bp_core_new_nav_item( $args, $component = 'members' ) { 
     40    if ( ! bp_is_active( $component ) ) { 
     41        return; 
     42    } 
     43 
     44    $defaults = array( 
     45        'name'                    => false, // Display name for the nav item. 
     46        'slug'                    => false, // URL slug for the nav item. 
     47        'item_css_id'             => false, // The CSS ID to apply to the HTML of the nav item. 
     48        'show_for_displayed_user' => true,  // When viewing another user does this nav item show up? 
     49        'site_admin_only'         => false, // Can only site admins see this nav item? 
     50        'position'                => 99,    // Index of where this nav item should be positioned. 
     51        'screen_function'         => false, // The name of the function to run when clicked. 
     52        'default_subnav_slug'     => false  // The slug of the default subnav item to select when clicked. 
     53    ); 
     54 
     55    $r = wp_parse_args( $args, $defaults ); 
     56 
     57    // Validate nav link data. 
     58    $nav_item = bp_core_create_nav_link( $r, $component ); 
     59 
     60    /* 
     61     * To mimic legacy behavior, if bp_core_create_nav_link() returns false, we make 
     62     * an early exit and don't attempt to register the screen function. 
     63     */ 
     64    if ( false === $nav_item ) { 
     65        return false; 
     66    } 
     67 
     68    // Then, hook the screen function for the added nav item. 
     69    $hooked = bp_core_register_nav_screen_function( $nav_item ); 
     70    if ( false === $hooked ){ 
     71        return false; 
     72    } 
     73 
     74    /** 
     75     * Fires after adding an item to the main BuddyPress navigation array. 
     76     * Note that, when possible, the more specific action hooks 
     77     * `bp_core_create_nav_link` or `bp_core_register_nav_screen_function` 
     78     * should be used. 
     79     * 
     80     * @since 1.5.0 
     81     * 
     82     * @param array $r        Parsed arguments for the nav item. 
     83     * @param array $args     Originally passed in arguments for the nav item. 
     84     * @param array $defaults Default arguments for a nav item. 
     85     */ 
     86    do_action( 'bp_core_new_nav_item', $r, $args, $defaults ); 
     87} 
     88 
     89/** 
     90 * Add a link to the main BuddyPress navigation. 
     91 * 
     92 * @since 2.4.0 
     93 * @since 2.6.0 Introduced the `$component` parameter. Began returning a BP_Nav_Item object on success. 
     94 * 
     95 * @param array|string $args { 
     96 *     Array describing the new nav item. 
     97 *     @type string      $name                    Display name for the nav item. 
     98 *     @type string      $slug                    Unique URL slug for the nav item. 
     99 *     @type bool|string $item_css_id             Optional. 'id' attribute for the nav item. Default: the value of `$slug`. 
     100 *     @type bool        $show_for_displayed_user Optional. Whether the nav item should be visible when viewing a 
     101 *                                                member profile other than your own. Default: true. 
     102 *     @type bool        $site_admin_only         Optional. Whether the nav item should be visible only to site admins 
     103 *                                                (those with the 'bp_moderate' cap). Default: false. 
     104 *     @type int         $position                Optional. Numerical index specifying where the item should appear in 
     105 *                                                the nav array. Default: 99. 
     106 *     @type callable    $screen_function         The callback function that will run when the nav item is clicked. 
     107 *     @type bool|string $default_subnav_slug     Optional. The slug of the default subnav item to select when the nav 
     108 *                                                item is clicked. 
     109 * } 
     110 * @param string $component Optional. Component that the nav belongs to. 
     111 * @return bool|BP_Nav_Item Returns false on failure, new nav item on success. 
     112 */ 
     113function bp_core_create_nav_link( $args = '', $component = 'members' ) { 
     114    $bp = buddypress(); 
     115 
     116    $defaults = array( 
     117        'name'                    => false, // Display name for the nav item. 
     118        'slug'                    => false, // URL slug for the nav item. 
     119        'item_css_id'             => false, // The CSS ID to apply to the HTML of the nav item. 
     120        'show_for_displayed_user' => true,  // When viewing another user does this nav item show up? 
     121        'site_admin_only'         => false, // Can only site admins see this nav item? 
     122        'position'                => 99,    // Index of where this nav item should be positioned. 
     123        'screen_function'         => false, // The name of the function to run when clicked. 
     124        'default_subnav_slug'     => false  // The slug of the default subnav item to select when clicked. 
     125    ); 
     126 
     127    $r = wp_parse_args( $args, $defaults ); 
     128 
     129    // If we don't have the required info we need, don't create this nav item. 
     130    if ( empty( $r['name'] ) || empty( $r['slug'] ) ) { 
     131        return false; 
     132    } 
     133 
     134    // If this is for site admins only and the user is not one, don't create the nav item. 
     135    if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) { 
     136        return false; 
     137    } 
     138 
     139    if ( empty( $r['item_css_id'] ) ) { 
     140        $r['item_css_id'] = $r['slug']; 
     141    } 
     142 
     143    $nav_item = array( 
     144        'name'                    => $r['name'], 
     145        'slug'                    => $r['slug'], 
     146        'link'                    => trailingslashit( bp_loggedin_user_domain() . $r['slug'] ), 
     147        'css_id'                  => $r['item_css_id'], 
     148        'show_for_displayed_user' => $r['show_for_displayed_user'], 
     149        'position'                => $r['position'], 
     150        'screen_function'         => &$r['screen_function'], 
     151        'default_subnav_slug'     => $r['default_subnav_slug'] 
     152    ); 
     153 
     154    // Add the item to the nav. 
     155    $retval = buddypress()->{$component}->nav->add_nav( $nav_item ); 
     156 
     157    /** 
     158     * Fires after a link is added to the main BuddyPress nav. 
     159     * 
     160     * @since 2.4.0 
     161     * @since 2.6.0 Added `$component` parameter. 
     162     * 
     163     * @param array  $r         Parsed arguments for the nav item. 
     164     * @param array  $args      Originally passed in arguments for the nav item. 
     165     * @param array  $defaults  Default arguments for a nav item. 
     166     * @param string $component Component that the nav belongs to. 
     167     */ 
     168    do_action( 'bp_core_create_nav_link', $r, $args, $defaults, $component ); 
     169 
     170    return $retval; 
     171} 
     172 
     173/** 
     174 * Register a screen function for an item in the main nav array. 
     175 * 
     176 * @since 2.4.0 
    19177 * 
    20178 * @param array|string $args { 
     
    35193 * @return bool|null Returns false on failure. 
    36194 */ 
    37 function bp_core_new_nav_item( $args = '' ) { 
    38  
    39     $defaults = array( 
    40         'name'                    => false, // Display name for the nav item. 
    41         'slug'                    => false, // URL slug for the nav item. 
    42         'item_css_id'             => false, // The CSS ID to apply to the HTML of the nav item. 
    43         'show_for_displayed_user' => true,  // When viewing another user does this nav item show up? 
    44         'site_admin_only'         => false, // Can only site admins see this nav item? 
    45         'position'                => 99,    // Index of where this nav item should be positioned. 
    46         'screen_function'         => false, // The name of the function to run when clicked. 
    47         'default_subnav_slug'     => false  // The slug of the default subnav item to select when clicked. 
    48     ); 
    49  
    50     $r = wp_parse_args( $args, $defaults ); 
    51  
    52     // First, add the nav item link to the bp_nav array. 
    53     $created = bp_core_create_nav_link( $r ); 
    54  
    55     // To mimic the existing behavior, if bp_core_create_nav_link() 
    56     // returns false, we make an early exit and don't attempt to register 
    57     // the screen function. 
    58     if ( false === $created ) { 
    59         return false; 
    60     } 
    61  
    62     // Then, hook the screen function for the added nav item. 
    63     $hooked = bp_core_register_nav_screen_function( $r ); 
    64     if ( false === $hooked ){ 
    65         return false; 
    66     } 
    67  
    68     /** 
    69      * Fires after adding an item to the main BuddyPress navigation array. 
    70      * Note that, when possible, the more specific action hooks 
    71      * `bp_core_create_nav_link` or `bp_core_register_nav_screen_function` 
    72      * should be used. 
    73      * 
    74      * @since 1.5.0 
    75      * 
    76      * @param array $r        Parsed arguments for the nav item. 
    77      * @param array $args     Originally passed in arguments for the nav item. 
    78      * @param array $defaults Default arguments for a nav item. 
    79      */ 
    80     do_action( 'bp_core_new_nav_item', $r, $args, $defaults ); 
    81 } 
    82  
    83 /** 
    84  * Add a link to the main BuddyPress navigation array. 
    85  * 
    86  * @since 2.4.0 
    87  * 
    88  * @param array|string $args { 
    89  *     Array describing the new nav item. 
    90  *     @type string      $name                    Display name for the nav item. 
    91  *     @type string      $slug                    Unique URL slug for the nav item. 
    92  *     @type bool|string $item_css_id             Optional. 'id' attribute for the nav item. Default: the value of `$slug`. 
    93  *     @type bool        $show_for_displayed_user Optional. Whether the nav item should be visible when viewing a 
    94  *                                                member profile other than your own. Default: true. 
    95  *     @type bool        $site_admin_only         Optional. Whether the nav item should be visible only to site admins 
    96  *                                                (those with the 'bp_moderate' cap). Default: false. 
    97  *     @type int         $position                Optional. Numerical index specifying where the item should appear in 
    98  *                                                the nav array. Default: 99. 
    99  *     @type callable    $screen_function         The callback function that will run when the nav item is clicked. 
    100  *     @type bool|string $default_subnav_slug     Optional. The slug of the default subnav item to select when the nav 
    101  *                                                item is clicked. 
    102  * } 
    103  * @return bool|null Returns false on failure. 
    104  */ 
    105 function bp_core_create_nav_link( $args = '' ) { 
    106     $bp = buddypress(); 
    107  
    108     $defaults = array( 
    109         'name'                    => false, // Display name for the nav item. 
    110         'slug'                    => false, // URL slug for the nav item. 
    111         'item_css_id'             => false, // The CSS ID to apply to the HTML of the nav item. 
    112         'show_for_displayed_user' => true,  // When viewing another user does this nav item show up? 
    113         'site_admin_only'         => false, // Can only site admins see this nav item? 
    114         'position'                => 99,    // Index of where this nav item should be positioned. 
    115         'screen_function'         => false, // The name of the function to run when clicked. 
    116         'default_subnav_slug'     => false  // The slug of the default subnav item to select when clicked. 
    117     ); 
    118  
    119     $r = wp_parse_args( $args, $defaults ); 
    120  
    121     // If we don't have the required info we need, don't create this nav item. 
    122     if ( empty( $r['name'] ) || empty( $r['slug'] ) ) { 
    123         return false; 
    124     } 
    125  
    126     // If this is for site admins only and the user is not one, don't create the nav item. 
    127     if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) { 
    128         return false; 
    129     } 
    130  
    131     if ( empty( $r['item_css_id'] ) ) { 
    132         $r['item_css_id'] = $r['slug']; 
    133     } 
    134  
    135     $bp->bp_nav[$r['slug']] = array( 
    136         'name'                    => $r['name'], 
    137         'slug'                    => $r['slug'], 
    138         'link'                    => trailingslashit( bp_loggedin_user_domain() . $r['slug'] ), 
    139         'css_id'                  => $r['item_css_id'], 
    140         'show_for_displayed_user' => $r['show_for_displayed_user'], 
    141         'position'                => $r['position'], 
    142         'screen_function'         => &$r['screen_function'], 
    143         'default_subnav_slug'     => $r['default_subnav_slug'] 
    144     ); 
    145  
    146     /** 
    147      * Fires after a link is added to the main BuddyPress navigation array. 
    148      * 
    149      * @since 2.4.0 
    150      * 
    151      * @param array $r        Parsed arguments for the nav item. 
    152      * @param array $args     Originally passed in arguments for the nav item. 
    153      * @param array $defaults Default arguments for a nav item. 
    154      */ 
    155     do_action( 'bp_core_create_nav_link', $r, $args, $defaults ); 
    156 } 
    157  
    158 /** 
    159  * Register a screen function for an item in the main nav array. 
    160  * 
    161  * @since 2.4.0 
    162  * 
    163  * @param array|string $args { 
    164  *     Array describing the new nav item. 
    165  *     @type string      $name                    Display name for the nav item. 
    166  *     @type string      $slug                    Unique URL slug for the nav item. 
    167  *     @type bool|string $item_css_id             Optional. 'id' attribute for the nav item. Default: the value of `$slug`. 
    168  *     @type bool        $show_for_displayed_user Optional. Whether the nav item should be visible when viewing a 
    169  *                                                member profile other than your own. Default: true. 
    170  *     @type bool        $site_admin_only         Optional. Whether the nav item should be visible only to site admins 
    171  *                                                (those with the 'bp_moderate' cap). Default: false. 
    172  *     @type int         $position                Optional. Numerical index specifying where the item should appear in 
    173  *                                                the nav array. Default: 99. 
    174  *     @type callable    $screen_function         The callback function that will run when the nav item is clicked. 
    175  *     @type bool|string $default_subnav_slug     Optional. The slug of the default subnav item to select when the nav 
    176  *                                                item is clicked. 
    177  * } 
    178  * @return bool|null Returns false on failure. 
    179  */ 
    180195function bp_core_register_nav_screen_function( $args = '' ) { 
    181196    $bp = buddypress(); 
     
    291306    $r = wp_parse_args( $args, $defaults ); 
    292307 
    293     if ( $function = $bp->bp_nav[$r['parent_slug']]['screen_function'] ) { 
     308    // This is specific to Members - it's not available in Groups. 
     309    $parent_nav = $bp->members->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false ); 
     310 
     311    if ( ! $parent_nav ) { 
     312        return ; 
     313    } 
     314 
     315    $parent_nav = reset( $parent_nav ); 
     316 
     317    if ( ! empty( $parent_nav->screen_function ) ) { 
    294318        // Remove our screen hook if screen function is callable. 
    295         if ( is_callable( $function ) ) { 
    296             remove_action( 'bp_screens', $function, 3 ); 
    297         } 
    298     } 
    299  
    300     $bp->bp_nav[$r['parent_slug']]['screen_function'] = &$r['screen_function']; 
    301  
    302     if ( bp_is_current_component( $r['parent_slug'] ) ) { 
     319        if ( is_callable( $parent_nav->screen_function ) ) { 
     320            remove_action( 'bp_screens', $parent_nav->screen_function, 3 ); 
     321        } 
     322    } 
     323 
     324    // Edit the screen function for the parent nav 
     325    $bp->members->nav->edit_nav( array( 
     326        'screen_function'     => &$r['screen_function'], 
     327        'default_subnav_slug' => $r['subnav_slug'], 
     328    ), $parent_nav->slug ); 
     329 
     330    if ( bp_is_current_component( $parent_nav->slug ) ) { 
    303331 
    304332        // The only way to tell whether to set the subnav is to peek at the unfiltered_uri 
    305333        // Find the component. 
    306         $component_uri_key = array_search( $r['parent_slug'], $bp->unfiltered_uri ); 
     334        $component_uri_key = array_search( $parent_nav->slug, $bp->unfiltered_uri ); 
    307335 
    308336        if ( false !== $component_uri_key ) { 
     
    340368 
    341369/** 
    342  * Sort the navigation menu items. 
    343  * 
    344  * The sorting is split into a separate function because it can only happen 
    345  * after all plugins have had a chance to register their navigation items. 
    346  * 
    347  * @since 1.0.0 
    348  * 
    349  * @return bool|null Returns false on failure. 
    350  */ 
    351 function bp_core_sort_nav_items() { 
    352     $bp = buddypress(); 
    353  
    354     if ( empty( $bp->bp_nav ) || ! is_array( $bp->bp_nav ) ) { 
    355         return false; 
    356     } 
    357  
    358     $temp = array(); 
    359  
    360     foreach ( (array) $bp->bp_nav as $slug => $nav_item ) { 
    361         if ( empty( $temp[$nav_item['position']] ) ) { 
    362             $temp[$nav_item['position']] = $nav_item; 
    363         } else { 
    364             // Increase numbers here to fit new items in. 
    365             do { 
    366                 $nav_item['position']++; 
    367             } while ( ! empty( $temp[$nav_item['position']] ) ); 
    368  
    369             $temp[$nav_item['position']] = $nav_item; 
    370         } 
    371     } 
    372  
    373     ksort( $temp ); 
    374     $bp->bp_nav = &$temp; 
    375 } 
    376 add_action( 'wp_head',    'bp_core_sort_nav_items' ); 
    377 add_action( 'admin_head', 'bp_core_sort_nav_items' ); 
    378  
    379 /** 
    380  * Add a subnav item to the BuddyPress navigation. 
     370 * Add an item to secondary navigation of the specified component. 
    381371 * 
    382372 * @since 1.1.0 
     373 * @since 2.6.0 Introduced the `$component` parameter. 
    383374 * 
    384375 * @param array|string $args { 
     
    404395 *                                          Admin Bar menu for group admins. Default: false. 
    405396 * } 
     397 * @param string $component The component the navigation is attached to. Defaults to 'members'. 
    406398 * @return bool|null Returns false on failure. 
    407399 */ 
    408 function bp_core_new_subnav_item( $args = '' ) { 
    409  
    410     // First, add the subnav item link to the bp_options_nav array. 
    411     $created = bp_core_create_subnav_link( $args ); 
    412  
    413     // To mimic the existing behavior, if bp_core_create_subnav_link() 
    414     // returns false, we make an early exit and don't attempt to register 
    415     // the screen function. 
    416     if ( false === $created ) { 
     400function bp_core_new_subnav_item( $args, $component = null ) { 
     401    // Backward compatibility for plugins using `bp_core_new_subnav_item()` without `$component` 
     402    // to add group subnav items. 
     403    if ( null === $component && bp_is_active( 'groups' ) && bp_is_group() && isset( $args['parent_slug'] ) ) { 
     404        /* 
     405         * Assume that this item is intended to belong to the current group if: 
     406         * a) the 'parent_slug' is the same as the slug of the current group, or 
     407         * b) the 'parent_slug' starts with the slug of the current group, and the members nav doesn't have 
     408         *    a primary item with that slug 
     409         */ 
     410        $group_slug = bp_get_current_group_slug(); 
     411        if ( 
     412            $group_slug === $args['parent_slug'] || 
     413            ( 0 === strpos( $args['parent_slug'], $group_slug ) && ! buddypress()->members->nav->get_primary( array( 'slug' => $args['parent_slug'] ), false ) ) 
     414        ) { 
     415            $component = 'groups'; 
     416        } 
     417    } 
     418 
     419    if ( ! $component ) { 
     420        $component = 'members'; 
     421    } 
     422 
     423    if ( ! bp_is_active( $component ) ) { 
     424        return; 
     425    } 
     426 
     427    // First, register the subnav item in the nav. 
     428    $subnav_item = bp_core_create_subnav_link( $args, $component ); 
     429 
     430    /* 
     431     * To mimic legacy behavior, if bp_core_create_subnav_link() returns false, we make an 
     432     * early exit and don't attempt to register the screen function. 
     433     */ 
     434    if ( false === $subnav_item ) { 
    417435        return false; 
    418436    } 
    419437 
    420438    // Then, hook the screen function for the added subnav item. 
    421     $hooked = bp_core_register_subnav_screen_function( $args ); 
     439    $hooked = bp_core_register_subnav_screen_function( $subnav_item, $component ); 
    422440    if ( false === $hooked ) { 
    423441        return false; 
     
    429447 * 
    430448 * @since 2.4.0 
     449 * @since 2.6.0 Introduced the `$component` parameter. Began returning a BP_Nav_Item object on success. 
    431450 * 
    432451 * @param array|string $args { 
     
    456475 *                                          Default: false. 
    457476 * } 
    458  * @return bool|null Returns false on failure. 
    459  */ 
    460 function bp_core_create_subnav_link( $args = '' ) { 
     477 * @param string $component The component the navigation is attached to. Defaults to 'members'. 
     478 * @return bool|BP_Nav_Item Returns false on failure, new nav item on success. 
     479 */ 
     480function bp_core_create_subnav_link( $args = '', $component = 'members' ) { 
    461481    $bp = buddypress(); 
    462482 
     
    484504        $r['link'] = trailingslashit( $r['parent_url'] . $r['slug'] ); 
    485505 
     506        $parent_nav = $bp->{$component}->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false ); 
     507 
    486508        // If this sub item is the default for its parent, skip the slug. 
    487         if ( ! empty( $bp->bp_nav[$r['parent_slug']]['default_subnav_slug'] ) && $r['slug'] == $bp->bp_nav[$r['parent_slug']]['default_subnav_slug'] ) { 
    488             $r['link'] = trailingslashit( $r['parent_url'] ); 
     509        if ( $parent_nav ) { 
     510            $parent_nav_item = reset( $parent_nav ); 
     511            if ( ! empty( $parent_nav_item->default_subnav_slug ) && $r['slug'] === $parent_nav_item->default_subnav_slug ) { 
     512                $r['link'] = trailingslashit( $r['parent_url'] ); 
     513            } 
    489514        } 
    490515    } 
     
    503528        'link'              => $r['link'], 
    504529        'slug'              => $r['slug'], 
     530        'parent_slug'       => $r['parent_slug'], 
    505531        'css_id'            => $r['item_css_id'], 
    506532        'position'          => $r['position'], 
     
    511537    ); 
    512538 
    513     $bp->bp_options_nav[$r['parent_slug']][$r['slug']] = $subnav_item; 
     539    return buddypress()->{$component}->nav->add_nav( $subnav_item ); 
    514540} 
    515541 
     
    518544 * 
    519545 * @since 2.4.0 
     546 * @since 2.6.0 Introduced the `$component` parameter. 
    520547 * 
    521548 * @param array|string $args { 
     
    542569 *                                       Default: false. 
    543570 * } 
     571 * @param string $component The component the navigation is attached to. Defaults to 'members'. 
    544572 * @return bool|null Returns false on failure. 
    545573 */ 
    546 function bp_core_register_subnav_screen_function( $args = '' ) { 
     574function bp_core_register_subnav_screen_function( $args = '', $component = 'members' ) { 
    547575    $bp = buddypress(); 
    548576 
     
    556584    ) ); 
    557585 
    558     /** 
     586    /* 
    559587     * Hook the screen function for the added subnav item. But this only needs to 
    560588     * be done if this subnav item is the current view, and the user has access to the 
     
    569597     *       and this subnav item is the default for the parent item (which we check by 
    570598     *       comparing this subnav item's screen function with the screen function of the 
    571      *       parent nav item in $bp->bp_nav). This condition only arises when viewing a 
    572      *       user, since groups should always have an action set. 
     599     *       parent nav item in the component's primary nav). This condition only arises 
     600     *       when viewing a user, since groups should always have an action set. 
    573601     */ 
    574602 
     
    578606    } 
    579607 
     608    $parent_nav = $bp->{$component}->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false ); 
     609 
    580610    // If we *do* meet condition (2), then the added subnav item is currently being requested. 
    581     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'] ) ) ) { 
     611    if ( ( bp_current_action() && bp_is_current_action( $r['slug'] ) ) || ( bp_is_user() && ! bp_current_action() && ! empty( $parent_nav->screen_function ) && $r['screen_function'] == $parent_nav->screen_function ) ) { 
    582612 
    583613        // If this is for site admins only and the user is not one, don't create the subnav item. 
     
    586616        } 
    587617 
    588         $hooked = bp_core_maybe_hook_new_subnav_screen_function( $r ); 
     618        $hooked = bp_core_maybe_hook_new_subnav_screen_function( $r, $component ); 
    589619 
    590620        // If redirect args have been returned, perform the redirect now. 
     
    599629 * 
    600630 * @since 2.1.0 
    601  * 
    602  * @param array $subnav_item The subnav array added to bp_options_nav in `bp_core_new_subnav_item()`. 
     631 * @since 2.6.0 Introduced the `$component` parameter. 
     632 * 
     633 * @param array  $subnav_item The subnav array added to the secondary navigation of 
     634 *                            the component in bp_core_new_subnav_item(). 
     635 * @param string $component   The component the navigation is attached to. Defaults to 'members'. 
    603636 * @return array 
    604637 */ 
    605 function bp_core_maybe_hook_new_subnav_screen_function( $subnav_item ) { 
     638function bp_core_maybe_hook_new_subnav_screen_function( $subnav_item, $component = 'members' ) { 
    606639    $retval = array( 
    607640        'status' => '', 
     
    646679            } elseif ( bp_is_user() ) { 
    647680 
     681                $parent_nav_default = $bp->{$component}->nav->get_primary( array( 'slug' => $bp->default_component ), false ); 
     682                if ( $parent_nav_default ) { 
     683                    $parent_nav_default_item = reset( $parent_nav_default ); 
     684                } 
     685 
    648686                // Redirect to the displayed user's default 
    649687                // component, as long as that component is 
    650688                // publicly accessible. 
    651                 if ( bp_is_my_profile() || ! empty( $bp->bp_nav[ $bp->default_component ]['show_for_displayed_user'] ) ) { 
     689                if ( bp_is_my_profile() || ( isset( $parent_nav_default_item ) && $parent_nav_default_item->show_for_displayed_user ) ) { 
    652690                    $message     = __( 'You do not have access to this page.', 'buddypress' ); 
    653691                    $redirect_to = bp_displayed_user_domain(); 
     
    692730 
    693731/** 
    694  * Sort all subnavigation arrays. 
    695  * 
    696  * @since 1.1.0 
    697  * 
    698  * @return bool|null Returns false on failure. 
    699  */ 
    700 function bp_core_sort_subnav_items() { 
     732 * Check whether a given nav item has subnav items. 
     733 * 
     734 * @since 1.5.0 
     735 * @since 2.6.0 Introduced the `$component` parameter. 
     736 * 
     737 * @param string $nav_item  The slug of the top-level nav item whose subnav items you're checking. 
     738 *                          Default: the current component slug. 
     739 * @param string $component The component the navigation is attached to. Defaults to 'members'. 
     740 * @return bool $has_subnav True if the nav item is found and has subnav items; false otherwise. 
     741 */ 
     742function bp_nav_item_has_subnav( $nav_item = '', $component = 'members' ) { 
    701743    $bp = buddypress(); 
    702744 
    703     if ( empty( $bp->bp_options_nav ) || !is_array( $bp->bp_options_nav ) ) 
    704         return false; 
    705  
    706     foreach ( (array) $bp->bp_options_nav as $parent_slug => $subnav_items ) { 
    707         if ( !is_array( $subnav_items ) ) 
    708             continue; 
    709  
    710         foreach ( (array) $subnav_items as $subnav_item ) { 
    711             if ( empty( $temp[$subnav_item['position']]) ) 
    712                 $temp[$subnav_item['position']] = $subnav_item; 
    713             else { 
    714                 // Increase numbers here to fit new items in. 
    715                 do { 
    716                     $subnav_item['position']++; 
    717                 } while ( !empty( $temp[$subnav_item['position']] ) ); 
    718  
    719                 $temp[$subnav_item['position']] = $subnav_item; 
    720             } 
    721         } 
    722         ksort( $temp ); 
    723         $bp->bp_options_nav[$parent_slug] = &$temp; 
    724         unset( $temp ); 
    725     } 
    726 } 
    727 add_action( 'wp_head',    'bp_core_sort_subnav_items' ); 
    728 add_action( 'admin_head', 'bp_core_sort_subnav_items' ); 
    729  
    730 /** 
    731  * Check whether a given nav item has subnav items. 
    732  * 
    733  * @since 1.5.0 
    734  * 
    735  * @param string $nav_item The slug of the top-level nav item whose subnav items you're checking. 
    736  *                         Default: the current component slug. 
    737  * @return bool $has_subnav True if the nav item is found and has subnav items; false otherwise. 
    738  */ 
    739 function bp_nav_item_has_subnav( $nav_item = '' ) { 
    740     $bp = buddypress(); 
    741  
    742     if ( !$nav_item ) 
     745    if ( ! isset( $bp->{$component}->nav ) ) { 
     746        return false; 
     747    } 
     748 
     749    if ( ! $nav_item ) { 
    743750        $nav_item = bp_current_component(); 
    744751 
    745     $has_subnav = isset( $bp->bp_options_nav[$nav_item] ) && count( $bp->bp_options_nav[$nav_item] ) > 0; 
     752        if ( bp_is_group() ) { 
     753            $nav_item = bp_current_item(); 
     754        } 
     755    } 
     756 
     757    $has_subnav = (bool) $bp->{$component}->nav->get_secondary( array( 'parent_slug' => $nav_item ), false ); 
    746758 
    747759    /** 
     
    757769 
    758770/** 
    759  * Remove a nav item from the navigation array. 
     771 * Deletes an item from the primary navigation of the specified component. 
    760772 * 
    761773 * @since 1.0.0 
    762  * 
    763  * @param int $parent_id The slug of the parent navigation item. 
    764  * @return bool Returns false on failure, ie if the nav item can't be found. 
    765  */ 
    766 function bp_core_remove_nav_item( $parent_id ) { 
     774 * @since 2.6.0 Introduced the `$component` parameter. 
     775 * 
     776 * @param string $slug      The slug of the primary navigation item. 
     777 * @param string $component The component the navigation is attached to. Defaults to 'members'. 
     778 * @return bool Returns false on failure, True on success. 
     779 */ 
     780function bp_core_remove_nav_item( $slug, $component = null ) { 
    767781    $bp = buddypress(); 
    768782 
    769     // Unset subnav items for this nav item. 
    770     if ( isset( $bp->bp_options_nav[$parent_id] ) && is_array( $bp->bp_options_nav[$parent_id] ) ) { 
    771         foreach( (array) $bp->bp_options_nav[$parent_id] as $subnav_item ) { 
    772             bp_core_remove_subnav_item( $parent_id, $subnav_item['slug'] ); 
    773         } 
    774     } 
    775  
    776     if ( empty( $bp->bp_nav[ $parent_id ] ) ) 
    777         return false; 
    778  
    779     if ( $function = $bp->bp_nav[$parent_id]['screen_function'] ) { 
    780         // Remove our screen hook if screen function is callable. 
    781         if ( is_callable( $function ) ) { 
    782             remove_action( 'bp_screens', $function, 3 ); 
    783         } 
    784     } 
    785  
    786     unset( $bp->bp_nav[$parent_id] ); 
    787 } 
    788  
    789 /** 
    790  * Remove a subnav item from the navigation array. 
    791  * 
    792  * @since 1.0.0 
    793  * 
    794  * @param string $parent_id The slug of the parent navigation item. 
    795  * @param string $slug      The slug of the subnav item to be removed. 
    796  */ 
    797 function bp_core_remove_subnav_item( $parent_id, $slug ) { 
    798     $bp = buddypress(); 
    799  
    800     $screen_function = isset( $bp->bp_options_nav[$parent_id][$slug]['screen_function'] ) 
    801         ? $bp->bp_options_nav[$parent_id][$slug]['screen_function'] 
    802         : false; 
    803  
    804     if ( ! empty( $screen_function ) ) { 
     783    // Backward compatibility for removing group nav items using the group slug as `$parent_slug`. 
     784    if ( ! $component && bp_is_active( 'groups' ) && isset( $bp->groups->nav ) ) { 
     785        if ( $bp->groups->nav->get_primary( array( 'slug' => $slug ) ) ) { 
     786            return bp_core_remove_nav_item( $slug, 'groups' ); 
     787        } 
     788    } 
     789 
     790    if ( ! $component ) { 
     791        $component = 'members'; 
     792    } 
     793 
     794    if ( ! isset( $bp->{$component}->nav ) ) { 
     795        return false; 
     796    } 
     797 
     798    $screen_functions = $bp->{$component}->nav->delete_nav( $slug ); 
     799 
     800    // Reset backcompat nav items so that subsequent references will be correct. 
     801    if ( buddypress()->do_nav_backcompat ) { 
     802        $bp->bp_nav->reset(); 
     803        $bp->bp_options_nav->reset(); 
     804    } 
     805 
     806    if ( ! is_array( $screen_functions ) ) { 
     807        return false; 
     808    } 
     809 
     810    foreach ( $screen_functions as $screen_function ) { 
    805811        // Remove our screen hook if screen function is callable. 
    806812        if ( is_callable( $screen_function ) ) { 
     
    809815    } 
    810816 
    811     unset( $bp->bp_options_nav[$parent_id][$slug] ); 
    812  
    813     if ( isset( $bp->bp_options_nav[$parent_id] ) && !count( $bp->bp_options_nav[$parent_id] ) ) 
    814         unset($bp->bp_options_nav[$parent_id]); 
     817    return true; 
     818} 
     819 
     820/** 
     821 * Deletes an item from the secondary navigation of the specified component. 
     822 * 
     823 * @since 1.0.0 
     824 * @since 2.6.0 Introduced the `$component` parameter. 
     825 * 
     826 * @param string $parent_slug The slug of the primary navigation item. 
     827 * @param string $slug        The slug of the secondary item to be removed. 
     828 * @param string $component   The component the navigation is attached to. Defaults to 'members'. 
     829 * @return bool Returns false on failure, True on success. 
     830 */ 
     831function bp_core_remove_subnav_item( $parent_slug, $slug, $component = null ) { 
     832    $bp = buddypress(); 
     833 
     834    // Backward compatibility for removing group nav items using the group slug as `$parent_slug`. 
     835    if ( ! $component && bp_is_active( 'groups' ) && isset( $bp->groups->nav ) ) { 
     836        if ( $bp->groups->nav->get_primary( array( 'slug' => $parent_slug ) ) ) { 
     837            return bp_core_remove_subnav_item( $slug, $parent_slug, 'groups' ); 
     838        } 
     839    } 
     840 
     841    if ( ! $component ) { 
     842        $component = 'members'; 
     843    } 
     844 
     845    if ( ! isset( $bp->{$component}->nav ) ) { 
     846        return false; 
     847    } 
     848 
     849    $screen_functions = $bp->{$component}->nav->delete_nav( $slug, $parent_slug ); 
     850 
     851    // Reset backcompat nav items so that subsequent references will be correct. 
     852    if ( buddypress()->do_nav_backcompat ) { 
     853        $bp->bp_nav->reset(); 
     854        $bp->bp_options_nav->reset(); 
     855    } 
     856 
     857    if ( ! is_array( $screen_functions ) ) { 
     858        return false; 
     859    } 
     860 
     861    $screen_function = reset( $screen_functions ); 
     862 
     863    // Remove our screen hook if screen function is callable. 
     864    if ( is_callable( $screen_function ) ) { 
     865        remove_action( 'bp_screens', $screen_function, 3 ); 
     866    } 
     867 
     868    return true; 
    815869} 
    816870 
     
    819873 * 
    820874 * @since 1.0.0 
     875 * @since 2.6.0 Introduced the `$component` parameter. 
    821876 * 
    822877 * @param string $parent_slug The slug of the parent navigation item. 
    823  */ 
    824 function bp_core_reset_subnav_items( $parent_slug ) { 
     878 * @param string $component   The component the navigation is attached to. Defaults to 'members'. 
     879 */ 
     880function bp_core_reset_subnav_items( $parent_slug, $component = 'members' ) { 
    825881    $bp = buddypress(); 
    826882 
    827     unset( $bp->bp_options_nav[$parent_slug] ); 
     883    if ( ! isset( $bp->{$component}->nav ) ) { 
     884        return; 
     885    } 
     886 
     887    $subnav_items = $bp->{$component}->nav->get_secondary( array( 'parent_slug' => $parent_slug ), false ); 
     888 
     889    if ( ! $subnav_items ) { 
     890        return; 
     891    } 
     892 
     893    foreach( $subnav_items as $subnav_item ) { 
     894        $bp->{$component}->nav->delete_nav( $subnav_item->slug, $parent_slug ); 
     895    } 
    828896} 
    829897 
  • trunk/src/bp-core/bp-core-classes.php

    r10514 r10745  
    3131require dirname( __FILE__ ) . '/classes/class-bp-email-delivery.php'; 
    3232require dirname( __FILE__ ) . '/classes/class-bp-phpmailer.php'; 
     33require dirname( __FILE__ ) . '/classes/class-bp-core-nav.php'; 
     34require dirname( __FILE__ ) . '/classes/class-bp-core-nav-item.php'; 
     35 
     36if ( buddypress()->do_nav_backcompat ) { 
     37    require dirname( __FILE__ ) . '/classes/class-bp-core-bp-nav-backcompat.php'; 
     38    require dirname( __FILE__ ) . '/classes/class-bp-core-bp-options-nav-backcompat.php'; 
     39} 
  • trunk/src/bp-core/bp-core-functions.php

    r10726 r10745  
    24442444    } 
    24452445 
    2446     // Pull up a list of items registered in BP's top-level nav array. 
    2447     $bp_menu_items = buddypress()->bp_nav; 
    2448  
    2449     // Alphabetize. 
    2450     $bp_menu_items = bp_alpha_sort_by_key( $bp_menu_items, 'name' ); 
     2446    // Pull up a list of items registered in BP's primary nav for the member. 
     2447    $bp_menu_items = buddypress()->members->nav->get_primary(); 
    24512448 
    24522449    // Some BP nav menu items will not be represented in bp_nav, because 
     
    25762573 * 
    25772574 * @param string $slug The slug of the nav item: login, register, or one of the 
    2578  *                     slugs from buddypress()->bp_nav. 
     2575 *                     slugs from the members navigation. 
    25792576 * @return string $nav_item_url The URL generated for the current user. 
    25802577 */ 
  • trunk/src/bp-core/bp-core-template.php

    r10693 r10745  
    1414 * Output the "options nav", the secondary-level single item navigation menu. 
    1515 * 
    16  * Uses the $bp->bp_options_nav global to render out the sub navigation for the 
     16 * Uses the component's nav global to render out the sub navigation for the 
    1717 * current component. Each component adds to its sub navigation array within 
    1818 * its own setup_nav() function. 
     
    4141    $selected_item   = bp_current_action(); 
    4242 
     43    // Default to the Members nav. 
    4344    if ( ! bp_is_single_item() ) { 
    44         if ( !isset( $bp->bp_options_nav[$component_index] ) || count( $bp->bp_options_nav[$component_index] ) < 1 ) { 
     45        // Set the parent slug, if not provided. 
     46        if ( empty( $parent_slug ) ) { 
     47            $parent_slug = $component_index; 
     48        } 
     49 
     50        $secondary_nav_items = $bp->members->nav->get_secondary( array( 'parent_slug' => $parent_slug ) ); 
     51 
     52        if ( ! $secondary_nav_items ) { 
    4553            return false; 
    46         } else { 
    47             $the_index = $component_index; 
    48         } 
     54        } 
     55 
     56    // For a single item, try to use the component's nav. 
    4957    } else { 
    5058        $current_item = bp_current_item(); 
    51  
     59        $single_item_component = bp_current_component(); 
     60 
     61        // Adjust the selected nav item for the current single item if needed. 
    5262        if ( ! empty( $parent_slug ) ) { 
    5363            $current_item  = $parent_slug; 
     
    5565        } 
    5666 
    57         if ( !isset( $bp->bp_options_nav[$current_item] ) || count( $bp->bp_options_nav[$current_item] ) < 1 ) { 
     67        // If the nav is not defined by the parent component, look in the Members nav. 
     68        if ( ! isset( $bp->{$single_item_component}->nav ) ) { 
     69            $secondary_nav_items = $bp->members->nav->get_secondary( array( 'parent_slug' => $current_item ) ); 
     70        } else { 
     71            $secondary_nav_items = $bp->{$single_item_component}->nav->get_secondary( array( 'parent_slug' => $current_item ) ); 
     72        } 
     73 
     74        if ( ! $secondary_nav_items ) { 
    5875            return false; 
    59         } else { 
    60             $the_index = $current_item; 
    6176        } 
    6277    } 
    6378 
    6479    // Loop through each navigation item. 
    65     foreach ( (array) $bp->bp_options_nav[$the_index] as $subnav_item ) { 
    66         if ( empty( $subnav_item['user_has_access'] ) ) { 
     80    foreach ( $secondary_nav_items as $subnav_item ) { 
     81        if ( empty( $subnav_item->user_has_access ) ) { 
    6782            continue; 
    6883        } 
    6984 
    7085        // If the current action or an action variable matches the nav item id, then add a highlight CSS class. 
    71         if ( $subnav_item['slug'] == $selected_item ) { 
     86        if ( $subnav_item->slug === $selected_item ) { 
    7287            $selected = ' class="current selected"'; 
    7388        } else { 
     
    89104         * @param string $selected_item Current action. 
    90105         */ 
    91         echo apply_filters( 'bp_get_options_nav_' . $subnav_item['css_id'], '<li id="' . esc_attr( $subnav_item['css_id'] . '-' . $list_type . '-li' ) . '" ' . $selected . '><a id="' . esc_attr( $subnav_item['css_id'] ) . '" href="' . esc_url( $subnav_item['link'] ) . '">' . $subnav_item['name'] . '</a></li>', $subnav_item, $selected_item ); 
     106        echo apply_filters( 'bp_get_options_nav_' . $subnav_item->css_id, '<li id="' . esc_attr( $subnav_item->css_id . '-' . $list_type . '-li' ) . '" ' . $selected . '><a id="' . esc_attr( $subnav_item->css_id ) . '" href="' . esc_url( $subnav_item->link ) . '">' . $subnav_item->name . '</a></li>', $subnav_item, $selected_item ); 
    92107    } 
    93108} 
     
    30113026        $component_subnav_name = ''; 
    30123027 
     3028        if ( ! empty( $bp->members->nav ) ) { 
     3029            $primary_nav_item = $bp->members->nav->get_primary( array( 'slug' => $component_id ), false ); 
     3030            $primary_nav_item = reset( $primary_nav_item ); 
     3031        } 
     3032 
    30133033        // Use the component nav name. 
    3014         if ( ! empty( $bp->bp_nav[$component_id] ) ) { 
    3015             $component_name = _bp_strip_spans_from_title( $bp->bp_nav[ $component_id ]['name'] ); 
     3034        if ( ! empty( $primary_nav_item->name ) ) { 
     3035            $component_name = _bp_strip_spans_from_title( $primary_nav_item->name ); 
    30163036 
    30173037        // Fall back on the component ID. 
     
    30203040        } 
    30213041 
     3042        if ( ! empty( $bp->members->nav ) ) { 
     3043            $secondary_nav_item = $bp->members->nav->get_secondary( array( 
     3044                'parent_slug' => $component_id, 
     3045                'slug'        => bp_current_action() 
     3046            ), false ); 
     3047 
     3048            if ( $secondary_nav_item ) { 
     3049                $secondary_nav_item = reset( $secondary_nav_item ); 
     3050            } 
     3051        } 
     3052 
    30223053        // Append action name if we're on a member component sub-page. 
    3023         if ( ! empty( $bp->bp_options_nav[ $component_id ] ) && ! empty( $bp->canonical_stack['action'] ) ) { 
    3024             $component_subnav_name = wp_filter_object_list( $bp->bp_options_nav[ $component_id ], array( 'slug' => bp_current_action() ), 'and', 'name' ); 
    3025  
    3026             if ( ! empty( $component_subnav_name ) ) { 
    3027                 $component_subnav_name = array_shift( $component_subnav_name ); 
    3028             } 
     3054        if ( ! empty( $secondary_nav_item->name ) && ! empty( $bp->canonical_stack['action'] ) ) { 
     3055            $component_subnav_name = $secondary_nav_item->name; 
    30293056        } 
    30303057 
     
    30463073        } 
    30473074 
    3048     // A single group. 
    3049     } elseif ( bp_is_active( 'groups' ) && ! empty( $bp->groups->current_group ) && ! empty( $bp->bp_options_nav[ $bp->groups->current_group->slug ] ) ) { 
    3050         $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'] : ''; 
    3051         $bp_title_parts = array( $bp->bp_options_title, $subnav ); 
    3052  
    3053     // A single item from a component other than groups. 
     3075    // A single item from a component other than Members. 
    30543076    } elseif ( bp_is_single_item() ) { 
    3055         $bp_title_parts = array( $bp->bp_options_title, $bp->bp_options_nav[ bp_current_item() ][ bp_current_action() ]['name'] ); 
     3077        $component_id = bp_current_component(); 
     3078 
     3079        if ( ! empty( $bp->{$component_id}->nav ) ) { 
     3080            $secondary_nav_item = $bp->{$component_id}->nav->get_secondary( array( 
     3081                'parent_slug' => bp_current_item(), 
     3082                'slug'        => bp_current_action() 
     3083            ), false ); 
     3084 
     3085            if ( $secondary_nav_item ) { 
     3086                $secondary_nav_item = reset( $secondary_nav_item ); 
     3087            } 
     3088        } 
     3089 
     3090        $single_item_subnav = ''; 
     3091 
     3092        if ( ! empty( $secondary_nav_item->name ) ) { 
     3093            $single_item_subnav = $secondary_nav_item->name; 
     3094        } 
     3095 
     3096        $bp_title_parts = array( $bp->bp_options_title, $single_item_subnav ); 
    30563097 
    30573098    // An index or directory. 
     
    34293470 * 
    34303471 * @since 1.7.0 
    3431  * 
     3472 * @since 2.6.0 Introduced the `$component` parameter. 
     3473 * 
     3474 * @param string $component Optional. Component whose nav items are being fetched. 
    34323475 * @return array A multidimensional array of all navigation items. 
    34333476 */ 
    3434 function bp_get_nav_menu_items() { 
    3435     $menus = $selected_menus = array(); 
    3436  
    3437     // Get the second level menus. 
    3438     foreach ( (array) buddypress()->bp_options_nav as $parent_menu => $sub_menus ) { 
    3439  
    3440         // The root menu's ID is "xprofile", but the Profile submenus are using "profile". See BP_Core::setup_nav(). 
    3441         if ( 'profile' === $parent_menu ) { 
    3442             $parent_menu = 'xprofile'; 
    3443         } 
    3444  
    3445         // Sort the items in this menu's navigation by their position property. 
    3446         $second_level_menus = (array) $sub_menus; 
    3447         usort( $second_level_menus, '_bp_nav_menu_sort' ); 
    3448  
    3449         // Iterate through the second level menus. 
    3450         foreach( $second_level_menus as $sub_nav ) { 
    3451  
    3452             // Skip items we don't have access to. 
    3453             if ( empty( $sub_nav['user_has_access'] ) ) { 
    3454                 continue; 
    3455             } 
    3456  
    3457             // Add this menu. 
    3458             $menu         = new stdClass; 
    3459             $menu->class  = array( 'menu-child' ); 
    3460             $menu->css_id = $sub_nav['css_id']; 
    3461             $menu->link   = $sub_nav['link']; 
    3462             $menu->name   = $sub_nav['name']; 
    3463             $menu->parent = $parent_menu;  // Associate this sub nav with a top-level menu. 
    3464  
    3465             // If we're viewing this item's screen, record that we need to mark its parent menu to be selected. 
    3466             if ( $sub_nav['slug'] == bp_current_action() ) { 
    3467                 $menu->class[]    = 'current-menu-item'; 
    3468                 $selected_menus[] = $parent_menu; 
    3469             } 
    3470  
    3471             $menus[] = $menu; 
    3472         } 
    3473     } 
    3474  
    3475     // Get the top-level menu parts (Friends, Groups, etc) and sort by their position property. 
    3476     $top_level_menus = (array) buddypress()->bp_nav; 
    3477     usort( $top_level_menus, '_bp_nav_menu_sort' ); 
    3478  
    3479     // Iterate through the top-level menus. 
    3480     foreach ( $top_level_menus as $nav ) { 
    3481  
    3482         // Skip items marked as user-specific if you're not on your own profile. 
    3483         if ( empty( $nav['show_for_displayed_user'] ) && ! bp_core_can_edit_settings()  ) { 
    3484             continue; 
    3485         } 
    3486  
     3477function bp_get_nav_menu_items( $component = 'members' ) { 
     3478    $bp    = buddypress(); 
     3479    $menus = array(); 
     3480 
     3481    if ( ! isset( $bp->{$component}->nav ) ) { 
     3482        return $menus; 
     3483    } 
     3484 
     3485    // Get the item nav and build the menus. 
     3486    foreach ( $bp->{$component}->nav->get_item_nav() as $nav_menu ) { 
    34873487        // Get the correct menu link. See https://buddypress.trac.wordpress.org/ticket/4624. 
    3488         $link = bp_loggedin_user_domain() ? str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $nav['link'] ) : trailingslashit( bp_displayed_user_domain() . $nav['link'] ); 
     3488        $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 ); 
    34893489 
    34903490        // Add this menu. 
    34913491        $menu         = new stdClass; 
    34923492        $menu->class  = array( 'menu-parent' ); 
    3493         $menu->css_id = $nav['css_id']; 
    3494         $menu->link   = $link; 
    3495         $menu->name   = $nav['name']; 
     3493        $menu->css_id = $nav_menu->css_id; 
     3494        $menu->link   = $nav_menu->link; 
     3495        $menu->name   = $nav_menu->name; 
    34963496        $menu->parent = 0; 
    34973497 
    3498         // Check if we need to mark this menu as selected. 
    3499         if ( in_array( $nav['css_id'], $selected_menus ) ) { 
    3500             $menu->class[] = 'current-menu-parent'; 
     3498        if ( ! empty( $nav_menu->children ) ) { 
     3499            $submenus = array(); 
     3500 
     3501            foreach( $nav_menu->children as $sub_menu ) { 
     3502                $submenu = new stdClass; 
     3503                $submenu->class  = array( 'menu-child' ); 
     3504                $submenu->css_id = $sub_menu->css_id; 
     3505                $submenu->link   = $sub_menu->link; 
     3506                $submenu->name   = $sub_menu->name; 
     3507                $submenu->parent = $nav_menu->slug; 
     3508 
     3509                // If we're viewing this item's screen, record that we need to mark its parent menu to be selected. 
     3510                if ( $sub_menu->slug == bp_current_action() ) { 
     3511                    $menu->class[]    = 'current-menu-parent'; 
     3512                    $submenu->class[] = 'current-menu-item'; 
     3513                } 
     3514 
     3515                $submenus[] = $submenu; 
     3516            } 
    35013517        } 
    35023518 
    35033519        $menus[] = $menu; 
     3520 
     3521        if ( ! empty( $submenus ) ) { 
     3522            $menus = array_merge( $menus, $submenus ); 
     3523        } 
    35043524    } 
    35053525 
  • trunk/src/bp-core/classes/class-bp-component.php

    r10555 r10745  
    490490        // No sub nav items without a main nav item. 
    491491        if ( !empty( $main_nav ) ) { 
    492             bp_core_new_nav_item( $main_nav ); 
     492            bp_core_new_nav_item( $main_nav, 'members' ); 
    493493 
    494494            // Sub nav items are not required. 
    495495            if ( !empty( $sub_nav ) ) { 
    496496                foreach( (array) $sub_nav as $nav ) { 
    497                     bp_core_new_subnav_item( $nav ); 
     497                    bp_core_new_subnav_item( $nav, 'members' ); 
    498498                } 
    499499            } 
  • trunk/src/bp-core/classes/class-bp-core.php

    r10536 r10745  
    254254        // bp-notifications instead. 
    255255        $bp->core->table_name_notifications = $bp->table_prefix . 'bp_notifications'; 
     256 
     257        // Backward compatibility for plugins modifying the legacy bp_nav and bp_options_nav global properties. 
     258        if ( buddypress()->do_nav_backcompat ) { 
     259            $bp->bp_nav         = new BP_Core_BP_Nav_BackCompat(); 
     260            $bp->bp_options_nav = new BP_Core_BP_Options_Nav_BackCompat(); 
     261        } 
    256262 
    257263        /** 
  • trunk/src/bp-core/deprecated/2.6.php

    r10723 r10745  
    2222    <?php 
    2323} 
     24 
     25/** 
     26 * Sort the navigation menu items. 
     27 * 
     28 * The sorting is split into a separate function because it can only happen 
     29 * after all plugins have had a chance to register their navigation items. 
     30 * 
     31 * @since 1.0.0 
     32 * @deprecated 2.6.0 
     33 * 
     34 * @return bool|null Returns false on failure. 
     35 */ 
     36function bp_core_sort_nav_items() { 
     37    _deprecated_function( __FUNCTION__, '2.6' ); 
     38} 
     39 
     40/** 
     41 * Sort all subnavigation arrays. 
     42 * 
     43 * @since 1.1.0 
     44 * @deprecated 2.6.0 
     45 * 
     46 * @return bool|null Returns false on failure. 
     47 */ 
     48function bp_core_sort_subnav_items() { 
     49    _deprecated_function( __FUNCTION__, '2.6' ); 
     50} 
  • trunk/src/bp-groups/bp-groups-adminbar.php

    r10417 r10745  
    4848 
    4949    // Index of the Manage tabs parent slug. 
    50     $nav_index = $bp->groups->current_group->slug . '_manage'; 
     50    $secondary_nav_items = $bp->groups->nav->get_secondary( array( 'parent_slug' => $bp->groups->current_group->slug . '_manage' ) ); 
    5151 
    5252    // Check if current group has Manage tabs. 
    53     if ( empty( $bp->bp_options_nav[ $nav_index ] ) ) { 
     53    if ( ! $secondary_nav_items ) { 
    5454        return; 
    5555    } 
    5656 
    5757    // Build the Group Admin menus. 
    58     foreach ( $bp->bp_options_nav[ $nav_index ] as $menu ) { 
     58    foreach ( $secondary_nav_items as $menu ) { 
    5959        /** 
    6060         * Should we add the current manage link in the Group's "Edit" Admin Bar menu ? 
     
    6464         * the 'show_in_admin_bar' argument of your edit screen to true 
    6565         */ 
    66         if ( $menu['show_in_admin_bar'] ) { 
    67             $title = sprintf( _x( 'Edit Group %s', 'Group WP Admin Bar manage links', 'buddypress' ), $menu['name'] ); 
     66        if ( $menu->show_in_admin_bar ) { 
     67            $title = sprintf( _x( 'Edit Group %s', 'Group WP Admin Bar manage links', 'buddypress' ), $menu->name ); 
    6868 
    6969            // Title is specific for delete. 
    70             if ( 'delete-group' == $menu['slug'] ) { 
    71                 $title = sprintf( _x( '%s Group', 'Group WP Admin Bar delete link', 'buddypress' ), $menu['name'] ); 
     70            if ( 'delete-group' == $menu->slug ) { 
     71                $title = sprintf( _x( '%s Group', 'Group WP Admin Bar delete link', 'buddypress' ), $menu->name ); 
    7272            } 
    7373 
    7474            $wp_admin_bar->add_menu( array( 
    7575                'parent' => $bp->group_admin_menu_id, 
    76                 'id'     => $menu['slug'], 
     76                'id'     => $menu->slug, 
    7777                'title'  => $title, 
    78                 'href'   => bp_get_groups_action_link( 'admin/' . $menu['slug'] ) 
     78                'href'   => bp_get_groups_action_link( 'admin/' . $menu->slug ) 
    7979            ) ); 
    8080        } 
  • trunk/src/bp-groups/classes/class-bp-group-extension.php

    r10454 r10745  
    738738                'user_has_access' => $user_can_see_nav_item, 
    739739                'no_access_url'   => $group_permalink, 
    740             ) ); 
     740            ), 'groups' ); 
    741741        } 
    742742 
     
    753753                'user_has_access' => $user_can_visit, 
    754754                'no_access_url'   => $group_permalink, 
    755             ) ); 
     755            ), 'groups' ); 
    756756 
    757757            // When we are viewing the extension display page, set the title and options title. 
     
    968968 
    969969        // Add the tab to the manage navigation. 
    970         bp_core_new_subnav_item( $subnav_args ); 
     970        bp_core_new_subnav_item( $subnav_args, 'groups' ); 
    971971 
    972972        // Catch the edit screen and forward it to the plugin template. 
  • trunk/src/bp-groups/classes/class-bp-groups-component.php

    r10679 r10745  
    253253            // Check once if the current group has a custom front template. 
    254254            $this->current_group->front_template = bp_groups_get_front_template( $this->current_group ); 
     255 
     256            // Initialize the nav for the groups component. 
     257            $this->nav = new BP_Core_Nav( $this->current_group->id ); 
    255258 
    256259        // Set current_group to 0 to prevent debug errors. 
     
    497500            $sub_nav = array(); 
    498501 
    499             // Add 'Groups' to the main navigation. 
    500             $main_nav = array( 
     502            /* 
     503             * The top-level Groups item is called 'Memberships' for legacy reasons. 
     504             * It does not appear in the interface. 
     505             */ 
     506            bp_core_new_nav_item( array( 
    501507                'name'                => __( 'Memberships', 'buddypress' ), 
    502508                'slug'                => $this->current_group->slug, 
     
    505511                'default_subnav_slug' => $this->default_extension, 
    506512                'item_css_id'         => $this->id 
    507             ); 
     513            ), 'groups' ); 
    508514 
    509515            $group_link = bp_get_group_permalink( $this->current_group ); 
     
    676682            } 
    677683 
    678             parent::setup_nav( $main_nav, $sub_nav ); 
     684            foreach ( $sub_nav as $nav ) { 
     685                bp_core_new_subnav_item( $nav, 'groups' ); 
     686            } 
    679687        } 
    680688 
  • trunk/src/bp-loader.php

    r10723 r10745  
    110110    public $do_autoload = false; 
    111111 
     112    /** 
     113     * Whether to load backward compatibility classes for navigation globals. 
     114     * 
     115     * @since 2.6.0 
     116     * @var bool 
     117     */ 
     118    public $do_nav_backcompat = false; 
     119 
    112120    /** Option Overload *******************************************************/ 
    113121 
     
    435443        $this->email_post_type     = apply_filters( 'bp_email_post_type', 'bp-email' ); 
    436444        $this->email_taxonomy_type = apply_filters( 'bp_email_tax_type', 'bp-email-type' ); 
     445 
     446        /** Navigation backward compatibility *********************************/ 
     447        if ( interface_exists( 'ArrayAccess', false ) ) { 
     448            // bp_nav and bp_options_nav compatibility depends on SPL. 
     449            $this->do_nav_backcompat = true; 
     450        } 
    437451    } 
    438452 
  • trunk/src/bp-members/bp-members-template.php

    r10711 r10745  
    12911291 
    12921292    // Loop through each navigation item. 
    1293     foreach( (array) $bp->bp_nav as $nav_item ) { 
     1293    foreach ( (array) $bp->members->nav->get_primary() as $nav_item ) { 
    12941294 
    12951295        $selected = ''; 
    12961296 
    12971297        // If the current component matches the nav item id, then add a highlight CSS class. 
    1298         if ( !bp_is_directory() && !empty( $bp->active_components[bp_current_component()] ) && $bp->active_components[bp_current_component()] == $nav_item['css_id'] ) { 
     1298        if ( ! bp_is_directory() && ! empty( $bp->active_components[ bp_current_component() ] ) && $bp->active_components[ bp_current_component() ] == $nav_item->css_id ) { 
    12991299            $selected = ' class="current selected"'; 
    13001300        } 
     
    13081308 
    13091309            if ( bp_is_active( 'friends' ) ) { 
    1310                 if ( $nav_item['css_id'] == $bp->friends->id ) { 
     1310                if ( $nav_item->css_id == $bp->friends->id ) { 
    13111311                    if ( friends_check_friendship( bp_loggedin_user_id(), bp_displayed_user_id() ) ) { 
    13121312                        $selected = ' class="current selected"'; 
     
    13171317 
    13181318        // Echo out the final list item. 
    1319         echo apply_filters_ref_array( 'bp_get_loggedin_user_nav_' . $nav_item['css_id'], array( '<li id="li-nav-' . $nav_item['css_id'] . '" ' . $selected . '><a id="my-' . $nav_item['css_id'] . '" href="' . $nav_item['link'] . '">' . $nav_item['name'] . '</a></li>', &$nav_item ) ); 
     1319        echo apply_filters_ref_array( 'bp_get_loggedin_user_nav_' . $nav_item->css_id, array( '<li id="li-nav-' . $nav_item->css_id . '" ' . $selected . '><a id="my-' . $nav_item->css_id . '" href="' . $nav_item->link . '">' . $nav_item->name . '</a></li>', &$nav_item ) ); 
    13201320    } 
    13211321 
     
    13341334    $bp = buddypress(); 
    13351335 
    1336     foreach ( (array) $bp->bp_nav as $user_nav_item ) { 
    1337         if ( empty( $user_nav_item['show_for_displayed_user'] ) && !bp_is_my_profile() ) 
     1336    foreach ( $bp->members->nav->get_primary() as $user_nav_item ) { 
     1337        if ( empty( $user_nav_item->show_for_displayed_user ) && ! bp_is_my_profile() ) { 
    13381338            continue; 
     1339        } 
    13391340 
    13401341        $selected = ''; 
    1341         if ( bp_is_current_component( $user_nav_item['slug'] ) ) { 
     1342        if ( bp_is_current_component( $user_nav_item->slug ) ) { 
    13421343            $selected = ' class="current selected"'; 
    13431344        } 
    13441345 
    13451346        if ( bp_loggedin_user_domain() ) { 
    1346             $link = str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $user_nav_item['link'] ); 
     1347            $link = str_replace( bp_loggedin_user_domain(), bp_displayed_user_domain(), $user_nav_item->link ); 
    13471348        } else { 
    1348             $link = trailingslashit( bp_displayed_user_domain() . $user_nav_item['link'] ); 
     1349            $link = trailingslashit( bp_displayed_user_domain() . $user_nav_item->link ); 
    13491350        } 
    13501351 
     
    13601361         *                              Passed by reference. 
    13611362         */ 
    1362         echo apply_filters_ref_array( 'bp_get_displayed_user_nav_' . $user_nav_item['css_id'], array( '<li id="' . $user_nav_item['css_id'] . '-personal-li" ' . $selected . '><a id="user-' . $user_nav_item['css_id'] . '" href="' . $link . '">' . $user_nav_item['name'] . '</a></li>', &$user_nav_item ) ); 
     1363        echo apply_filters_ref_array( 'bp_get_displayed_user_nav_' . $user_nav_item->css_id, array( '<li id="' . $user_nav_item->css_id . '-personal-li" ' . $selected . '><a id="user-' . $user_nav_item->css_id . '" href="' . $link . '">' . $user_nav_item->name . '</a></li>', &$user_nav_item ) ); 
    13631364    } 
    13641365} 
  • trunk/src/bp-members/classes/class-bp-members-component.php

    r10711 r10745  
    151151        $bp->displayed_user->domain   = bp_core_get_user_domain( bp_displayed_user_id() ); 
    152152 
     153        // Initialize the nav for the members component. 
     154        $this->nav = new BP_Core_Nav(); 
     155 
    153156        /** Signup *********************************************************** 
    154157         */ 
  • trunk/src/bp-messages/bp-messages-screens.php

    r10417 r10745  
    133133    $nav_name = sprintf( __( 'Messages <span class="%s">%s</span>', 'buddypress' ), esc_attr( $class ), bp_core_number_format( $count ) ); 
    134134 
    135     $bp->bp_nav[ $bp->messages->slug ]['name'] = $nav_name; 
     135    // Edit the Navigation name. 
     136    $bp->members->nav->edit_nav( array( 
     137        'name' => $nav_name, 
     138    ), $bp->messages->slug ); 
    136139 
    137140    /** 
  • trunk/src/bp-xprofile/classes/class-bp-xprofile-component.php

    r10740 r10745  
    303303            'position'        => 30, 
    304304            'user_has_access' => bp_core_can_edit_settings() 
    305         ) ); 
     305        ), 'members' ); 
    306306    } 
    307307 
  • trunk/tests/phpunit/testcases/core/nav/bpCoreMaybeHookNewSubnavScreenFunction.php

    r9988 r10745  
    8383        $old_default_component = buddypress()->default_component; 
    8484        buddypress()->default_component = 'foo'; 
    85         buddypress()->bp_nav = array( 
    86             'foo' => array( 
    87                 'show_for_displayed_user' => true, 
    88             ), 
    89         ); 
     85 
     86        bp_core_new_nav_item( array( 
     87            'slug' => 'foo', 
     88            'name' => 'Foo', 
     89            'screen_function' => 'foo', 
     90            'default_subnav_item' => 'bar', 
     91        ) ); 
    9092 
    9193        $subnav_item = array( 
     
    9597        // Just test relevant info 
    9698        $found = bp_core_maybe_hook_new_subnav_screen_function( $subnav_item ); 
    97         $this->assertSame( 'failure', $found['status'] ); 
    98         $this->assertSame( bp_core_get_user_domain( $u2 ), $found['redirect_args']['root'] ); 
    9999 
    100100        // Clean up 
     
    102102        buddypress()->default_component = $old_default_component; 
    103103        buddypress()->bp_nav = $old_bp_nav; 
     104 
     105        $this->assertSame( 'failure', $found['status'] ); 
     106        $this->assertSame( bp_core_get_user_domain( $u2 ), $found['redirect_args']['root'] ); 
    104107    } 
    105108 
     
    115118        $old_default_component = buddypress()->default_component; 
    116119        buddypress()->default_component = 'foo'; 
    117         buddypress()->bp_nav = array( 
    118             'foo' => array( 
    119                 'show_for_displayed_user' => false, 
    120             ), 
    121         ); 
     120 
     121        bp_core_new_nav_item( array( 
     122            'slug' => 'foo', 
     123            'name' => 'Foo', 
     124            'screen_function' => 'foo', 
     125            'default_subnav_item' => 'bar', 
     126            'show_for_displayed_user' => false, 
     127        ) ); 
    122128 
    123129        $subnav_item = array( 
     
    127133        // Just test relevant info 
    128134        $found = bp_core_maybe_hook_new_subnav_screen_function( $subnav_item ); 
    129         $this->assertSame( 'failure', $found['status'] ); 
    130         $this->assertSame( bp_core_get_user_domain( $u2 ) . bp_get_activity_slug() . '/', $found['redirect_args']['root'] ); 
    131135 
    132136        // Clean up 
     
    134138        buddypress()->default_component = $old_default_component; 
    135139        buddypress()->bp_nav = $old_bp_nav; 
     140 
     141        $this->assertSame( 'failure', $found['status'] ); 
     142        $this->assertSame( bp_core_get_user_domain( $u2 ) . bp_get_activity_slug() . '/', $found['redirect_args']['root'] ); 
    136143    } 
    137144 
  • trunk/tests/phpunit/testcases/core/nav/bpCoreNewNavItem.php

    r10326 r10745  
    66class BP_Tests_Core_Nav_BpCoreNewNavItem extends BP_UnitTestCase { 
    77 
     8    /** 
     9     * @expectedIncorrectUsage bp_nav 
     10     */ 
    811    public function test_user_nav() { 
    912        $bp_nav = buddypress()->bp_nav; 
     
    3437        ); 
    3538 
    36         $this->assertSame( buddypress()->bp_nav['foo'], $expected ); 
    37  
    38         // Clean up 
    39         buddypress()->bp_nav = $bp_nav; 
    40         $this->set_current_user( $old_current_user ); 
    41     } 
    42  
     39        foreach ( $expected as $k => $v ) { 
     40            $this->assertEquals( $v, buddypress()->bp_nav['foo'][ $k ] ); 
     41        } 
     42 
     43        // Clean up 
     44        buddypress()->bp_nav = $bp_nav; 
     45        $this->set_current_user( $old_current_user ); 
     46    } 
     47 
     48    /** 
     49     * @expectedIncorrectUsage bp_nav 
     50     */ 
    4351    public function test_group_nav() { 
    4452        $bp_nav = buddypress()->bp_nav; 
     
    9098    } 
    9199 
     100    /** 
     101     * @expectedIncorrectUsage bp_nav 
     102     */ 
    92103    public function test_css_id_should_fall_back_on_slug() { 
    93104        $args = array( 
     
    100111    } 
    101112 
     113    /** 
     114     * @expectedIncorrectUsage bp_nav 
     115     */ 
    102116    public function test_css_id_should_be_respected() { 
    103117        $args = array( 
     
    125139    } 
    126140 
     141    /** 
     142     * @expectedIncorrectUsage bp_nav 
     143     */ 
    127144    public function test_existence_of_access_protected_user_nav() { 
    128145        $bp_nav = buddypress()->bp_nav; 
     
    146163        ); 
    147164 
    148         $this->assertSame( buddypress()->bp_nav['settings'], $expected ); 
    149  
    150         // Clean up 
    151         buddypress()->bp_nav = $bp_nav; 
    152         $this->set_current_user( $old_current_user ); 
    153     } 
    154  
     165        foreach ( $expected as $k => $v ) { 
     166            $this->assertEquals( $v, buddypress()->bp_nav['settings'][ $k ] ); 
     167        } 
     168 
     169        // Clean up 
     170        buddypress()->bp_nav = $bp_nav; 
     171        $this->set_current_user( $old_current_user ); 
     172    } 
     173 
     174    /** 
     175     * @expectedIncorrectUsage bp_nav 
     176     */ 
    155177    public function test_creation_of_access_protected_user_nav() { 
    156178        // The nav item must be added to bp_nav, even if the current user 
     
    185207        ); 
    186208 
    187         $this->assertSame( buddypress()->bp_nav['woof'], $expected ); 
     209        foreach ( $expected as $k => $v ) { 
     210            $this->assertEquals( $v, buddypress()->bp_nav['woof'][ $k ] ); 
     211        } 
    188212 
    189213        // Clean up 
  • trunk/tests/phpunit/testcases/core/nav/bpCoreNewSubnavItem.php

    r9991 r10745  
    66class BP_Tests_Core_Nav_BpCoreNewSubnavItem extends BP_UnitTestCase { 
    77 
     8    /** 
     9     * @expectedIncorrectUsage bp_nav 
     10     */ 
    811    public function test_user_subnav() { 
    912        $bp_options_nav = buddypress()->bp_options_nav; 
     
    1720        $this->go_to( $user_domain ); 
    1821 
     22        bp_core_new_nav_item( array( 
     23            'name'            => 'Foo Parent', 
     24            'slug'            => 'foo-parent', 
     25            'link'            => trailingslashit( $user_domain . 'foo-parent' ), 
     26            'screen_function' => 'foo_screen_function', 
     27            'position'        => 10, 
     28        ) ); 
     29 
    1930        bp_core_new_subnav_item( array( 
    2031            'name'            => 'Foo', 
    2132            'slug'            => 'foo', 
    22             'parent_url'      => trailingslashit( $user_domain . 'foo' ), 
    23             'parent_slug'     => 'foo', 
     33            'parent_url'      => trailingslashit( $user_domain . 'foo-parent' ), 
     34            'parent_slug'     => 'foo-parent', 
    2435            'screen_function' => 'foo_screen_function', 
    2536            'position'        => 10 
     
    2839        $expected = array( 
    2940            'name'              => 'Foo', 
    30             'link'              => trailingslashit( $user_domain . 'foo/foo' ), 
     41            'link'              => trailingslashit( $user_domain . 'foo-parent/foo' ), 
    3142            'slug'              => 'foo', 
    3243            'css_id'            => 'foo', 
     
    3849        ); 
    3950 
    40         $this->assertSame( buddypress()->bp_options_nav['foo']['foo'], $expected ); 
     51        foreach ( $expected as $k => $v ) { 
     52            $this->assertSame( $v, buddypress()->bp_options_nav['foo-parent']['foo'][ $k ] ); 
     53        } 
    4154 
    4255        // Clean up 
     
    103116    } 
    104117 
     118    /** 
     119     * @expectedIncorrectUsage bp_nav 
     120     */ 
    105121    public function test_link_provided() { 
    106122        $bp_options_nav = buddypress()->bp_options_nav; 
    107123 
    108         bp_core_new_subnav_item( array( 
    109             'name' => 'bar', 
    110             'slug' => 'bar', 
    111             'parent_slug' => 'foo', 
    112             'parent_url' => 'foo', 
     124        bp_core_new_nav_item( array( 
     125            'name' => 'Foo', 
     126            'slug' => 'foo', 
    113127            'screen_function' => 'foo', 
    114128            'link' => 'https://buddypress.org/', 
    115129        ) ); 
    116130 
     131        bp_core_new_subnav_item( array( 
     132            'name' => 'bar', 
     133            'slug' => 'bar', 
     134            'parent_slug' => 'foo', 
     135            'parent_url' => 'foo', 
     136            'screen_function' => 'foo', 
     137            'link' => 'https://buddypress.org/', 
     138        ) ); 
     139 
    117140        $this->assertSame( 'https://buddypress.org/', buddypress()->bp_options_nav['foo']['bar']['link'] ); 
    118141 
     
    120143    } 
    121144 
     145    /** 
     146     * @expectedIncorrectUsage bp_nav 
     147     */ 
    122148    public function test_link_built_from_parent_url_and_slug() { 
    123149        $bp_options_nav = buddypress()->bp_options_nav; 
    124150 
     151        bp_core_new_nav_item( array( 
     152            'name' => 'Foo', 
     153            'slug' => 'foo', 
     154            'screen_function' => 'foo', 
     155            'link' => 'https://buddypress.org/', 
     156        ) ); 
     157 
    125158        bp_core_new_subnav_item( array( 
    126159            'name' => 'bar', 
     
    136169    } 
    137170 
     171    /** 
     172     * @expectedIncorrectUsage bp_nav 
     173     */ 
    138174    public function test_link_built_from_parent_url_and_slug_where_slug_is_default() { 
    139175        $bp_nav = buddypress()->bp_nav; 
    140176        $bp_options_nav = buddypress()->bp_options_nav; 
    141177 
    142         // fake the parent 
    143         buddypress()->bp_nav = array( 
    144             'foo' => array( 
    145                 'default_subnav_slug' => 'bar', 
    146             ), 
    147         ); 
     178        bp_core_new_nav_item( array( 
     179            'name' => 'Foo', 
     180            'slug' => 'foo', 
     181            'screen_function' => 'foo', 
     182            'default_subnav_slug' => 'bar', 
     183        ) ); 
    148184 
    149185        bp_core_new_subnav_item( array( 
     
    162198    } 
    163199 
     200    /** 
     201     * @expectedIncorrectUsage bp_nav 
     202     */ 
    164203    public function test_should_trailingslash_link_when_link_is_autogenerated_using_slug() { 
     204        bp_core_new_nav_item( array( 
     205            'name' => 'Foo', 
     206            'slug' => 'foo', 
     207            'screen_function' => 'foo', 
     208            'link' => 'https://buddypress.org/', 
     209        ) ); 
     210 
    165211        bp_core_new_subnav_item( array( 
    166212            'name' => 'bar', 
     
    175221    } 
    176222 
     223    /** 
     224     * @expectedIncorrectUsage bp_nav 
     225     */ 
    177226    public function test_should_trailingslash_link_when_link_is_autogenerated_not_using_slug() { 
    178227        bp_core_new_nav_item( array( 
     
    188237            'slug' => 'bar', 
    189238            'parent_slug' => 'foo-parent', 
    190             'parent_url' => bp_get_root_domain() . 'foo-parent/', 
     239            'parent_url' => bp_get_root_domain() . '/foo-parent/', 
    191240            'screen_function' => 'bar', 
    192241        ) ); 
    193242 
    194         $expected = bp_get_root_domain() . 'foo-parent/'; 
     243        $expected = bp_get_root_domain() . '/foo-parent/'; 
    195244        $this->assertSame( $expected, buddypress()->bp_options_nav['foo-parent']['bar']['link'] ); 
    196245    } 
     
    198247    /** 
    199248     * @ticket BP6353 
     249     * @expectedIncorrectUsage bp_nav 
    200250     */ 
    201251    public function test_link_should_not_trailingslash_link_explicit_link() { 
    202252        $link = 'http://example.com/foo/bar/blah/?action=edit&id=30'; 
    203253 
     254        bp_core_new_nav_item( array( 
     255            'name' => 'Foo', 
     256            'slug' => 'foo', 
     257            'screen_function' => 'foo', 
     258            'link' => 'http://example.com/foo/', 
     259        ) ); 
     260 
    204261        bp_core_new_subnav_item( array( 
    205262            'name' => 'bar', 
     
    215272 
    216273    public function test_should_return_false_if_site_admin_only_and_current_user_cannot_bp_moderate() { 
     274        bp_core_new_nav_item( array( 
     275            'name' => 'Foo', 
     276            'slug' => 'foo', 
     277            'screen_function' => 'foo', 
     278        ) ); 
     279 
    217280        // Should already be set to a 0 user. 
    218281        $this->assertFalse( bp_current_user_can( 'bp_moderate' ) ); 
     
    229292    } 
    230293 
     294    /** 
     295     * @expectedIncorrectUsage bp_nav 
     296     */ 
    231297    public function test_css_id_should_fall_back_on_slug() { 
     298        bp_core_new_nav_item( array( 
     299            'name' => 'Parent', 
     300            'slug' => 'parent', 
     301            'screen_function' => 'foo', 
     302        ) ); 
     303 
    232304        $args = array( 
    233305            'name' => 'Foo', 
     
    242314    } 
    243315 
     316    /** 
     317     * @expectedIncorrectUsage bp_nav 
     318     */ 
    244319    public function test_css_id_should_be_respected() { 
     320        bp_core_new_nav_item( array( 
     321            'name' => 'Parent', 
     322            'slug' => 'parent', 
     323            'screen_function' => 'foo', 
     324        ) ); 
     325 
    245326        $args = array( 
    246327            'name' => 'Foo', 
  • trunk/tests/phpunit/testcases/core/nav/bpCoreRemoveNavItem.php

    r10743 r10745  
    66 */ 
    77class BP_Tests_Core_Nav_BpCoreRemoveNavItem extends BP_UnitTestCase { 
     8    /** 
     9     * @expectedIncorrectUsage bp_nav 
     10     */ 
    811    public function test_should_remove_subnav_items() { 
    912        $bp = buddypress(); 
     
    3841    } 
    3942 
     43    /** 
     44     * @expectedIncorrectUsage bp_nav 
     45     */ 
    4046    public function test_should_remove_nav_item() { 
    4147        $bp = buddypress(); 
  • trunk/tests/phpunit/testcases/core/nav/bpCoreRemoveSubnavItem.php

    r10744 r10745  
    66 */ 
    77class BP_Tests_Core_Nav_BpCoreRemoveSubnavItem extends BP_UnitTestCase { 
     8    /** 
     9     * @expectedIncorrectUsage bp_nav 
     10     */ 
    811    public function test_should_remove_subnav_item() { 
    912        $bp = buddypress(); 
     
    3639    } 
    3740 
     41    /** 
     42     * @expectedIncorrectUsage bp_nav 
     43     */ 
    3844    public function test_should_fail_on_incorrect_parent() { 
    3945        $bp = buddypress(); 
     
    6571        $bp->bp_options_nav = $_bp_options_nav; 
    6672    } 
    67  
    68     public function test_should_remove_parent_array_if_left_childless() { 
    69         $bp = buddypress(); 
    70  
    71         $_bp_nav = $bp->bp_nav; 
    72         $_bp_options_nav = $bp->bp_options_nav; 
    73  
    74         bp_core_new_nav_item( array( 
    75             'name' => 'Foo', 
    76             'slug' => 'foo', 
    77             'screen_function' => 'foo', 
    78         ) ); 
    79  
    80         bp_core_new_subnav_item( array( 
    81             'name' => 'Bar', 
    82             'slug' => 'bar', 
    83             'parent_slug' => 'foo', 
    84             'parent_url' => 'foo', 
    85             'screen_function' => 'bar', 
    86         ) ); 
    87  
    88         $this->assertTrue( isset( $bp->bp_options_nav['foo']['bar'] ) ); 
    89  
    90         bp_core_remove_subnav_item( 'foo', 'bar' ); 
    91  
    92         $this->assertFalse( isset( $bp->bp_options_nav['foo'] ) ); 
    93  
    94         $bp->bp_nav = $_bp_nav; 
    95         $bp->bp_options_nav = $_bp_options_nav; 
    96     } 
    9773} 
  • trunk/tests/phpunit/testcases/groups/class-bp-group-extension.php

    r9819 r10745  
    218218    /** 
    219219     * @group enable_nav_item 
     220     * @expectedIncorrectUsage bp_nav 
    220221     */ 
    221222    public function test_enable_nav_item_true() { 
     
    240241    /** 
    241242     * @group enable_nav_item 
     243     * @expectedIncorrectUsage bp_nav 
    242244     */ 
    243245    public function test_enable_nav_item_false() { 
     
    262264    /** 
    263265     * @group visibility 
     266     * @expectedIncorrectUsage bp_nav 
    264267     */ 
    265268    public function test_visibility_private() { 
     
    299302    /** 
    300303     * @group visibility 
     304     * @expectedIncorrectUsage bp_nav 
    301305     * 
    302306     * visibility=public + status=private results in adding the item to 
  • trunk/tests/phpunit/testcases/routing/anonymous.php

    r9819 r10745  
    1111    function test_nav_menu() { 
    1212        $this->go_to( '/' ); 
    13         $this->assertEmpty( buddypress()->bp_nav ); 
     13        $nav = buddypress()->members->nav->get_item_nav(); 
     14        $this->assertEmpty( $nav ); 
    1415    } 
    1516} 
  • trunk/tests/phpunit/testcases/routing/core.php

    r9819 r10745  
    2323    } 
    2424 
     25    /** 
     26     * @expectedIncorrectUsage bp_nav 
     27     */ 
    2528    function test_nav_menu() { 
    2629        $this->go_to( '/' ); 
Note: See TracChangeset for help on using the changeset viewer.