Ticket #4140: bp-core-catchuri.patch
File bp-core-catchuri.patch, 52.0 KB (added by , 13 years ago) |
---|
-
C:\xampp\htdocs\wp-content\plugins\
# This patch file was generated by NetBeans IDE # This patch can be applied using context Tools: Apply Diff Patch action on respective folder. # It uses platform neutral UTF-8 encoding. # Above lines and this line are ignored by the patching process.
old new 1 1 <?php 2 2 3 3 /** 4 * BUDDYPRESS ROUTER 5 * Analyzes a URI passed from the web server and determines the correct page module to send the request to. 4 * BuddyPress URI catcher 6 5 * 7 * @version 1.6 8 * @since 1.6 9 * @package Core 10 * @subpackage Router 11 * @license GPL v2.0 6 * Functions for parsing the URI and determining which BuddyPress template file 7 * to use on-screen. 12 8 * 13 * ======================================================================================================== 9 * Based on contributions from: Chris Taylor - http://www.stillbreathing.co.uk/ 10 * Modified for BuddyPress by: Andy Peatling - http://apeatling.wordpress.com/ 11 * 12 * @package BuddyPress 13 * @subpackage Core 14 14 */ 15 15 16 class BP_router { 16 // Exit if accessed directly 17 if ( !defined( 'ABSPATH' ) ) exit; 17 18 18 19 var $http_referer; // $_SERVER['HTTP_REFERER'] sent in from the web server20 var $request_uri; // $_SERVER['REQUEST_URI'] sent in from the web server21 var $wp_http_referer; // $_REQUEST['_wp_http_referer'] sent in from the web server22 23 var $bp; // Local copy of $bp singleton24 25 var $wpdb; // Local copy of $wpdb singleton26 var $wp_query; // Local copy of $wp_query singleton27 var $current_blog; // Local copy of WordPress $current_blog global28 var $current_site; // Local copy of WordPress $current_site global29 30 var $walk; // Walk array for current URI31 var $flat_pages; // The page tree for the root blog or current blog as a flat array32 var $lofted_pages; // The page tree for the root blog or current blog as a hierarchical array33 var $intersect; // Intersect object34 35 var $unit_test = false; // Set true to disable die() calls in template loader methods36 37 38 // ================================================================================================================39 40 41 function BP_router($args=null) {42 43 $this->__construct($args);44 }45 46 function __construct($args=null) {47 48 // Handle dependency-injection for unit tests49 if($args){50 51 $this->http_referer = &$args['http_referer'];52 $this->request_uri = &$args['request_uri'];53 $this->wp_http_referer = &$args['wp_http_referer'];54 55 $this->bp = &$args['bp'];56 57 $this->wpdb = &$args['wpdb'];58 $this->wp_query = &$args['wp_query'];59 $this->current_blog = &$args['current_blog'];60 $this->current_site = &$args['current_site'];61 62 $this->walk = &$args['walk'];63 $this->flat_pages = &$args['flat_pages'];64 $this->lofted_pages = &$args['lofted_pages'];65 $this->intersect = &$args['intersect'];66 67 }68 else {69 70 global $bp;71 global $wpdb, $wp_query, $current_blog, $current_site;72 73 $this->http_referer = $_SERVER['HTTP_REFERER'];74 $this->request_uri = $_SERVER['REQUEST_URI'];75 $this->wp_http_referer = $_REQUEST['_wp_http_referer'];76 77 $this->bp = &$bp;78 79 $this->wpdb = &$wpdb;80 $this->wp_query = &$wp_query;81 $this->current_blog = &$current_blog;82 $this->current_site = &$current_site;83 84 $this->walk = null;85 $this->flat_pages = null;86 $this->lofted_pages = null;87 $this->intersect = null;88 }89 90 }91 92 93 19 /** 94 * Given a URI owned by BuddyPress, load the correct templates 20 * Analyzes the URI structure and breaks it down into parts for use in code. 21 * BuddyPress can use complete custom friendly URI's without the user having to 22 * add new re-write rules. Custom components are able to use their own custom 23 * URI structures with very little work. 95 24 * 96 * @version 1.6 97 * @since 1.6 25 * @package BuddyPress Core 26 * @since BuddyPress (r100) 27 * 28 * The URI's are broken down as follows: 29 * - http:// domain.com / members / andy / [current_component] / [current_action] / [action_variables] / [action_variables] / ... 30 * - OUTSIDE ROOT: http:// domain.com / sites / buddypress / members / andy / [current_component] / [current_action] / [action_variables] / [action_variables] / ... 31 * 32 * Example: 33 * - http://domain.com/members/andy/profile/edit/group/5/ 34 * - $bp->current_component: string 'xprofile' 35 * - $bp->current_action: string 'edit' 36 * - $bp->action_variables: array ['group', 5] 37 * 98 38 */ 39 function bp_core_set_uri_globals() { 40 global $bp, $current_blog, $wp_rewrite; 99 41 100 public function route(&$status=null, &$error=null) {101 102 103 // Reset the global component, action, and item variables104 // ===============================================================105 106 $this->bp->current_component = "";107 $this->bp->current_action = "";108 $this->bp->current_item = "";109 $this->bp->action_variables = array();110 $this->bp->displayed_user->id = null;111 112 42 // Don't catch URIs on non-root blogs unless multiblog mode is on 113 // =============================================================== 114 115 if( !bp_is_root_blog() && !bp_is_multiblog_mode() ){ 116 117 $status = array( 118 'numeric'=>0, // We normally start numbering at 1 but this is a 119 // special case due to the &$status reference from 120 // the matchComponent() method 121 122 'text'=>"Multiblog mode is off and URI was on non-root blog", 123 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 124 ); 43 if ( !bp_is_root_blog() && !bp_is_multiblog_mode() ) 125 44 return false; 126 }127 45 128 // Convert the URI passed by the web server into a walk array 129 // =============================================================== 46 // Define local variables 47 $root_profile = $match = false; 48 $key_slugs = $matches = $uri_chunks = array(); 130 49 131 $this->walk = self::buildWalk(&$walk_error); 50 // Fetch all the WP page names for each component 51 if ( empty( $bp->pages ) ) 52 $bp->pages = bp_core_get_directory_pages(); 132 53 133 if($walk_error){ 54 // Ajax or not? 55 if ( strpos( $_SERVER['REQUEST_URI'], 'wp-load.php' ) ) 56 $path = bp_core_referrer(); 57 else 58 $path = esc_url( $_SERVER['REQUEST_URI'] ); 134 59 135 $error = array( 136 'numeric'=>1, 137 'text'=>"Walk error", 138 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 139 'child'=>$walk_error 140 ); 141 return false; 142 } 60 // Filter the path 61 $path = apply_filters( 'bp_uri', $path ); 143 62 144 // Intersect the walk array with the site's page tree145 // ===============================================================63 // Take GET variables off the URL to avoid problems 64 $path = strtok( $path, '?' ); 146 65 147 $this->intersect = self::pageIntersect($this->walk, &$intersect_error); 66 // Fetch current URI and explode each part separated by '/' into an array 67 $bp_uri = explode( '/', $path ); 148 68 149 if($intersect_error){ 150 151 $error = array( 152 'numeric'=>2, 153 'text'=>"Intersect error", 154 'data'=>array('walk'=>$this->walk), 155 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 156 'child'=>$intersect_error 157 ); 158 return false; 69 // Loop and remove empties 70 foreach ( (array) $bp_uri as $key => $uri_chunk ) { 71 if ( empty( $bp_uri[$key] ) ) { 72 unset( $bp_uri[$key] ); 159 73 } 160 161 // Match the intersect to a BuddyPress component, and set the global BP variables162 // ===============================================================163 164 $result = self::matchComponent($this->intersect, &$status, &$match_error);165 166 if($match_error){167 168 $error = array(169 'numeric'=>3,170 'text'=>"Match error",171 'data'=>array('intersect'=>$this->intersect),172 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,173 'child'=>$match_error174 );175 return false;176 74 } 177 75 178 return $result; 76 // If running off blog other than root, any subdirectory names must be 77 // removed from $bp_uri. This includes two cases: 78 // 79 // 1. when WP is installed in a subdirectory, 80 // 2. when BP is running on secondary blog of a subdirectory 81 // multisite installation. Phew! 82 if ( is_multisite() && !is_subdomain_install() && ( bp_is_multiblog_mode() || 1 != bp_get_root_blog_id() ) ) { 179 83 180 } 84 // Blow chunks 85 $chunks = explode( '/', $current_blog->path ); 181 86 87 // If chunks exist... 88 if ( !empty( $chunks ) ) { 182 89 183 /** 184 * Given a URI from the web server, create a walk array 185 * 186 * @link http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Walks 187 * @version 1.6 188 * @since 1.6 189 * @return array $walk | Walk array 190 */ 90 // ...loop through them... 91 foreach( $chunks as $key => $chunk ) { 92 $bkey = array_search( $chunk, $bp_uri ); 191 93 192 public function buildWalk(&$error=null) { 193 194 195 if ( strpos($this->request_uri, 'wp-load.php') ){ 196 197 // Try to match on the $_REQUEST['_wp_http_referer'] variable 198 if( !empty($this->_wp_http_referer) ){ 199 200 $ref = $this->_wp_http_referer; 94 // ...and unset offending keys 95 if ( false !== $bkey ) { 96 unset( $bp_uri[$bkey] ); 201 97 } 202 // Otherwise, try to match on the $_SERVER['http_referer'] variable203 elseif( !empty($this->http_referer) ){204 98 205 $ ref = $this->http_referer;99 $bp_uri = array_values( $bp_uri ); 206 100 } 207 208 // If the $_SERVER['request_uri'] variable is NULL, or if the referer209 // is pointing to itself, this is not a valid request210 211 if($ref == $this->request_uri){212 213 $error = array(214 'numeric'=>1,215 'text'=>"Invalid AJAX referer",216 'data'=>array( "_wp_http_referer"=>$this->_wp_http_referer,217 "http_referer"=>$this->http_referer,218 "request_uri"=>$this->request_uri219 ),220 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,221 'child'=>null222 );223 return false;224 101 } 225 226 // The $_wp_http_referer and $http_referer variables have the structure227 // "http://site.com/foo/bar/baz" so we remove the "http://site.com/" from228 // the string to make it have the same structure as $request_uri229 230 $referer = explode('/', $ref);231 unset($referer[0], $referer[1], $referer[2]);232 $raw_uri = implode('/', $referer);233 234 102 } 235 else {236 // The $request_uri variable has the structure "/foo/bar/baz"237 $raw_uri = esc_url($this->request_uri);238 }239 103 104 // Get site path items 105 $paths = explode( '/', bp_core_get_site_path() ); 240 106 241 // Parse the URI into an array of tokens 242 // ================================================= 107 // Take empties off the end of path 108 if ( empty( $paths[count( $paths ) - 1] ) ) 109 array_pop( $paths ); 243 110 244 $raw_uri = apply_filters('bp_uri', $raw_uri); 245 $parsed_uri = parse_url($raw_uri); 111 // Take empties off the start of path 112 if ( empty( $paths[0] ) ) 113 array_shift( $paths ); 246 114 247 if(!$parsed_uri){ 115 // Reset indexes 116 $bp_uri = array_values( $bp_uri ); 117 $paths = array_values( $paths ); 248 118 249 $error = array( 250 'numeric'=>2, 251 'text'=>"Couldn't parse supplied URI string", 252 'data'=>$raw_uri, 253 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 254 'child'=>null 255 ); 256 return false; 119 // Unset URI indices if they intersect with the paths 120 foreach ( (array) $bp_uri as $key => $uri_chunk ) { 121 if ( isset( $paths[$key] ) && $uri_chunk == $paths[$key] ) { 122 unset( $bp_uri[$key] ); 257 123 } 258 259 // Strip any surplus "/" characters from the URI string, and260 // explode it into a walk array261 262 $walk = explode('/', trim($parsed_uri["path"], '/') );263 264 265 // If BP is running off a non-root blog, remove the266 // the blog's base path from the beginning of the walk267 // =================================================268 269 if( is_multisite() && !is_subdomain_install() && ( bp_is_multiblog_mode() || bp_get_root_blog_id() != 1 ) ){270 271 // Any subdirectory names must be removed from $bp_uri. This includes two cases:272 // a) when WP is installed in a subdirectory,273 // b) when BP is running on secondary blog of a subdirectory multisite install274 275 $base_walk = explode( '/', trim($this->current_blog->path, '/') );276 $base_count = count($base_walk);277 278 if($base_count > 0){279 280 // Remove the base tokens from the walk array while281 // simultaneously re-basing the array282 283 $temp_walk = array();284 285 foreach($walk as $index => $token){286 287 if($token == $base_walk[$index]){288 289 $intersect_count++;290 124 } 291 else {292 $temp_walk[] = $token;293 }294 }295 unset($index, $token);296 125 297 // If any tokens in the base array fail to intersect with298 // walk array, this is not a valid URI126 // Reset the keys by merging with an empty array 127 $bp_uri = array_merge( array(), $bp_uri ); 299 128 300 if($base_count != $intersect_count){ 301 302 $error = array( 303 'numeric'=>3, 304 'text'=>"Malformed base URI", 305 'data'=>array( 306 "walk"=>$walk, 307 "base_tokens"=>$base_walk, 308 "result"=>$temp_walk 309 ), 310 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 311 'child'=>null 312 ); 313 return false; 129 // If a component is set to the front page, force its name into $bp_uri 130 // so that $current_component is populated (unless a specific WP post is being requested 131 // via a URL parameter, usually signifying Preview mode) 132 if ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_on_front' ) && empty( $bp_uri ) && empty( $_GET['p'] ) && empty( $_GET['page_id'] ) ) { 133 $post = get_post( get_option( 'page_on_front' ) ); 134 if ( !empty( $post ) ) { 135 $bp_uri[0] = $post->post_name; 314 136 } 315 316 $walk = $temp_walk;317 318 137 } 319 138 320 } 139 // Keep the unfiltered URI safe 140 $bp->unfiltered_uri = $bp_uri; 321 141 322 return $walk; 142 // Get slugs of pages into array 143 foreach ( (array) $bp->pages as $page_key => $bp_page ) 144 $key_slugs[$page_key] = trailingslashit( '/' . $bp_page->slug ); 323 145 324 } 146 // Bail if keyslugs are empty, as BP is not setup correct 147 if ( empty( $key_slugs ) ) 148 return; 325 149 326 327 /** 328 * Intersect a walk with the site's pages tree, returning the endpoint id, 329 * endpoint slug, and transect array 330 * 331 * @link http://en.wikipedia.org/wiki/Tree_(graph_theory) 332 * @link http://en.wikipedia.org/wiki/Union_(set_theory) 333 * @version 1.6 334 * @since 1.6 335 * @param array $walk | Walk array 336 * @return array $result | Result array 337 */ 338 339 public function pageIntersect($walk, &$error=null) { 340 341 342 // Fetch the site's pages and loft them into a hierarchical tree 343 // ============================================================== 344 345 $this->flat_pages = self::getPageHierarchy(&$pages_error); 346 347 if($pages_error){ 348 349 $error = array( 350 'numeric'=>1, 351 'text'=>"Error fetching site pages", 352 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 353 'child'=>$pages_error 354 ); 355 return false; 150 // Loop through page slugs and look for exact match to path 151 foreach ( $key_slugs as $key => $slug ) { 152 if ( $slug == $path ) { 153 $match = $bp->pages->{$key}; 154 $match->key = $key; 155 $matches[] = 1; 156 break; 356 157 } 357 358 $this->lofted_pages = self::loftHierarchy($this->flat_pages, &$loft_error);359 360 if($loft_error){361 362 $error = array(363 'numeric'=>2,364 'text'=>"Error lofting pages array",365 'data'=>array('flat_pages'=>$this->flat_pages),366 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,367 'child'=>$loft_error368 );369 return false;370 158 } 371 159 160 // No exact match, so look for partials 161 if ( empty( $match ) ) { 372 162 373 // Intersect the walk array with the pages tree374 // ==============================================================163 // Loop through each page in the $bp->pages global 164 foreach ( (array) $bp->pages as $page_key => $bp_page ) { 375 165 376 $intersect = self::walkIntersectTree($walk, $this->lofted_pages, &$intersect_error); 166 // Look for a match (check members first) 167 if ( in_array( $bp_page->name, (array) $bp_uri ) ) { 377 168 378 if($intersect_error){ 169 // Match found, now match the slug to make sure. 170 $uri_chunks = explode( '/', $bp_page->slug ); 379 171 380 $error = array( 381 'numeric'=>3, 382 'text'=>"Error intersecting walk with pages tree", 383 'data'=>array("walk"=>$walk, "lofted_pages"=>$this->lofted_pages), 384 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 385 'child'=>$intersect_error 386 ); 387 return false; 388 } 172 // Loop through uri_chunks 173 foreach ( (array) $uri_chunks as $key => $uri_chunk ) { 389 174 390 return $intersect; 175 // Make sure chunk is in the correct position 176 if ( !empty( $bp_uri[$key] ) && ( $bp_uri[$key] == $uri_chunk ) ) { 177 $matches[] = 1; 391 178 179 // No match 180 } else { 181 $matches[] = 0; 392 182 } 393 394 395 /**396 * Determine which BP component (if any) matches a given transect397 *398 * @link http://en.wikipedia.org/wiki/Cycle_(graph_theory)399 * @link http://en.wikipedia.org/wiki/Cycle_detection400 * @version 1.6401 * @since 1.6402 * @param array $intersect | Intersect array403 * @param array $status | Reason no match was found404 * @return bool $result | True on match. False on no match.405 */406 407 public function matchComponent($intersect, &$status, &$error=null) {408 409 410 $transect = $intersect["transect"];411 412 // CASE 1: Front-page component413 // ====================================================================414 if( $intersect["endpoint_id"] === null ){415 416 // If a component is set to the front page, and the user is not requesting417 // a specific post via a URL parameter, we have a match418 419 $not_preview_mode = ( empty($_GET['p']) && empty($_GET['page_id']) );420 421 if($not_preview_mode){422 423 $show_page_on_front = (get_option('show_on_front') == 'page'); // Note comparison operator424 $post_id = get_option('page_on_front');425 426 if($show_page_on_front && $post_id){427 428 $post = get_post($post_id);429 430 if( !empty($post) ){431 432 $this->bp->current_component = (string)$post->post_name;433 434 $status = array(435 'numeric'=>1,436 'text'=>"Successful match on front-page component.",437 'data'=>array('current_component'=>$this->bp->current_component,438 'post_id'=>$post_id,439 'post'=>$post ),440 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__441 );442 183 } 443 else {444 184 445 $error = array( 446 'numeric'=>1, 447 'text'=>"Site front page set to component, but component's post was empty", 448 'data'=>array("post_id"=>$post_id), 449 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 450 'child'=>null 451 ); 452 return false; 453 } 454 } 455 } 185 // Have a match 186 if ( !in_array( 0, (array) $matches ) ) { 187 $match = $bp_page; 188 $match->key = $page_key; 189 break; 190 }; 456 191 457 if(!$route_found){ 458 459 $status = array( 460 'numeric'=>2, 461 'text'=>"Site front page with no components active on front page.", 462 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 463 ); 464 return false; 192 // Unset matches 193 unset( $matches ); 465 194 } 466 195 196 // Unset uri chunks 197 unset( $uri_chunks ); 467 198 } 468 469 // CASE 2: Any non-nested component470 // ====================================================================471 472 if(!$this->bp->current_component){473 474 $this->bp->current_component = self::getPrimaryComponentName($intersect["endpoint_name"], &$primary_component_error);475 476 if($primary_component_error){477 478 $error = array(479 'numeric'=>2,480 'text'=>"Error fetching primary component name",481 'data'=>array("endpoint_name"=>$intersect["endpoint_name"]),482 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,483 'child'=>$primary_component_error484 );485 return false;486 199 } 487 200 488 if($this->bp->current_component){ 201 // URLs with BP_ENABLE_ROOT_PROFILES enabled won't be caught above 202 if ( empty( $matches ) && bp_core_enable_root_profiles() ) { 489 203 490 $status = array( 491 'numeric'=>3, 492 'text'=>"Successful match on primary component", 493 'data'=>array('current_component'=>$this->bp->current_component), 494 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 495 ); 204 // Switch field based on compat 205 $field = bp_is_username_compatibility_mode() ? 'login' : 'slug'; 496 206 497 }498 }207 // Make sure there's a user corresponding to $bp_uri[0] 208 if ( !empty( $bp->pages->members ) && !empty( $bp_uri[0] ) && $root_profile = get_user_by( $field, $bp_uri[0] ) ) { 499 209 210 // Force BP to recognize that this is a members page 211 $matches[] = 1; 212 $match = $bp->pages->members; 213 $match->key = 'members'; 500 214 501 // CASE 3: Root profile 502 // ==================================================================== 503 504 if ( !$this->bp->current_component // 1) Has not matched a component in an earlier stage 505 && !empty($transect) // 2) There are tokens in the transect 506 && !empty($this->bp->pages->members) // 3) Members component is active 507 && defined( 'BP_ENABLE_ROOT_PROFILES' ) && BP_ENABLE_ROOT_PROFILES ) // 4) Root profiles constant is defined and true 508 { 509 510 // Shift the user name off the transect 511 $user_name = array_shift($transect); 512 513 // Switch the user_id based on compatibility mode 514 if( bp_is_username_compatibility_mode() ){ 515 516 $user_id = (int) bp_core_get_userid( urldecode($user_name) ); 215 // Without the 'members' URL chunk, WordPress won't know which page to load 216 // This filter intercepts the WP query and tells it to load the members page 217 add_filter( 'request', create_function( '$query_args', '$query_args["pagename"] = "' . $match->name . '"; return $query_args;' ) ); 517 218 } 518 else {519 $user_id = (int) bp_core_get_userid_from_nicename( urldecode($user_name) );520 219 } 521 220 522 if($user_id){ 523 524 $this->bp->current_component = "members"; 525 $this->bp->displayed_user->id = $user_id; 526 527 $status = array( 528 'numeric'=>4, 529 'text'=>"Successful match on root profile", 530 'data'=>array('current_component'=>$this->bp->current_component), 531 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 532 ); 533 534 // Without the 'members' URL chunk, WordPress won't know which page to load, 535 // so this filter intercepts the WP query and tells it to load the members page 536 537 $function_string = '$query_args["pagename"] = "'; 538 $function_string .= $this->bp->pages->members->name; 539 $function_string .= '"; return $query_args;'; 540 541 add_filter( 'request', create_function('$query_args', $function_string) ); 542 221 // Search doesn't have an associated page, so we check for it separately 222 if ( !empty( $bp_uri[0] ) && ( bp_get_search_slug() == $bp_uri[0] ) ) { 223 $matches[] = 1; 224 $match = new stdClass; 225 $match->key = 'search'; 226 $match->slug = bp_get_search_slug(); 543 227 } 544 else {545 228 546 $status = array( 547 'numeric'=>5, 548 'text'=>"Root profiles enabled. No matching user.", 549 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 550 ); 229 // This is not a BuddyPress page, so just return. 230 if ( empty( $matches ) ) 551 231 return false; 552 }553 232 554 }233 $wp_rewrite->use_verbose_page_rules = false; 555 234 556 // CASE 4: No match 557 // ==================================================================== 235 // Find the offset. With $root_profile set, we fudge the offset down so later parsing works 236 $slug = !empty ( $match ) ? explode( '/', $match->slug ) : ''; 237 $uri_offset = empty( $root_profile ) ? 0 : -1; 558 238 559 if(!$this->bp->current_component){ 560 561 $status = array( 562 'numeric'=>6, 563 'text'=>"No matching components", 564 'data'=>array('intersect'=>$this->intersect, 'walk'=>$this->walk), 565 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 566 ); 567 return false; 239 // Rejig the offset 240 if ( !empty( $slug ) && ( 1 < count( $slug ) ) ) { 241 array_pop( $slug ); 242 $uri_offset = count( $slug ); 568 243 } 569 244 570 // Members Component secondary processing 571 // ==================================================================== 245 // Global the unfiltered offset to use in bp_core_load_template(). 246 // To avoid PHP warnings in bp_core_load_template(), it must always be >= 0 247 $bp->unfiltered_uri_offset = $uri_offset >= 0 ? $uri_offset : 0; 572 248 573 if( ($this->bp->current_component == "members") && !empty($transect) ){ 249 // We have an exact match 250 if ( isset( $match->key ) ) { 574 251 575 // If the component is "members", the transect must either contain no tokens (show all users on site),576 // or the first token in the transect must be a valid user name (show single user)252 // Set current component to matched key 253 $bp->current_component = $match->key; 577 254 578 $user_name = array_shift($transect); 255 // If members component, do more work to find the actual component 256 if ( 'members' == $match->key ) { 579 257 580 // Switch the user_id based on compatibility mode581 if ( bp_is_username_compatibility_mode() ){258 // Viewing a specific user 259 if ( !empty( $bp_uri[$uri_offset + 1] ) ) { 582 260 583 $user_id = (int) bp_core_get_userid( urldecode($user_name) ); 261 // Switch the displayed_user based on compatbility mode 262 if ( bp_is_username_compatibility_mode() ) { 263 $bp->displayed_user->id = (int) bp_core_get_userid( urldecode( $bp_uri[$uri_offset + 1] ) ); 264 } else { 265 $bp->displayed_user->id = (int) bp_core_get_userid_from_nicename( urldecode( $bp_uri[$uri_offset + 1] ) ); 584 266 } 585 else {586 $user_id = (int) bp_core_get_userid_from_nicename( urldecode($user_name) );587 }588 267 589 // CASE 1: Token in first transect position isn't a valid user_id 590 // --------------------------------------------------------------------------------------- 591 if( empty($user_id) ){ 268 if ( !bp_displayed_user_id() ) { 592 269 593 $this->bp->current_component = null;// Prevent components from loading their templates594 bp_do_404();270 // Prevent components from loading their templates 271 $bp->current_component = ''; 595 272 596 $status = array( 597 'numeric'=>7, 598 'text'=>"Match on members component, but user_id is not valid.", 599 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 600 ); 601 return false; 602 273 bp_do_404(); 274 return; 603 275 } 604 276 605 elseif( !empty($user_id) ){ 606 607 $this->bp->displayed_user->id = $user_id; 608 609 // CASE 2: Token in first transect position matches a user_id that 610 // has been marked as a spammer 611 // --------------------------------------------------------------------------------------- 612 if( bp_core_is_user_spammer($user_id) ){ 613 614 if( is_super_admin() ){ 615 616 bp_core_add_message( __( 'This user has been marked as a spammer. Only site admins can view this profile.', 'buddypress' ), 'error' ); 617 } 618 else { 619 // If the user viewing the profile is not a super-admin, hide the page 277 // If the displayed user is marked as a spammer, 404 (unless logged- 278 // in user is a super admin) 279 if ( bp_displayed_user_id() && bp_is_user_spammer( bp_displayed_user_id() ) ) { 280 if ( bp_current_user_can( 'bp_moderate' ) ) { 281 bp_core_add_message( __( 'This user has been marked as a spammer. Only site admins can view this profile.', 'buddypress' ), 'warning' ); 282 } else { 620 283 bp_do_404(); 621 622 $status = array( 623 'numeric'=>8, 624 'text'=>"Match on members component, but user_id is marked as a spammer and viewer is not a super-admin.", 625 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 626 ); 627 return false; 284 return; 628 285 } 629 630 286 } 631 // CASE 3: There are one or more tokens left in the transect after the user_name has632 // been shifted-out. This means we have a secondary component nested inside the members633 // component. The secondary component's *slug* will be the first token in the transect. We634 // have to set $this->bp->current_component to the *name* of the secondary component so635 // BP loads the correct template chain.636 // ---------------------------------------------------------------------------------------637 elseif( count($transect) > 0) {638 287 639 $current_component_slug = array_shift($transect); 288 // Bump the offset 289 if ( isset( $bp_uri[$uri_offset + 2] ) ) { 290 $bp_uri = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) ); 291 $bp->current_component = $bp_uri[0]; 640 292 641 // CASE 3A: Match against the "primary" components that can exist both as a top-level 642 // page and a secondary page nested beneath the "members" component. External plugins 643 // following the "BuddyPress Example Component" pattern will appear in this array. 644 // 645 // TODO: This creates a cardinality problem. Primary components will appear at 646 // both "example.com/members/membername/slug_name" and "example.com/slug_name". This 647 // is further complicated by the fact that some components use the alias location as a 648 // *context*, for example, "activity" at the root node shows activity for all users on 649 // the site, but "activity" nested in the "members" component shows activity for a user. 650 // There needs to be a set of configuration options on the admin back-end to specify 651 // which location to use for a given component. Note that this is a legacy problem with 652 // the original BP router design and we have emulated it for compatibility. 653 // --------------------------------------------------------------------------------------- 654 655 $this->bp->current_component = self::getPrimaryComponentName($current_component_slug, &$primary_component_error); 656 657 if($primary_component_error){ 658 659 $error = array( 660 'numeric'=>3, 661 'text'=>"Error fetching primary component name", 662 'data'=>array("current_component_slug"=>$current_component_slug), 663 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 664 'child'=>$primary_component_error 665 ); 666 return false; 293 // No component, so default will be picked later 294 } else { 295 $bp_uri = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) ); 296 $bp->current_component = ''; 667 297 } 668 298 669 if($this->bp->current_component != null){ 670 671 $status = array( 672 'numeric'=>9, 673 'text'=>"Match on members component with primary nested component", 674 'data'=>array( 'bp_pages'=>$this->bp->pages, 675 'active_components'=>$this->bp->active_components, 676 'current_component_slug'=>$current_component_slug, 677 "component"=>$this->bp->current_component), 678 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 679 ); 299 // Reset the offset 300 $uri_offset = 0; 680 301 } 681 else {682 683 // CASE 3B: Match against the "secondary" components that can only exist as a secondary684 // page nested beneath the "members" component. Matching is determined by the component's685 // action functions, which hook on the 'bp_init' action. Action functions are located686 // in "/component_name/bp-component_name-actions.php".687 // ---------------------------------------------------------------------------------------688 689 $this->bp->current_component = $current_component_slug;690 691 $status = array(692 'numeric'=>10,693 'text'=>"Match on members component, with possible match on secondary nested component",694 'data'=>array( 'bp_pages'=>$this->bp->pages,695 'active_components'=>$this->bp->active_components,696 'current_component_slug'=>$current_component_slug),697 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__698 );699 700 701 302 } 702 703 303 } 704 // CASE 4: There are no tokens left in the transect, so we're at the default screen705 // in the members component. Set $this->bp->current_component to the default profile706 // component (defined in bp-members-loader.php line 113)707 // ---------------------------------------------------------------------------------------708 else {709 $this->bp->current_component = $this->bp->default_component;710 304 711 $status = array( 712 'numeric'=>11, 713 'text'=>"Match on members component with no nested component", 714 'data'=>array("component"=>$this->bp->current_component), 715 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__ 716 ); 717 } 305 // Set the current action 306 $bp->current_action = isset( $bp_uri[$uri_offset + 1] ) ? $bp_uri[$uri_offset + 1] : ''; 718 307 308 // Slice the rest of the $bp_uri array and reset offset 309 $bp_uri = array_slice( $bp_uri, $uri_offset + 2 ); 310 $uri_offset = 0; 719 311 720 } 312 // Set the entire URI as the action variables, we will unset the current_component and action in a second 313 $bp->action_variables = $bp_uri; 721 314 722 315 // Reset the keys by merging with an empty array 316 $bp->action_variables = array_merge( array(), $bp->action_variables ); 723 317 } 724 318 725 726 // Set BP's global variables727 // ====================================================================728 729 if( isset($transect[0]) ){730 731 $this->bp->current_action = array_shift($transect);732 733 if( count($transect) > 0 ){734 735 $this->bp->action_variables = $transect;736 }737 738 }739 740 // Set WP global variables741 // ====================================================================742 if( !empty($object_id) ){743 744 // Set WP's internal query variables to the same state they would be in if745 // WP had loaded the page itself instead of BP intercepting the page load746 // and replacing it with our own content747 748 // TODO: We've emulated this for compatibility. BP should try to avoid749 // doing this unless actually necessary, because it costs an extra query on750 // each page load.751 752 $this->wp_query->queried_object_id = $this->intersect["endpoint_id"];753 $this->wp_query->queried_object = &get_post($this->intersect["endpoint_id"]);754 755 }756 757 }758 759 760 319 /** 761 * Returns a flat array of the site's page hierarchy 320 * Are root profiles enabled and allowed 762 321 * 763 * @version 1.6 764 * @since 1.6 765 * @return array $result | Page hierarchy as flat array 322 * @since BuddyPress (1.6) 323 * @return bool True if yes, false if no 766 324 */ 325 function bp_core_enable_root_profiles() { 767 326 768 public function getPageHierarchy(&$error=null) {327 $retval = false; 769 328 770 // TODO: Add caching capabilities 329 if ( defined( 'BP_ENABLE_ROOT_PROFILES' ) && ( true == BP_ENABLE_ROOT_PROFILES ) ) 330 $retval = true; 771 331 772 global $wpdb; 773 774 // Always get page data from the root blog, except on multiblog mode, when it comes 775 // from the current blog 776 777 if( bp_is_multiblog_mode() ){ 778 779 $posts_table_name = $wpdb->posts; 332 return apply_filters( 'bp_core_enable_root_profiles', $retval ); 780 333 } 781 else {782 $posts_table_name = $wpdb->get_blog_prefix( bp_get_root_blog_id() ) . 'posts';783 }784 334 785 $sql = "SELECT ID, post_name, post_parent, post_title FROM {$posts_table_name} WHERE post_type = 'page' AND post_status != 'auto-draft'";786 $pages = $wpdb->get_results($sql);787 788 // Trap any database errors789 $sql_error = mysql_error($wpdb->dbh);790 791 if($sql_error){792 793 $error = array(794 'numeric'=>1,795 'text'=>"Database error",796 'data'=>array($sql, $sql_error),797 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,798 'child'=>null799 );800 801 return false;802 }803 804 // Spin the SQL server's output into a useful format805 $result = array();806 807 foreach($pages as $page){808 809 $result[$page->ID] = array( "parent"=>$page->post_parent,810 "slug"=>$page->post_name,811 "title"=>$page->post_title812 );813 }814 unset($page);815 816 return $result;817 818 }819 820 821 335 /** 822 * Lofts a flat array of nodes into a rooted directed tree in O(n) time 823 * with only O(n) extra memory. This is also known as the "in-place quick 824 * union" algorithm. 336 * bp_core_load_template() 825 337 * 826 * @link http://en.wikipedia.org/wiki/Tree_(graph_theory) 827 * @link http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Walks 828 * @link http://en.wikipedia.org/wiki/Quicksort (in-place version) 338 * Load a specific template file with fallback support. 829 339 * 830 * @version 1.6 831 * @since 1.6 832 * @param array $nodes | Flat array of nodes 833 * @return array $result | Hierarchical array of nodes 834 */ 835 836 public function loftHierarchy($nodes) { 837 838 $tree = array(); 839 840 foreach( $nodes as $node_id => $data){ 841 842 // Note: we can operate directly on the passed parameter, because unless 843 // explicitly told not to by using the "&$" sigil, PHP passes copies 844 // of variables into a function. 845 846 $nodes[$node_id]["node_id"] = $node_id; // Insert the node_id into each node to make the data 847 // structure easier to use. Note the unit tests are very 848 // picky about the order this gets done in because it 849 // affects its position in the output array. 850 if( empty($data["parent"]) ){ 851 852 $tree["children"][$node_id] =& $nodes[$node_id]; 853 } 854 else { 855 $nodes[$data["parent"]]["children"][$node_id] =& $nodes[$node_id]; 856 } 857 } 858 859 return $tree; 860 } 861 862 863 /** 864 * Finds the longest intersect between a walk and a tree. 340 * Example: 341 * bp_core_load_template( 'members/index' ); 342 * Loads: 343 * wp-content/themes/[activated_theme]/members/index.php 865 344 * 866 * @link http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Walks 867 * @link http://en.wikipedia.org/wiki/Breadth-first_search 868 * 869 * @version 1.6 870 * @since 1.6 871 * @param array $walk | Walk array 872 * @param array $tree | Tree array 873 * @return array $result | Walk key and matching node id 345 * @package BuddyPress Core 346 * @param $username str Username to check. 347 * @return false|int The user ID of the matched user, or false. 874 348 */ 349 function bp_core_load_template( $templates ) { 350 global $post, $bp, $wp_query, $wpdb; 875 351 876 public function walkIntersectTree($walk, $tree, &$error=null) { 877 878 879 if( !is_array($walk) ){ 880 881 $error = array( 882 'numeric'=>1, 883 'text'=>"Walk is not a valid array", 884 'data'=>array( "walk"=>$walk, "tree"=>$tree), 885 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 886 'child'=>null 887 ); 352 // Determine if the root object WP page exists for this request 353 // note: get_page_by_path() breaks non-root pages 354 if ( !empty( $bp->unfiltered_uri_offset ) ) { 355 if ( !$page_exists = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s", $bp->unfiltered_uri[$bp->unfiltered_uri_offset] ) ) ) { 888 356 return false; 889 357 } 890 891 if( !is_array($tree) ){892 893 $error = array(894 'numeric'=>2,895 'text'=>"Tree is not a valid array",896 'data'=>array( "walk"=>$walk, "tree"=>$tree),897 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__,898 'child'=>null899 );900 return false;901 358 } 902 359 903 904 // Loop through each child node, searching for the 905 // child node with the longest walk 906 // ================================================ 907 908 $min_offset = null; 909 $min_node = null; 910 911 foreach( $tree["children"] as $node_id => $data){ 912 913 if($data["slug"] == $walk[0]){ 914 915 $reduced_walk = array_slice($walk, 1); 916 $intersect = self::walkIntersectTree_iterator($reduced_walk, $data); 917 918 if( ($min_offset === null) || ($intersect["walk_offset"] < $min_offset) ){ 919 920 $min_offset = $intersect["walk_offset"]; 921 $min_node = $intersect["node_id"]; 360 // Set the root object as the current wp_query-ied item 361 $object_id = 0; 362 foreach ( (array) $bp->pages as $page ) { 363 if ( $page->name == $bp->unfiltered_uri[$bp->unfiltered_uri_offset] ) { 364 $object_id = $page->id; 922 365 } 923 366 } 924 367 368 // Make the queried/post object an actual valid page 369 if ( !empty( $object_id ) ) { 370 $wp_query->queried_object = &get_post( $object_id ); 371 $wp_query->queried_object_id = $object_id; 372 $post = $wp_query->queried_object; 925 373 } 926 374 927 // Return the child node with the longest walk, or if928 // there was no matching child node, return this node929 // ================================================375 // Define local variables 376 $located_template = false; 377 $filtered_templates = array(); 930 378 931 if($min_offset === null){ 932 933 $result = array( 934 "endpoint_id"=>null, 935 "endpoint_name"=>null, 936 "walk_key"=>null, 937 "transect"=>array() 938 ); 939 } 940 else { 941 942 // Convert offset to array key number so functions further down 943 // the chain can use array_slice() to find the tokens after the 944 // endpoint that correspond to actions/arguements (if they exist) 945 946 $walk_key = (count($walk) - $min_offset) - 1; 947 948 $result = array( 949 "endpoint_id" => $min_node, 950 "endpoint_name"=>$walk[$walk_key], 951 "walk_key" => $walk_key, 952 "transect"=>array_slice($walk, ($walk_key +1) ) 953 ); 954 } 955 956 return $result; 957 958 } 959 960 961 /** 962 * Finds the longest intersect between the walk and the tree. 963 * 964 * @link http://en.wikipedia.org/wiki/Glossary_of_graph_theory#Walks 965 * @link http://en.wikipedia.org/wiki/Breadth-first_search 966 * 967 * @version 1.6 968 * @since 1.6 969 * @param array $walk | Walk array 970 * @param array $tree | Tree array 971 * @return array $result | Walk offset and matching node id 972 */ 973 974 public function walkIntersectTree_iterator($walk, $tree) { 975 976 977 // Calculate offsets 978 // ================================================ 979 980 $walk_offset = count($walk); 981 982 if( is_array($tree["children"]) ){ 983 984 $children_count = count($tree["children"]); 985 } 986 else { 987 $children_count = 0; 988 } 989 990 // If either termination condition is met, return 991 // ================================================ 992 993 if( ($walk_offset == 0) || ($children_count == 0) ){ 994 995 $result = array( "node_id"=>$tree["node_id"], 996 "walk_offset"=>$walk_offset 997 ); 998 999 return $result; 1000 } 1001 1002 // Loop through each child node, searching for the 1003 // child node with the longest walk 1004 // ================================================ 1005 1006 $min_offset = null; 1007 $min_node = null; 1008 1009 foreach( $tree["children"] as $node_id => $data){ 1010 1011 if($data["slug"] == $walk[0]){ 1012 1013 $reduced_walk = array_slice($walk, 1); 1014 $intersect = self::walkIntersectTree_iterator($reduced_walk, $data); 1015 1016 if( ($min_offset === null) || ($intersect["walk_offset"] < $min_offset) ){ 1017 1018 $min_offset = $intersect["walk_offset"]; 1019 $min_node = $intersect["node_id"]; 1020 } 1021 } 1022 1023 } 1024 1025 // Return the child node with the longest walk, or if 1026 // there was no matching child node, return this node 1027 // ================================================ 1028 1029 if($min_offset === null){ 1030 1031 $result = array( 1032 "node_id"=>$tree["node_id"], 1033 "walk_offset"=>$walk_offset 1034 ); 1035 } 1036 else { 1037 $result = array( 1038 "node_id"=>$min_node, 1039 "walk_offset"=>$min_offset 1040 ); 1041 } 1042 1043 return $result; 1044 1045 } 1046 1047 1048 /** 1049 * Checks if a slug matches an active "primary" BuddyPress component. Primary components 1050 * are components which can exist as a top-level page on the site, and in some cases 1051 * a secondary page nested below the "members" component. Third-party components following 1052 * the "BuddyPress Example Component" pattern will appear in the results. 1053 * 1054 * @version 1.6 1055 * @since 1.6 1056 * @param string $slug | Name of slug to check 1057 * @return bool/string $result | False on failure. Null on nonexistent. Name of component on success. 1058 */ 1059 1060 public function getPrimaryComponentName($slug, &$error=null) { 1061 1062 1063 if( empty($slug) ){ 1064 1065 $error = array( 1066 'numeric'=>1, 1067 'text'=>"Called with empty slug", 1068 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 1069 'child'=>null 1070 ); 1071 return false; 1072 } 1073 1074 // If the BP Pages object hasn't been loaded yet, try to load it 1075 if( empty($this->bp->pages) ){ 1076 1077 $this->bp->pages = self::buildDirectoryPages($this->flat_pages); 1078 } 1079 1080 if( empty($this->bp->pages) ){ 1081 1082 $error = array( 1083 'numeric'=>2, 1084 'text'=>"Failed to load BP pages object", 1085 'data'=>array("bp_pages"=>$this->bp->pages), 1086 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 1087 'child'=>null 1088 ); 1089 return false; 1090 } 1091 1092 1093 foreach($this->bp->pages as $component_name => $data){ 1094 1095 // NOTE: We cannot use an algorithm that checks against $this->bp->active_components, 1096 // because its impossible for 3rd-party components to add themselves to this array 1097 // using the 'bp_active_components' filter. The filter is placed so early in the call 1098 // stack it runs before 3rd-party components can load any of their plugin files. 1099 1100 if( !array_key_exists($component_name, $this->bp->deactivated_components) // 1) Component is active 1101 && $data->name == $slug ) // 2) Slug matches 1102 { 1103 return $component_name; 1104 } 1105 } 1106 unset($component_name, $data); 1107 1108 // Separate check for search component (because its not a real BP component, 1109 // and its not included in the $bp->active_components array) 1110 1111 if($slug == bp_get_search_slug()){ 1112 1113 return "search"; 1114 } 1115 1116 return null; 1117 1118 } 1119 1120 /** 1121 * Generates the BP component pages array 1122 * 1123 * @version 1.6 1124 * @since 1.6 1125 * @param array $flat_pages | Flat array of all WordPress pages on the site 1126 * @return obj $pages | Structured object containing page ID's, Names, and Slugs 1127 */ 1128 function buildDirectoryPages($flat_pages, &$error=null) { 1129 1130 1131 if( empty($flat_pages) ){ 1132 1133 $error = array( 1134 'numeric'=>1, 1135 'text'=>"Called with empty flat_pages array", 1136 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 1137 'child'=>null 1138 ); 1139 return false; 1140 } 1141 1142 1143 $page_ids = (array)bp_core_get_directory_page_ids(); 1144 1145 if( empty($page_ids) ){ 1146 1147 $error = array( 1148 'numeric'=>2, 1149 'text'=>"BP core directory page ids option is empty", 1150 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 1151 'child'=>null 1152 ); 1153 return false; 1154 } 1155 1156 1157 $pages = new stdClass; 1158 1159 // Iterate through each entry in the BP pages config option 1160 foreach( $page_ids as $component_id => $bp_page_id ) { 1161 1162 // Iterate through each WP site page in the flat pages array 1163 foreach( $flat_pages as $wp_page_id => $data ) { 1164 1165 // If the page ids match, add this page to the components array 1166 if( $wp_page_id == $bp_page_id ) { 1167 1168 $pages->{$component_id}->name = $data['slug']; 1169 $pages->{$component_id}->id = $wp_page_id; 1170 $pages->{$component_id}->title = $data['title']; 1171 1172 $stem = array(); 1173 $stem[] = $data['slug']; 1174 1175 $parent = $data['parent']; 1176 1177 // If the page is not attached to the root node, traverse the page tree backwards to the 1178 // root node generating the reverse walk, then flip it and implode it to a string. 1179 1180 while( $parent != 0 ){ 1181 1182 $stem[] = $flat_pages[$parent]['slug']; 1183 $parent = $flat_pages[$parent]['parent']; 1184 } 1185 1186 // TODO: BuddyPress incorrectly calls this a "slug", which is confusing. The correct term 1187 // is a "stem" (in string form) and a "walk" (in array form). 1188 1189 $pages->{$component_id}->slug = implode( '/', array_reverse( (array)$stem ) ); 1190 } 1191 1192 unset($slug); 1193 } 1194 unset($wp_page_id, $data); 1195 1196 } 1197 unset($component_id, $bp_page_id); 1198 1199 return apply_filters( 'bp_core_get_directory_pages', $pages ); 1200 1201 } 1202 1203 1204 /** 1205 * Load a specific template file, with fallback support. 1206 * 1207 * Example: bp_core_load_template( 'members/index' ); 1208 * Loads: wp-content/themes/[activated_theme]/members/index.php 1209 * 1210 * @version 1.6 1211 * @since 1.6 1212 * @param string/array $templates | Single template name as string. Multiple template names as array of string. 1213 * @return bool/die $result | False on failure. Loads template and terminates thread on success. 1214 */ 1215 function loadTemplate($templates, &$error=null) { 1216 1217 1218 if( !$this->intersect["endpoint_id"] ){ 1219 1220 $error = array( 1221 'numeric'=>1, 1222 'text'=>"Cannot load template because router was unable to intersect the current 1223 request URI with any pages in the site's page tree.", 1224 'data'=>array("intersect"=>$this->intersect, 1225 "walk"=>$this->walk, 1226 "templates"=>$templates), 1227 'file'=>__FILE__, 'line'=>__LINE__, 'method'=>__METHOD__, 1228 'child'=>null 1229 ); 1230 return false; 1231 } 1232 1233 // Add a ".php" suffix to each template file in the $templates array 1234 foreach( (array)$templates as $template ){ 1235 379 // Fetch each template and add the php suffix 380 foreach ( (array) $templates as $template ) 1236 381 $filtered_templates[] = $template . '.php'; 1237 }1238 382 1239 383 // Filter the template locations so that plugins can alter where they are located 1240 384 $located_template = apply_filters( 'bp_located_template', locate_template( (array) $filtered_templates, false ), $filtered_templates ); 385 if ( !empty( $located_template ) ) { 1241 386 1242 if($located_template){ 387 // Template was located, lets set this as a valid page and not a 404. 388 status_header( 200 ); 389 $wp_query->is_page = $wp_query->is_singular = true; 390 $wp_query->is_404 = false; 1243 391 1244 // Explicitly set WP's internal query variables to the correct state (because the 1245 // default is to 404 the page) 392 do_action( 'bp_core_pre_load_template', $located_template ); 1246 393 1247 $this->wp_query->is_page = true;1248 $this->wp_query->is_404 = false;1249 1250 // Explicitly set the HTTP headers. Note that this only sets the headers for the web1251 // page. The web server generates its own headers for individual items such as images1252 // and CSS stylesheets loaded by the page.1253 1254 $protocol = $_SERVER["SERVER_PROTOCOL"];1255 $code = 200;1256 $text = "OK";1257 1258 if( ($protocol != 'HTTP/1.1') && ($protocol != 'HTTP/1.0') ){1259 1260 $protocol = 'HTTP/1.0';1261 }1262 1263 $status_header = "$protocol $code $text";1264 1265 header($status_header, true, $code);1266 1267 394 load_template( apply_filters( 'bp_load_template', $located_template ) ); 1268 395 396 do_action( 'bp_core_post_load_template', $located_template ); 1269 397 } 1270 398 1271 if(!$this->unit_test){ 1272 1273 // TODO: It's bad practice to place silent die() calls all over an application's code because it 1274 // makes it very difficult to unit-test. There should only be ONE silent die() in an app, used on 1275 // successful termination in the controller's core. Beyond that, die() should ONLY be used in 1276 // a "kernel panic" situation, and should ALWAYS include debugging info like line numbers and 1277 // a variable dump. 1278 399 // Kill any other output after this. 1279 400 die; 1280 401 } 1281 402 1282 }1283 1284 1285 1286 } // End class BP_router1287 1288 1289 1290 // BRIDGE FUNCTIONS1291 // ========================================================================================================1292 // These functions allow legacy code to access the new router class1293 1294 1295 function bp_core_set_uri_globals(){1296 1297 global $bp;1298 $bp->router = new BP_router();1299 1300 $result = $bp->router->route(&$status, &$error);1301 return $result;1302 }1303 1304 function bp_core_load_template($templates){1305 1306 global $bp;1307 $result = $bp->router->loadTemplate($templates, &$error);1308 return $result;1309 }1310 1311 // ========================================================================================================1312 1313 1314 403 /** 1315 * Are root profiles enabled and allowed1316 *1317 * @since BuddyPress (1.6)1318 * @return bool True if yes, false if no1319 */1320 function bp_core_enable_root_profiles() {1321 1322 $retval = false;1323 1324 if ( defined( 'BP_ENABLE_ROOT_PROFILES' ) && ( true == BP_ENABLE_ROOT_PROFILES ) )1325 $retval = true;1326 1327 return apply_filters( 'bp_core_enable_root_profiles', $retval );1328 }1329 1330 /**1331 404 * bp_core_catch_profile_uri() 1332 405 * 1333 406 * If the extended profiles component is not installed we still need … … 1587 660 } 1588 661 } 1589 662 add_action( 'wp_head', '_bp_maybe_remove_rel_canonical', 8 ); 1590 1591 1592 No newline at end of file1593 663 ?>