[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

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

   1  <?php
   2  /**
   3   * BuddyPress URI catcher.
   4   *
   5   * Functions for parsing the URI and determining which BuddyPress template file
   6   * to use on-screen.
   7   *
   8   * @package BuddyPress
   9   * @subpackage Core
  10   * @since 1.0.0
  11   */
  12  
  13  // Exit if accessed directly.
  14  defined( 'ABSPATH' ) || exit;
  15  
  16  /**
  17   * Analyze the URI and break it down into BuddyPress-usable chunks.
  18   *
  19   * BuddyPress can use complete custom friendly URIs without the user having to
  20   * add new rewrite rules. Custom components are able to use their own custom
  21   * URI structures with very little work.
  22   *
  23   * The URIs are broken down as follows:
  24   *   - http:// example.com / members / andy / [current_component] / [current_action] / [action_variables] / [action_variables] / ...
  25   *   - OUTSIDE ROOT: http:// example.com / sites / buddypress / members / andy / [current_component] / [current_action] / [action_variables] / [action_variables] / ...
  26   *
  27   * Example:
  28   *    - http://example.com/members/andy/profile/edit/group/5/
  29   *    - $bp->current_component: string 'xprofile'
  30   *    - $bp->current_action: string 'edit'
  31   *    - $bp->action_variables: array ['group', 5]
  32   *
  33   * @since 1.0.0
  34   */
  35  function bp_core_set_uri_globals() {
  36      global $current_blog, $wp_rewrite;
  37  
  38      // Don't catch URIs on non-root blogs unless multiblog mode is on.
  39      if ( !bp_is_root_blog() && !bp_is_multiblog_mode() )
  40          return false;
  41  
  42      $bp = buddypress();
  43  
  44      // Define local variables.
  45      $root_profile = $match   = false;
  46      $key_slugs    = $matches = $uri_chunks = array();
  47  
  48      // Fetch all the WP page names for each component.
  49      if ( empty( $bp->pages ) )
  50          $bp->pages = bp_core_get_directory_pages();
  51  
  52      // Ajax or not?
  53      if ( defined( 'DOING_AJAX' ) && DOING_AJAX || strpos( $_SERVER['REQUEST_URI'], 'wp-load.php' ) )
  54          $path = bp_get_referer_path();
  55      else
  56          $path = esc_url( $_SERVER['REQUEST_URI'] );
  57  
  58      /**
  59       * Filters the BuddyPress global URI path.
  60       *
  61       * @since 1.0.0
  62       *
  63       * @param string $path Path to set.
  64       */
  65      $path = apply_filters( 'bp_uri', $path );
  66  
  67      // Take GET variables off the URL to avoid problems.
  68      $path = strtok( $path, '?' );
  69  
  70      // Fetch current URI and explode each part separated by '/' into an array.
  71      $bp_uri = explode( '/', $path );
  72  
  73      // Loop and remove empties.
  74      foreach ( (array) $bp_uri as $key => $uri_chunk ) {
  75          if ( empty( $bp_uri[$key] ) ) {
  76              unset( $bp_uri[$key] );
  77          }
  78      }
  79  
  80      /*
  81       * If running off blog other than root, any subdirectory names must be
  82       * removed from $bp_uri. This includes two cases:
  83       *
  84       * 1. when WP is installed in a subdirectory,
  85       * 2. when BP is running on secondary blog of a subdirectory
  86       * multisite installation. Phew!
  87       */
  88      if ( is_multisite() && !is_subdomain_install() && ( bp_is_multiblog_mode() || 1 != bp_get_root_blog_id() ) ) {
  89  
  90          // Blow chunks.
  91          $chunks = explode( '/', $current_blog->path );
  92  
  93          // If chunks exist...
  94          if ( !empty( $chunks ) ) {
  95  
  96              // ...loop through them...
  97              foreach( $chunks as $key => $chunk ) {
  98                  $bkey = array_search( $chunk, $bp_uri );
  99  
 100                  // ...and unset offending keys
 101                  if ( false !== $bkey ) {
 102                      unset( $bp_uri[$bkey] );
 103                  }
 104  
 105                  $bp_uri = array_values( $bp_uri );
 106              }
 107          }
 108      }
 109  
 110      // Get site path items.
 111      $paths = explode( '/', bp_core_get_site_path() );
 112  
 113      // Take empties off the end of path.
 114      if ( empty( $paths[count( $paths ) - 1] ) )
 115          array_pop( $paths );
 116  
 117      // Take empties off the start of path.
 118      if ( empty( $paths[0] ) )
 119          array_shift( $paths );
 120  
 121      // Reset indexes.
 122      $bp_uri = array_values( $bp_uri );
 123      $paths  = array_values( $paths );
 124  
 125      // Unset URI indices if they intersect with the paths.
 126      foreach ( (array) $bp_uri as $key => $uri_chunk ) {
 127          if ( isset( $paths[$key] ) && $uri_chunk == $paths[$key] ) {
 128              unset( $bp_uri[$key] );
 129          }
 130      }
 131  
 132      // Reset the keys by merging with an empty array.
 133      $bp_uri = array_merge( array(), $bp_uri );
 134  
 135      /*
 136       * If a component is set to the front page, force its name into $bp_uri
 137       * so that $current_component is populated (unless a specific WP post is being requested
 138       * via a URL parameter, usually signifying Preview mode).
 139       */
 140      if ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_on_front' ) && empty( $bp_uri ) && empty( $_GET['p'] ) && empty( $_GET['page_id'] ) ) {
 141          $post = get_post( get_option( 'page_on_front' ) );
 142          if ( !empty( $post ) ) {
 143              $bp_uri[0] = $post->post_name;
 144          }
 145      }
 146  
 147      // Keep the unfiltered URI safe.
 148      $bp->unfiltered_uri = $bp_uri;
 149  
 150      // Don't use $bp_unfiltered_uri, this is only for backpat with old plugins. Use $bp->unfiltered_uri.
 151      $GLOBALS['bp_unfiltered_uri'] = &$bp->unfiltered_uri;
 152  
 153      // Get slugs of pages into array.
 154      foreach ( (array) $bp->pages as $page_key => $bp_page )
 155          $key_slugs[$page_key] = trailingslashit( '/' . $bp_page->slug );
 156  
 157      // Bail if keyslugs are empty, as BP is not setup correct.
 158      if ( empty( $key_slugs ) )
 159          return;
 160  
 161      // Loop through page slugs and look for exact match to path.
 162      foreach ( $key_slugs as $key => $slug ) {
 163          if ( $slug == $path ) {
 164              $match      = $bp->pages->{$key};
 165              $match->key = $key;
 166              $matches[]  = 1;
 167              break;
 168          }
 169      }
 170  
 171      // No exact match, so look for partials.
 172      if ( empty( $match ) ) {
 173  
 174          // Loop through each page in the $bp->pages global.
 175          foreach ( (array) $bp->pages as $page_key => $bp_page ) {
 176  
 177              // Look for a match (check members first).
 178              if ( in_array( $bp_page->name, (array) $bp_uri ) ) {
 179  
 180                  // Match found, now match the slug to make sure.
 181                  $uri_chunks = explode( '/', $bp_page->slug );
 182  
 183                  // Loop through uri_chunks.
 184                  foreach ( (array) $uri_chunks as $key => $uri_chunk ) {
 185  
 186                      // Make sure chunk is in the correct position.
 187                      if ( !empty( $bp_uri[$key] ) && ( $bp_uri[$key] == $uri_chunk ) ) {
 188                          $matches[] = 1;
 189  
 190                      // No match.
 191                      } else {
 192                          $matches[] = 0;
 193                      }
 194                  }
 195  
 196                  // Have a match.
 197                  if ( !in_array( 0, (array) $matches ) ) {
 198                      $match      = $bp_page;
 199                      $match->key = $page_key;
 200                      break;
 201                  };
 202  
 203                  // Unset matches.
 204                  unset( $matches );
 205              }
 206  
 207              // Unset uri chunks.
 208              unset( $uri_chunks );
 209          }
 210      }
 211  
 212      // URLs with BP_ENABLE_ROOT_PROFILES enabled won't be caught above.
 213      if ( empty( $matches ) && bp_core_enable_root_profiles() && ! empty( $bp_uri[0] ) ) {
 214  
 215          // Switch field based on compat.
 216          $field = bp_is_username_compatibility_mode() ? 'login' : 'slug';
 217  
 218          /**
 219           * Filter the portion of the URI that is the displayed user's slug.
 220           *
 221           * Eg. example.com/ADMIN (when root profiles is enabled)
 222           *     example.com/members/ADMIN (when root profiles isn't enabled)
 223           *
 224           * ADMIN would be the displayed user's slug.
 225           *
 226           * @since 2.6.0
 227           *
 228           * @param string $member_slug
 229           */
 230          $member_slug = apply_filters( 'bp_core_set_uri_globals_member_slug', $bp_uri[0] );
 231  
 232          // Make sure there's a user corresponding to $bp_uri[0].
 233          if ( ! empty( $bp->pages->members ) && $root_profile = get_user_by( $field, $member_slug ) ) {
 234  
 235              // Force BP to recognize that this is a members page.
 236              $matches[]  = 1;
 237              $match      = $bp->pages->members;
 238              $match->key = 'members';
 239          }
 240      }
 241  
 242      // Search doesn't have an associated page, so we check for it separately.
 243      if ( isset( $_POST['search-terms'] ) && !empty( $bp_uri[0] ) && ( bp_get_search_slug() == $bp_uri[0] ) ) {
 244          $matches[]   = 1;
 245          $match       = new stdClass;
 246          $match->key  = 'search';
 247          $match->slug = bp_get_search_slug();
 248      }
 249  
 250      // This is not a BuddyPress page, so just return.
 251      if ( empty( $matches ) )
 252          return false;
 253  
 254      $wp_rewrite->use_verbose_page_rules = false;
 255  
 256      // Find the offset. With $root_profile set, we fudge the offset down so later parsing works.
 257      $slug       = !empty ( $match ) ? explode( '/', $match->slug ) : '';
 258      $uri_offset = empty( $root_profile ) ? 0 : -1;
 259  
 260      // Rejig the offset.
 261      if ( !empty( $slug ) && ( 1 < count( $slug ) ) ) {
 262          // Only offset if not on a root profile. Fixes issue when Members page is nested.
 263          if ( false === $root_profile ) {
 264              array_pop( $slug );
 265              $uri_offset = count( $slug );
 266          }
 267      }
 268  
 269      // Global the unfiltered offset to use in bp_core_load_template().
 270      // To avoid PHP warnings in bp_core_load_template(), it must always be >= 0.
 271      $bp->unfiltered_uri_offset = $uri_offset >= 0 ? $uri_offset : 0;
 272  
 273      // We have an exact match.
 274      if ( isset( $match->key ) ) {
 275  
 276          // Set current component to matched key.
 277          $bp->current_component = $match->key;
 278  
 279          // If members component, do more work to find the actual component.
 280          if ( 'members' == $match->key ) {
 281  
 282              $after_member_slug = false;
 283              if ( ! empty( $bp_uri[ $uri_offset + 1 ] ) ) {
 284                  $after_member_slug = $bp_uri[ $uri_offset + 1 ];
 285              }
 286  
 287              // Are we viewing a specific user?
 288              if ( $after_member_slug ) {
 289  
 290                  /** This filter is documented in bp-core/bp-core-catchuri.php */
 291                  $after_member_slug = apply_filters( 'bp_core_set_uri_globals_member_slug', $after_member_slug );
 292  
 293                  // If root profile, we've already queried for the user.
 294                  if ( $root_profile instanceof WP_User ) {
 295                      $bp->displayed_user->id = $root_profile->ID;
 296  
 297                  // Switch the displayed_user based on compatibility mode.
 298                  } elseif ( bp_is_username_compatibility_mode() ) {
 299                      $bp->displayed_user->id = (int) bp_core_get_userid( urldecode( $after_member_slug ) );
 300  
 301                  } else {
 302                      $bp->displayed_user->id = (int) bp_core_get_userid_from_nicename( $after_member_slug );
 303                  }
 304              }
 305  
 306              // Is this a member type directory?
 307              if ( ! bp_displayed_user_id() && $after_member_slug === bp_get_members_member_type_base() && ! empty( $bp_uri[ $uri_offset + 2 ] ) ) {
 308                  $matched_types = bp_get_member_types( array(
 309                      'has_directory'  => true,
 310                      'directory_slug' => $bp_uri[ $uri_offset + 2 ],
 311                  ) );
 312  
 313                  if ( ! empty( $matched_types ) ) {
 314                      $bp->current_member_type = reset( $matched_types );
 315                      unset( $bp_uri[ $uri_offset + 1 ] );
 316                  }
 317              }
 318  
 319              // If the slug matches neither a member type nor a specific member, 404.
 320              if ( ! bp_displayed_user_id() && ! bp_get_current_member_type() && $after_member_slug ) {
 321                  // Prevent components from loading their templates.
 322                  $bp->current_component = '';
 323                  bp_do_404();
 324                  return;
 325              }
 326  
 327              // If the displayed user is marked as a spammer, 404 (unless logged-in user is a super admin).
 328              if ( bp_displayed_user_id() && bp_is_user_spammer( bp_displayed_user_id() ) ) {
 329                  if ( bp_current_user_can( 'bp_moderate' ) ) {
 330                      bp_core_add_message( __( 'This user has been marked as a spammer. Only site admins can view this profile.', 'buddypress' ), 'warning' );
 331                  } else {
 332                      bp_do_404();
 333                      return;
 334                  }
 335              }
 336  
 337              // Bump the offset.
 338              if ( bp_displayed_user_id() ) {
 339                  if ( isset( $bp_uri[$uri_offset + 2] ) ) {
 340                      $bp_uri                = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) );
 341                      $bp->current_component = $bp_uri[0];
 342  
 343                  // No component, so default will be picked later.
 344                  } else {
 345                      $bp_uri                = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) );
 346                      $bp->current_component = '';
 347                  }
 348  
 349                  // Reset the offset.
 350                  $uri_offset = 0;
 351              }
 352          }
 353      }
 354  
 355      // Determine the current action.
 356      $current_action = isset( $bp_uri[ $uri_offset + 1 ] ) ? $bp_uri[ $uri_offset + 1 ] : '';
 357  
 358      /*
 359       * If a BuddyPress directory is set to the WP front page, URLs like example.com/members/?s=foo
 360       * shouldn't interfere with blog searches.
 361       */
 362      if ( empty( $current_action) && ! empty( $_GET['s'] ) && 'page' == get_option( 'show_on_front' ) && ! empty( $match->id ) ) {
 363          $page_on_front = (int) get_option( 'page_on_front' );
 364          if ( (int) $match->id === $page_on_front ) {
 365              $bp->current_component = '';
 366              return false;
 367          }
 368      }
 369  
 370      $bp->current_action = $current_action;
 371  
 372      // Slice the rest of the $bp_uri array and reset offset.
 373      $bp_uri      = array_slice( $bp_uri, $uri_offset + 2 );
 374      $uri_offset  = 0;
 375  
 376      // Set the entire URI as the action variables, we will unset the current_component and action in a second.
 377      $bp->action_variables = $bp_uri;
 378  
 379      // Reset the keys by merging with an empty array.
 380      $bp->action_variables = array_merge( array(), $bp->action_variables );
 381  }
 382  
 383  /**
 384   * Are root profiles enabled and allowed?
 385   *
 386   * @since 1.6.0
 387   *
 388   * @return bool True if yes, false if no.
 389   */
 390  function bp_core_enable_root_profiles() {
 391  
 392      $retval = false;
 393  
 394      if ( defined( 'BP_ENABLE_ROOT_PROFILES' ) && ( true == BP_ENABLE_ROOT_PROFILES ) )
 395          $retval = true;
 396  
 397      /**
 398       * Filters whether or not root profiles are enabled and allowed.
 399       *
 400       * @since 1.6.0
 401       *
 402       * @param bool $retval Whether or not root profiles are available.
 403       */
 404      return apply_filters( 'bp_core_enable_root_profiles', $retval );
 405  }
 406  
 407  /**
 408   * Load a specific template file with fallback support.
 409   *
 410   * Example:
 411   *   bp_core_load_template( 'members/index' );
 412   * Loads:
 413   *   wp-content/themes/[activated_theme]/members/index.php
 414   *
 415   * @since 1.0.0
 416   *
 417   * @param array $templates Array of templates to attempt to load.
 418   */
 419  function bp_core_load_template( $templates ) {
 420      global $wp_query;
 421  
 422      // Reset the post.
 423      bp_theme_compat_reset_post( array(
 424          'ID'          => 0,
 425          'is_404'      => true,
 426          'post_status' => 'publish',
 427      ) );
 428  
 429      // Set theme compat to false since the reset post function automatically sets
 430      // theme compat to true.
 431      bp_set_theme_compat_active( false );
 432  
 433      // Fetch each template and add the php suffix.
 434      $filtered_templates = array();
 435      foreach ( (array) $templates as $template ) {
 436          $filtered_templates[] = $template . '.php';
 437      }
 438  
 439      // Only perform template lookup for bp-default themes.
 440      if ( ! bp_use_theme_compat_with_current_theme() ) {
 441          $template = locate_template( (array) $filtered_templates, false );
 442  
 443      // Theme compat doesn't require a template lookup.
 444      } else {
 445          $template = '';
 446      }
 447  
 448      /**
 449       * Filters the template locations.
 450       *
 451       * Allows plugins to alter where the template files are located.
 452       *
 453       * @since 1.1.0
 454       *
 455       * @param string $template           Located template path.
 456       * @param array  $filtered_templates Array of templates to attempt to load.
 457       */
 458      $located_template = apply_filters( 'bp_located_template', $template, $filtered_templates );
 459  
 460      /*
 461       * If current page is an embed, wipe out bp-default template.
 462       *
 463       * Wiping out the bp-default template allows WordPress to use their special
 464       * embed template, which is what we want.
 465       */
 466      if ( function_exists( 'is_embed' ) && is_embed() ) {
 467          $located_template = '';
 468      }
 469  
 470      if ( !empty( $located_template ) ) {
 471          // Template was located, lets set this as a valid page and not a 404.
 472          status_header( 200 );
 473          $wp_query->is_page     = true;
 474          $wp_query->is_singular = true;
 475          $wp_query->is_404      = false;
 476  
 477          /**
 478           * Fires before the loading of a located template file.
 479           *
 480           * @since 1.6.0
 481           *
 482           * @param string $located_template Template found to be loaded.
 483           */
 484          do_action( 'bp_core_pre_load_template', $located_template );
 485  
 486          /**
 487           * Filters the selected template right before loading.
 488           *
 489           * @since 1.1.0
 490           *
 491           * @param string $located_template Template found to be loaded.
 492           */
 493          load_template( apply_filters( 'bp_load_template', $located_template ) );
 494  
 495          /**
 496           * Fires after the loading of a located template file.
 497           *
 498           * @since 1.6.0
 499           *
 500           * @param string $located_template Template found that was loaded.
 501           */
 502          do_action( 'bp_core_post_load_template', $located_template );
 503  
 504          // Kill any other output after this.
 505          exit();
 506  
 507      // No template found, so setup theme compatibility.
 508      // @todo Some other 404 handling if theme compat doesn't kick in.
 509      } else {
 510  
 511          // We know where we are, so reset important $wp_query bits here early.
 512          // The rest will be done by bp_theme_compat_reset_post() later.
 513          if ( is_buddypress() ) {
 514              status_header( 200 );
 515              $wp_query->is_page     = true;
 516              $wp_query->is_singular = true;
 517              $wp_query->is_404      = false;
 518          }
 519  
 520          /**
 521           * Fires if there are no found templates to load and theme compat is needed.
 522           *
 523           * @since 1.7.0
 524           */
 525          do_action( 'bp_setup_theme_compat' );
 526      }
 527  }
 528  
 529  /**
 530   * Redirect away from /profile URIs if XProfile is not enabled.
 531   *
 532   * @since 1.0.0
 533   */
 534  function bp_core_catch_profile_uri() {
 535      if ( !bp_is_active( 'xprofile' ) ) {
 536  
 537          /**
 538           * Filters the path to redirect users to if XProfile is not enabled.
 539           *
 540           * @since 1.0.0
 541           *
 542           * @param string $value Path to redirect users to.
 543           */
 544          bp_core_load_template( apply_filters( 'bp_core_template_display_profile', 'members/single/home' ) );
 545      }
 546  }
 547  
 548  /**
 549   * Members user shortlink redirector.
 550   *
 551   * Redirects x.com/members/me/* to x.com/members/{LOGGED_IN_USER_SLUG}/*
 552   *
 553   * @since 2.6.0
 554   *
 555   * @param string $member_slug The current member slug.
 556   * @return string $member_slug The current member slug.
 557   */
 558  function bp_core_members_shortlink_redirector( $member_slug ) {
 559  
 560      /**
 561       * Shortlink slug to redirect to logged-in user.
 562       *
 563       * The x.com/members/me/* url will redirect to x.com/members/{LOGGED_IN_USER_SLUG}/*
 564       *
 565       * @since 2.6.0
 566       *
 567       * @param string $slug Defaults to 'me'.
 568       */
 569      $me_slug = apply_filters( 'bp_core_members_shortlink_slug', 'me' );
 570  
 571      // Check if we're on our special shortlink slug. If not, bail.
 572      if ( $me_slug !== $member_slug ) {
 573          return $member_slug;
 574      }
 575  
 576      // If logged out, redirect user to login.
 577      if ( false === is_user_logged_in() ) {
 578          // Add our login redirector hook.
 579          add_action( 'template_redirect', 'bp_core_no_access', 0 );
 580  
 581          return $member_slug;
 582      }
 583  
 584      $user = wp_get_current_user();
 585  
 586      return bp_core_get_username( $user->ID, $user->user_nicename, $user->user_login );
 587  }
 588  add_filter( 'bp_core_set_uri_globals_member_slug', 'bp_core_members_shortlink_redirector' );
 589  
 590  /**
 591   * Catch unauthorized access to certain BuddyPress pages and redirect accordingly.
 592   *
 593   * @since 1.5.0
 594   */
 595  function bp_core_catch_no_access() {
 596      global $wp_query;
 597  
 598      $bp = buddypress();
 599  
 600      // If coming from bp_core_redirect() and $bp_no_status_set is true,
 601      // we are redirecting to an accessible page so skip this check.
 602      if ( !empty( $bp->no_status_set ) )
 603          return false;
 604  
 605      if ( !isset( $wp_query->queried_object ) && !bp_is_blog_page() ) {
 606          bp_do_404();
 607      }
 608  }
 609  add_action( 'bp_template_redirect', 'bp_core_catch_no_access', 1 );
 610  
 611  /**
 612   * Redirect a user to log in for BP pages that require access control.
 613   *
 614   * Add an error message (if one is provided).
 615   *
 616   * If authenticated, redirects user back to requested content by default.
 617   *
 618   * @since 1.5.0
 619   *
 620   * @param array|string $args {
 621   *     @type int    $mode     Specifies the destination of the redirect. 1 will
 622   *                            direct to the root domain (home page), which assumes you have a
 623   *                            log-in form there; 2 directs to wp-login.php. Default: 2.
 624   *     @type string $redirect The URL the user will be redirected to after successfully
 625   *                            logging in. Default: the URL originally requested.
 626   *     @type string $root     The root URL of the site, used in case of error or mode 1 redirects.
 627   *                            Default: the value of {@link bp_get_root_domain()}.
 628   *     @type string $message  An error message to display to the user on the log-in page.
 629   *                            Default: "You must log in to access the page you requested."
 630   * }
 631   */
 632  function bp_core_no_access( $args = '' ) {
 633  
 634      // Build the redirect URL.
 635      $redirect_url  = is_ssl() ? 'https://' : 'http://';
 636      $redirect_url .= $_SERVER['HTTP_HOST'];
 637      $redirect_url .= $_SERVER['REQUEST_URI'];
 638  
 639      $defaults = array(
 640          'mode'     => 2,                    // 1 = $root, 2 = wp-login.php.
 641          'redirect' => $redirect_url,        // the URL you get redirected to when a user successfully logs in.
 642          'root'     => bp_get_root_domain(), // the landing page you get redirected to when a user doesn't have access.
 643          'message'  => __( 'You must log in to access the page you requested.', 'buddypress' )
 644      );
 645  
 646      $r = wp_parse_args( $args, $defaults );
 647  
 648      /**
 649       * Filters the arguments used for user redirecting when visiting access controlled areas.
 650       *
 651       * @since 1.6.0
 652       *
 653       * @param array $r Array of parsed arguments for redirect determination.
 654       */
 655      $r = apply_filters( 'bp_core_no_access', $r );
 656      extract( $r, EXTR_SKIP );
 657  
 658      /*
 659       * @ignore Ignore these filters and use 'bp_core_no_access' above.
 660       */
 661      $mode     = apply_filters( 'bp_no_access_mode',     $mode,     $root,     $redirect, $message );
 662      $redirect = apply_filters( 'bp_no_access_redirect', $redirect, $root,     $message,  $mode    );
 663      $root     = apply_filters( 'bp_no_access_root',     $root,     $redirect, $message,  $mode    );
 664      $message  = apply_filters( 'bp_no_access_message',  $message,  $root,     $redirect, $mode    );
 665      $root     = trailingslashit( $root );
 666  
 667      switch ( $mode ) {
 668  
 669          // Option to redirect to wp-login.php.
 670          // Error message is displayed with bp_core_no_access_wp_login_error().
 671          case 2 :
 672              if ( !empty( $redirect ) ) {
 673                  bp_core_redirect( add_query_arg( array(
 674                      'bp-auth' => 1,
 675                      'action'  => 'bpnoaccess'
 676                  ), wp_login_url( $redirect ) ) );
 677              } else {
 678                  bp_core_redirect( $root );
 679              }
 680  
 681              break;
 682  
 683          // Redirect to root with "redirect_to" parameter.
 684          // Error message is displayed with bp_core_add_message().
 685          case 1 :
 686          default :
 687  
 688              $url = $root;
 689              if ( !empty( $redirect ) ) {
 690                  $url = add_query_arg( 'redirect_to', urlencode( $redirect ), $root );
 691              }
 692  
 693              if ( !empty( $message ) ) {
 694                  bp_core_add_message( $message, 'error' );
 695              }
 696  
 697              bp_core_redirect( $url );
 698  
 699              break;
 700      }
 701  }
 702  
 703  /**
 704   * Login redirector.
 705   *
 706   * If a link is not publicly available, we can send members from external
 707   * locations, like following links in an email, through the login screen.
 708   *
 709   * If a user clicks on this link and is already logged in, we should attempt
 710   * to redirect the user to the authorized content instead of forcing the user
 711   * to re-authenticate.
 712   *
 713   * @since 2.9.0
 714   */
 715  function bp_login_redirector() {
 716      // Redirect links must include the `redirect_to` and `bp-auth` parameters.
 717      if ( empty( $_GET['redirect_to'] ) || empty( $_GET['bp-auth'] ) ) {
 718          return;
 719      }
 720  
 721      /*
 722       * If the user is already logged in,
 723       * skip the login form and redirect them to the content.
 724       */
 725      if ( bp_loggedin_user_id() ) {
 726          wp_safe_redirect( esc_url_raw( $_GET['redirect_to'] ) );
 727          exit;
 728      }
 729  }
 730  add_action( 'login_init', 'bp_login_redirector', 1 );
 731  
 732  /**
 733   * Add a custom BuddyPress no access error message to wp-login.php.
 734   *
 735   * @since 1.5.0
 736   * @since 2.7.0 Hook moved to 'wp_login_errors' made available since WP 3.6.0.
 737   *
 738   * @param  WP_Error $errors Current error container.
 739   * @return WP_Error
 740   */
 741  function bp_core_no_access_wp_login_error( $errors ) {
 742      if ( empty( $_GET['action'] ) || 'bpnoaccess' !== $_GET['action'] ) {
 743          return $errors;
 744      }
 745  
 746      /**
 747       * Filters the error message for wp-login.php when needing to log in before accessing.
 748       *
 749       * @since 1.5.0
 750       *
 751       * @param string $value Error message to display.
 752       * @param string $value URL to redirect user to after successful login.
 753       */
 754      $message = apply_filters( 'bp_wp_login_error', __( 'You must log in to access the page you requested.', 'buddypress' ), $_REQUEST['redirect_to'] );
 755  
 756      $errors->add( 'bp_no_access', $message );
 757  
 758      return $errors;
 759  }
 760  add_filter( 'wp_login_errors', 'bp_core_no_access_wp_login_error' );
 761  
 762  /**
 763   * Add our custom error code to WP login's shake error codes.
 764   *
 765   * @since 2.7.0
 766   *
 767   * @param  array $codes Array of WP error codes.
 768   * @return array
 769   */
 770  function bp_core_login_filter_shake_codes( $codes ) {
 771      $codes[] = 'bp_no_access';
 772      return $codes;
 773  }
 774  add_filter( 'shake_error_codes', 'bp_core_login_filter_shake_codes' );
 775  
 776  /**
 777   * Canonicalize BuddyPress URLs.
 778   *
 779   * This function ensures that requests for BuddyPress content are always
 780   * redirected to their canonical versions. Canonical versions are always
 781   * trailingslashed, and are typically the most general possible versions of the
 782   * URL - eg, example.com/groups/mygroup/ instead of
 783   * example.com/groups/mygroup/home/.
 784   *
 785   * @since 1.6.0
 786   *
 787   * @see BP_Members_Component::setup_globals() where
 788   *      $bp->canonical_stack['base_url'] and ['component'] may be set.
 789   * @see bp_core_new_nav_item() where $bp->canonical_stack['action'] may be set.
 790   */
 791  function bp_redirect_canonical() {
 792  
 793      /**
 794       * Filters whether or not to do canonical redirects on BuddyPress URLs.
 795       *
 796       * @since 1.6.0
 797       *
 798       * @param bool $value Whether or not to do canonical redirects. Default true.
 799       */
 800      if ( !bp_is_blog_page() && apply_filters( 'bp_do_redirect_canonical', true ) ) {
 801          // If this is a POST request, don't do a canonical redirect.
 802          // This is for backward compatibility with plugins that submit form requests to
 803          // non-canonical URLs. Plugin authors should do their best to use canonical URLs in
 804          // their form actions.
 805          if ( !empty( $_POST ) ) {
 806              return;
 807          }
 808  
 809          // Build the URL in the address bar.
 810          $requested_url  = bp_get_requested_url();
 811  
 812          // Stash query args.
 813          $url_stack      = explode( '?', $requested_url );
 814          $req_url_clean  = $url_stack[0];
 815          $query_args     = isset( $url_stack[1] ) ? $url_stack[1] : '';
 816  
 817          $canonical_url  = bp_get_canonical_url();
 818  
 819          // Only redirect if we've assembled a URL different from the request.
 820          if ( $canonical_url !== $req_url_clean ) {
 821  
 822              $bp = buddypress();
 823  
 824              // Template messages have been deleted from the cookie by this point, so
 825              // they must be readded before redirecting.
 826              if ( isset( $bp->template_message ) ) {
 827                  $message      = stripslashes( $bp->template_message );
 828                  $message_type = isset( $bp->template_message_type ) ? $bp->template_message_type : 'success';
 829  
 830                  bp_core_add_message( $message, $message_type );
 831              }
 832  
 833              if ( !empty( $query_args ) ) {
 834                  $canonical_url .= '?' . $query_args;
 835              }
 836  
 837              bp_core_redirect( $canonical_url, 301 );
 838          }
 839      }
 840  }
 841  
 842  /**
 843   * Output rel=canonical header tag for BuddyPress content.
 844   *
 845   * @since 1.6.0
 846   */
 847  function bp_rel_canonical() {
 848      $canonical_url = bp_get_canonical_url();
 849  
 850      // Output rel=canonical tag.
 851      echo "<link rel='canonical' href='" . esc_attr( $canonical_url ) . "' />\n";
 852  }
 853  
 854  /**
 855   * Get the canonical URL of the current page.
 856   *
 857   * @since 1.6.0
 858   *
 859   * @param array $args {
 860   *     Optional array of arguments.
 861   *     @type bool $include_query_args Whether to include current URL arguments
 862   *                                    in the canonical URL returned from the function.
 863   * }
 864   * @return string Canonical URL for the current page.
 865   */
 866  function bp_get_canonical_url( $args = array() ) {
 867  
 868      // For non-BP content, return the requested url, and let WP do the work.
 869      if ( bp_is_blog_page() ) {
 870          return bp_get_requested_url();
 871      }
 872  
 873      $bp = buddypress();
 874  
 875      $defaults = array(
 876          'include_query_args' => false // Include URL arguments, eg ?foo=bar&foo2=bar2.
 877      );
 878      $r = wp_parse_args( $args, $defaults );
 879      extract( $r );
 880  
 881      // Special case: when a BuddyPress directory (eg example.com/members)
 882      // is set to be the front page, ensure that the current canonical URL
 883      // is the home page URL.
 884      if ( 'page' == get_option( 'show_on_front' ) && $page_on_front = (int) get_option( 'page_on_front' ) ) {
 885          $front_page_component = array_search( $page_on_front, bp_core_get_directory_page_ids() );
 886  
 887          /*
 888           * If requesting the front page component directory, canonical
 889           * URL is the front page. We detect whether we're detecting a
 890           * component *directory* by checking that bp_current_action()
 891           * is empty - ie, this not a single item, a feed, or an item
 892           * type directory.
 893           */
 894          if ( false !== $front_page_component && bp_is_current_component( $front_page_component ) && ! bp_current_action() && ! bp_get_current_member_type() ) {
 895              $bp->canonical_stack['canonical_url'] = trailingslashit( bp_get_root_domain() );
 896  
 897          // Except when the front page is set to the registration page
 898          // and the current user is logged in. In this case we send to
 899          // the members directory to avoid redirect loops.
 900          } elseif ( bp_is_register_page() && 'register' == $front_page_component && is_user_logged_in() ) {
 901  
 902              /**
 903               * Filters the logged in register page redirect URL.
 904               *
 905               * @since 1.5.1
 906               *
 907               * @param string $value URL to redirect logged in members to.
 908               */
 909              $bp->canonical_stack['canonical_url'] = apply_filters( 'bp_loggedin_register_page_redirect_to', bp_get_members_directory_permalink() );
 910          }
 911      }
 912  
 913      if ( empty( $bp->canonical_stack['canonical_url'] ) ) {
 914          // Build the URL in the address bar.
 915          $requested_url  = bp_get_requested_url();
 916  
 917          // Stash query args.
 918          $url_stack      = explode( '?', $requested_url );
 919  
 920          // Build the canonical URL out of the redirect stack.
 921          if ( isset( $bp->canonical_stack['base_url'] ) )
 922              $url_stack[0] = $bp->canonical_stack['base_url'];
 923  
 924          if ( isset( $bp->canonical_stack['component'] ) )
 925              $url_stack[0] = trailingslashit( $url_stack[0] . $bp->canonical_stack['component'] );
 926  
 927          if ( isset( $bp->canonical_stack['action'] ) )
 928              $url_stack[0] = trailingslashit( $url_stack[0] . $bp->canonical_stack['action'] );
 929  
 930          if ( !empty( $bp->canonical_stack['action_variables'] ) ) {
 931              foreach( (array) $bp->canonical_stack['action_variables'] as $av ) {
 932                  $url_stack[0] = trailingslashit( $url_stack[0] . $av );
 933              }
 934          }
 935  
 936          // Add trailing slash.
 937          $url_stack[0] = trailingslashit( $url_stack[0] );
 938  
 939          // Stash in the $bp global.
 940          $bp->canonical_stack['canonical_url'] = implode( '?', $url_stack );
 941      }
 942  
 943      $canonical_url = $bp->canonical_stack['canonical_url'];
 944  
 945      if ( !$include_query_args ) {
 946          $canonical_url = array_reverse( explode( '?', $canonical_url ) );
 947          $canonical_url = array_pop( $canonical_url );
 948      }
 949  
 950      /**
 951       * Filters the canonical url of the current page.
 952       *
 953       * @since 1.6.0
 954       *
 955       * @param string $canonical_url Canonical URL of the current page.
 956       * @param array  $args          Array of arguments to help determine canonical URL.
 957       */
 958      return apply_filters( 'bp_get_canonical_url', $canonical_url, $args );
 959  }
 960  
 961  /**
 962   * Return the URL as requested on the current page load by the user agent.
 963   *
 964   * @since 1.6.0
 965   *
 966   * @return string Requested URL string.
 967   */
 968  function bp_get_requested_url() {
 969      $bp = buddypress();
 970  
 971      if ( empty( $bp->canonical_stack['requested_url'] ) ) {
 972          $bp->canonical_stack['requested_url']  = is_ssl() ? 'https://' : 'http://';
 973          $bp->canonical_stack['requested_url'] .= $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
 974      }
 975  
 976      /**
 977       * Filters the URL as requested on the current page load by the user agent.
 978       *
 979       * @since 1.7.0
 980       *
 981       * @param string $value Requested URL string.
 982       */
 983      return apply_filters( 'bp_get_requested_url', $bp->canonical_stack['requested_url'] );
 984  }
 985  
 986  /**
 987   * Remove WP's canonical redirect when we are trying to load BP-specific content.
 988   *
 989   * Avoids issues with WordPress thinking that a BuddyPress URL might actually
 990   * be a blog post or page.
 991   *
 992   * This function should be considered temporary, and may be removed without
 993   * notice in future versions of BuddyPress.
 994   *
 995   * @since 1.6.0
 996   */
 997  function _bp_maybe_remove_redirect_canonical() {
 998      if ( ! bp_is_blog_page() )
 999          remove_action( 'template_redirect', 'redirect_canonical' );
1000  }
1001  add_action( 'bp_init', '_bp_maybe_remove_redirect_canonical' );
1002  
1003  /**
1004   * Rehook maybe_redirect_404() to run later than the default.
1005   *
1006   * WordPress's maybe_redirect_404() allows admins on a multisite installation
1007   * to define 'NOBLOGREDIRECT', a URL to which 404 requests will be redirected.
1008   * maybe_redirect_404() is hooked to template_redirect at priority 10, which
1009   * creates a race condition with bp_template_redirect(), our piggyback hook.
1010   * Due to a legacy bug in BuddyPress, internal BP content (such as members and
1011   * groups) is marked 404 in $wp_query until bp_core_load_template(), when BP
1012   * manually overrides the automatic 404. However, the race condition with
1013   * maybe_redirect_404() means that this manual un-404-ing doesn't happen in
1014   * time, with the results that maybe_redirect_404() thinks that the page is
1015   * a legitimate 404, and redirects incorrectly to NOBLOGREDIRECT.
1016   *
1017   * By switching maybe_redirect_404() to catch at a higher priority, we avoid
1018   * the race condition. If bp_core_load_template() runs, it dies before reaching
1019   * maybe_redirect_404(). If bp_core_load_template() does not run, it means that
1020   * the 404 is legitimate, and maybe_redirect_404() can proceed as expected.
1021   *
1022   * This function will be removed in a later version of BuddyPress. Plugins
1023   * (and plugin authors!) should ignore it.
1024   *
1025   * @since 1.6.1
1026   *
1027   * @link https://buddypress.trac.wordpress.org/ticket/4329
1028   * @link https://buddypress.trac.wordpress.org/ticket/4415
1029   */
1030  function _bp_rehook_maybe_redirect_404() {
1031      if ( defined( 'NOBLOGREDIRECT' ) && is_multisite() ) {
1032          remove_action( 'template_redirect', 'maybe_redirect_404' );
1033          add_action( 'template_redirect', 'maybe_redirect_404', 100 );
1034      }
1035  }
1036  add_action( 'template_redirect', '_bp_rehook_maybe_redirect_404', 1 );
1037  
1038  /**
1039   * Remove WP's rel=canonical HTML tag if we are trying to load BP-specific content.
1040   *
1041   * This function should be considered temporary, and may be removed without
1042   * notice in future versions of BuddyPress.
1043   *
1044   * @since 1.6.0
1045   */
1046  function _bp_maybe_remove_rel_canonical() {
1047      if ( ! bp_is_blog_page() && ! is_404() ) {
1048          remove_action( 'wp_head', 'rel_canonical' );
1049          add_action( 'bp_head', 'bp_rel_canonical' );
1050      }
1051  }
1052  add_action( 'wp_head', '_bp_maybe_remove_rel_canonical', 8 );
1053  
1054  /**
1055   * Stop WordPress performing a DB query for its main loop.
1056   *
1057   * As of WordPress 4.6, it is possible to bypass the main WP_Query entirely.
1058   * This saves us one unnecessary database query! :)
1059   *
1060   * @since 2.7.0
1061   *
1062   * @param  null     $retval Current return value for filter.
1063   * @param  WP_Query $query  Current WordPress query object.
1064   * @return null|array
1065   */
1066  function bp_core_filter_wp_query( $retval, $query ) {
1067      if ( ! $query->is_main_query() ) {
1068          return $retval;
1069      }
1070  
1071      /*
1072       * If not on a BP single page, bail.
1073       * Too early to use bp_is_single_item(), so use BP conditionals.
1074       */
1075      if ( false === ( bp_is_group() || bp_is_user() || bp_is_single_activity() ) ) {
1076          return $retval;
1077      }
1078  
1079      // Set default properties as recommended in the 'posts_pre_query' DocBlock.
1080      $query->found_posts   = 0;
1081      $query->max_num_pages = 0;
1082  
1083      // Return something other than a null value to bypass WP_Query.
1084      return array();
1085  }


Generated: Tue Jul 16 01:01:43 2019 Cross-referenced by PHPXref 0.7.1