/** * Register a screen function, whether or not a related subnav link exists. * * @param array|string $args { * Array describing the new subnav item. * @type string $slug Unique URL slug for the subnav item. * @type string $parent_slug Slug of the top-level nav item under which the * new subnav item should be added. * @type string $parent_url URL of the parent nav item. * @type bool $user_has_access Optional. True if the logged-in user has access to the * subnav item, otherwise false. Can be set dynamically * when registering the subnav; eg, use bp_is_my_profile() * to restrict access to profile owners only. Default: true. * @type bool $site_admin_only Optional. Whether the nav item should be visible * only to site admins (those with the 'bp_moderate' cap). * Default: false. * @type int $position Optional. Numerical index specifying where the item * should appear in the subnav array. Default: 90. * @type callable $screen_function The callback function that will run * when the nav item is clicked. * @type string $link Optional. The URL that the subnav item should point to. * Defaults to a value generated from the $parent_url + $slug. * @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. * } * * @return bool|null Returns false on failure. */ function bp_core_register_subnav_screen_function($args = '') { $bp = buddypress(); $r = wp_parse_args($args, array('slug' => false, 'parent_slug' => false, 'user_has_access' => true, 'no_access_url' => '', 'site_admin_only' => false, 'screen_function' => false)); /** * Hook the screen function for the added subnav item. But this only needs to * be done if this subnav item is the current view, and the user has access to the * subnav item. We figure out whether we're currently viewing this subnav by * checking the following two conditions: * (1) Either: * (a) the parent slug matches the current_component, or * (b) the parent slug matches the current_item * (2) And either: * (a) the current_action matches $slug, or * (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 * user, since groups should always have an action set. */ // If we *don't* meet condition (1), return if (!bp_is_current_component($r['parent_slug']) && !bp_is_current_item($r['parent_slug'])) { return; } // 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 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); // If redirect args have been returned, perform the redirect now if (!empty($hooked['status']) && 'failure' === $hooked['status'] && isset($hooked['redirect_args'])) { bp_core_no_access($hooked['redirect_args']); } } }
public function test_user_has_access_false_user_logged_in_group_no_redirect_url_provided() { $u = $this->factory->user->create(); $g = $this->factory->group->create(); $old_current_user = get_current_user_id(); $this->set_current_user($u); $group = groups_get_group(array('group_id' => $g)); $this->go_to(bp_get_group_permalink($group)); $subnav_item = array('user_has_access' => false); // Just test relevant info $found = bp_core_maybe_hook_new_subnav_screen_function($subnav_item); $this->assertSame('failure', $found['status']); $this->assertSame(bp_get_root_domain(), $found['redirect_args']['root']); // Clean up $this->set_current_user($old_current_user); }
/** * Add a subnav item to the BuddyPress navigation. * * @param array $args { * Array describing the new subnav item. * @type string $name Display name for the subnav item. * @type string $slug Unique URL slug for the subnav item. * @type string $parent_slug Slug of the top-level nav item under which the * new subnav item should be added. * @type string $parent_url URL of the parent nav item. * @type bool|string $item_css_id Optional. 'id' attribute for the nav * item. Default: the value of $slug. * @type bool $user_has_access Optional. True if the logged-in user has * access to the subnav item, otherwise false. Can be set dynamically * when registering the subnav; eg, use bp_is_my_profile() to restrict * access to profile owners only. Default: true. * @type bool $site_admin_only Optional. Whether the nav item should be * visible only to site admins (those with the 'bp_moderate' cap). * Default: false. * @type int $position Optional. Numerical index specifying where the item * should appear in the subnav array. Default: 90. * @type callable $screen_function The callback function that will run * when the nav item is clicked. * @type string $link Optional. The URL that the subnav item should point * to. Defaults to a value generated from the $parent_url + $slug. * @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. * } * @return bool|null Returns false on failure. */ function bp_core_new_subnav_item($args = '') { $bp = buddypress(); $r = wp_parse_args($args, array('name' => false, 'slug' => false, 'parent_slug' => false, 'parent_url' => false, 'item_css_id' => false, 'user_has_access' => true, 'no_access_url' => '', 'site_admin_only' => false, 'position' => 90, 'screen_function' => false, 'link' => '', 'show_in_admin_bar' => false)); extract($r, EXTR_SKIP); // If we don't have the required info we need, don't create this subnav item if (empty($name) || empty($slug) || empty($parent_slug) || empty($parent_url) || empty($screen_function)) { return false; } // Link was not forced, so create one if (empty($link)) { $link = trailingslashit($parent_url . $slug); // If this sub item is the default for its parent, skip the slug if (!empty($bp->bp_nav[$parent_slug]['default_subnav_slug']) && $slug == $bp->bp_nav[$parent_slug]['default_subnav_slug']) { $link = trailingslashit($parent_url); } } // If this is for site admins only and the user is not one, don't create the subnav item if (!empty($site_admin_only) && !bp_current_user_can('bp_moderate')) { return false; } if (empty($item_css_id)) { $item_css_id = $slug; } $subnav_item = array('name' => $name, 'link' => $link, 'slug' => $slug, 'css_id' => $item_css_id, 'position' => $position, 'user_has_access' => $user_has_access, 'no_access_url' => $no_access_url, 'screen_function' => &$screen_function, 'show_in_admin_bar' => (bool) $r['show_in_admin_bar']); $bp->bp_options_nav[$parent_slug][$slug] = $subnav_item; /** * The last step is to hook the screen function for the added subnav item. But this only * needs to be done if this subnav item is the current view, and the user has access to the * subnav item. We figure out whether we're currently viewing this subnav by checking the * following two conditions: * (1) Either: * (a) the parent slug matches the current_component, or * (b) the parent slug matches the current_item * (2) And either: * (a) the current_action matches $slug, or * (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 * user, since groups should always have an action set. */ // If we *don't* meet condition (1), return if (!bp_is_current_component($parent_slug) && !bp_is_current_item($parent_slug)) { return; } // If we *do* meet condition (2), then the added subnav item is currently being requested if (bp_current_action() && bp_is_current_action($slug) || bp_is_user() && !bp_current_action() && $screen_function == $bp->bp_nav[$parent_slug]['screen_function']) { $hooked = bp_core_maybe_hook_new_subnav_screen_function($subnav_item); // If redirect args have been returned, perform the redirect now if (!empty($hooked['status']) && 'failure' === $hooked['status'] && isset($hooked['redirect_args'])) { bp_core_no_access($hooked['redirect_args']); } } }