[ 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          /**
 253           * Fires when the the current page is not a BuddyPress one.
 254           *
 255           * @since 10.0.0
 256           */
 257          do_action( 'is_not_buddypress' );
 258          return false;
 259      }
 260  
 261      $wp_rewrite->use_verbose_page_rules = false;
 262  
 263      // Find the offset. With $root_profile set, we fudge the offset down so later parsing works.
 264      $slug       = !empty ( $match ) ? explode( '/', $match->slug ) : '';
 265      $uri_offset = empty( $root_profile ) ? 0 : -1;
 266  
 267      // Rejig the offset.
 268      if ( !empty( $slug ) && ( 1 < count( $slug ) ) ) {
 269          // Only offset if not on a root profile. Fixes issue when Members page is nested.
 270          if ( false === $root_profile ) {
 271              array_pop( $slug );
 272              $uri_offset = count( $slug );
 273          }
 274      }
 275  
 276      // Global the unfiltered offset to use in bp_core_load_template().
 277      // To avoid PHP warnings in bp_core_load_template(), it must always be >= 0.
 278      $bp->unfiltered_uri_offset = $uri_offset >= 0 ? $uri_offset : 0;
 279  
 280      // We have an exact match.
 281      if ( isset( $match->key ) ) {
 282  
 283          // Set current component to matched key.
 284          $bp->current_component = $match->key;
 285  
 286          // If members component, do more work to find the actual component.
 287          if ( 'members' == $match->key ) {
 288  
 289              $after_member_slug = false;
 290              if ( ! empty( $bp_uri[ $uri_offset + 1 ] ) ) {
 291                  $after_member_slug = $bp_uri[ $uri_offset + 1 ];
 292              }
 293  
 294              // Are we viewing a specific user?
 295              if ( $after_member_slug ) {
 296  
 297                  /** This filter is documented in bp-core/bp-core-catchuri.php */
 298                  $after_member_slug = apply_filters( 'bp_core_set_uri_globals_member_slug', $after_member_slug );
 299  
 300                  // If root profile, we've already queried for the user.
 301                  if ( $root_profile instanceof WP_User ) {
 302                      $bp->displayed_user->id = $root_profile->ID;
 303  
 304                  // Switch the displayed_user based on compatibility mode.
 305                  } elseif ( bp_is_username_compatibility_mode() ) {
 306                      $bp->displayed_user->id = (int) bp_core_get_userid( urldecode( $after_member_slug ) );
 307  
 308                  } else {
 309                      $bp->displayed_user->id = (int) bp_core_get_userid_from_nicename( $after_member_slug );
 310                  }
 311              }
 312  
 313              // Is this a member type directory?
 314              if ( ! bp_displayed_user_id() && $after_member_slug === bp_get_members_member_type_base() && ! empty( $bp_uri[ $uri_offset + 2 ] ) ) {
 315                  $matched_types = bp_get_member_types( array(
 316                      'has_directory'  => true,
 317                      'directory_slug' => $bp_uri[ $uri_offset + 2 ],
 318                  ) );
 319  
 320                  if ( ! empty( $matched_types ) ) {
 321                      $bp->current_member_type = reset( $matched_types );
 322                      unset( $bp_uri[ $uri_offset + 1 ] );
 323                  }
 324              }
 325  
 326              // If the slug matches neither a member type nor a specific member, 404.
 327              if ( ! bp_displayed_user_id() && ! bp_get_current_member_type() && $after_member_slug ) {
 328                  // Prevent components from loading their templates.
 329                  $bp->current_component = '';
 330                  bp_do_404();
 331                  return;
 332              }
 333  
 334              // If the displayed user is marked as a spammer, 404 (unless logged-in user is a super admin).
 335              if ( bp_displayed_user_id() && bp_is_user_spammer( bp_displayed_user_id() ) ) {
 336                  if ( bp_current_user_can( 'bp_moderate' ) ) {
 337                      bp_core_add_message( __( 'This user has been marked as a spammer. Only site admins can view this profile.', 'buddypress' ), 'warning' );
 338                  } else {
 339                      bp_do_404();
 340                      return;
 341                  }
 342              }
 343  
 344              // Bump the offset.
 345              if ( bp_displayed_user_id() ) {
 346                  if ( isset( $bp_uri[$uri_offset + 2] ) ) {
 347                      $bp_uri                = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) );
 348                      $bp->current_component = $bp_uri[0];
 349  
 350                  // No component, so default will be picked later.
 351                  } else {
 352                      $bp_uri                = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) );
 353                      $bp->current_component = '';
 354                  }
 355  
 356                  // Reset the offset.
 357                  $uri_offset = 0;
 358              }
 359          }
 360      }
 361  
 362      // Determine the current action.
 363      $current_action = isset( $bp_uri[ $uri_offset + 1 ] ) ? $bp_uri[ $uri_offset + 1 ] : '';
 364  
 365      /*
 366       * If a BuddyPress directory is set to the WP front page, URLs like example.com/members/?s=foo
 367       * shouldn't interfere with blog searches.
 368       */
 369      if ( empty( $current_action) && ! empty( $_GET['s'] ) && 'page' == get_option( 'show_on_front' ) && ! empty( $match->id ) ) {
 370          $page_on_front = (int) get_option( 'page_on_front' );
 371          if ( (int) $match->id === $page_on_front ) {
 372              $bp->current_component = '';
 373              return false;
 374          }
 375      }
 376  
 377      $bp->current_action = $current_action;
 378  
 379      // Slice the rest of the $bp_uri array and reset offset.
 380      $bp_uri      = array_slice( $bp_uri, $uri_offset + 2 );
 381      $uri_offset  = 0;
 382  
 383      // Set the entire URI as the action variables, we will unset the current_component and action in a second.
 384      $bp->action_variables = $bp_uri;
 385  
 386      // Reset the keys by merging with an empty array.
 387      $bp->action_variables = array_merge( array(), $bp->action_variables );
 388  }
 389  
 390  /**
 391   * Are root profiles enabled and allowed?
 392   *
 393   * @since 1.6.0
 394   *
 395   * @return bool True if yes, false if no.
 396   */
 397  function bp_core_enable_root_profiles() {
 398  
 399      $retval = false;
 400  
 401      if ( defined( 'BP_ENABLE_ROOT_PROFILES' ) && ( true == BP_ENABLE_ROOT_PROFILES ) )
 402          $retval = true;
 403  
 404      /**
 405       * Filters whether or not root profiles are enabled and allowed.
 406       *
 407       * @since 1.6.0
 408       *
 409       * @param bool $retval Whether or not root profiles are available.
 410       */
 411      return apply_filters( 'bp_core_enable_root_profiles', $retval );
 412  }
 413  
 414  /**
 415   * Load a specific template file with fallback support.
 416   *
 417   * Example:
 418   *   bp_core_load_template( 'members/index' );
 419   * Loads:
 420   *   wp-content/themes/[activated_theme]/members/index.php
 421   *
 422   * @since 1.0.0
 423   *
 424   * @param array $templates Array of templates to attempt to load.
 425   */
 426  function bp_core_load_template( $templates ) {
 427      global $wp_query;
 428  
 429      // Reset the post.
 430      bp_theme_compat_reset_post( array(
 431          'ID'          => 0,
 432          'is_404'      => true,
 433          'post_status' => 'publish',
 434      ) );
 435  
 436      // Set theme compat to false since the reset post function automatically sets
 437      // theme compat to true.
 438      bp_set_theme_compat_active( false );
 439  
 440      // Fetch each template and add the php suffix.
 441      $filtered_templates = array();
 442      foreach ( (array) $templates as $template ) {
 443          $filtered_templates[] = $template . '.php';
 444      }
 445  
 446      // Only perform template lookup for bp-default themes.
 447      if ( ! bp_use_theme_compat_with_current_theme() ) {
 448          $template = locate_template( (array) $filtered_templates, false );
 449  
 450      // Theme compat doesn't require a template lookup.
 451      } else {
 452          $template = '';
 453      }
 454  
 455      /**
 456       * Filters the template locations.
 457       *
 458       * Allows plugins to alter where the template files are located.
 459       *
 460       * @since 1.1.0
 461       *
 462       * @param string $template           Located template path.
 463       * @param array  $filtered_templates Array of templates to attempt to load.
 464       */
 465      $located_template = apply_filters( 'bp_located_template', $template, $filtered_templates );
 466  
 467      /*
 468       * If current page is an embed, wipe out bp-default template.
 469       *
 470       * Wiping out the bp-default template allows WordPress to use their special
 471       * embed template, which is what we want.
 472       */
 473      if ( is_embed() ) {
 474          $located_template = '';
 475      }
 476  
 477      if ( !empty( $located_template ) ) {
 478          // Template was located, lets set this as a valid page and not a 404.
 479          status_header( 200 );
 480          $wp_query->is_page     = true;
 481          $wp_query->is_singular = true;
 482          $wp_query->is_404      = false;
 483  
 484          /**
 485           * Fires before the loading of a located template file.
 486           *
 487           * @since 1.6.0
 488           *
 489           * @param string $located_template Template found to be loaded.
 490           */
 491          do_action( 'bp_core_pre_load_template', $located_template );
 492  
 493          /**
 494           * Filters the selected template right before loading.
 495           *
 496           * @since 1.1.0
 497           *
 498           * @param string $located_template Template found to be loaded.
 499           */
 500          load_template( apply_filters( 'bp_load_template', $located_template ) );
 501  
 502          /**
 503           * Fires after the loading of a located template file.
 504           *
 505           * @since 1.6.0
 506           *
 507           * @param string $located_template Template found that was loaded.
 508           */
 509          do_action( 'bp_core_post_load_template', $located_template );
 510  
 511          // Kill any other output after this.
 512          exit();
 513  
 514      // No template found, so setup theme compatibility.
 515      // @todo Some other 404 handling if theme compat doesn't kick in.
 516      } else {
 517  
 518          // We know where we are, so reset important $wp_query bits here early.
 519          // The rest will be done by bp_theme_compat_reset_post() later.
 520          if ( is_buddypress() ) {
 521              status_header( 200 );
 522              $wp_query->is_page     = true;
 523              $wp_query->is_singular = true;
 524              $wp_query->is_404      = false;
 525          }
 526  
 527          /**
 528           * Fires if there are no found templates to load and theme compat is needed.
 529           *
 530           * @since 1.7.0
 531           */
 532          do_action( 'bp_setup_theme_compat' );
 533      }
 534  }
 535  
 536  /**
 537   * Redirect away from /profile URIs if XProfile is not enabled.
 538   *
 539   * @since 1.0.0
 540   */
 541  function bp_core_catch_profile_uri() {
 542      if ( !bp_is_active( 'xprofile' ) ) {
 543  
 544          /**
 545           * Filters the path to redirect users to if XProfile is not enabled.
 546           *
 547           * @since 1.0.0
 548           *
 549           * @param string $value Path to redirect users to.
 550           */
 551          bp_core_load_template( apply_filters( 'bp_core_template_display_profile', 'members/single/home' ) );
 552      }
 553  }
 554  
 555  /**
 556   * Members user shortlink redirector.
 557   *
 558   * Redirects x.com/members/me/* to x.com/members/{LOGGED_IN_USER_SLUG}/*
 559   *
 560   * @since 2.6.0
 561   *
 562   * @param string $member_slug The current member slug.
 563   * @return string $member_slug The current member slug.
 564   */
 565  function bp_core_members_shortlink_redirector( $member_slug ) {
 566  
 567      /**
 568       * Shortlink slug to redirect to logged-in user.
 569       *
 570       * The x.com/members/me/* url will redirect to x.com/members/{LOGGED_IN_USER_SLUG}/*
 571       *
 572       * @since 2.6.0
 573       *
 574       * @param string $slug Defaults to 'me'.
 575       */
 576      $me_slug = apply_filters( 'bp_core_members_shortlink_slug', 'me' );
 577  
 578      // Check if we're on our special shortlink slug. If not, bail.
 579      if ( $me_slug !== $member_slug ) {
 580          return $member_slug;
 581      }
 582  
 583      // If logged out, redirect user to login.
 584      if ( false === is_user_logged_in() ) {
 585          // Add our login redirector hook.
 586          add_action( 'template_redirect', 'bp_core_no_access', 0 );
 587  
 588          return $member_slug;
 589      }
 590  
 591      $user = wp_get_current_user();
 592  
 593      return bp_core_get_username( $user->ID, $user->user_nicename, $user->user_login );
 594  }
 595  add_filter( 'bp_core_set_uri_globals_member_slug', 'bp_core_members_shortlink_redirector' );
 596  
 597  /**
 598   * Catch unauthorized access to certain BuddyPress pages and redirect accordingly.
 599   *
 600   * @since 1.5.0
 601   */
 602  function bp_core_catch_no_access() {
 603      global $wp_query;
 604  
 605      $bp = buddypress();
 606  
 607      // If coming from bp_core_redirect() and $bp_no_status_set is true,
 608      // we are redirecting to an accessible page so skip this check.
 609      if ( !empty( $bp->no_status_set ) )
 610          return false;
 611  
 612      if ( !isset( $wp_query->queried_object ) && !bp_is_blog_page() ) {
 613          bp_do_404();
 614      }
 615  }
 616  add_action( 'bp_template_redirect', 'bp_core_catch_no_access', 1 );
 617  
 618  /**
 619   * Redirect a user to log in for BP pages that require access control.
 620   *
 621   * Add an error message (if one is provided).
 622   *
 623   * If authenticated, redirects user back to requested content by default.
 624   *
 625   * @since 1.5.0
 626   *
 627   * @param array|string $args {
 628   *     @type int    $mode     Specifies the destination of the redirect. 1 will
 629   *                            direct to the root domain (home page), which assumes you have a
 630   *                            log-in form there; 2 directs to wp-login.php. Default: 2.
 631   *     @type string $redirect The URL the user will be redirected to after successfully
 632   *                            logging in. Default: the URL originally requested.
 633   *     @type string $root     The root URL of the site, used in case of error or mode 1 redirects.
 634   *                            Default: the value of {@link bp_get_root_domain()}.
 635   *     @type string $message  An error message to display to the user on the log-in page.
 636   *                            Default: "You must log in to access the page you requested."
 637   * }
 638   */
 639  function bp_core_no_access( $args = '' ) {
 640  
 641      // Build the redirect URL.
 642      $redirect_url  = is_ssl() ? 'https://' : 'http://';
 643      $redirect_url .= $_SERVER['HTTP_HOST'];
 644      $redirect_url .= $_SERVER['REQUEST_URI'];
 645  
 646      $defaults = array(
 647          'mode'     => 2,                    // 1 = $root, 2 = wp-login.php.
 648          'redirect' => $redirect_url,        // the URL you get redirected to when a user successfully logs in.
 649          'root'     => bp_get_root_domain(), // the landing page you get redirected to when a user doesn't have access.
 650          'message'  => __( 'You must log in to access the page you requested.', 'buddypress' )
 651      );
 652  
 653      $r = bp_parse_args(
 654          $args,
 655          $defaults
 656      );
 657  
 658      /**
 659       * Filters the arguments used for user redirecting when visiting access controlled areas.
 660       *
 661       * @since 1.6.0
 662       *
 663       * @param array $r Array of parsed arguments for redirect determination.
 664       */
 665      $r = apply_filters( 'bp_core_no_access', $r );
 666      extract( $r, EXTR_SKIP );
 667  
 668      /*
 669       * @ignore Ignore these filters and use 'bp_core_no_access' above.
 670       */
 671      $mode     = apply_filters( 'bp_no_access_mode',     $mode,     $root,     $redirect, $message );
 672      $redirect = apply_filters( 'bp_no_access_redirect', $redirect, $root,     $message,  $mode    );
 673      $root     = apply_filters( 'bp_no_access_root',     $root,     $redirect, $message,  $mode    );
 674      $message  = apply_filters( 'bp_no_access_message',  $message,  $root,     $redirect, $mode    );
 675      $root     = trailingslashit( $root );
 676  
 677      switch ( $mode ) {
 678  
 679          // Option to redirect to wp-login.php.
 680          // Error message is displayed with bp_core_no_access_wp_login_error().
 681          case 2 :
 682              if ( !empty( $redirect ) ) {
 683                  bp_core_redirect( add_query_arg( array(
 684                      'bp-auth' => 1,
 685                      'action'  => 'bpnoaccess'
 686                  ), wp_login_url( $redirect ) ) );
 687              } else {
 688                  bp_core_redirect( $root );
 689              }
 690  
 691              break;
 692  
 693          // Redirect to root with "redirect_to" parameter.
 694          // Error message is displayed with bp_core_add_message().
 695          case 1 :
 696          default :
 697  
 698              $url = $root;
 699              if ( !empty( $redirect ) ) {
 700                  $url = add_query_arg( 'redirect_to', urlencode( $redirect ), $root );
 701              }
 702  
 703              if ( !empty( $message ) ) {
 704                  bp_core_add_message( $message, 'error' );
 705              }
 706  
 707              bp_core_redirect( $url );
 708  
 709              break;
 710      }
 711  }
 712  
 713  /**
 714   * Login redirector.
 715   *
 716   * If a link is not publicly available, we can send members from external
 717   * locations, like following links in an email, through the login screen.
 718   *
 719   * If a user clicks on this link and is already logged in, we should attempt
 720   * to redirect the user to the authorized content instead of forcing the user
 721   * to re-authenticate.
 722   *
 723   * @since 2.9.0
 724   */
 725  function bp_login_redirector() {
 726      // Redirect links must include the `redirect_to` and `bp-auth` parameters.
 727      if ( empty( $_GET['redirect_to'] ) || empty( $_GET['bp-auth'] ) ) {
 728          return;
 729      }
 730  
 731      /*
 732       * If the user is already logged in,
 733       * skip the login form and redirect them to the content.
 734       */
 735      if ( bp_loggedin_user_id() ) {
 736          wp_safe_redirect( esc_url_raw( $_GET['redirect_to'] ) );
 737          exit;
 738      }
 739  }
 740  add_action( 'login_init', 'bp_login_redirector', 1 );
 741  
 742  /**
 743   * Add a custom BuddyPress no access error message to wp-login.php.
 744   *
 745   * @since 1.5.0
 746   * @since 2.7.0 Hook moved to 'wp_login_errors' made available since WP 3.6.0.
 747   *
 748   * @param  WP_Error $errors Current error container.
 749   * @return WP_Error
 750   */
 751  function bp_core_no_access_wp_login_error( $errors ) {
 752      if ( empty( $_GET['action'] ) || 'bpnoaccess' !== $_GET['action'] ) {
 753          return $errors;
 754      }
 755  
 756      /**
 757       * Filters the error message for wp-login.php when needing to log in before accessing.
 758       *
 759       * @since 1.5.0
 760       *
 761       * @param string $value Error message to display.
 762       * @param string $value URL to redirect user to after successful login.
 763       */
 764      $message = apply_filters( 'bp_wp_login_error', __( 'You must log in to access the page you requested.', 'buddypress' ), $_REQUEST['redirect_to'] );
 765  
 766      $errors->add( 'bp_no_access', $message );
 767  
 768      return $errors;
 769  }
 770  add_filter( 'wp_login_errors', 'bp_core_no_access_wp_login_error' );
 771  
 772  /**
 773   * Add our custom error code to WP login's shake error codes.
 774   *
 775   * @since 2.7.0
 776   *
 777   * @param  array $codes Array of WP error codes.
 778   * @return array
 779   */
 780  function bp_core_login_filter_shake_codes( $codes ) {
 781      $codes[] = 'bp_no_access';
 782      return $codes;
 783  }
 784  add_filter( 'shake_error_codes', 'bp_core_login_filter_shake_codes' );
 785  
 786  /**
 787   * Canonicalize BuddyPress URLs.
 788   *
 789   * This function ensures that requests for BuddyPress content are always
 790   * redirected to their canonical versions. Canonical versions are always
 791   * trailingslashed, and are typically the most general possible versions of the
 792   * URL - eg, example.com/groups/mygroup/ instead of
 793   * example.com/groups/mygroup/home/.
 794   *
 795   * @since 1.6.0
 796   *
 797   * @see BP_Members_Component::setup_globals() where
 798   *      $bp->canonical_stack['base_url'] and ['component'] may be set.
 799   * @see bp_core_new_nav_item() where $bp->canonical_stack['action'] may be set.
 800   */
 801  function bp_redirect_canonical() {
 802  
 803      /**
 804       * Filters whether or not to do canonical redirects on BuddyPress URLs.
 805       *
 806       * @since 1.6.0
 807       *
 808       * @param bool $value Whether or not to do canonical redirects. Default true.
 809       */
 810      if ( !bp_is_blog_page() && apply_filters( 'bp_do_redirect_canonical', true ) ) {
 811          // If this is a POST request, don't do a canonical redirect.
 812          // This is for backward compatibility with plugins that submit form requests to
 813          // non-canonical URLs. Plugin authors should do their best to use canonical URLs in
 814          // their form actions.
 815          if ( !empty( $_POST ) ) {
 816              return;
 817          }
 818  
 819          // Build the URL in the address bar.
 820          $requested_url  = bp_get_requested_url();
 821  
 822          // Stash query args.
 823          $url_stack      = explode( '?', $requested_url );
 824          $req_url_clean  = $url_stack[0];
 825          $query_args     = isset( $url_stack[1] ) ? $url_stack[1] : '';
 826  
 827          $canonical_url  = bp_get_canonical_url();
 828  
 829          // Only redirect if we've assembled a URL different from the request.
 830          if ( $canonical_url !== $req_url_clean ) {
 831  
 832              $bp = buddypress();
 833  
 834              // Template messages have been deleted from the cookie by this point, so
 835              // they must be readded before redirecting.
 836              if ( isset( $bp->template_message ) ) {
 837                  $message      = stripslashes( $bp->template_message );
 838                  $message_type = isset( $bp->template_message_type ) ? $bp->template_message_type : 'success';
 839  
 840                  bp_core_add_message( $message, $message_type );
 841              }
 842  
 843              if ( !empty( $query_args ) ) {
 844                  $canonical_url .= '?' . $query_args;
 845              }
 846  
 847              bp_core_redirect( $canonical_url, 301 );
 848          }
 849      }
 850  }
 851  
 852  /**
 853   * Output rel=canonical header tag for BuddyPress content.
 854   *
 855   * @since 1.6.0
 856   */
 857  function bp_rel_canonical() {
 858      $canonical_url = bp_get_canonical_url();
 859  
 860      // Output rel=canonical tag.
 861      echo "<link rel='canonical' href='" . esc_attr( $canonical_url ) . "' />\n";
 862  }
 863  
 864  /**
 865   * Get the canonical URL of the current page.
 866   *
 867   * @since 1.6.0
 868   *
 869   * @param array $args {
 870   *     Optional array of arguments.
 871   *     @type bool $include_query_args Whether to include current URL arguments
 872   *                                    in the canonical URL returned from the function.
 873   * }
 874   * @return string Canonical URL for the current page.
 875   */
 876  function bp_get_canonical_url( $args = array() ) {
 877  
 878      // For non-BP content, return the requested url, and let WP do the work.
 879      if ( bp_is_blog_page() ) {
 880          return bp_get_requested_url();
 881      }
 882  
 883      $bp = buddypress();
 884  
 885      $defaults = array(
 886          'include_query_args' => false, // Include URL arguments, eg ?foo=bar&foo2=bar2.
 887      );
 888  
 889      $r = bp_parse_args(
 890          $args,
 891          $defaults
 892      );
 893  
 894      extract( $r );
 895  
 896      // Special case: when a BuddyPress directory (eg example.com/members)
 897      // is set to be the front page, ensure that the current canonical URL
 898      // is the home page URL.
 899      if ( 'page' == get_option( 'show_on_front' ) && $page_on_front = (int) get_option( 'page_on_front' ) ) {
 900          $front_page_component = array_search( $page_on_front, bp_core_get_directory_page_ids() );
 901  
 902          /*
 903           * If requesting the front page component directory, canonical
 904           * URL is the front page. We detect whether we're detecting a
 905           * component *directory* by checking that bp_current_action()
 906           * is empty - ie, this not a single item, a feed, or an item
 907           * type directory.
 908           */
 909          if ( false !== $front_page_component && bp_is_current_component( $front_page_component ) && ! bp_current_action() && ! bp_get_current_member_type() ) {
 910              $bp->canonical_stack['canonical_url'] = trailingslashit( bp_get_root_domain() );
 911  
 912          // Except when the front page is set to the registration page
 913          // and the current user is logged in. In this case we send to
 914          // the members directory to avoid redirect loops.
 915          } elseif ( bp_is_register_page() && 'register' == $front_page_component && is_user_logged_in() ) {
 916  
 917              /**
 918               * Filters the logged in register page redirect URL.
 919               *
 920               * @since 1.5.1
 921               *
 922               * @param string $value URL to redirect logged in members to.
 923               */
 924              $bp->canonical_stack['canonical_url'] = apply_filters( 'bp_loggedin_register_page_redirect_to', bp_get_members_directory_permalink() );
 925          }
 926      }
 927  
 928      if ( empty( $bp->canonical_stack['canonical_url'] ) ) {
 929          // Build the URL in the address bar.
 930          $requested_url  = bp_get_requested_url();
 931  
 932          // Stash query args.
 933          $url_stack      = explode( '?', $requested_url );
 934  
 935          // Build the canonical URL out of the redirect stack.
 936          if ( isset( $bp->canonical_stack['base_url'] ) )
 937              $url_stack[0] = $bp->canonical_stack['base_url'];
 938  
 939          if ( isset( $bp->canonical_stack['component'] ) )
 940              $url_stack[0] = trailingslashit( $url_stack[0] . $bp->canonical_stack['component'] );
 941  
 942          if ( isset( $bp->canonical_stack['action'] ) )
 943              $url_stack[0] = trailingslashit( $url_stack[0] . $bp->canonical_stack['action'] );
 944  
 945          if ( !empty( $bp->canonical_stack['action_variables'] ) ) {
 946              foreach( (array) $bp->canonical_stack['action_variables'] as $av ) {
 947                  $url_stack[0] = trailingslashit( $url_stack[0] . $av );
 948              }
 949          }
 950  
 951          // Add trailing slash.
 952          $url_stack[0] = trailingslashit( $url_stack[0] );
 953  
 954          // Stash in the $bp global.
 955          $bp->canonical_stack['canonical_url'] = implode( '?', $url_stack );
 956      }
 957  
 958      $canonical_url = $bp->canonical_stack['canonical_url'];
 959  
 960      if ( !$include_query_args ) {
 961          $canonical_url = array_reverse( explode( '?', $canonical_url ) );
 962          $canonical_url = array_pop( $canonical_url );
 963      }
 964  
 965      /**
 966       * Filters the canonical url of the current page.
 967       *
 968       * @since 1.6.0
 969       *
 970       * @param string $canonical_url Canonical URL of the current page.
 971       * @param array  $args          Array of arguments to help determine canonical URL.
 972       */
 973      return apply_filters( 'bp_get_canonical_url', $canonical_url, $args );
 974  }
 975  
 976  /**
 977   * Return the URL as requested on the current page load by the user agent.
 978   *
 979   * @since 1.6.0
 980   *
 981   * @return string Requested URL string.
 982   */
 983  function bp_get_requested_url() {
 984      $bp = buddypress();
 985  
 986      if ( empty( $bp->canonical_stack['requested_url'] ) ) {
 987          $bp->canonical_stack['requested_url']  = is_ssl() ? 'https://' : 'http://';
 988          $bp->canonical_stack['requested_url'] .= $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
 989      }
 990  
 991      /**
 992       * Filters the URL as requested on the current page load by the user agent.
 993       *
 994       * @since 1.7.0
 995       *
 996       * @param string $value Requested URL string.
 997       */
 998      return apply_filters( 'bp_get_requested_url', $bp->canonical_stack['requested_url'] );
 999  }
