[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * BuddyPress Filters. 4 * 5 * This file contains the filters that are used throughout BuddyPress. They are 6 * consolidated here to make searching for them easier, and to help developers 7 * understand at a glance the order in which things occur. 8 * 9 * There are a few common places that additional filters can currently be found. 10 * 11 * - BuddyPress: In {@link BuddyPress::setup_actions()} in buddypress.php 12 * - Component: In {@link BP_Component::setup_actions()} in 13 * bp-core/bp-core-component.php 14 * - Admin: More in {@link BP_Admin::setup_actions()} in 15 * bp-core/bp-core-admin.php 16 * 17 * @package BuddyPress 18 * @subpackage Core 19 * @since 1.5.0 20 * 21 * @see bp-core-actions.php 22 */ 23 24 // Exit if accessed directly. 25 defined( 'ABSPATH' ) || exit; 26 27 /** 28 * Attach BuddyPress to WordPress. 29 * 30 * BuddyPress uses its own internal actions to help aid in third-party plugin 31 * development, and to limit the amount of potential future code changes when 32 * updates to WordPress core occur. 33 * 34 * These actions exist to create the concept of 'plugin dependencies'. They 35 * provide a safe way for plugins to execute code *only* when BuddyPress is 36 * installed and activated, without needing to do complicated guesswork. 37 * 38 * For more information on how this works, see the 'Plugin Dependency' section 39 * near the bottom of this file. 40 * 41 * v--WordPress Actions v--BuddyPress Sub-actions 42 */ 43 add_filter( 'request', 'bp_request', 10 ); 44 add_filter( 'template_include', 'bp_template_include', 10 ); 45 add_filter( 'login_redirect', 'bp_login_redirect', 10, 3 ); 46 add_filter( 'map_meta_cap', 'bp_map_meta_caps', 10, 4 ); 47 48 // Add some filters to feedback messages. 49 add_filter( 'bp_core_render_message_content', 'wptexturize' ); 50 add_filter( 'bp_core_render_message_content', 'convert_smilies' ); 51 add_filter( 'bp_core_render_message_content', 'convert_chars' ); 52 add_filter( 'bp_core_render_message_content', 'wpautop' ); 53 add_filter( 'bp_core_render_message_content', 'shortcode_unautop' ); 54 add_filter( 'bp_core_render_message_content', 'wp_kses_data', 5 ); 55 56 // Emails. 57 add_filter( 'bp_email_set_content_html', 'wp_filter_post_kses', 6 ); 58 add_filter( 'bp_email_set_content_html', 'stripslashes', 8 ); 59 add_filter( 'bp_email_set_content_plaintext', 'wp_strip_all_tags', 6 ); 60 add_filter( 'bp_email_set_subject', 'sanitize_text_field', 6 ); 61 62 // Avatars. 63 add_filter( 'bp_core_fetch_avatar', 'bp_core_add_loading_lazy_attribute' ); 64 65 /** 66 * Template Compatibility. 67 * 68 * If you want to completely bypass this and manage your own custom BuddyPress 69 * template hierarchy, start here by removing this filter, then look at how 70 * bp_template_include() works and do something similar. :) 71 */ 72 add_filter( 'bp_template_include', 'bp_template_include_theme_supports', 2, 1 ); 73 add_filter( 'bp_template_include', 'bp_template_include_theme_compat', 4, 2 ); 74 75 // Filter BuddyPress template locations. 76 add_filter( 'bp_get_template_stack', 'bp_add_template_stack_locations' ); 77 78 // Turn comments off for BuddyPress pages. 79 add_filter( 'comments_open', 'bp_comments_open', 10, 2 ); 80 81 // Prevent DB query for WP's main loop. 82 add_filter( 'posts_pre_query', 'bp_core_filter_wp_query', 10, 2 ); 83 84 /** 85 * Prevent specific pages (eg 'Activate') from showing on page listings. 86 * 87 * @since 1.5.0 88 * 89 * @param array $pages List of excluded page IDs, as passed to the 90 * 'wp_list_pages_excludes' filter. 91 * @return array The exclude list, with BP's pages added. 92 */ 93 function bp_core_exclude_pages( $pages = array() ) { 94 95 // Bail if not the root blog. 96 if ( ! bp_is_root_blog() ) 97 return $pages; 98 99 $bp = buddypress(); 100 101 if ( !empty( $bp->pages->activate ) ) 102 $pages[] = $bp->pages->activate->id; 103 104 if ( !empty( $bp->pages->register ) ) 105 $pages[] = $bp->pages->register->id; 106 107 /** 108 * Filters specific pages that shouldn't show up on page listings. 109 * 110 * @since 1.5.0 111 * 112 * @param array $pages Array of pages to exclude. 113 */ 114 return apply_filters( 'bp_core_exclude_pages', $pages ); 115 } 116 add_filter( 'wp_list_pages_excludes', 'bp_core_exclude_pages' ); 117 118 /** 119 * Prevent specific pages (eg 'Activate') from showing in the Pages meta box of the Menu Administration screen. 120 * 121 * @since 2.0.0 122 * 123 * @param object|null $object The post type object used in the meta box. 124 * @return object|null The $object, with a query argument to remove register and activate pages id. 125 */ 126 function bp_core_exclude_pages_from_nav_menu_admin( $object = null ) { 127 128 // Bail if not the root blog. 129 if ( ! bp_is_root_blog() ) { 130 return $object; 131 } 132 133 if ( 'page' != $object->name ) { 134 return $object; 135 } 136 137 $bp = buddypress(); 138 $pages = array(); 139 140 if ( ! empty( $bp->pages->activate ) ) { 141 $pages[] = $bp->pages->activate->id; 142 } 143 144 if ( ! empty( $bp->pages->register ) ) { 145 $pages[] = $bp->pages->register->id; 146 } 147 148 if ( ! empty( $pages ) ) { 149 $object->_default_query['post__not_in'] = $pages; 150 } 151 152 return $object; 153 } 154 add_filter( 'nav_menu_meta_box_object', 'bp_core_exclude_pages_from_nav_menu_admin', 11, 1 ); 155 156 /** 157 * Adds current page CSS classes to the parent BP page in a WP Page Menu. 158 * 159 * Because BuddyPress primarily uses virtual pages, we need a way to highlight 160 * the BP parent page during WP menu generation. This function checks the 161 * current BP component against the current page in the WP menu to see if we 162 * should highlight the WP page. 163 * 164 * @since 2.2.0 165 * 166 * @param array $retval CSS classes for the current menu page in the menu. 167 * @param WP_Post $page The page properties for the current menu item. 168 * @return array 169 */ 170 function bp_core_menu_highlight_parent_page( $retval, $page ) { 171 if ( ! is_buddypress() ) { 172 return $retval; 173 } 174 175 $page_id = false; 176 177 // Loop against all BP component pages. 178 foreach ( (array) buddypress()->pages as $component => $bp_page ) { 179 // Handles the majority of components. 180 if ( bp_is_current_component( $component ) ) { 181 $page_id = (int) $bp_page->id; 182 } 183 184 // Stop if not on a user page. 185 if ( ! bp_is_user() && ! empty( $page_id ) ) { 186 break; 187 } 188 189 // Members component requires an explicit check due to overlapping components. 190 if ( bp_is_user() && 'members' === $component ) { 191 $page_id = (int) $bp_page->id; 192 break; 193 } 194 } 195 196 // Duplicate some logic from Walker_Page::start_el() to highlight menu items. 197 if ( ! empty( $page_id ) ) { 198 $_bp_page = get_post( $page_id ); 199 if ( in_array( $page->ID, $_bp_page->ancestors, true ) ) { 200 $retval[] = 'current_page_ancestor'; 201 } 202 if ( $page->ID === $page_id ) { 203 $retval[] = 'current_page_item'; 204 } elseif ( $_bp_page && $page->ID === $_bp_page->post_parent ) { 205 $retval[] = 'current_page_parent'; 206 } 207 } 208 209 $retval = array_unique( $retval ); 210 211 return $retval; 212 } 213 add_filter( 'page_css_class', 'bp_core_menu_highlight_parent_page', 10, 2 ); 214 215 /** 216 * Adds current page CSS classes to the parent BP page in a WP Nav Menu. 217 * 218 * When {@link wp_nav_menu()} is used, this function helps to highlight the 219 * current BP parent page during nav menu generation. 220 * 221 * @since 2.2.0 222 * 223 * @param array $retval CSS classes for the current nav menu item in the menu. 224 * @param WP_Post $item The properties for the current nav menu item. 225 * @return array 226 */ 227 function bp_core_menu_highlight_nav_menu_item( $retval, $item ) { 228 // If we're not on a BP page or if the current nav item is not a page, stop! 229 if ( ! is_buddypress() || 'page' !== $item->object ) { 230 return $retval; 231 } 232 233 // Get the WP page. 234 $page = get_post( $item->object_id ); 235 236 // See if we should add our highlight CSS classes for the page. 237 $retval = bp_core_menu_highlight_parent_page( $retval, $page ); 238 239 return $retval; 240 } 241 add_filter( 'nav_menu_css_class', 'bp_core_menu_highlight_nav_menu_item', 10, 2 ); 242 243 /** 244 * Filter the blog post comments array and insert BuddyPress URLs for users. 245 * 246 * @since 1.2.0 247 * 248 * @param array $comments The array of comments supplied to the comments template. 249 * @param int $post_id The post ID. 250 * @return array $comments The modified comment array. 251 */ 252 function bp_core_filter_comments( $comments, $post_id ) { 253 global $wpdb; 254 255 foreach( (array) $comments as $comment ) { 256 if ( $comment->user_id ) 257 $user_ids[] = $comment->user_id; 258 } 259 260 if ( empty( $user_ids ) ) 261 return $comments; 262 263 $user_ids = implode( ',', wp_parse_id_list( $user_ids ) ); 264 265 if ( !$userdata = $wpdb->get_results( "SELECT ID as user_id, user_login, user_nicename FROM {$wpdb->users} WHERE ID IN ({$user_ids})" ) ) 266 return $comments; 267 268 foreach( (array) $userdata as $user ) 269 $users[$user->user_id] = bp_core_get_user_domain( $user->user_id, $user->user_nicename, $user->user_login ); 270 271 foreach( (array) $comments as $i => $comment ) { 272 if ( !empty( $comment->user_id ) ) { 273 if ( !empty( $users[$comment->user_id] ) ) 274 $comments[$i]->comment_author_url = $users[$comment->user_id]; 275 } 276 } 277 278 return $comments; 279 } 280 add_filter( 'comments_array', 'bp_core_filter_comments', 10, 2 ); 281 282 /** 283 * When a user logs in, redirect him in a logical way. 284 * 285 * @since 1.2.0 286 * 287 * are redirected to on login. 288 * 289 * @param string $redirect_to The URL to be redirected to, sanitized in wp-login.php. 290 * @param string $redirect_to_raw The unsanitized redirect_to URL ($_REQUEST['redirect_to']). 291 * @param WP_User $user The WP_User object corresponding to a successfully 292 * logged-in user. Otherwise a WP_Error object. 293 * @return string The redirect URL. 294 */ 295 function bp_core_login_redirect( $redirect_to, $redirect_to_raw, $user ) { 296 297 // Only modify the redirect if we're on the main BP blog. 298 if ( !bp_is_root_blog() ) { 299 return $redirect_to; 300 } 301 302 // Only modify the redirect once the user is logged in. 303 if ( !is_a( $user, 'WP_User' ) ) { 304 return $redirect_to; 305 } 306 307 /** 308 * Filters whether or not to redirect. 309 * 310 * Allows plugins to have finer grained control of redirect upon login. 311 * 312 * @since 1.6.0 313 * 314 * @param bool $value Whether or not to redirect. 315 * @param string $redirect_to Sanitized URL to be redirected to. 316 * @param string $redirect_to_raw Unsanitized URL to be redirected to. 317 * @param WP_User $user The WP_User object corresponding to a 318 * successfully logged in user. 319 */ 320 $maybe_redirect = apply_filters( 'bp_core_login_redirect', false, $redirect_to, $redirect_to_raw, $user ); 321 if ( false !== $maybe_redirect ) { 322 return $maybe_redirect; 323 } 324 325 // If a 'redirect_to' parameter has been passed that contains 'wp-admin', verify that the 326 // logged-in user has any business to conduct in the Dashboard before allowing the 327 // redirect to go through. 328 if ( !empty( $redirect_to ) && ( false === strpos( $redirect_to, 'wp-admin' ) || user_can( $user, 'edit_posts' ) ) ) { 329 return $redirect_to; 330 } 331 332 if ( false === strpos( wp_get_referer(), 'wp-login.php' ) && false === strpos( wp_get_referer(), 'activate' ) && empty( $_REQUEST['nr'] ) ) { 333 return wp_get_referer(); 334 } 335 336 /** 337 * Filters the URL to redirect users to upon successful login. 338 * 339 * @since 1.9.0 340 * 341 * @param string $value URL to redirect to. 342 */ 343 return apply_filters( 'bp_core_login_redirect_to', bp_get_root_domain() ); 344 } 345 add_filter( 'bp_login_redirect', 'bp_core_login_redirect', 10, 3 ); 346 347 /** 348 * Decode HTML entities for plain-text emails. 349 * 350 * @since 2.5.0 351 * 352 * @param string $retval Current email content. 353 * @param string $prop Email property to check against. 354 * @param string $transform Either 'raw' or 'replace-tokens'. 355 * @return string|null $retval Modified email content. 356 */ 357 function bp_email_plaintext_entity_decode( $retval, $prop, $transform ) { 358 switch ( $prop ) { 359 case 'content_plaintext' : 360 case 'subject' : 361 // Only decode if 'replace-tokens' is the current type. 362 if ( 'replace-tokens' === $transform ) { 363 return html_entity_decode( $retval, ENT_QUOTES ); 364 } else { 365 return $retval; 366 } 367 break; 368 369 default : 370 return $retval; 371 break; 372 } 373 } 374 add_filter( 'bp_email_get_property', 'bp_email_plaintext_entity_decode', 10, 3 ); 375 376 /** 377 * Replace the generated password in the welcome email with '[User Set]'. 378 * 379 * On a standard BP installation, users who register themselves also set their 380 * own passwords. Therefore there is no need for the insecure practice of 381 * emailing the plaintext password to the user in the welcome email. 382 * 383 * This filter will not fire when a user is registered by the site admin. 384 * 385 * @since 1.2.1 386 * 387 * @param string $welcome_email Complete email passed through WordPress. 388 * @return string Filtered $welcome_email with the password replaced 389 * by '[User Set]'. 390 */ 391 function bp_core_filter_user_welcome_email( $welcome_email ) { 392 393 // Don't touch the email when a user is registered by the site admin. 394 if ( ( is_admin() || is_network_admin() ) && buddypress()->members->admin->signups_page != get_current_screen()->id ) { 395 return $welcome_email; 396 } 397 398 if ( strpos( bp_get_requested_url(), 'wp-activate.php' ) !== false ) { 399 return $welcome_email; 400 } 401 402 // Don't touch the email if we don't have a custom registration template. 403 if ( ! bp_has_custom_signup_page() ) { 404 return $welcome_email; 405 } 406 407 // [User Set] Replaces 'PASSWORD' in welcome email; Represents value set by user 408 return str_replace( 'PASSWORD', __( '[User Set]', 'buddypress' ), $welcome_email ); 409 } 410 add_filter( 'update_welcome_user_email', 'bp_core_filter_user_welcome_email' ); 411 412 /** 413 * Replace the generated password in the welcome email with '[User Set]'. 414 * 415 * On a standard BP installation, users who register themselves also set their 416 * own passwords. Therefore there is no need for the insecure practice of 417 * emailing the plaintext password to the user in the welcome email. 418 * 419 * This filter will not fire when a user is registered by the site admin. 420 * 421 * @since 1.2.1 422 * 423 * @param string $welcome_email Complete email passed through WordPress. 424 * @param int $blog_id ID of the blog user is joining. 425 * @param int $user_id ID of the user joining. 426 * @param string $password Password of user. 427 * @return string Filtered $welcome_email with $password replaced by '[User Set]'. 428 */ 429 function bp_core_filter_blog_welcome_email( $welcome_email, $blog_id, $user_id, $password ) { 430 431 // Don't touch the email when a user is registered by the site admin. 432 if ( ( is_admin() || is_network_admin() ) && buddypress()->members->admin->signups_page != get_current_screen()->id ) { 433 return $welcome_email; 434 } 435 436 // Don't touch the email if we don't have a custom registration template. 437 if ( ! bp_has_custom_signup_page() ) 438 return $welcome_email; 439 440 // [User Set] Replaces $password in welcome email; Represents value set by user. 441 return str_replace( $password, __( '[User Set]', 'buddypress' ), $welcome_email ); 442 } 443 add_filter( 'update_welcome_email', 'bp_core_filter_blog_welcome_email', 10, 4 ); 444 445 /** 446 * Notify new users of a successful registration (with blog). 447 * 448 * This function filter's WP's 'wpmu_signup_blog_notification', and replaces 449 * WP's default welcome email with a BuddyPress-specific message. 450 * 451 * @since 1.0.0 452 * 453 * @see wpmu_signup_blog_notification() for a description of parameters. 454 * 455 * @param string $domain The new blog domain. 456 * @param string $path The new blog path. 457 * @param string $title The site title. 458 * @param string $user The user's login name. 459 * @param string $user_email The user's email address. 460 * @param string $key The activation key created in wpmu_signup_blog(). 461 * @return bool Returns false to stop original WPMU function from continuing. 462 */ 463 function bp_core_activation_signup_blog_notification( $domain, $path, $title, $user, $user_email, $key ) { 464 $is_signup_resend = false; 465 if ( is_admin() && buddypress()->members->admin->signups_page == get_current_screen()->id ) { 466 // The admin is just approving/sending/resending the verification email. 467 $is_signup_resend = true; 468 } 469 470 $args = array( 471 'tokens' => array( 472 'activate-site.url' => esc_url( bp_get_activation_page() . '?key=' . urlencode( $key ) ), 473 'domain' => $domain, 474 'key_blog' => $key, 475 'path' => $path, 476 'user-site.url' => esc_url( set_url_scheme( "http://{$domain}{$path}" ) ), 477 'title' => $title, 478 'user.email' => $user_email, 479 ), 480 ); 481 482 $signup = bp_members_get_signup_by( 'activation_key', $key ); 483 $salutation = $user; 484 if ( $signup && bp_is_active( 'xprofile' ) ) { 485 if ( isset( $signup->meta[ 'field_' . bp_xprofile_fullname_field_id() ] ) ) { 486 $salutation = $signup->meta[ 'field_' . bp_xprofile_fullname_field_id() ]; 487 } 488 } 489 490 /** 491 * Filters if BuddyPress should send an activation key for a new multisite signup. 492 * 493 * @since 10.0.0 494 * 495 * @param string $user The user's login name. 496 * @param string $user_email The user's email address. 497 * @param string $key The activation key created in wpmu_signup_blog(). 498 * @param bool $is_signup_resend Is the site admin sending this email? 499 * @param string $domain The new blog domain. 500 * @param string $path The new blog path. 501 * @param string $title The site title. 502 */ 503 if ( apply_filters( 'bp_core_signup_send_activation_key_multisite_blog', true, $user, $user_email, $key, $is_signup_resend, $domain, $path, $title ) ) { 504 bp_send_email( 'core-user-registration-with-blog', array( array( $user_email => $salutation ) ), $args ); 505 } 506 507 // Return false to stop the original WPMU function from continuing. 508 return false; 509 } 510 add_filter( 'wpmu_signup_blog_notification', 'bp_core_activation_signup_blog_notification', 1, 6 ); 511 512 /** 513 * Notify new users of a successful registration (without blog). 514 * 515 * @since 1.0.0 516 * 517 * @see wpmu_signup_user_notification() for a full description of params. 518 * 519 * @param string $user The user's login name. 520 * @param string $user_email The user's email address. 521 * @param string $key The activation key created in wpmu_signup_user(). 522 * @param array $meta By default, an empty array. 523 * @return false|string Returns false to stop original WPMU function from continuing. 524 */ 525 function bp_core_activation_signup_user_notification( $user, $user_email, $key, $meta ) { 526 $is_signup_resend = false; 527 if ( is_admin() ) { 528 529 // If the user is created from the WordPress Add User screen, don't send BuddyPress signup notifications. 530 if( in_array( get_current_screen()->id, array( 'user', 'user-network' ) ) ) { 531 // If the Super Admin want to skip confirmation email. 532 if ( isset( $_POST[ 'noconfirmation' ] ) && is_super_admin() ) { 533 return false; 534 535 // WordPress will manage the signup process. 536 } else { 537 return $user; 538 } 539 540 // The site admin is approving/resending from the "manage signups" screen. 541 } elseif ( buddypress()->members->admin->signups_page == get_current_screen()->id ) { 542 /* 543 * There can be a case where the user was created without the skip confirmation 544 * And the super admin goes in pending accounts to resend it. In this case, as the 545 * meta['password'] is not set, the activation url must be WordPress one. 546 */ 547 $is_hashpass_in_meta = maybe_unserialize( $meta ); 548 549 if ( empty( $is_hashpass_in_meta['password'] ) ) { 550 return $user; 551 } 552 553 // Or the admin is just approving/sending/resending the verification email. 554 $is_signup_resend = true; 555 } 556 } 557 558 $user_id = 0; 559 $user_object = get_user_by( 'login', $user ); 560 if ( $user_object ) { 561 $user_id = $user_object->ID; 562 } 563 564 $salutation = $user; 565 if ( bp_is_active( 'xprofile' ) && isset( $meta[ 'field_' . bp_xprofile_fullname_field_id() ] ) ) { 566 $salutation = $meta[ 'field_' . bp_xprofile_fullname_field_id() ]; 567 } elseif ( $user_id ) { 568 $salutation = bp_core_get_user_displayname( $user_id ); 569 } 570 571 $args = array( 572 'tokens' => array( 573 'activate.url' => esc_url( trailingslashit( bp_get_activation_page() ) . "{$key}/" ), 574 'key' => $key, 575 'user.email' => $user_email, 576 'user.id' => $user_id, 577 ), 578 ); 579 580 /** 581 * Filters if BuddyPress should send an activation key for a new multisite signup. 582 * 583 * @since 10.0.0 584 * 585 * @param string $user The user's login name. 586 * @param string $user_email The user's email address. 587 * @param string $key The activation key created in wpmu_signup_blog(). 588 * @param bool $is_signup_resend Is the site admin sending this email? 589 */ 590 if ( apply_filters( 'bp_core_signup_send_activation_key_multisite', true, $user, $user_email, $key, $is_signup_resend ) ) { 591 bp_send_email( 'core-user-registration', array( array( $user_email => $salutation ) ), $args ); 592 } 593 594 // Return false to stop the original WPMU function from continuing. 595 return false; 596 } 597 add_filter( 'wpmu_signup_user_notification', 'bp_core_activation_signup_user_notification', 1, 4 ); 598 599 /** 600 * Ensure that some meta values are set for new multisite signups. 601 * 602 * @since 10.0.0 603 * 604 * @see wpmu_signup_user() for a full description of params. 605 * 606 * @param array $meta Signup meta data. Default empty array. 607 * @return array Signup meta data. 608 */ 609 function bp_core_add_meta_to_multisite_signups( $meta ) { 610 611 // Ensure that sent_date and count_sent are set in meta. 612 if ( ! isset( $meta['sent_date'] ) ) { 613 $meta['sent_date'] = '0000-00-00 00:00:00'; 614 } 615 if ( ! isset( $meta['count_sent'] ) ) { 616 $meta['count_sent'] = 0; 617 } 618 619 return $meta; 620 } 621 add_filter( 'signup_user_meta', 'bp_core_add_meta_to_multisite_signups' ); 622 add_filter( 'signup_site_meta', 'bp_core_add_meta_to_multisite_signups' ); 623 624 /** 625 * Filter the page title for BuddyPress pages. 626 * 627 * @since 1.5.0 628 * 629 * @see wp_title() 630 * @global object $bp BuddyPress global settings. 631 * 632 * @param string $title Original page title. 633 * @param string $sep How to separate the various items within the page title. 634 * @param string $seplocation Direction to display title. 635 * @return string New page title. 636 */ 637 function bp_modify_page_title( $title = '', $sep = '»', $seplocation = 'right' ) { 638 global $paged, $page, $_wp_theme_features; 639 640 // Get the BuddyPress title parts. 641 $bp_title_parts = bp_get_title_parts( $seplocation ); 642 643 // If not set, simply return the original title. 644 if ( ! $bp_title_parts ) { 645 return $title; 646 } 647 648 // Get the blog name, so we can check if the original $title included it. 649 $blogname = get_bloginfo( 'name', 'display' ); 650 651 /** 652 * Are we going to fake 'title-tag' theme functionality? 653 * 654 * @link https://buddypress.trac.wordpress.org/ticket/6107 655 * @see wp_title() 656 */ 657 $title_tag_compatibility = (bool) ( ! empty( $_wp_theme_features['title-tag'] ) || ( $blogname && strstr( $title, $blogname ) ) ); 658 659 // Append the site title to title parts if theme supports title tag. 660 if ( true === $title_tag_compatibility ) { 661 $bp_title_parts['site'] = $blogname; 662 663 if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() && ! bp_is_single_activity() ) { 664 /* translators: %s: the page number. */ 665 $bp_title_parts['page'] = sprintf( __( 'Page %s', 'buddypress' ), max( $paged, $page ) ); 666 } 667 } 668 669 // Pad the separator with 1 space on each side. 670 $prefix = str_pad( $sep, strlen( $sep ) + 2, ' ', STR_PAD_BOTH ); 671 672 // Join the parts together. 673 $new_title = join( $prefix, array_filter( $bp_title_parts ) ); 674 675 // Append the prefix for pre `title-tag` compatibility. 676 if ( false === $title_tag_compatibility ) { 677 $new_title = $new_title . $prefix; 678 } 679 680 /** 681 * Filters the older 'wp_title' page title for BuddyPress pages. 682 * 683 * @since 1.5.0 684 * 685 * @param string $new_title The BuddyPress page title. 686 * @param string $title The original WordPress page title. 687 * @param string $sep The title parts separator. 688 * @param string $seplocation Location of the separator (left or right). 689 */ 690 return apply_filters( 'bp_modify_page_title', $new_title, $title, $sep, $seplocation ); 691 } 692 add_filter( 'wp_title', 'bp_modify_page_title', 20, 3 ); 693 add_filter( 'bp_modify_page_title', 'wptexturize' ); 694 add_filter( 'bp_modify_page_title', 'convert_chars' ); 695 add_filter( 'bp_modify_page_title', 'esc_html' ); 696 697 /** 698 * Filter the document title for BuddyPress pages. 699 * 700 * @since 2.4.3 701 * 702 * @param array $title The WordPress document title parts. 703 * @return array the unchanged title parts or the BuddyPress ones 704 */ 705 function bp_modify_document_title_parts( $title = array() ) { 706 // Get the BuddyPress title parts. 707 $bp_title_parts = bp_get_title_parts(); 708 709 // If not set, simply return the original title. 710 if ( ! $bp_title_parts ) { 711 return $title; 712 } 713 714 // Get the separator used by wp_get_document_title(). 715 $sep = apply_filters( 'document_title_separator', '-' ); 716 717 // Build the BuddyPress portion of the title. 718 // We don't need to sanitize this as WordPress will take care of it. 719 $bp_title = array( 720 'title' => join( " $sep ", $bp_title_parts ) 721 ); 722 723 // Add the pagination number if needed (not sure if this is necessary). 724 if ( isset( $title['page'] ) && ! bp_is_single_activity() ) { 725 $bp_title['page'] = $title['page']; 726 } 727 728 // Add the sitename if needed. 729 if ( isset( $title['site'] ) ) { 730 $bp_title['site'] = $title['site']; 731 } 732 733 /** 734 * Filters BuddyPress title parts that will be used into the document title. 735 * 736 * @since 2.4.3 737 * 738 * @param array $bp_title The BuddyPress page title parts. 739 * @param array $title The original WordPress title parts. 740 */ 741 return apply_filters( 'bp_modify_document_title_parts', $bp_title, $title ); 742 } 743 add_filter( 'document_title_parts', 'bp_modify_document_title_parts', 20, 1 ); 744 745 /** 746 * Add BuddyPress-specific items to the wp_nav_menu. 747 * 748 * @since 1.9.0 749 * 750 * @param WP_Post $menu_item The menu item. 751 * @return WP_Post The modified WP_Post object. 752 */ 753 function bp_setup_nav_menu_item( $menu_item ) { 754 if ( is_admin() ) { 755 if ( 'bp_nav_menu_item' === $menu_item->object ) { 756 $menu_item->type = 'custom'; 757 $menu_item->url = $menu_item->guid; 758 759 if ( ! in_array( array( 'bp-menu', 'bp-'. $menu_item->post_excerpt .'-nav' ), $menu_item->classes ) ) { 760 $menu_item->classes[] = 'bp-menu'; 761 $menu_item->classes[] = 'bp-'. $menu_item->post_excerpt .'-nav'; 762 } 763 } 764 765 return $menu_item; 766 } 767 768 // Prevent a notice error when using the customizer. 769 $menu_classes = $menu_item->classes; 770 771 if ( is_array( $menu_classes ) ) { 772 $menu_classes = implode( ' ', $menu_item->classes); 773 } 774 775 // We use information stored in the CSS class to determine what kind of 776 // menu item this is, and how it should be treated. 777 preg_match( '/\sbp-(.*)-nav/', $menu_classes, $matches ); 778 779 // If this isn't a BP menu item, we can stop here. 780 if ( empty( $matches[1] ) ) { 781 return $menu_item; 782 } 783 784 switch ( $matches[1] ) { 785 case 'login' : 786 if ( is_user_logged_in() ) { 787 $menu_item->_invalid = true; 788 } else { 789 $menu_item->url = wp_login_url( bp_get_requested_url() ); 790 } 791 792 break; 793 794 case 'logout' : 795 if ( ! is_user_logged_in() ) { 796 $menu_item->_invalid = true; 797 } else { 798 $menu_item->url = wp_logout_url( bp_get_requested_url() ); 799 } 800 801 break; 802 803 // Don't show the Register link to logged-in users. 804 case 'register' : 805 if ( is_user_logged_in() ) { 806 $menu_item->_invalid = true; 807 } 808 809 break; 810 811 // All other BP nav items are specific to the logged-in user, 812 // and so are not relevant to logged-out users. 813 default: 814 if ( is_user_logged_in() ) { 815 $menu_item->url = bp_nav_menu_get_item_url( $matches[1] ); 816 } else { 817 $menu_item->_invalid = true; 818 } 819 820 break; 821 } 822 823 // If component is deactivated, make sure menu item doesn't render. 824 if ( empty( $menu_item->url ) ) { 825 $menu_item->_invalid = true; 826 827 // Highlight the current page. 828 } else { 829 $current = bp_get_requested_url(); 830 if ( strpos( $current, $menu_item->url ) !== false ) { 831 if ( is_array( $menu_item->classes ) ) { 832 $menu_item->classes[] = 'current_page_item'; 833 $menu_item->classes[] = 'current-menu-item'; 834 } else { 835 $menu_item->classes = array( 'current_page_item', 'current-menu-item' ); 836 } 837 } 838 } 839 840 return $menu_item; 841 } 842 add_filter( 'wp_setup_nav_menu_item', 'bp_setup_nav_menu_item', 10, 1 ); 843 844 /** 845 * Populate BuddyPress user nav items for the customizer. 846 * 847 * @since 2.3.3 848 * 849 * @param array $items The array of menu items. 850 * @param string $type The requested type. 851 * @param string $object The requested object name. 852 * @param integer $page The page num being requested. 853 * @return array The paginated BuddyPress user nav items. 854 */ 855 function bp_customizer_nav_menus_get_items( $items = array(), $type = '', $object = '', $page = 0 ) { 856 if ( 'bp_loggedin_nav' === $object ) { 857 $bp_items = bp_nav_menu_get_loggedin_pages(); 858 } elseif ( 'bp_loggedout_nav' === $object ) { 859 $bp_items = bp_nav_menu_get_loggedout_pages(); 860 } else { 861 return $items; 862 } 863 864 foreach ( $bp_items as $bp_item ) { 865 $items[] = array( 866 'id' => "bp-{$bp_item->post_excerpt}", 867 'title' => html_entity_decode( $bp_item->post_title, ENT_QUOTES, get_bloginfo( 'charset' ) ), 868 'type' => $type, 869 'url' => esc_url_raw( $bp_item->guid ), 870 'classes' => "bp-menu bp-{$bp_item->post_excerpt}-nav", 871 'type_label' => _x( 'Custom Link', 'customizer menu type label', 'buddypress' ), 872 'object' => $object, 873 'object_id' => -1, 874 ); 875 } 876 877 return array_slice( $items, 10 * $page, 10 ); 878 } 879 add_filter( 'customize_nav_menu_available_items', 'bp_customizer_nav_menus_get_items', 10, 4 ); 880 881 /** 882 * Set BuddyPress item navs for the customizer. 883 * 884 * @since 2.3.3 885 * 886 * @param array $item_types An associative array structured for the customizer. 887 * @return array $item_types An associative array structured for the customizer. 888 */ 889 function bp_customizer_nav_menus_set_item_types( $item_types = array() ) { 890 $item_types = array_merge( $item_types, array( 891 'bp_loggedin_nav' => array( 892 'title' => _x( 'BuddyPress (logged-in)', 'customizer menu section title', 'buddypress' ), 893 'type' => 'bp_nav', 894 'object' => 'bp_loggedin_nav', 895 ), 896 'bp_loggedout_nav' => array( 897 'title' => _x( 'BuddyPress (logged-out)', 'customizer menu section title', 'buddypress' ), 898 'type' => 'bp_nav', 899 'object' => 'bp_loggedout_nav', 900 ), 901 ) ); 902 903 return $item_types; 904 } 905 add_filter( 'customize_nav_menu_available_item_types', 'bp_customizer_nav_menus_set_item_types', 10, 1 ); 906 907 /** 908 * Filter SQL query strings to swap out the 'meta_id' column. 909 * 910 * WordPress uses the meta_id column for commentmeta and postmeta, and so 911 * hardcodes the column name into its *_metadata() functions. BuddyPress, on 912 * the other hand, uses 'id' for the primary column. To make WP's functions 913 * usable for BuddyPress, we use this just-in-time filter on 'query' to swap 914 * 'meta_id' with 'id. 915 * 916 * @since 2.0.0 917 * 918 * @access private Do not use. 919 * 920 * @param string $q SQL query. 921 * @return string 922 */ 923 function bp_filter_metaid_column_name( $q ) { 924 /* 925 * Replace quoted content with __QUOTE__ to avoid false positives. 926 * This regular expression will match nested quotes. 927 */ 928 $quoted_regex = "/'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'/s"; 929 preg_match_all( $quoted_regex, $q, $quoted_matches ); 930 $q = preg_replace( $quoted_regex, '__QUOTE__', $q ); 931 932 $q = str_replace( 'meta_id', 'id', $q ); 933 934 // Put quoted content back into the string. 935 if ( ! empty( $quoted_matches[0] ) ) { 936 for ( $i = 0; $i < count( $quoted_matches[0] ); $i++ ) { 937 $quote_pos = strpos( $q, '__QUOTE__' ); 938 $q = substr_replace( $q, $quoted_matches[0][ $i ], $quote_pos, 9 ); 939 } 940 } 941 942 return $q; 943 } 944 945 /** 946 * Filter the edit post link to avoid its display in BuddyPress pages. 947 * 948 * @since 2.1.0 949 * 950 * @param string $edit_link The edit link. 951 * @param int $post_id Post ID. 952 * @return false|string Will be a boolean (false) if $post_id is 0. Will be a string (the unchanged edit link) 953 * otherwise 954 */ 955 function bp_core_filter_edit_post_link( $edit_link = '', $post_id = 0 ) { 956 if ( 0 === $post_id ) { 957 $edit_link = false; 958 } 959 960 return $edit_link; 961 } 962 963 /** 964 * Add 'loading="lazy"' attribute into images and iframes. 965 * 966 * @since 7.0.0 967 * 968 * @string $content Content to inject attribute into. 969 * @return string 970 */ 971 function bp_core_add_loading_lazy_attribute( $content = '' ) { 972 if ( false === strpos( $content, '<img ' ) && false === strpos( $content, '<iframe ' ) ) { 973 return $content; 974 } 975 976 $content = str_replace( '<img ', '<img loading="lazy" ', $content ); 977 $content = str_replace( '<iframe ', '<iframe loading="lazy" ', $content ); 978 979 // WordPress posts need their position absolute removed for lazyloading. 980 $find_pos_absolute = ' style="position: absolute; clip: rect(1px, 1px, 1px, 1px);" '; 981 if ( false !== strpos( $content, 'data-secret=' ) && false !== strpos( $content, $find_pos_absolute ) ) { 982 $content = str_replace( $find_pos_absolute, '', $content ); 983 } 984 985 return $content; 986 } 987 988 /** 989 * Should BuddyPress load the mentions scripts and related assets, including results to prime the 990 * mentions suggestions? 991 * 992 * @since 2.2.0 993 * 994 * @param bool $load_mentions True to load mentions assets, false otherwise. 995 * @param bool $mentions_enabled True if mentions are enabled. 996 * @return bool True if mentions scripts should be loaded. 997 */ 998 function bp_maybe_load_mentions_scripts_for_blog_content( $load_mentions, $mentions_enabled ) { 999 if ( ! $mentions_enabled ) { 1000 return $load_mentions; 1001 } 1002 1003 if ( $load_mentions || ( bp_is_blog_page() && is_singular() && comments_open() ) ) { 1004 return true; 1005 } 1006 1007 return $load_mentions; 1008 } 1009 add_filter( 'bp_activity_maybe_load_mentions_scripts', 'bp_maybe_load_mentions_scripts_for_blog_content', 10, 2 ); 1010 1011 /** 1012 * Injects specific BuddyPress CSS classes into a widget sidebar. 1013 * 1014 * Helps to standardize styling of BuddyPress widgets within a theme that 1015 * does not use dynamic CSS classes in their widget sidebar's 'before_widget' 1016 * call. 1017 * 1018 * @since 2.4.0 1019 * @access private 1020 * 1021 * @global array $wp_registered_widgets Current registered widgets. 1022 * 1023 * @param array $params Current sidebar params. 1024 * @return array 1025 */ 1026 function _bp_core_inject_bp_widget_css_class( $params ) { 1027 global $wp_registered_widgets; 1028 1029 $widget_id = $params[0]['widget_id']; 1030 1031 // If callback isn't an array, bail. 1032 if ( false === is_array( $wp_registered_widgets[ $widget_id ]['callback'] ) ) { 1033 return $params; 1034 } 1035 1036 // If the current widget isn't a BuddyPress one, stop! 1037 // We determine if a widget is a BuddyPress widget, if the widget class 1038 // begins with 'bp_'. 1039 if ( 0 !== strpos( $wp_registered_widgets[ $widget_id ]['callback'][0]->id_base, 'bp_' ) ) { 1040 return $params; 1041 } 1042 1043 // Dynamically add our widget CSS classes for BP widgets if not already there. 1044 $classes = array(); 1045 1046 // Try to find 'widget' CSS class. 1047 if ( false === strpos( $params[0]['before_widget'], 'widget ' ) ) { 1048 $classes[] = 'widget'; 1049 } 1050 1051 // Try to find 'buddypress' CSS class. 1052 if ( false === strpos( $params[0]['before_widget'], ' buddypress' ) ) { 1053 $classes[] = 'buddypress'; 1054 } 1055 1056 // Stop if widget already has our CSS classes. 1057 if ( empty( $classes ) ) { 1058 return $params; 1059 } 1060 1061 // CSS injection time! 1062 $params[0]['before_widget'] = str_replace( 'class="', 'class="' . implode( ' ', $classes ) . ' ', $params[0]['before_widget'] ); 1063 1064 return $params; 1065 } 1066 add_filter( 'dynamic_sidebar_params', '_bp_core_inject_bp_widget_css_class' ); 1067 1068 /** 1069 * Add email link styles to rendered email template. 1070 * 1071 * This is only used when the email content has been merged into the email template. 1072 * 1073 * @since 2.5.0 1074 * 1075 * @param string $value Property value. 1076 * @param string $property_name Email template property name. 1077 * @param string $transform How the return value was transformed. 1078 * @return string Updated value. 1079 */ 1080 function bp_email_add_link_color_to_template( $value, $property_name, $transform ) { 1081 if ( $property_name !== 'template' || $transform !== 'add-content' ) { 1082 return $value; 1083 } 1084 1085 $settings = bp_email_get_appearance_settings(); 1086 $replacement = 'style="color: ' . esc_attr( $settings['link_text_color'] ) . ';'; 1087 1088 // Find all links. 1089 preg_match_all( '#<a[^>]+>#i', $value, $links, PREG_SET_ORDER ); 1090 foreach ( $links as $link ) { 1091 $new_link = $link = array_shift( $link ); 1092 1093 // Add/modify style property. 1094 if ( strpos( $link, 'style="' ) !== false ) { 1095 $new_link = str_replace( 'style="', $replacement, $link ); 1096 } else { 1097 $new_link = str_replace( '<a ', "<a {$replacement}\" ", $link ); 1098 } 1099 1100 if ( $new_link !== $link ) { 1101 $value = str_replace( $link, $new_link, $value ); 1102 } 1103 } 1104 1105 return $value; 1106 } 1107 add_filter( 'bp_email_get_property', 'bp_email_add_link_color_to_template', 6, 3 ); 1108 1109 /** 1110 * Add custom headers to outgoing emails. 1111 * 1112 * @since 2.5.0 1113 * 1114 * @param array $headers Array of email headers. 1115 * @param string $property Name of property. Unused. 1116 * @param string $transform Return value transformation. Unused. 1117 * @param BP_Email $email Email object reference. 1118 * @return array 1119 */ 1120 function bp_email_set_default_headers( $headers, $property, $transform, $email ) { 1121 $headers['X-BuddyPress'] = bp_get_version(); 1122 $headers['X-BuddyPress-Type'] = $email->get( 'type' ); 1123 1124 $tokens = $email->get_tokens(); 1125 1126 // Add 'List-Unsubscribe' header if applicable. 1127 if ( ! empty( $tokens['unsubscribe'] ) && $tokens['unsubscribe'] !== wp_login_url() ) { 1128 $user = get_user_by( 'email', $tokens['recipient.email'] ); 1129 $user_id = isset( $user->ID ) ? $user->ID : 0; 1130 1131 $args = array( 1132 'user_id' => $user_id, 1133 'notification_type' => $email->get( 'type' ), 1134 ); 1135 1136 // If this email is not to a current member, include the nonmember's email address and the Inviter ID. 1137 if ( ! $user_id ) { 1138 $args['email_address'] = $tokens['recipient.email']; 1139 $args['member_id'] = bp_loggedin_user_id(); 1140 } 1141 1142 $link = bp_email_get_unsubscribe_link( $args ); 1143 1144 if ( ! empty( $link ) ) { 1145 $headers['List-Unsubscribe'] = sprintf( '<%s>', esc_url_raw( $link ) ); 1146 } 1147 } 1148 1149 return $headers; 1150 } 1151 add_filter( 'bp_email_get_headers', 'bp_email_set_default_headers', 6, 4 ); 1152 1153 /** 1154 * Add default email tokens. 1155 * 1156 * @since 2.5.0 1157 * 1158 * @param array $tokens Email tokens. 1159 * @param string $property_name Unused. 1160 * @param string $transform Unused. 1161 * @param BP_Email $email Email being sent. 1162 * @return array 1163 */ 1164 function bp_email_set_default_tokens( $tokens, $property_name, $transform, $email ) { 1165 $tokens['site.admin-email'] = bp_get_option( 'admin_email' ); 1166 $tokens['site.url'] = bp_get_root_domain(); 1167 $tokens['email.subject'] = $email->get_subject(); 1168 1169 // These options are escaped with esc_html on the way into the database in sanitize_option(). 1170 $tokens['site.description'] = wp_specialchars_decode( bp_get_option( 'blogdescription' ), ENT_QUOTES ); 1171 $tokens['site.name'] = wp_specialchars_decode( bp_get_option( 'blogname' ), ENT_QUOTES ); 1172 1173 // Default values for tokens set conditionally below. 1174 $tokens['email.preheader'] = ''; 1175 $tokens['recipient.email'] = ''; 1176 $tokens['recipient.name'] = ''; 1177 $tokens['recipient.username'] = ''; 1178 1179 // Who is the email going to? 1180 $recipient = $email->get( 'to' ); 1181 if ( $recipient ) { 1182 $recipient = array_shift( $recipient ); 1183 $user_obj = $recipient->get_user( 'search-email' ); 1184 1185 $tokens['recipient.email'] = $recipient->get_address(); 1186 $tokens['recipient.name'] = $recipient->get_name(); 1187 1188 if ( ! $user_obj && $tokens['recipient.email'] ) { 1189 $user_obj = get_user_by( 'email', $tokens['recipient.email'] ); 1190 } 1191 1192 if ( $user_obj ) { 1193 $tokens['recipient.username'] = $user_obj->user_login; 1194 1195 if ( bp_is_active( 'settings' ) && empty( $tokens['unsubscribe'] ) ) { 1196 $tokens['unsubscribe'] = esc_url( sprintf( 1197 '%s%s/notifications/', 1198 bp_core_get_user_domain( $user_obj->ID ), 1199 bp_get_settings_slug() 1200 ) ); 1201 } 1202 } 1203 } 1204 1205 // Set default unsubscribe link if not passed. 1206 if ( empty( $tokens['unsubscribe'] ) ) { 1207 $tokens['unsubscribe'] = wp_login_url(); 1208 } 1209 1210 // Email preheader. 1211 $preheader = $email->get_preheader(); 1212 if ( $preheader ) { 1213 $tokens['email.preheader'] = $preheader; 1214 } 1215 1216 return $tokens; 1217 } 1218 add_filter( 'bp_email_get_tokens', 'bp_email_set_default_tokens', 6, 4 ); 1219 1220 /** 1221 * Find and render the template for Email posts (the Customizer and admin previews). 1222 * 1223 * Misuses the `template_include` filter which expects a string, but as we need to replace 1224 * the `{{{content}}}` token with the post's content, we use object buffering to load the 1225 * template, replace the token, and render it. 1226 * 1227 * The function returns an empty string to prevent WordPress rendering another template. 1228 * 1229 * @since 2.5.0 1230 * 1231 * @param string $template Path to template (probably single.php). 1232 * @return string 1233 */ 1234 function bp_core_render_email_template( $template ) { 1235 if ( get_post_type() !== bp_get_email_post_type() || ! is_single() ) { 1236 return $template; 1237 } 1238 1239 /** 1240 * Filter template used to display Email posts. 1241 * 1242 * @since 2.5.0 1243 * 1244 * @param string $template Path to current template (probably single.php). 1245 */ 1246 $email_template = apply_filters( 'bp_core_render_email_template', 1247 bp_locate_template( bp_email_get_template( get_queried_object() ), false ), 1248 $template 1249 ); 1250 1251 if ( ! $email_template ) { 1252 return $template; 1253 } 1254 1255 ob_start(); 1256 include( $email_template ); 1257 $template = ob_get_contents(); 1258 ob_end_clean(); 1259 1260 // Make sure we add a <title> tag so WP Customizer picks it up. 1261 $template = str_replace( '<head>', '<head><title>' . esc_html_x( 'BuddyPress Emails', 'screen heading', 'buddypress' ) . '</title>', $template ); 1262 echo str_replace( '{{{content}}}', wpautop( get_post()->post_content ), $template ); 1263 1264 /* 1265 * Link colours are applied directly in the email template before sending, so we 1266 * need to add an extra style here to set the colour for the Customizer or preview. 1267 */ 1268 $settings = bp_email_get_appearance_settings(); 1269 printf( 1270 '<style>a { color: %s; }</style>', 1271 esc_attr( $settings['highlight_color'] ) 1272 ); 1273 1274 return ''; 1275 } 1276 add_action( 'bp_template_include', 'bp_core_render_email_template', 12 ); 1277 1278 /** 1279 * Adds BuddyPress components' slugs to the WordPress Multisite subdirectory reserved names. 1280 * 1281 * @since 6.0.0 1282 * 1283 * @param array $names The WordPress Multisite subdirectory reserved names. 1284 * @return array The WordPress & BuddyPress Multisite subdirectory reserved names. 1285 */ 1286 function bp_core_components_subdirectory_reserved_names( $names = array() ) { 1287 $bp_pages = (array) buddypress()->pages; 1288 1289 return array_merge( $names, wp_list_pluck( $bp_pages, 'slug' ) ); 1290 } 1291 add_filter( 'subdirectory_reserved_names', 'bp_core_components_subdirectory_reserved_names' );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Nov 21 01:00:57 2024 | Cross-referenced by PHPXref 0.7.1 |