1 | <?php |
---|
2 | |
---|
3 | /** |
---|
4 | * BuddyPress URI catcher. |
---|
5 | * |
---|
6 | * Functions for parsing the URI and determining which BuddyPress template file |
---|
7 | * to use on-screen. |
---|
8 | * |
---|
9 | * @package BuddyPress |
---|
10 | * @subpackage Core |
---|
11 | */ |
---|
12 | |
---|
13 | // Exit if accessed directly |
---|
14 | if ( !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:// domain.com / members / andy / [current_component] / [current_action] / [action_variables] / [action_variables] / ... |
---|
25 | * - OUTSIDE ROOT: http:// domain.com / sites / buddypress / members / andy / [current_component] / [current_action] / [action_variables] / [action_variables] / ... |
---|
26 | * |
---|
27 | * Example: |
---|
28 | * - http://domain.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 BuddyPress (1.0.0) |
---|
34 | */ |
---|
35 | function bp_core_set_uri_globals() { |
---|
36 | global $bp, $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 | // Define local variables |
---|
43 | $root_profile = $match = false; |
---|
44 | $key_slugs = $matches = $uri_chunks = array(); |
---|
45 | |
---|
46 | // Fetch all the WP page names for each component |
---|
47 | if ( empty( $bp->pages ) ) |
---|
48 | $bp->pages = bp_core_get_directory_pages(); |
---|
49 | |
---|
50 | // Ajax or not? |
---|
51 | if ( defined( 'DOING_AJAX' ) && DOING_AJAX || strpos( $_SERVER['REQUEST_URI'], 'wp-load.php' ) ) |
---|
52 | $path = bp_core_referrer(); |
---|
53 | else |
---|
54 | $path = esc_url( $_SERVER['REQUEST_URI'] ); |
---|
55 | |
---|
56 | // Filter the path |
---|
57 | $path = apply_filters( 'bp_uri', $path ); |
---|
58 | |
---|
59 | // Force lowercase for correct match comparison when there are encoded url slugs |
---|
60 | $path = strtolower($path); |
---|
61 | |
---|
62 | // Take GET variables off the URL to avoid problems |
---|
63 | $path = strtok( $path, '?' ); |
---|
64 | |
---|
65 | // Fetch current URI and explode each part separated by '/' into an array |
---|
66 | $bp_uri = explode( '/', $path ); |
---|
67 | |
---|
68 | // Loop and remove empties |
---|
69 | foreach ( (array) $bp_uri as $key => $uri_chunk ) { |
---|
70 | if ( empty( $bp_uri[$key] ) ) { |
---|
71 | unset( $bp_uri[$key] ); |
---|
72 | } |
---|
73 | } |
---|
74 | |
---|
75 | // If running off blog other than root, any subdirectory names must be |
---|
76 | // removed from $bp_uri. This includes two cases: |
---|
77 | // |
---|
78 | // 1. when WP is installed in a subdirectory, |
---|
79 | // 2. when BP is running on secondary blog of a subdirectory |
---|
80 | // multisite installation. Phew! |
---|
81 | if ( is_multisite() && !is_subdomain_install() && ( bp_is_multiblog_mode() || 1 != bp_get_root_blog_id() ) ) { |
---|
82 | |
---|
83 | // Blow chunks |
---|
84 | $chunks = explode( '/', $current_blog->path ); |
---|
85 | |
---|
86 | // If chunks exist... |
---|
87 | if ( !empty( $chunks ) ) { |
---|
88 | |
---|
89 | // ...loop through them... |
---|
90 | foreach( $chunks as $key => $chunk ) { |
---|
91 | $bkey = array_search( $chunk, $bp_uri ); |
---|
92 | |
---|
93 | // ...and unset offending keys |
---|
94 | if ( false !== $bkey ) { |
---|
95 | unset( $bp_uri[$bkey] ); |
---|
96 | } |
---|
97 | |
---|
98 | $bp_uri = array_values( $bp_uri ); |
---|
99 | } |
---|
100 | } |
---|
101 | } |
---|
102 | |
---|
103 | // Get site path items |
---|
104 | $paths = explode( '/', bp_core_get_site_path() ); |
---|
105 | |
---|
106 | // Take empties off the end of path |
---|
107 | if ( empty( $paths[count( $paths ) - 1] ) ) |
---|
108 | array_pop( $paths ); |
---|
109 | |
---|
110 | // Take empties off the start of path |
---|
111 | if ( empty( $paths[0] ) ) |
---|
112 | array_shift( $paths ); |
---|
113 | |
---|
114 | // Reset indexes |
---|
115 | $bp_uri = array_values( $bp_uri ); |
---|
116 | $paths = array_values( $paths ); |
---|
117 | |
---|
118 | // Unset URI indices if they intersect with the paths |
---|
119 | foreach ( (array) $bp_uri as $key => $uri_chunk ) { |
---|
120 | if ( isset( $paths[$key] ) && $uri_chunk == $paths[$key] ) { |
---|
121 | unset( $bp_uri[$key] ); |
---|
122 | } |
---|
123 | } |
---|
124 | |
---|
125 | // Reset the keys by merging with an empty array |
---|
126 | $bp_uri = array_merge( array(), $bp_uri ); |
---|
127 | |
---|
128 | // If a component is set to the front page, force its name into $bp_uri |
---|
129 | // so that $current_component is populated (unless a specific WP post is being requested |
---|
130 | // via a URL parameter, usually signifying Preview mode) |
---|
131 | if ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_on_front' ) && empty( $bp_uri ) && empty( $_GET['p'] ) && empty( $_GET['page_id'] ) ) { |
---|
132 | $post = get_post( get_option( 'page_on_front' ) ); |
---|
133 | if ( !empty( $post ) ) { |
---|
134 | $bp_uri[0] = $post->post_name; |
---|
135 | } |
---|
136 | } |
---|
137 | |
---|
138 | // Keep the unfiltered URI safe |
---|
139 | $bp->unfiltered_uri = $bp_uri; |
---|
140 | |
---|
141 | // Don't use $bp_unfiltered_uri, this is only for backpat with old plugins. Use $bp->unfiltered_uri. |
---|
142 | $GLOBALS['bp_unfiltered_uri'] = &$bp->unfiltered_uri; |
---|
143 | |
---|
144 | // Get slugs of pages into array |
---|
145 | foreach ( (array) $bp->pages as $page_key => $bp_page ) |
---|
146 | $key_slugs[$page_key] = trailingslashit( '/' . $bp_page->slug ); |
---|
147 | |
---|
148 | // Bail if keyslugs are empty, as BP is not setup correct |
---|
149 | if ( empty( $key_slugs ) ) |
---|
150 | return; |
---|
151 | |
---|
152 | // Loop through page slugs and look for exact match to path |
---|
153 | foreach ( $key_slugs as $key => $slug ) { |
---|
154 | if ( $slug == $path ) { |
---|
155 | $match = $bp->pages->{$key}; |
---|
156 | $match->key = $key; |
---|
157 | $matches[] = 1; |
---|
158 | break; |
---|
159 | } |
---|
160 | } |
---|
161 | |
---|
162 | // No exact match, so look for partials |
---|
163 | if ( empty( $match ) ) { |
---|
164 | |
---|
165 | // Loop through each page in the $bp->pages global |
---|
166 | foreach ( (array) $bp->pages as $page_key => $bp_page ) { |
---|
167 | |
---|
168 | // Look for a match (check members first) |
---|
169 | if ( in_array( $bp_page->name, (array) $bp_uri ) ) { |
---|
170 | |
---|
171 | // Match found, now match the slug to make sure. |
---|
172 | $uri_chunks = explode( '/', $bp_page->slug ); |
---|
173 | |
---|
174 | // Loop through uri_chunks |
---|
175 | foreach ( (array) $uri_chunks as $key => $uri_chunk ) { |
---|
176 | |
---|
177 | // Make sure chunk is in the correct position |
---|
178 | if ( !empty( $bp_uri[$key] ) && ( $bp_uri[$key] == $uri_chunk ) ) { |
---|
179 | $matches[] = 1; |
---|
180 | |
---|
181 | // No match |
---|
182 | } else { |
---|
183 | $matches[] = 0; |
---|
184 | } |
---|
185 | } |
---|
186 | |
---|
187 | // Have a match |
---|
188 | if ( !in_array( 0, (array) $matches ) ) { |
---|
189 | $match = $bp_page; |
---|
190 | $match->key = $page_key; |
---|
191 | break; |
---|
192 | }; |
---|
193 | |
---|
194 | // Unset matches |
---|
195 | unset( $matches ); |
---|
196 | } |
---|
197 | |
---|
198 | // Unset uri chunks |
---|
199 | unset( $uri_chunks ); |
---|
200 | } |
---|
201 | } |
---|
202 | |
---|
203 | // URLs with BP_ENABLE_ROOT_PROFILES enabled won't be caught above |
---|
204 | if ( empty( $matches ) && bp_core_enable_root_profiles() ) { |
---|
205 | |
---|
206 | // Switch field based on compat |
---|
207 | $field = bp_is_username_compatibility_mode() ? 'login' : 'slug'; |
---|
208 | |
---|
209 | // Make sure there's a user corresponding to $bp_uri[0] |
---|
210 | if ( !empty( $bp->pages->members ) && !empty( $bp_uri[0] ) && $root_profile = get_user_by( $field, $bp_uri[0] ) ) { |
---|
211 | |
---|
212 | // Force BP to recognize that this is a members page |
---|
213 | $matches[] = 1; |
---|
214 | $match = $bp->pages->members; |
---|
215 | $match->key = 'members'; |
---|
216 | } |
---|
217 | } |
---|
218 | |
---|
219 | // Search doesn't have an associated page, so we check for it separately |
---|
220 | if ( !empty( $bp_uri[0] ) && ( bp_get_search_slug() == $bp_uri[0] ) ) { |
---|
221 | $matches[] = 1; |
---|
222 | $match = new stdClass; |
---|
223 | $match->key = 'search'; |
---|
224 | $match->slug = bp_get_search_slug(); |
---|
225 | } |
---|
226 | |
---|
227 | // This is not a BuddyPress page, so just return. |
---|
228 | if ( empty( $matches ) ) |
---|
229 | return false; |
---|
230 | |
---|
231 | $wp_rewrite->use_verbose_page_rules = false; |
---|
232 | |
---|
233 | // Find the offset. With $root_profile set, we fudge the offset down so later parsing works |
---|
234 | $slug = !empty ( $match ) ? explode( '/', $match->slug ) : ''; |
---|
235 | $uri_offset = empty( $root_profile ) ? 0 : -1; |
---|
236 | |
---|
237 | // Rejig the offset |
---|
238 | if ( !empty( $slug ) && ( 1 < count( $slug ) ) ) { |
---|
239 | array_pop( $slug ); |
---|
240 | $uri_offset = count( $slug ); |
---|
241 | } |
---|
242 | |
---|
243 | // Global the unfiltered offset to use in bp_core_load_template(). |
---|
244 | // To avoid PHP warnings in bp_core_load_template(), it must always be >= 0 |
---|
245 | $bp->unfiltered_uri_offset = $uri_offset >= 0 ? $uri_offset : 0; |
---|
246 | |
---|
247 | // We have an exact match |
---|
248 | if ( isset( $match->key ) ) { |
---|
249 | |
---|
250 | // Set current component to matched key |
---|
251 | $bp->current_component = $match->key; |
---|
252 | |
---|
253 | // If members component, do more work to find the actual component |
---|
254 | if ( 'members' == $match->key ) { |
---|
255 | |
---|
256 | // Viewing a specific user |
---|
257 | if ( !empty( $bp_uri[$uri_offset + 1] ) ) { |
---|
258 | |
---|
259 | // Switch the displayed_user based on compatbility mode |
---|
260 | if ( bp_is_username_compatibility_mode() ) { |
---|
261 | $bp->displayed_user->id = (int) bp_core_get_userid( urldecode( $bp_uri[$uri_offset + 1] ) ); |
---|
262 | } else { |
---|
263 | $bp->displayed_user->id = (int) bp_core_get_userid_from_nicename( urldecode( $bp_uri[$uri_offset + 1] ) ); |
---|
264 | } |
---|
265 | |
---|
266 | if ( !bp_displayed_user_id() ) { |
---|
267 | |
---|
268 | // Prevent components from loading their templates |
---|
269 | $bp->current_component = ''; |
---|
270 | |
---|
271 | bp_do_404(); |
---|
272 | return; |
---|
273 | } |
---|
274 | |
---|
275 | // If the displayed user is marked as a spammer, 404 (unless logged- |
---|
276 | // in user is a super admin) |
---|
277 | if ( bp_displayed_user_id() && bp_is_user_spammer( bp_displayed_user_id() ) ) { |
---|
278 | if ( bp_current_user_can( 'bp_moderate' ) ) { |
---|
279 | bp_core_add_message( __( 'This user has been marked as a spammer. Only site admins can view this profile.', 'buddypress' ), 'warning' ); |
---|
280 | } else { |
---|
281 | bp_do_404(); |
---|
282 | return; |
---|
283 | } |
---|
284 | } |
---|
285 | |
---|
286 | // Bump the offset |
---|
287 | if ( isset( $bp_uri[$uri_offset + 2] ) ) { |
---|
288 | $bp_uri = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) ); |
---|
289 | $bp->current_component = $bp_uri[0]; |
---|
290 | |
---|
291 | // No component, so default will be picked later |
---|
292 | } else { |
---|
293 | $bp_uri = array_merge( array(), array_slice( $bp_uri, $uri_offset + 2 ) ); |
---|
294 | $bp->current_component = ''; |
---|
295 | } |
---|
296 | |
---|
297 | // Reset the offset |
---|
298 | $uri_offset = 0; |
---|
299 | } |
---|
300 | } |
---|
301 | } |
---|
302 | |
---|
303 | // Set the current action |
---|
304 | $bp->current_action = isset( $bp_uri[$uri_offset + 1] ) ? $bp_uri[$uri_offset + 1] : ''; |
---|
305 | |
---|
306 | // Slice the rest of the $bp_uri array and reset offset |
---|
307 | $bp_uri = array_slice( $bp_uri, $uri_offset + 2 ); |
---|
308 | $uri_offset = 0; |
---|
309 | |
---|
310 | // Set the entire URI as the action variables, we will unset the current_component and action in a second |
---|
311 | $bp->action_variables = $bp_uri; |
---|
312 | |
---|
313 | // Reset the keys by merging with an empty array |
---|
314 | $bp->action_variables = array_merge( array(), $bp->action_variables ); |
---|
315 | } |
---|
316 | |
---|
317 | /** |
---|
318 | * Are root profiles enabled and allowed? |
---|
319 | * |
---|
320 | * @since BuddyPress (1.6.0) |
---|
321 | * |
---|
322 | * @return bool True if yes, false if no. |
---|
323 | */ |
---|
324 | function bp_core_enable_root_profiles() { |
---|
325 | |
---|
326 | $retval = false; |
---|
327 | |
---|
328 | if ( defined( 'BP_ENABLE_ROOT_PROFILES' ) && ( true == BP_ENABLE_ROOT_PROFILES ) ) |
---|
329 | $retval = true; |
---|
330 | |
---|
331 | return apply_filters( 'bp_core_enable_root_profiles', $retval ); |
---|
332 | } |
---|
333 | |
---|
334 | /** |
---|
335 | * Load a specific template file with fallback support. |
---|
336 | * |
---|
337 | * Example: |
---|
338 | * bp_core_load_template( 'members/index' ); |
---|
339 | * Loads: |
---|
340 | * wp-content/themes/[activated_theme]/members/index.php |
---|
341 | * |
---|
342 | * @param array $templates Array of templates to attempt to load. |
---|
343 | * @return bool|null Returns false on failure. |
---|
344 | */ |
---|
345 | function bp_core_load_template( $templates ) { |
---|
346 | global $post, $bp, $wp_query, $wpdb; |
---|
347 | |
---|
348 | // Determine if the root object WP page exists for this request |
---|
349 | // note: get_page_by_path() breaks non-root pages |
---|
350 | if ( !empty( $bp->unfiltered_uri_offset ) ) { |
---|
351 | if ( !$page_exists = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_name = %s", $bp->unfiltered_uri[$bp->unfiltered_uri_offset] ) ) ) { |
---|
352 | return false; |
---|
353 | } |
---|
354 | } |
---|
355 | |
---|
356 | // Set the root object as the current wp_query-ied item |
---|
357 | $object_id = 0; |
---|
358 | foreach ( (array) $bp->pages as $page ) { |
---|
359 | if ( $page->name == $bp->unfiltered_uri[$bp->unfiltered_uri_offset] ) { |
---|
360 | $object_id = $page->id; |
---|
361 | } |
---|
362 | } |
---|
363 | |
---|
364 | // Make the queried/post object an actual valid page |
---|
365 | if ( !empty( $object_id ) ) { |
---|
366 | $wp_query->queried_object = get_post( $object_id ); |
---|
367 | $wp_query->queried_object_id = $object_id; |
---|
368 | $post = $wp_query->queried_object; |
---|
369 | } |
---|
370 | |
---|
371 | // Fetch each template and add the php suffix |
---|
372 | $filtered_templates = array(); |
---|
373 | foreach ( (array) $templates as $template ) { |
---|
374 | $filtered_templates[] = $template . '.php'; |
---|
375 | } |
---|
376 | |
---|
377 | // Filter the template locations so that plugins can alter where they are located |
---|
378 | $located_template = apply_filters( 'bp_located_template', locate_template( (array) $filtered_templates, false ), $filtered_templates ); |
---|
379 | if ( !empty( $located_template ) ) { |
---|
380 | |
---|
381 | // Template was located, lets set this as a valid page and not a 404. |
---|
382 | status_header( 200 ); |
---|
383 | $wp_query->is_page = true; |
---|
384 | $wp_query->is_singular = true; |
---|
385 | $wp_query->is_404 = false; |
---|
386 | |
---|
387 | do_action( 'bp_core_pre_load_template', $located_template ); |
---|
388 | |
---|
389 | load_template( apply_filters( 'bp_load_template', $located_template ) ); |
---|
390 | |
---|
391 | do_action( 'bp_core_post_load_template', $located_template ); |
---|
392 | |
---|
393 | // Kill any other output after this. |
---|
394 | exit(); |
---|
395 | |
---|
396 | // No template found, so setup theme compatability |
---|
397 | // @todo Some other 404 handling if theme compat doesn't kick in |
---|
398 | } else { |
---|
399 | |
---|
400 | // We know where we are, so reset important $wp_query bits here early. |
---|
401 | // The rest will be done by bp_theme_compat_reset_post() later. |
---|
402 | if ( is_buddypress() ) { |
---|
403 | status_header( 200 ); |
---|
404 | $wp_query->is_page = true; |
---|
405 | $wp_query->is_singular = true; |
---|
406 | $wp_query->is_404 = false; |
---|
407 | } |
---|
408 | |
---|
409 | do_action( 'bp_setup_theme_compat' ); |
---|
410 | } |
---|
411 | } |
---|
412 | |
---|
413 | /** |
---|
414 | * Redirect away from /profile URIs if XProfile is not enabled. |
---|
415 | */ |
---|
416 | function bp_core_catch_profile_uri() { |
---|
417 | if ( !bp_is_active( 'xprofile' ) ) { |
---|
418 | bp_core_load_template( apply_filters( 'bp_core_template_display_profile', 'members/single/home' ) ); |
---|
419 | } |
---|
420 | } |
---|
421 | |
---|
422 | /** |
---|
423 | * Catch unauthorized access to certain BuddyPress pages and redirect accordingly. |
---|
424 | * |
---|
425 | * @since BuddyPress (1.5.0) |
---|
426 | */ |
---|
427 | function bp_core_catch_no_access() { |
---|
428 | global $bp, $wp_query; |
---|
429 | |
---|
430 | // If coming from bp_core_redirect() and $bp_no_status_set is true, |
---|
431 | // we are redirecting to an accessible page so skip this check. |
---|
432 | if ( !empty( $bp->no_status_set ) ) |
---|
433 | return false; |
---|
434 | |
---|
435 | if ( !isset( $wp_query->queried_object ) && !bp_is_blog_page() ) { |
---|
436 | bp_do_404(); |
---|
437 | } |
---|
438 | } |
---|
439 | add_action( 'bp_template_redirect', 'bp_core_catch_no_access', 1 ); |
---|
440 | |
---|
441 | /** |
---|
442 | * Redirect a user to log in for BP pages that require access control. |
---|
443 | * |
---|
444 | * Add an error message (if one is provided). |
---|
445 | * |
---|
446 | * If authenticated, redirects user back to requested content by default. |
---|
447 | * |
---|
448 | * @since BuddyPress (1.5.0) |
---|
449 | * |
---|
450 | * @param array $args { |
---|
451 | * @type int $mode Specifies the destintation of the redirect. 1 will |
---|
452 | * direct to the root domain (home page), which assumes you have a |
---|
453 | * log-in form there; 2 directs to wp-login.php. Default: 2. |
---|
454 | * @type string $redirect The URL the user will be redirected to after |
---|
455 | * successfully logging in. Default: the URL originally requested. |
---|
456 | * @type string $root The root URL of the site, used in case of error or |
---|
457 | * mode 1 redirects. Default: the value of {@link bp_get_root_domain()}. |
---|
458 | * @type string $message An error message to display to the user on the |
---|
459 | * log-in page. Default: "You must log in to access the page you |
---|
460 | * requested." |
---|
461 | * } |
---|
462 | */ |
---|
463 | function bp_core_no_access( $args = '' ) { |
---|
464 | |
---|
465 | // Build the redirect URL |
---|
466 | $redirect_url = is_ssl() ? 'https://' : 'http://'; |
---|
467 | $redirect_url .= $_SERVER['HTTP_HOST']; |
---|
468 | $redirect_url .= $_SERVER['REQUEST_URI']; |
---|
469 | |
---|
470 | $defaults = array( |
---|
471 | 'mode' => 2, // 1 = $root, 2 = wp-login.php |
---|
472 | 'redirect' => $redirect_url, // the URL you get redirected to when a user successfully logs in |
---|
473 | 'root' => bp_get_root_domain(), // the landing page you get redirected to when a user doesn't have access |
---|
474 | 'message' => __( 'You must log in to access the page you requested.', 'buddypress' ) |
---|
475 | ); |
---|
476 | |
---|
477 | $r = wp_parse_args( $args, $defaults ); |
---|
478 | $r = apply_filters( 'bp_core_no_access', $r ); |
---|
479 | extract( $r, EXTR_SKIP ); |
---|
480 | |
---|
481 | /** |
---|
482 | * @ignore Ignore these filters and use 'bp_core_no_access' above |
---|
483 | */ |
---|
484 | $mode = apply_filters( 'bp_no_access_mode', $mode, $root, $redirect, $message ); |
---|
485 | $redirect = apply_filters( 'bp_no_access_redirect', $redirect, $root, $message, $mode ); |
---|
486 | $root = apply_filters( 'bp_no_access_root', $root, $redirect, $message, $mode ); |
---|
487 | $message = apply_filters( 'bp_no_access_message', $message, $root, $redirect, $mode ); |
---|
488 | $root = trailingslashit( $root ); |
---|
489 | |
---|
490 | switch ( $mode ) { |
---|
491 | |
---|
492 | // Option to redirect to wp-login.php |
---|
493 | // Error message is displayed with bp_core_no_access_wp_login_error() |
---|
494 | case 2 : |
---|
495 | if ( !empty( $redirect ) ) { |
---|
496 | bp_core_redirect( add_query_arg( array( 'action' => 'bpnoaccess' ), wp_login_url( $redirect ) ) ); |
---|
497 | } else { |
---|
498 | bp_core_redirect( $root ); |
---|
499 | } |
---|
500 | |
---|
501 | break; |
---|
502 | |
---|
503 | // Redirect to root with "redirect_to" parameter |
---|
504 | // Error message is displayed with bp_core_add_message() |
---|
505 | case 1 : |
---|
506 | default : |
---|
507 | |
---|
508 | $url = $root; |
---|
509 | if ( !empty( $redirect ) ) |
---|
510 | $url = add_query_arg( 'redirect_to', urlencode( $redirect ), $root ); |
---|
511 | |
---|
512 | if ( !empty( $message ) ) { |
---|
513 | bp_core_add_message( $message, 'error' ); |
---|
514 | } |
---|
515 | |
---|
516 | bp_core_redirect( $url ); |
---|
517 | |
---|
518 | break; |
---|
519 | } |
---|
520 | } |
---|
521 | |
---|
522 | /** |
---|
523 | * Add an error message to wp-login.php. |
---|
524 | * |
---|
525 | * Hooks into the "bpnoaccess" action defined in bp_core_no_access(). |
---|
526 | * |
---|
527 | * @since BuddyPress (1.5.0) |
---|
528 | * |
---|
529 | * @global $error Error message to pass to wp-login.php |
---|
530 | */ |
---|
531 | function bp_core_no_access_wp_login_error() { |
---|
532 | global $error; |
---|
533 | |
---|
534 | $error = apply_filters( 'bp_wp_login_error', __( 'You must log in to access the page you requested.', 'buddypress' ), $_REQUEST['redirect_to'] ); |
---|
535 | |
---|
536 | // shake shake shake! |
---|
537 | add_action( 'login_head', 'wp_shake_js', 12 ); |
---|
538 | } |
---|
539 | add_action( 'login_form_bpnoaccess', 'bp_core_no_access_wp_login_error' ); |
---|
540 | |
---|
541 | /** |
---|
542 | * Canonicalize BuddyPress URLs. |
---|
543 | * |
---|
544 | * This function ensures that requests for BuddyPress content are always |
---|
545 | * redirected to their canonical versions. Canonical versions are always |
---|
546 | * trailingslashed, and are typically the most general possible versions of the |
---|
547 | * URL - eg, example.com/groups/mygroup/ instead of |
---|
548 | * example.com/groups/mygroup/home/. |
---|
549 | * |
---|
550 | * @since BuddyPress (1.6.0) |
---|
551 | * |
---|
552 | * @see BP_Members_Component::setup_globals() where |
---|
553 | * $bp->canonical_stack['base_url'] and ['component'] may be set. |
---|
554 | * @see bp_core_new_nav_item() where $bp->canonical_stack['action'] may be set. |
---|
555 | * @uses bp_get_canonical_url() |
---|
556 | * @uses bp_get_requested_url() |
---|
557 | */ |
---|
558 | function bp_redirect_canonical() { |
---|
559 | global $bp; |
---|
560 | |
---|
561 | if ( !bp_is_blog_page() && apply_filters( 'bp_do_redirect_canonical', true ) ) { |
---|
562 | // If this is a POST request, don't do a canonical redirect. |
---|
563 | // This is for backward compatibility with plugins that submit form requests to |
---|
564 | // non-canonical URLs. Plugin authors should do their best to use canonical URLs in |
---|
565 | // their form actions. |
---|
566 | if ( !empty( $_POST ) ) { |
---|
567 | return; |
---|
568 | } |
---|
569 | |
---|
570 | // build the URL in the address bar |
---|
571 | $requested_url = bp_get_requested_url(); |
---|
572 | |
---|
573 | // Stash query args |
---|
574 | $url_stack = explode( '?', $requested_url ); |
---|
575 | $req_url_clean = $url_stack[0]; |
---|
576 | $query_args = isset( $url_stack[1] ) ? $url_stack[1] : ''; |
---|
577 | |
---|
578 | $canonical_url = bp_get_canonical_url(); |
---|
579 | |
---|
580 | // Only redirect if we've assembled a URL different from the request |
---|
581 | if ( $canonical_url !== $req_url_clean ) { |
---|
582 | |
---|
583 | // Template messages have been deleted from the cookie by this point, so |
---|
584 | // they must be readded before redirecting |
---|
585 | if ( isset( $bp->template_message ) ) { |
---|
586 | $message = stripslashes( $bp->template_message ); |
---|
587 | $message_type = isset( $bp->template_message_type ) ? $bp->template_message_type : 'success'; |
---|
588 | |
---|
589 | bp_core_add_message( $message, $message_type ); |
---|
590 | } |
---|
591 | |
---|
592 | if ( !empty( $query_args ) ) { |
---|
593 | $canonical_url .= '?' . $query_args; |
---|
594 | } |
---|
595 | |
---|
596 | bp_core_redirect( $canonical_url, 301 ); |
---|
597 | } |
---|
598 | } |
---|
599 | } |
---|
600 | |
---|
601 | /** |
---|
602 | * Output rel=canonical header tag for BuddyPress content. |
---|
603 | * |
---|
604 | * @since BuddyPress (1.6.0) |
---|
605 | */ |
---|
606 | function bp_rel_canonical() { |
---|
607 | $canonical_url = bp_get_canonical_url(); |
---|
608 | |
---|
609 | // Output rel=canonical tag |
---|
610 | echo "<link rel='canonical' href='" . esc_attr( $canonical_url ) . "' />\n"; |
---|
611 | } |
---|
612 | |
---|
613 | /** |
---|
614 | * Get the canonical URL of the current page. |
---|
615 | * |
---|
616 | * @since BuddyPress (1.6.0) |
---|
617 | * |
---|
618 | * @uses apply_filters() Filter bp_get_canonical_url to modify return value. |
---|
619 | * |
---|
620 | * @param array $args { |
---|
621 | * Optional array of arguments. |
---|
622 | * @type bool $include_query_args Whether to include current URL arguments |
---|
623 | * in the canonical URL returned from the function. |
---|
624 | * } |
---|
625 | * @return string Canonical URL for the current page. |
---|
626 | */ |
---|
627 | function bp_get_canonical_url( $args = array() ) { |
---|
628 | global $bp; |
---|
629 | |
---|
630 | // For non-BP content, return the requested url, and let WP do the work |
---|
631 | if ( bp_is_blog_page() ) { |
---|
632 | return bp_get_requested_url(); |
---|
633 | } |
---|
634 | |
---|
635 | $defaults = array( |
---|
636 | 'include_query_args' => false // Include URL arguments, eg ?foo=bar&foo2=bar2 |
---|
637 | ); |
---|
638 | $r = wp_parse_args( $args, $defaults ); |
---|
639 | extract( $r ); |
---|
640 | |
---|
641 | // Special case: when a BuddyPress directory (eg example.com/members) |
---|
642 | // is set to be the front page, ensure that the current canonical URL |
---|
643 | // is the home page URL. |
---|
644 | if ( 'page' == get_option( 'show_on_front' ) && $page_on_front = (int) get_option( 'page_on_front' ) ) { |
---|
645 | $front_page_component = array_search( $page_on_front, bp_core_get_directory_page_ids() ); |
---|
646 | |
---|
647 | // If requesting the front page component directory, canonical |
---|
648 | // URL is the front page. We detect whether we're detecting a |
---|
649 | // component *directory* by checking that bp_current_action() |
---|
650 | // is empty - ie, this not a single item or a feed |
---|
651 | if ( false !== $front_page_component && bp_is_current_component( $front_page_component ) && ! bp_current_action() ) { |
---|
652 | $bp->canonical_stack['canonical_url'] = trailingslashit( bp_get_root_domain() ); |
---|
653 | |
---|
654 | // Except when the front page is set to the registration page |
---|
655 | // and the current user is logged in. In this case we send to |
---|
656 | // the members directory to avoid redirect loops |
---|
657 | } else if ( bp_is_register_page() && 'register' == $front_page_component && is_user_logged_in() ) { |
---|
658 | $bp->canonical_stack['canonical_url'] = apply_filters( 'bp_loggedin_register_page_redirect_to', trailingslashit( bp_get_root_domain() . '/' . bp_get_members_root_slug() ) ); |
---|
659 | } |
---|
660 | } |
---|
661 | |
---|
662 | if ( empty( $bp->canonical_stack['canonical_url'] ) ) { |
---|
663 | // Build the URL in the address bar |
---|
664 | $requested_url = bp_get_requested_url(); |
---|
665 | |
---|
666 | // Stash query args |
---|
667 | $url_stack = explode( '?', $requested_url ); |
---|
668 | |
---|
669 | // Build the canonical URL out of the redirect stack |
---|
670 | if ( isset( $bp->canonical_stack['base_url'] ) ) |
---|
671 | $url_stack[0] = $bp->canonical_stack['base_url']; |
---|
672 | |
---|
673 | if ( isset( $bp->canonical_stack['component'] ) ) |
---|
674 | $url_stack[0] = trailingslashit( $url_stack[0] . $bp->canonical_stack['component'] ); |
---|
675 | |
---|
676 | if ( isset( $bp->canonical_stack['action'] ) ) |
---|
677 | $url_stack[0] = trailingslashit( $url_stack[0] . $bp->canonical_stack['action'] ); |
---|
678 | |
---|
679 | if ( !empty( $bp->canonical_stack['action_variables'] ) ) { |
---|
680 | foreach( (array) $bp->canonical_stack['action_variables'] as $av ) { |
---|
681 | $url_stack[0] = trailingslashit( $url_stack[0] . $av ); |
---|
682 | } |
---|
683 | } |
---|
684 | |
---|
685 | // Add trailing slash |
---|
686 | $url_stack[0] = trailingslashit( $url_stack[0] ); |
---|
687 | |
---|
688 | // Stash in the $bp global |
---|
689 | $bp->canonical_stack['canonical_url'] = implode( '?', $url_stack ); |
---|
690 | } |
---|
691 | |
---|
692 | $canonical_url = $bp->canonical_stack['canonical_url']; |
---|
693 | |
---|
694 | if ( !$include_query_args ) { |
---|
695 | $canonical_url = array_reverse( explode( '?', $canonical_url ) ); |
---|
696 | $canonical_url = array_pop( $canonical_url ); |
---|
697 | } |
---|
698 | |
---|
699 | return apply_filters( 'bp_get_canonical_url', $canonical_url, $args ); |
---|
700 | } |
---|
701 | |
---|
702 | /** |
---|
703 | * Return the URL as requested on the current page load by the user agent. |
---|
704 | * |
---|
705 | * @since BuddyPress (1.6.0) |
---|
706 | * |
---|
707 | * @return string Requested URL string. |
---|
708 | */ |
---|
709 | function bp_get_requested_url() { |
---|
710 | global $bp; |
---|
711 | |
---|
712 | if ( empty( $bp->canonical_stack['requested_url'] ) ) { |
---|
713 | $bp->canonical_stack['requested_url'] = is_ssl() ? 'https://' : 'http://'; |
---|
714 | $bp->canonical_stack['requested_url'] .= $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; |
---|
715 | } |
---|
716 | |
---|
717 | return apply_filters( 'bp_get_requested_url', $bp->canonical_stack['requested_url'] ); |
---|
718 | } |
---|
719 | |
---|
720 | /** |
---|
721 | * Remove WP's canonical redirect when we are trying to load BP-specific content. |
---|
722 | * |
---|
723 | * Avoids issues with WordPress thinking that a BuddyPress URL might actually |
---|
724 | * be a blog post or page. |
---|
725 | * |
---|
726 | * This function should be considered temporary, and may be removed without |
---|
727 | * notice in future versions of BuddyPress. |
---|
728 | * |
---|
729 | * @since BuddyPress (1.6.0) |
---|
730 | * |
---|
731 | * @uses bp_is_blog_page() |
---|
732 | */ |
---|
733 | function _bp_maybe_remove_redirect_canonical() { |
---|
734 | if ( ! bp_is_blog_page() ) |
---|
735 | remove_action( 'template_redirect', 'redirect_canonical' ); |
---|
736 | } |
---|
737 | add_action( 'bp_init', '_bp_maybe_remove_redirect_canonical' ); |
---|
738 | |
---|
739 | /** |
---|
740 | * Rehook maybe_redirect_404() to run later than the default. |
---|
741 | * |
---|
742 | * WordPress's maybe_redirect_404() allows admins on a multisite installation |
---|
743 | * to define 'NOBLOGREDIRECT', a URL to which 404 requests will be redirected. |
---|
744 | * maybe_redirect_404() is hooked to template_redirect at priority 10, which |
---|
745 | * creates a race condition with bp_template_redirect(), our piggyback hook. |
---|
746 | * Due to a legacy bug in BuddyPress, internal BP content (such as members and |
---|
747 | * groups) is marked 404 in $wp_query until bp_core_load_template(), when BP |
---|
748 | * manually overrides the automatic 404. However, the race condition with |
---|
749 | * maybe_redirect_404() means that this manual un-404-ing doesn't happen in |
---|
750 | * time, with the results that maybe_redirect_404() thinks that the page is |
---|
751 | * a legitimate 404, and redirects incorrectly to NOBLOGREDIRECT. |
---|
752 | * |
---|
753 | * By switching maybe_redirect_404() to catch at a higher priority, we avoid |
---|
754 | * the race condition. If bp_core_load_template() runs, it dies before reaching |
---|
755 | * maybe_redirect_404(). If bp_core_load_template() does not run, it means that |
---|
756 | * the 404 is legitimate, and maybe_redirect_404() can proceed as expected. |
---|
757 | * |
---|
758 | * This function will be removed in a later version of BuddyPress. Plugins |
---|
759 | * (and plugin authors!) should ignore it. |
---|
760 | * |
---|
761 | * @since BuddyPress (1.6.1) |
---|
762 | * |
---|
763 | * @link http://buddypress.trac.wordpress.org/ticket/4329 |
---|
764 | * @link http://buddypress.trac.wordpress.org/ticket/4415 |
---|
765 | */ |
---|
766 | function _bp_rehook_maybe_redirect_404() { |
---|
767 | if ( defined( 'NOBLOGREDIRECT' ) ) { |
---|
768 | remove_action( 'template_redirect', 'maybe_redirect_404' ); |
---|
769 | add_action( 'template_redirect', 'maybe_redirect_404', 100 ); |
---|
770 | } |
---|
771 | } |
---|
772 | add_action( 'template_redirect', '_bp_rehook_maybe_redirect_404', 1 ); |
---|
773 | |
---|
774 | /** |
---|
775 | * Remove WP's rel=canonical HTML tag if we are trying to load BP-specific content. |
---|
776 | * |
---|
777 | * This function should be considered temporary, and may be removed without |
---|
778 | * notice in future versions of BuddyPress. |
---|
779 | * |
---|
780 | * @since BuddyPress (1.6.0) |
---|
781 | */ |
---|
782 | function _bp_maybe_remove_rel_canonical() { |
---|
783 | if ( ! bp_is_blog_page() && ! is_404() ) { |
---|
784 | remove_action( 'wp_head', 'rel_canonical' ); |
---|
785 | add_action( 'bp_head', 'bp_rel_canonical' ); |
---|
786 | } |
---|
787 | } |
---|
788 | add_action( 'wp_head', '_bp_maybe_remove_rel_canonical', 8 ); |
---|