1000  
1001  /**
1002   * Remove WP's canonical redirect when we are trying to load BP-specific content.
1003   *
1004   * Avoids issues with WordPress thinking that a BuddyPress URL might actually
1005   * be a blog post or page.
1006   *
1007   * This function should be considered temporary, and may be removed without
1008   * notice in future versions of BuddyPress.
1009   *
1010   * @since 1.6.0
1011   */
1012  function _bp_maybe_remove_redirect_canonical() {
1013      if ( ! bp_is_blog_page() )
1014          remove_action( 'template_redirect', 'redirect_canonical' );
1015  }
1016  add_action( 'bp_init', '_bp_maybe_remove_redirect_canonical' );
1017  
1018  /**
1019   * Rehook maybe_redirect_404() to run later than the default.
1020   *
1021   * WordPress's maybe_redirect_404() allows admins on a multisite installation
1022   * to define 'NOBLOGREDIRECT', a URL to which 404 requests will be redirected.
1023   * maybe_redirect_404() is hooked to template_redirect at priority 10, which
1024   * creates a race condition with bp_template_redirect(), our piggyback hook.
1025   * Due to a legacy bug in BuddyPress, internal BP content (such as members and
1026   * groups) is marked 404 in $wp_query until bp_core_load_template(), when BP
1027   * manually overrides the automatic 404. However, the race condition with
1028   * maybe_redirect_404() means that this manual un-404-ing doesn't happen in
1029   * time, with the results that maybe_redirect_404() thinks that the page is
1030   * a legitimate 404, and redirects incorrectly to NOBLOGREDIRECT.
1031   *
1032   * By switching maybe_redirect_404() to catch at a higher priority, we avoid
1033   * the race condition. If bp_core_load_template() runs, it dies before reaching
1034   * maybe_redirect_404(). If bp_core_load_template() does not run, it means that
1035   * the 404 is legitimate, and maybe_redirect_404() can proceed as expected.
1036   *
1037   * This function will be removed in a later version of BuddyPress. Plugins
1038   * (and plugin authors!) should ignore it.
1039   *
1040   * @since 1.6.1
1041   *
1042   * @link https://buddypress.trac.wordpress.org/ticket/4329
1043   * @link https://buddypress.trac.wordpress.org/ticket/4415
1044   */
1045  function _bp_rehook_maybe_redirect_404() {
1046      if ( defined( 'NOBLOGREDIRECT' ) && is_multisite() ) {
1047          remove_action( 'template_redirect', 'maybe_redirect_404' );
1048          add_action( 'template_redirect', 'maybe_redirect_404', 100 );
1049      }
1050  }
1051  add_action( 'template_redirect', '_bp_rehook_maybe_redirect_404', 1 );
1052  
1053  /**
1054   * Remove WP's rel=canonical HTML tag if we are trying to load BP-specific content.
1055   *
1056   * This function should be considered temporary, and may be removed without
1057   * notice in future versions of BuddyPress.
1058   *
1059   * @since 1.6.0
1060   */
1061  function _bp_maybe_remove_rel_canonical() {
1062      if ( ! bp_is_blog_page() && ! is_404() ) {
1063          remove_action( 'wp_head', 'rel_canonical' );
1064          add_action( 'bp_head', 'bp_rel_canonical' );
1065      }
1066  }
1067  add_action( 'wp_head', '_bp_maybe_remove_rel_canonical', 8 );
1068  
1069  /**
1070   * Stop WordPress performing a DB query for its main loop.
1071   *
1072   * As of WordPress 4.6, it is possible to bypass the main WP_Query entirely.
1073   * This saves us one unnecessary database query! :)
1074   *
1075   * @since 2.7.0
1076   *
1077   * @param  null     $retval Current return value for filter.
1078   * @param  WP_Query $query  Current WordPress query object.
1079   * @return null|array
1080   */
1081  function bp_core_filter_wp_query( $retval, $query ) {
1082      if ( ! $query->is_main_query() ) {
1083          return $retval;
1084      }
1085  
1086      /*
1087       * If not on a BP single page, bail.
1088       * Too early to use bp_is_single_item(), so use BP conditionals.
1089       */
1090      if ( false === ( bp_is_group() || bp_is_user() || bp_is_single_activity() ) ) {
1091          return $retval;
1092      }
1093  
1094      // Set default properties as recommended in the 'posts_pre_query' DocBlock.
1095      $query->found_posts   = 0;
1096      $query->max_num_pages = 0;
1097  
1098      // Return something other than a null value to bypass WP_Query.
1099      return array();
1100  }


Generated: Thu Nov 21 01:00:57 2024 Cross-referenced by PHPXref 0.7.1