[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-core/ -> bp-core-buddybar.php (source)

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


Generated: Tue Mar 19 01:01:09 2024 Cross-referenced by PHPXref 0.7.1