/bp-core/bp-core-buddybar.php

  1. <?php 
  2. /** 
  3. * Core BuddyPress Navigational Functions. 
  4. * 
  5. * @package BuddyPress 
  6. * @subpackage Core 
  7. * @since 1.5.0 
  8. * 
  9. * @todo Deprecate BuddyBar functions. 
  10. */ 
  11.  
  12. // Exit if accessed directly. 
  13. defined( 'ABSPATH' ) || exit; 
  14.  
  15. /** 
  16. * Add an item to the primary navigation of the specified component. 
  17. * 
  18. * @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. */ 
  39. function bp_core_new_nav_item( $args, $component = 'members' ) { 
  40. if ( ! bp_is_active( $component ) ) { 
  41. return; 
  42.  
  43. $defaults = array( 
  44. 'name' => false, // Display name for the nav item. 
  45. 'slug' => false, // URL slug for the nav item. 
  46. 'item_css_id' => false, // The CSS ID to apply to the HTML of the nav item. 
  47. 'show_for_displayed_user' => true, // When viewing another user does this nav item show up? 
  48. 'site_admin_only' => false, // Can only site admins see this nav item? 
  49. 'position' => 99, // Index of where this nav item should be positioned. 
  50. 'screen_function' => false, // The name of the function to run when clicked. 
  51. 'default_subnav_slug' => false // The slug of the default subnav item to select when clicked. 
  52. ); 
  53.  
  54. $r = wp_parse_args( $args, $defaults ); 
  55.  
  56. // Validate nav link data. 
  57. $nav_item = bp_core_create_nav_link( $r, $component ); 
  58.  
  59. /** 
  60. * To mimic legacy behavior, if bp_core_create_nav_link() returns false, we make 
  61. * an early exit and don't attempt to register the screen function. 
  62. */ 
  63. if ( false === $nav_item ) { 
  64. return false; 
  65.  
  66. // Then, hook the screen function for the added nav item. 
  67. $hooked = bp_core_register_nav_screen_function( $nav_item ); 
  68. if ( false === $hooked ) { 
  69. return false; 
  70.  
  71. /** 
  72. * Fires after adding an item to the main BuddyPress navigation array. 
  73. * Note that, when possible, the more specific action hooks 
  74. * `bp_core_create_nav_link` or `bp_core_register_nav_screen_function` 
  75. * should be used. 
  76. * 
  77. * @since 1.5.0 
  78. * 
  79. * @param array $r Parsed arguments for the nav item. 
  80. * @param array $args Originally passed in arguments for the nav item. 
  81. * @param array $defaults Default arguments for a nav item. 
  82. */ 
  83. do_action( 'bp_core_new_nav_item', $r, $args, $defaults ); 
  84.  
  85. /** 
  86. * Add a link to the main BuddyPress navigation. 
  87. * 
  88. * @since 2.4.0 
  89. * @since 2.6.0 Introduced the `$component` parameter. Began returning a BP_Core_Nav_Item object on success. 
  90. * 
  91. * @param array|string $args { 
  92. * Array describing the new nav item. 
  93. * @type string $name Display name for the nav item. 
  94. * @type string $slug Unique URL slug for the nav item. 
  95. * @type bool|string $item_css_id Optional. 'id' attribute for the nav item. Default: the value of `$slug`. 
  96. * @type bool $show_for_displayed_user Optional. Whether the nav item should be visible when viewing a 
  97. * member profile other than your own. Default: true. 
  98. * @type bool $site_admin_only Optional. Whether the nav item should be visible only to site admins 
  99. * (those with the 'bp_moderate' cap). Default: false. 
  100. * @type int $position Optional. Numerical index specifying where the item should appear in 
  101. * the nav array. Default: 99. 
  102. * @type callable $screen_function The callback function that will run when the nav item is clicked. 
  103. * @type bool|string $default_subnav_slug Optional. The slug of the default subnav item to select when the nav 
  104. * item is clicked. 
  105. * } 
  106. * @param string $component Optional. Component that the nav belongs to. 
  107. * @return bool|BP_Core_Nav_Item Returns false on failure, new nav item on success. 
  108. */ 
  109. function bp_core_create_nav_link( $args = '', $component = 'members' ) { 
  110. $bp = buddypress(); 
  111.  
  112. $defaults = array( 
  113. 'name' => false, // Display name for the nav item. 
  114. 'slug' => false, // URL slug for the nav item. 
  115. 'item_css_id' => false, // The CSS ID to apply to the HTML of the nav item. 
  116. 'show_for_displayed_user' => true, // When viewing another user does this nav item show up? 
  117. 'site_admin_only' => false, // Can only site admins see this nav item? 
  118. 'position' => 99, // Index of where this nav item should be positioned. 
  119. 'screen_function' => false, // The name of the function to run when clicked. 
  120. 'default_subnav_slug' => false // The slug of the default subnav item to select when clicked. 
  121. ); 
  122.  
  123. $r = wp_parse_args( $args, $defaults ); 
  124.  
  125. // If we don't have the required info we need, don't create this nav item. 
  126. if ( empty( $r['name'] ) || empty( $r['slug'] ) ) { 
  127. return false; 
  128.  
  129. // If this is for site admins only and the user is not one, don't create the nav item. 
  130. if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) { 
  131. return false; 
  132.  
  133. if ( empty( $r['item_css_id'] ) ) { 
  134. $r['item_css_id'] = $r['slug']; 
  135.  
  136. $nav_item = array( 
  137. 'name' => $r['name'],  
  138. 'slug' => $r['slug'],  
  139. 'link' => trailingslashit( bp_loggedin_user_domain() . $r['slug'] ),  
  140. 'css_id' => $r['item_css_id'],  
  141. 'show_for_displayed_user' => $r['show_for_displayed_user'],  
  142. 'position' => $r['position'],  
  143. 'screen_function' => &$r['screen_function'],  
  144. 'default_subnav_slug' => $r['default_subnav_slug'] 
  145. ); 
  146.  
  147. // Add the item to the nav. 
  148. buddypress()->{$component}->nav->add_nav( $nav_item ); 
  149.  
  150. /** 
  151. * Fires after a link is added to the main BuddyPress nav. 
  152. * 
  153. * @since 2.4.0 
  154. * @since 2.6.0 Added `$component` parameter. 
  155. * 
  156. * @param array $r Parsed arguments for the nav item. 
  157. * @param array $args Originally passed in arguments for the nav item. 
  158. * @param array $defaults Default arguments for a nav item. 
  159. * @param string $component Component that the nav belongs to. 
  160. */ 
  161. do_action( 'bp_core_create_nav_link', $r, $args, $defaults, $component ); 
  162.  
  163. return $nav_item; 
  164.  
  165. /** 
  166. * Register a screen function for an item in the main nav array. 
  167. * 
  168. * @since 2.4.0 
  169. * 
  170. * @param array|string $args { 
  171. * Array describing the new nav item. 
  172. * @type string $name Display name for the nav item. 
  173. * @type string $slug Unique URL slug for the nav item. 
  174. * @type bool|string $item_css_id Optional. 'id' attribute for the nav item. Default: the value of `$slug`. 
  175. * @type bool $show_for_displayed_user Optional. Whether the nav item should be visible when viewing a 
  176. * member profile other than your own. Default: true. 
  177. * @type bool $site_admin_only Optional. Whether the nav item should be visible only to site admins 
  178. * (those with the 'bp_moderate' cap). Default: false. 
  179. * @type int $position Optional. Numerical index specifying where the item should appear in 
  180. * the nav array. Default: 99. 
  181. * @type callable $screen_function The callback function that will run when the nav item is clicked. 
  182. * @type bool|string $default_subnav_slug Optional. The slug of the default subnav item to select when the nav 
  183. * item is clicked. 
  184. * } 
  185. * @return bool|null Returns false on failure. 
  186. */ 
  187. function bp_core_register_nav_screen_function( $args = '' ) { 
  188. $bp = buddypress(); 
  189.  
  190. $defaults = array( 
  191. 'name' => false, // Display name for the nav item. 
  192. 'slug' => false, // URL slug for the nav item. 
  193. 'item_css_id' => false, // The CSS ID to apply to the HTML of the nav item. 
  194. 'show_for_displayed_user' => true, // When viewing another user does this nav item show up? 
  195. 'site_admin_only' => false, // Can only site admins see this nav item? 
  196. 'position' => 99, // Index of where this nav item should be positioned. 
  197. 'screen_function' => false, // The name of the function to run when clicked. 
  198. 'default_subnav_slug' => false // The slug of the default subnav item to select when clicked. 
  199. ); 
  200.  
  201. $r = wp_parse_args( $args, $defaults ); 
  202.  
  203. // If we don't have the required info we need, don't register this screen function. 
  204. if ( empty( $r['slug'] ) ) { 
  205. return false; 
  206.  
  207. /** 
  208. * If this is for site admins only and the user is not one,  
  209. * don't register this screen function. 
  210. */ 
  211. if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) { 
  212. return false; 
  213.  
  214. /** 
  215. * If this nav item is hidden for the displayed user, and 
  216. * the logged in user is not the displayed user 
  217. * looking at their own profile, don't don't register this screen function. 
  218. */ 
  219. if ( empty( $r['show_for_displayed_user'] ) && ! bp_user_has_access() ) { 
  220. return false; 
  221.  
  222. /** 
  223. * If the nav item is visible, we are not viewing a user, and this is a root 
  224. * component, don't attach the default subnav function so we can display a 
  225. * directory or something else. 
  226. */ 
  227. if ( ( -1 != $r['position'] ) && bp_is_root_component( $r['slug'] ) && ! bp_displayed_user_id() ) { 
  228. return; 
  229.  
  230. // Look for current component. 
  231. if ( bp_is_current_component( $r['slug'] ) || bp_is_current_item( $r['slug'] ) ) { 
  232.  
  233. // The requested URL has explicitly included the default subnav 
  234. // (eg: http://example.com/members/membername/activity/just-me/) 
  235. // The canonical version will not contain this subnav slug. 
  236. if ( ! empty( $r['default_subnav_slug'] ) && bp_is_current_action( $r['default_subnav_slug'] ) && ! bp_action_variable( 0 ) ) { 
  237. unset( $bp->canonical_stack['action'] ); 
  238. } elseif ( ! bp_current_action() ) { 
  239.  
  240. // Add our screen hook if screen function is callable. 
  241. if ( is_callable( $r['screen_function'] ) ) { 
  242. add_action( 'bp_screens', $r['screen_function'], 3 ); 
  243.  
  244. if ( ! empty( $r['default_subnav_slug'] ) ) { 
  245.  
  246. /** 
  247. * Filters the default component subnav item. 
  248. * 
  249. * @since 1.5.0 
  250. * 
  251. * @param string $value The slug of the default subnav item 
  252. * to select when clicked. 
  253. * @param array $r Parsed arguments for the nav item. 
  254. */ 
  255. $bp->current_action = apply_filters( 'bp_default_component_subnav', $r['default_subnav_slug'], $r ); 
  256.  
  257. /** 
  258. * Fires after the screen function for an item in the BuddyPress main 
  259. * navigation is registered. 
  260. * 
  261. * @since 2.4.0 
  262. * 
  263. * @param array $r Parsed arguments for the nav item. 
  264. * @param array $args Originally passed in arguments for the nav item. 
  265. * @param array $defaults Default arguments for a nav item. 
  266. */ 
  267. do_action( 'bp_core_register_nav_screen_function', $r, $args, $defaults ); 
  268.  
  269. /** 
  270. * Modify the default subnav item that loads when a top level nav item is clicked. 
  271. * 
  272. * @since 1.1.0 
  273. * 
  274. * @param array|string $args { 
  275. * @type string $parent_slug The slug of the nav item whose default is being changed. 
  276. * @type callable $screen_function The new default callback function that will run when the nav item is clicked. 
  277. * @type string $subnav_slug The slug of the new default subnav item. 
  278. * } 
  279. */ 
  280. function bp_core_new_nav_default( $args = '' ) { 
  281. $bp = buddypress(); 
  282.  
  283. $defaults = array( 
  284. 'parent_slug' => false, // Slug of the parent. 
  285. 'screen_function' => false, // The name of the function to run when clicked. 
  286. 'subnav_slug' => false // The slug of the subnav item to select when clicked. 
  287. ); 
  288.  
  289. $r = wp_parse_args( $args, $defaults ); 
  290.  
  291. // This is specific to Members - it's not available in Groups. 
  292. $parent_nav = $bp->members->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false ); 
  293.  
  294. if ( ! $parent_nav ) { 
  295. return ; 
  296.  
  297. $parent_nav = reset( $parent_nav ); 
  298.  
  299. if ( ! empty( $parent_nav->screen_function ) ) { 
  300. // Remove our screen hook if screen function is callable. 
  301. if ( is_callable( $parent_nav->screen_function ) ) { 
  302. remove_action( 'bp_screens', $parent_nav->screen_function, 3 ); 
  303.  
  304. // Edit the screen function for the parent nav. 
  305. $bp->members->nav->edit_nav( array( 
  306. 'screen_function' => &$r['screen_function'],  
  307. 'default_subnav_slug' => $r['subnav_slug'],  
  308. ), $parent_nav->slug ); 
  309.  
  310. if ( bp_is_current_component( $parent_nav->slug ) ) { 
  311.  
  312. // The only way to tell whether to set the subnav is to peek at the unfiltered_uri 
  313. // Find the component. 
  314. $component_uri_key = array_search( $parent_nav->slug, $bp->unfiltered_uri ); 
  315.  
  316. if ( false !== $component_uri_key ) { 
  317. if ( ! empty( $bp->unfiltered_uri[$component_uri_key + 1] ) ) { 
  318. $unfiltered_action = $bp->unfiltered_uri[$component_uri_key + 1]; 
  319.  
  320. // No subnav item has been requested in the URL, so set a new nav default. 
  321. if ( empty( $unfiltered_action ) ) { 
  322. if ( ! bp_is_current_action( $r['subnav_slug'] ) ) { 
  323. if ( is_callable( $r['screen_function'] ) ) { 
  324. add_action( 'bp_screens', $r['screen_function'], 3 ); 
  325.  
  326. $bp->current_action = $r['subnav_slug']; 
  327. unset( $bp->canonical_stack['action'] ); 
  328.  
  329. // The URL is explicitly requesting the new subnav item, but should be 
  330. // directed to the canonical URL. 
  331. } elseif ( $unfiltered_action == $r['subnav_slug'] ) { 
  332. unset( $bp->canonical_stack['action'] ); 
  333.  
  334. // In all other cases (including the case where the original subnav item 
  335. // is explicitly called in the URL), the canonical URL will contain the 
  336. // subnav slug. 
  337. } else { 
  338. $bp->canonical_stack['action'] = bp_current_action(); 
  339.  
  340. return; 
  341.  
  342. /** 
  343. * Add an item to secondary navigation of the specified component. 
  344. * 
  345. * @since 1.1.0 
  346. * @since 2.6.0 Introduced the `$component` parameter. 
  347. * 
  348. * @param array|string $args { 
  349. * Array describing the new subnav item. 
  350. * @type string $name Display name for the subnav item. 
  351. * @type string $slug Unique URL slug for the subnav item. 
  352. * @type string $parent_slug Slug of the top-level nav item under which the new subnav item should 
  353. * be added. 
  354. * @type string $parent_url URL of the parent nav item. 
  355. * @type bool|string $item_css_id Optional. 'id' attribute for the nav item. Default: the value of `$slug`. 
  356. * @type bool $user_has_access Optional. True if the logged-in user has access to the subnav item,  
  357. * otherwise false. Can be set dynamically when registering the subnav; 
  358. * eg, use `bp_is_my_profile()` to restrict access to profile owners only. 
  359. * Default: true. 
  360. * @type bool $site_admin_only Optional. Whether the nav item should be visible only to site admins 
  361. * (those with the 'bp_moderate' cap). Default: false. 
  362. * @type int $position Optional. Numerical index specifying where the item should appear in the 
  363. * subnav array. Default: 90. 
  364. * @type callable $screen_function The callback function that will run when the nav item is clicked. 
  365. * @type string $link Optional. The URL that the subnav item should point to. Defaults to a value 
  366. * generated from the `$parent_url` + `$slug`. 
  367. * @type bool $show_in_admin_bar Optional. Whether the nav item should be added into the group's "Edit" 
  368. * Admin Bar menu for group admins. Default: false. 
  369. * } 
  370. * @param string $component The component the navigation is attached to. Defaults to 'members'. 
  371. * @return bool|null Returns false on failure. 
  372. */ 
  373. function bp_core_new_subnav_item( $args, $component = null ) { 
  374. // Backward compatibility for plugins using `bp_core_new_subnav_item()` without `$component` 
  375. // to add group subnav items. 
  376. if ( null === $component && bp_is_active( 'groups' ) && bp_is_group() && isset( $args['parent_slug'] ) ) { 
  377. /** 
  378. * Assume that this item is intended to belong to the current group if: 
  379. * a) the 'parent_slug' is the same as the slug of the current group, or 
  380. * b) the 'parent_slug' starts with the slug of the current group, and the members nav doesn't have 
  381. * a primary item with that slug. 
  382. */ 
  383. $group_slug = bp_get_current_group_slug(); 
  384. if ( 
  385. $group_slug === $args['parent_slug'] || 
  386. ( 0 === strpos( $args['parent_slug'], $group_slug ) && ! buddypress()->members->nav->get_primary( array( 'slug' => $args['parent_slug'] ), false ) ) 
  387. ) { 
  388. $component = 'groups'; 
  389.  
  390. if ( ! $component ) { 
  391. $component = 'members'; 
  392.  
  393. if ( ! bp_is_active( $component ) ) { 
  394. return; 
  395.  
  396. // First, register the subnav item in the nav. 
  397. $subnav_item = bp_core_create_subnav_link( $args, $component ); 
  398.  
  399. /** 
  400. * To mimic legacy behavior, if bp_core_create_subnav_link() returns false, we make an 
  401. * early exit and don't attempt to register the screen function. 
  402. */ 
  403. if ( false === $subnav_item ) { 
  404. return false; 
  405.  
  406. // Then, hook the screen function for the added subnav item. 
  407. $hooked = bp_core_register_subnav_screen_function( $subnav_item, $component ); 
  408. if ( false === $hooked ) { 
  409. return false; 
  410.  
  411. /** 
  412. * Add a subnav link to the BuddyPress navigation. 
  413. * 
  414. * @since 2.4.0 
  415. * @since 2.6.0 Introduced the `$component` parameter. Began returning a BP_Core_Nav_Item object on success. 
  416. * 
  417. * @param array|string $args { 
  418. * Array describing the new subnav item. 
  419. * @type string $name Display name for the subnav item. 
  420. * @type string $slug Unique URL slug for the subnav item. 
  421. * @type string $parent_slug Slug of the top-level nav item under which the 
  422. * new subnav item should be added. 
  423. * @type string $parent_url URL of the parent nav item. 
  424. * @type bool|string $item_css_id Optional. 'id' attribute for the nav 
  425. * item. Default: the value of $slug. 
  426. * @type bool $user_has_access Optional. True if the logged-in user has access to the 
  427. * subnav item, otherwise false. Can be set dynamically 
  428. * when registering the subnav; eg, use bp_is_my_profile() 
  429. * to restrict access to profile owners only. Default: true. 
  430. * @type bool $site_admin_only Optional. Whether the nav item should be visible only 
  431. * to site admins (those with the 'bp_moderate' cap). 
  432. * Default: false. 
  433. * @type int $position Optional. Numerical index specifying where the item 
  434. * should appear in the subnav array. Default: 90. 
  435. * @type callable $screen_function The callback function that will run 
  436. * when the nav item is clicked. 
  437. * @type string $link Optional. The URL that the subnav item should point 
  438. * to. Defaults to a value generated from the $parent_url + $slug. 
  439. * @type bool $show_in_admin_bar Optional. Whether the nav item should be added into 
  440. * the group's "Edit" Admin Bar menu for group admins. 
  441. * Default: false. 
  442. * } 
  443. * @param string $component The component the navigation is attached to. Defaults to 'members'. 
  444. * @return bool|object Returns false on failure, new BP_Core_Nav_Item instance on success. 
  445. */ 
  446. function bp_core_create_subnav_link( $args = '', $component = 'members' ) { 
  447. $bp = buddypress(); 
  448.  
  449. $r = wp_parse_args( $args, array( 
  450. 'name' => false, // Display name for the nav item. 
  451. 'slug' => false, // URL slug for the nav item. 
  452. 'parent_slug' => false, // URL slug of the parent nav item. 
  453. 'parent_url' => false, // URL of the parent item. 
  454. 'item_css_id' => false, // The CSS ID to apply to the HTML of the nav item. 
  455. 'user_has_access' => true, // Can the logged in user see this nav item? 
  456. 'no_access_url' => '',  
  457. 'site_admin_only' => false, // Can only site admins see this nav item? 
  458. 'position' => 90, // Index of where this nav item should be positioned. 
  459. 'screen_function' => false, // The name of the function to run when clicked. 
  460. 'link' => '', // The link for the subnav item; optional, not usually required. 
  461. 'show_in_admin_bar' => false, // Show the Manage link in the current group's "Edit" Admin Bar menu. 
  462. ) ); 
  463.  
  464. // If we don't have the required info we need, don't create this subnav item. 
  465. if ( empty( $r['name'] ) || empty( $r['slug'] ) || empty( $r['parent_slug'] ) || empty( $r['parent_url'] ) || empty( $r['screen_function'] ) ) 
  466. return false; 
  467.  
  468. // Link was not forced, so create one. 
  469. if ( empty( $r['link'] ) ) { 
  470. $r['link'] = trailingslashit( $r['parent_url'] . $r['slug'] ); 
  471.  
  472. $parent_nav = $bp->{$component}->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false ); 
  473.  
  474. // If this sub item is the default for its parent, skip the slug. 
  475. if ( $parent_nav ) { 
  476. $parent_nav_item = reset( $parent_nav ); 
  477. if ( ! empty( $parent_nav_item->default_subnav_slug ) && $r['slug'] === $parent_nav_item->default_subnav_slug ) { 
  478. $r['link'] = trailingslashit( $r['parent_url'] ); 
  479.  
  480. // If this is for site admins only and the user is not one, don't create the subnav item. 
  481. if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) { 
  482. return false; 
  483.  
  484. if ( empty( $r['item_css_id'] ) ) { 
  485. $r['item_css_id'] = $r['slug']; 
  486.  
  487. $subnav_item = array( 
  488. 'name' => $r['name'],  
  489. 'link' => $r['link'],  
  490. 'slug' => $r['slug'],  
  491. 'parent_slug' => $r['parent_slug'],  
  492. 'css_id' => $r['item_css_id'],  
  493. 'position' => $r['position'],  
  494. 'user_has_access' => $r['user_has_access'],  
  495. 'no_access_url' => $r['no_access_url'],  
  496. 'screen_function' => &$r['screen_function'],  
  497. 'show_in_admin_bar' => (bool) $r['show_in_admin_bar'],  
  498. ); 
  499.  
  500. buddypress()->{$component}->nav->add_nav( $subnav_item ); 
  501.  
  502. return $subnav_item; 
  503.  
  504. /** 
  505. * Register a screen function, whether or not a related subnav link exists. 
  506. * 
  507. * @since 2.4.0 
  508. * @since 2.6.0 Introduced the `$component` parameter. 
  509. * 
  510. * @param array|string $args { 
  511. * Array describing the new subnav item. 
  512. * @type string $slug Unique URL slug for the subnav item. 
  513. * @type string $parent_slug Slug of the top-level nav item under which the 
  514. * new subnav item should be added. 
  515. * @type string $parent_url URL of the parent nav item. 
  516. * @type bool $user_has_access Optional. True if the logged-in user has access to the 
  517. * subnav item, otherwise false. Can be set dynamically 
  518. * when registering the subnav; eg, use bp_is_my_profile() 
  519. * to restrict access to profile owners only. Default: true. 
  520. * @type bool $site_admin_only Optional. Whether the nav item should be visible 
  521. * only to site admins (those with the 'bp_moderate' cap). 
  522. * Default: false. 
  523. * @type int $position Optional. Numerical index specifying where the item 
  524. * should appear in the subnav array. Default: 90. 
  525. * @type callable $screen_function The callback function that will run 
  526. * when the nav item is clicked. 
  527. * @type string $link Optional. The URL that the subnav item should point to. 
  528. * Defaults to a value generated from the $parent_url + $slug. 
  529. * @type bool $show_in_admin_bar Optional. Whether the nav item should be added into 
  530. * the group's "Edit" Admin Bar menu for group admins. 
  531. * Default: false. 
  532. * } 
  533. * @param string $component The component the navigation is attached to. Defaults to 'members'. 
  534. * @return bool|null Returns false on failure. 
  535. */ 
  536. function bp_core_register_subnav_screen_function( $args = '', $component = 'members' ) { 
  537. $bp = buddypress(); 
  538.  
  539. $r = wp_parse_args( $args, array( 
  540. 'slug' => false, // URL slug for the screen. 
  541. 'parent_slug' => false, // URL slug of the parent screen. 
  542. 'user_has_access' => true, // Can the user visit this screen? 
  543. 'no_access_url' => '',  
  544. 'site_admin_only' => false, // Can only site admins visit this screen? 
  545. 'screen_function' => false, // The name of the function to run when clicked. 
  546. ) ); 
  547.  
  548. /** 
  549. * Hook the screen function for the added subnav item. But this only needs to 
  550. * be done if this subnav item is the current view, and the user has access to the 
  551. * subnav item. We figure out whether we're currently viewing this subnav by 
  552. * checking the following two conditions: 
  553. * (1) Either: 
  554. * (a) the parent slug matches the current_component, or 
  555. * (b) the parent slug matches the current_item 
  556. * (2) And either: 
  557. * (a) the current_action matches $slug, or 
  558. * (b) there is no current_action (ie, this is the default subnav for the parent nav) 
  559. * and this subnav item is the default for the parent item (which we check by 
  560. * comparing this subnav item's screen function with the screen function of the 
  561. * parent nav item in the component's primary nav). This condition only arises 
  562. * when viewing a user, since groups should always have an action set. 
  563. */ 
  564.  
  565. // If we *don't* meet condition (1), return. 
  566. if ( ! bp_is_current_component( $r['parent_slug'] ) && ! bp_is_current_item( $r['parent_slug'] ) ) { 
  567. return; 
  568.  
  569. $parent_nav = $bp->{$component}->nav->get_primary( array( 'slug' => $r['parent_slug'] ), false ); 
  570.  
  571. // If we *do* meet condition (2), then the added subnav item is currently being requested. 
  572. 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 ) ) { 
  573.  
  574. // If this is for site admins only and the user is not one, don't create the subnav item. 
  575. if ( ! empty( $r['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) { 
  576. return false; 
  577.  
  578. $hooked = bp_core_maybe_hook_new_subnav_screen_function( $r, $component ); 
  579.  
  580. // If redirect args have been returned, perform the redirect now. 
  581. if ( ! empty( $hooked['status'] ) && 'failure' === $hooked['status'] && isset( $hooked['redirect_args'] ) ) { 
  582. bp_core_no_access( $hooked['redirect_args'] ); 
  583.  
  584. /** 
  585. * For a given subnav item, either hook the screen function or generate redirect arguments, as necessary. 
  586. * 
  587. * @since 2.1.0 
  588. * @since 2.6.0 Introduced the `$component` parameter. 
  589. * 
  590. * @param array $subnav_item The subnav array added to the secondary navigation of 
  591. * the component in bp_core_new_subnav_item(). 
  592. * @param string $component The component the navigation is attached to. Defaults to 'members'. 
  593. * @return array 
  594. */ 
  595. function bp_core_maybe_hook_new_subnav_screen_function( $subnav_item, $component = 'members' ) { 
  596. $retval = array( 
  597. 'status' => '',  
  598. ); 
  599.  
  600. // Is this accessible by site admins only? 
  601. $site_admin_restricted = false; 
  602. if ( ! empty( $subnav_item['site_admin_only'] ) && ! bp_current_user_can( 'bp_moderate' ) ) { 
  603. $site_admin_restricted = true; 
  604.  
  605. // User has access, so let's try to hook the display callback. 
  606. if ( ! empty( $subnav_item['user_has_access'] ) && ! $site_admin_restricted ) { 
  607.  
  608. // Screen function is invalid. 
  609. if ( ! is_callable( $subnav_item['screen_function'] ) ) { 
  610. $retval['status'] = 'failure'; 
  611.  
  612. // Success - hook to bp_screens. 
  613. } else { 
  614. add_action( 'bp_screens', $subnav_item['screen_function'], 3 ); 
  615. $retval['status'] = 'success'; 
  616.  
  617. // User doesn't have access. Determine redirect arguments based on 
  618. // user status. 
  619. } else { 
  620. $retval['status'] = 'failure'; 
  621.  
  622. if ( is_user_logged_in() ) { 
  623.  
  624. $bp = buddypress(); 
  625.  
  626. // If a redirect URL has been passed to the subnav 
  627. // item, respect it. 
  628. if ( ! empty( $subnav_item['no_access_url'] ) ) { 
  629. $message = __( 'You do not have access to this page.', 'buddypress' ); 
  630. $redirect_to = trailingslashit( $subnav_item['no_access_url'] ); 
  631.  
  632. // In the case of a user page, we try to assume a 
  633. // redirect URL. 
  634. } elseif ( bp_is_user() ) { 
  635.  
  636. $parent_nav_default = $bp->{$component}->nav->get_primary( array( 'slug' => $bp->default_component ), false ); 
  637. if ( $parent_nav_default ) { 
  638. $parent_nav_default_item = reset( $parent_nav_default ); 
  639.  
  640. // Redirect to the displayed user's default 
  641. // component, as long as that component is 
  642. // publicly accessible. 
  643. if ( bp_is_my_profile() || ( isset( $parent_nav_default_item ) && $parent_nav_default_item->show_for_displayed_user ) ) { 
  644. $message = __( 'You do not have access to this page.', 'buddypress' ); 
  645. $redirect_to = bp_displayed_user_domain(); 
  646.  
  647. // In some cases, the default tab is not accessible to 
  648. // the logged-in user. So we fall back on a tab that we 
  649. // know will be accessible. 
  650. } else { 
  651. // Try 'activity' first. 
  652. if ( bp_is_active( 'activity' ) && isset( $bp->pages->activity ) ) { 
  653. $redirect_to = trailingslashit( bp_displayed_user_domain() . bp_get_activity_slug() ); 
  654. // Then try 'profile'. 
  655. } else { 
  656. $redirect_to = trailingslashit( bp_displayed_user_domain() . ( 'xprofile' == $bp->profile->id ? 'profile' : $bp->profile->id ) ); 
  657.  
  658. $message = ''; 
  659.  
  660. // Fall back to the home page. 
  661. } else { 
  662. $message = __( 'You do not have access to this page.', 'buddypress' ); 
  663. $redirect_to = bp_get_root_domain(); 
  664.  
  665. $retval['redirect_args'] = array( 
  666. 'message' => $message,  
  667. 'root' => $redirect_to,  
  668. 'redirect' => false,  
  669. ); 
  670.  
  671. } else { 
  672. // When the user is logged out, pass an empty array 
  673. // This indicates that the default arguments should be 
  674. // used in bp_core_no_access(). 
  675. $retval['redirect_args'] = array(); 
  676.  
  677. return $retval; 
  678.  
  679. /** 
  680. * Check whether a given nav item has subnav items. 
  681. * 
  682. * @since 1.5.0 
  683. * @since 2.6.0 Introduced the `$component` parameter. 
  684. * 
  685. * @param string $nav_item The slug of the top-level nav item whose subnav items you're checking. 
  686. * Default: the current component slug. 
  687. * @param string $component The component the navigation is attached to. Defaults to 'members'. 
  688. * @return bool $has_subnav True if the nav item is found and has subnav items; false otherwise. 
  689. */ 
  690. function bp_nav_item_has_subnav( $nav_item = '', $component = 'members' ) { 
  691. $bp = buddypress(); 
  692.  
  693. if ( ! isset( $bp->{$component}->nav ) ) { 
  694. return false; 
  695.  
  696. if ( ! $nav_item ) { 
  697. $nav_item = bp_current_component(); 
  698.  
  699. if ( bp_is_group() ) { 
  700. $nav_item = bp_current_item(); 
  701.  
  702. $has_subnav = (bool) $bp->{$component}->nav->get_secondary( array( 'parent_slug' => $nav_item ), false ); 
  703.  
  704. /** 
  705. * Filters whether or not a given nav item has subnav items. 
  706. * 
  707. * @since 1.5.0 
  708. * 
  709. * @param bool $has_subnav Whether or not there is any subnav items. 
  710. * @param string $nav_item The slug of the top-level nav item whose subnav items you're checking. 
  711. */ 
  712. return apply_filters( 'bp_nav_item_has_subnav', $has_subnav, $nav_item ); 
  713.  
  714. /** 
  715. * Deletes an item from the primary navigation of the specified component. 
  716. * 
  717. * @since 1.0.0 
  718. * @since 2.6.0 Introduced the `$component` parameter. 
  719. * 
  720. * @param string $slug The slug of the primary navigation item. 
  721. * @param string $component The component the navigation is attached to. Defaults to 'members'. 
  722. * @return bool Returns false on failure, True on success. 
  723. */ 
  724. function bp_core_remove_nav_item( $slug, $component = null ) { 
  725. $bp = buddypress(); 
  726.  
  727. // Backward compatibility for removing group nav items using the group slug as `$parent_slug`. 
  728. if ( ! $component && bp_is_active( 'groups' ) && isset( $bp->groups->nav ) ) { 
  729. if ( $bp->groups->nav->get_primary( array( 'slug' => $slug ) ) ) { 
  730. $component = 'groups'; 
  731.  
  732. if ( ! $component ) { 
  733. $component = 'members'; 
  734.  
  735. if ( ! isset( $bp->{$component}->nav ) ) { 
  736. return false; 
  737.  
  738. $screen_functions = $bp->{$component}->nav->delete_nav( $slug ); 
  739.  
  740. // Reset backcompat nav items so that subsequent references will be correct. 
  741. $bp->bp_nav->reset(); 
  742. $bp->bp_options_nav->reset(); 
  743.  
  744. if ( ! is_array( $screen_functions ) ) { 
  745. return false; 
  746.  
  747. foreach ( $screen_functions as $screen_function ) { 
  748. // Remove our screen hook if screen function is callable. 
  749. if ( is_callable( $screen_function ) ) { 
  750. remove_action( 'bp_screens', $screen_function, 3 ); 
  751.  
  752. return true; 
  753.  
  754. /** 
  755. * Deletes an item from the secondary navigation of the specified component. 
  756. * 
  757. * @since 1.0.0 
  758. * @since 2.6.0 Introduced the `$component` parameter. 
  759. * 
  760. * @param string $parent_slug The slug of the primary navigation item. 
  761. * @param string $slug The slug of the secondary item to be removed. 
  762. * @param string $component The component the navigation is attached to. Defaults to 'members'. 
  763. * @return bool Returns false on failure, True on success. 
  764. */ 
  765. function bp_core_remove_subnav_item( $parent_slug, $slug, $component = null ) { 
  766. $bp = buddypress(); 
  767.  
  768. // Backward compatibility for removing group nav items using the group slug as `$parent_slug`. 
  769. if ( ! $component && bp_is_active( 'groups' ) && isset( $bp->groups->nav ) ) { 
  770. if ( $bp->groups->nav->get_primary( array( 'slug' => $parent_slug ) ) ) { 
  771. $component = 'groups'; 
  772.  
  773. if ( ! $component ) { 
  774. $component = 'members'; 
  775.  
  776. if ( ! isset( $bp->{$component}->nav ) ) { 
  777. return false; 
  778.  
  779. $screen_functions = $bp->{$component}->nav->delete_nav( $slug, $parent_slug ); 
  780.  
  781. // Reset backcompat nav items so that subsequent references will be correct. 
  782. $bp->bp_nav->reset(); 
  783. $bp->bp_options_nav->reset(); 
  784.  
  785. if ( ! is_array( $screen_functions ) ) { 
  786. return false; 
  787.  
  788. $screen_function = reset( $screen_functions ); 
  789.  
  790. // Remove our screen hook if screen function is callable. 
  791. if ( is_callable( $screen_function ) ) { 
  792. remove_action( 'bp_screens', $screen_function, 3 ); 
  793.  
  794. return true; 
  795.  
  796. /** 
  797. * Clear all subnav items from a specific nav item. 
  798. * 
  799. * @since 1.0.0 
  800. * @since 2.6.0 Introduced the `$component` parameter. 
  801. * 
  802. * @param string $parent_slug The slug of the parent navigation item. 
  803. * @param string $component The component the navigation is attached to. Defaults to 'members'. 
  804. */ 
  805. function bp_core_reset_subnav_items( $parent_slug, $component = 'members' ) { 
  806. $bp = buddypress(); 
  807.  
  808. if ( ! isset( $bp->{$component}->nav ) ) { 
  809. return; 
  810.  
  811. $subnav_items = $bp->{$component}->nav->get_secondary( array( 'parent_slug' => $parent_slug ), false ); 
  812.  
  813. if ( ! $subnav_items ) { 
  814. return; 
  815.  
  816. foreach( $subnav_items as $subnav_item ) { 
  817. $bp->{$component}->nav->delete_nav( $subnav_item->slug, $parent_slug ); 
  818.  
  819.  
  820. /** 
  821. * Retrieve the Toolbar display preference of a user based on context. 
  822. * 
  823. * This is a direct copy of WP's private _get_admin_bar_pref() 
  824. * 
  825. * @since 1.5.0 
  826. * 
  827. * @param string $context Context of this preference check. 'admin' or 'front'. 
  828. * @param int $user Optional. ID of the user to check. Default: 0 (which falls back to the logged-in user's ID). 
  829. * @return bool True if the toolbar should be showing for this user. 
  830. */ 
  831. function bp_get_admin_bar_pref( $context, $user = 0 ) { 
  832. $pref = get_user_option( "show_admin_bar_{$context}", $user ); 
  833. if ( false === $pref ) 
  834. return true; 
  835.  
  836. return 'true' === $pref; 
.