[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Main BuddyPress Admin Class. 4 * 5 * @package BuddyPress 6 * @subpackage CoreAdministration 7 * @since 1.0.0 8 */ 9 10 // Exit if accessed directly. 11 defined( 'ABSPATH' ) || exit; 12 13 if ( !class_exists( 'BP_Admin' ) ) : 14 15 /** 16 * Load BuddyPress plugin admin area. 17 * 18 * @todo Break this apart into each applicable Component. 19 * 20 * @since 1.6.0 21 */ 22 class BP_Admin { 23 24 /** Directory *************************************************************/ 25 26 /** 27 * Path to the BuddyPress admin directory. 28 * 29 * @since 1.6.0 30 * @var string $admin_dir 31 */ 32 public $admin_dir = ''; 33 34 /** URLs ******************************************************************/ 35 36 /** 37 * URL to the BuddyPress admin directory. 38 * 39 * @since 1.6.0 40 * @var string $admin_url 41 */ 42 public $admin_url = ''; 43 44 /** 45 * URL to the BuddyPress images directory. 46 * 47 * @since 1.6.0 48 * @var string $images_url 49 */ 50 public $images_url = ''; 51 52 /** 53 * URL to the BuddyPress admin CSS directory. 54 * 55 * @since 1.6.0 56 * @var string $css_url 57 */ 58 public $css_url = ''; 59 60 /** 61 * URL to the BuddyPress admin JS directory. 62 * 63 * @since 1.6.0 64 * @var string 65 */ 66 public $js_url = ''; 67 68 /** Other *****************************************************************/ 69 70 /** 71 * Notices used for user feedback, like saving settings. 72 * 73 * @since 1.9.0 74 * @var array() 75 */ 76 public $notices = array(); 77 78 /** 79 * BuddyPress admin screens nav tabs. 80 * 81 * @since 10.0.0 82 * @var array() 83 */ 84 public $nav_tabs = array(); 85 86 /** 87 * BuddyPress admin active nav tab. 88 * 89 * @since 10.0.0 90 * @var string() 91 */ 92 public $active_nav_tab = ''; 93 94 /** 95 * BuddyPress admin screens submenu pages. 96 * 97 * @since 10.0.0 98 * @var array() 99 */ 100 public $submenu_pages = array(); 101 102 /** Methods ***************************************************************/ 103 104 /** 105 * The main BuddyPress admin loader. 106 * 107 * @since 1.6.0 108 * 109 */ 110 public function __construct() { 111 $this->setup_globals(); 112 $this->includes(); 113 $this->setup_actions(); 114 } 115 116 /** 117 * Set admin-related globals. 118 * 119 * @since 1.6.0 120 */ 121 private function setup_globals() { 122 $bp = buddypress(); 123 124 // Paths and URLs 125 $this->admin_dir = trailingslashit( $bp->plugin_dir . 'bp-core/admin' ); // Admin path. 126 $this->admin_url = trailingslashit( $bp->plugin_url . 'bp-core/admin' ); // Admin url. 127 $this->images_url = trailingslashit( $this->admin_url . 'images' ); // Admin images URL. 128 $this->css_url = trailingslashit( $this->admin_url . 'css' ); // Admin css URL. 129 $this->js_url = trailingslashit( $this->admin_url . 'js' ); // Admin css URL. 130 131 // Main settings page. 132 $this->settings_page = bp_core_do_network_admin() ? 'settings.php' : 'options-general.php'; 133 134 // Main capability. 135 $this->capability = bp_core_do_network_admin() ? 'manage_network_options' : 'manage_options'; 136 } 137 138 /** 139 * Include required files. 140 * 141 * @since 1.6.0 142 */ 143 private function includes() { 144 require( $this->admin_dir . 'bp-core-admin-actions.php' ); 145 require( $this->admin_dir . 'bp-core-admin-settings.php' ); 146 require( $this->admin_dir . 'bp-core-admin-functions.php' ); 147 require( $this->admin_dir . 'bp-core-admin-components.php' ); 148 require( $this->admin_dir . 'bp-core-admin-slugs.php' ); 149 require( $this->admin_dir . 'bp-core-admin-tools.php' ); 150 require( $this->admin_dir . 'bp-core-admin-optouts.php' ); 151 } 152 153 /** 154 * Set up the admin hooks, actions, and filters. 155 * 156 * @since 1.6.0 157 * 158 */ 159 private function setup_actions() { 160 161 /* General Actions ***************************************************/ 162 163 // Add some page specific output to the <head>. 164 add_action( 'bp_admin_head', array( $this, 'admin_head' ), 999 ); 165 166 // Add menu item to settings menu. 167 add_action( 'admin_menu', array( $this, 'site_admin_menus' ), 5 ); 168 add_action( bp_core_admin_hook(), array( $this, 'admin_menus' ), 5 ); 169 170 // Enqueue all admin JS and CSS. 171 add_action( 'bp_admin_enqueue_scripts', array( $this, 'admin_register_styles' ), 1 ); 172 add_action( 'bp_admin_enqueue_scripts', array( $this, 'admin_register_scripts' ), 1 ); 173 add_action( 'bp_admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 174 175 /* BuddyPress Actions ************************************************/ 176 177 // Load the BuddyPress metabox in the WP Nav Menu Admin UI. 178 add_action( 'load-nav-menus.php', 'bp_admin_wp_nav_menu_meta_box' ); 179 180 // Add settings. 181 add_action( 'bp_register_admin_settings', array( $this, 'register_admin_settings' ) ); 182 183 // Add a link to BuddyPress Hello in the admin bar. 184 add_action( 'admin_bar_menu', array( $this, 'admin_bar_about_link' ), 100 ); 185 186 // Add a description of new BuddyPress tools in the available tools page. 187 add_action( 'tool_box', 'bp_core_admin_available_tools_intro' ); 188 add_action( 'bp_network_tool_box', 'bp_core_admin_available_tools_intro' ); 189 190 // On non-multisite, catch. 191 add_action( 'load-users.php', 'bp_core_admin_user_manage_spammers' ); 192 193 // Emails. 194 add_filter( 'manage_' . bp_get_email_post_type() . '_posts_columns', array( $this, 'emails_register_situation_column' ) ); 195 add_action( 'manage_' . bp_get_email_post_type() . '_posts_custom_column', array( $this, 'emails_display_situation_column_data' ), 10, 2 ); 196 197 // Privacy Policy. 198 add_action( 'bp_admin_init', array( $this, 'add_privacy_policy_content' ) ); 199 200 // BuddyPress Hello. 201 add_action( 'admin_footer', array( $this, 'about_screen' ) ); 202 203 // BuddyPress Types administration. 204 add_action( 'load-edit-tags.php', array( 'BP_Admin_Types', 'register_types_admin' ) ); 205 206 // Official BuddyPress supported Add-ons. 207 add_action( 'install_plugins_bp-add-ons', array( $this, 'display_addons_table' ) ); 208 209 /* Filters ***********************************************************/ 210 211 // Add link to settings page. 212 add_filter( 'plugin_action_links', array( $this, 'modify_plugin_action_links' ), 10, 2 ); 213 add_filter( 'network_admin_plugin_action_links', array( $this, 'modify_plugin_action_links' ), 10, 2 ); 214 215 // Add "Mark as Spam" row actions on users.php. 216 add_filter( 'ms_user_row_actions', 'bp_core_admin_user_row_actions', 10, 2 ); 217 add_filter( 'user_row_actions', 'bp_core_admin_user_row_actions', 10, 2 ); 218 219 // Emails 220 add_filter( 'bp_admin_menu_order', array( $this, 'emails_admin_menu_order' ), 20 ); 221 222 // Official BuddyPress supported Add-ons. 223 add_filter( 'install_plugins_tabs', array( $this, 'addons_tab' ) ); 224 add_filter( 'install_plugins_table_api_args_bp-add-ons', array( $this,'addons_args' ) ); 225 } 226 227 /** 228 * Register site- or network-admin nav menu elements. 229 * 230 * Contextually hooked to site or network-admin depending on current configuration. 231 * 232 * @since 1.6.0 233 */ 234 public function admin_menus() { 235 236 // Bail if user cannot moderate. 237 if ( ! bp_current_user_can( 'manage_options' ) ) { 238 return; 239 } 240 241 $hooks = array(); 242 243 // Changed in BP 1.6 . See bp_core_admin_backpat_menu(). 244 $hooks[] = add_menu_page( 245 __( 'BuddyPress', 'buddypress' ), 246 __( 'BuddyPress', 'buddypress' ), 247 $this->capability, 248 'bp-general-settings', 249 'bp_core_admin_backpat_menu', 250 'div' 251 ); 252 253 $hooks[] = add_submenu_page( 254 'bp-general-settings', 255 __( 'BuddyPress Help', 'buddypress' ), 256 __( 'Help', 'buddypress' ), 257 $this->capability, 258 'bp-general-settings', 259 'bp_core_admin_backpat_page' 260 ); 261 262 // Add the option pages. 263 $bp_components_page = add_submenu_page( 264 $this->settings_page, 265 __( 'BuddyPress Components', 'buddypress' ), 266 __( 'BuddyPress', 'buddypress' ), 267 $this->capability, 268 'bp-components', 269 'bp_core_admin_components_settings' 270 ); 271 272 $this->submenu_pages['settings']['bp-components'] = $bp_components_page; 273 $hooks[] = $bp_components_page; 274 275 $bp_page_settings_page = add_submenu_page( 276 $this->settings_page, 277 __( 'BuddyPress Pages', 'buddypress' ), 278 __( 'BuddyPress Pages', 'buddypress' ), 279 $this->capability, 280 'bp-page-settings', 281 'bp_core_admin_slugs_settings' 282 ); 283 284 $this->submenu_pages['settings']['bp-page-settings'] = $bp_page_settings_page; 285 $hooks[] = $bp_page_settings_page; 286 287 $bp_settings_page = add_submenu_page( 288 $this->settings_page, 289 __( 'BuddyPress Options', 'buddypress' ), 290 __( 'BuddyPress Options', 'buddypress' ), 291 $this->capability, 292 'bp-settings', 293 'bp_core_admin_settings' 294 ); 295 296 $this->submenu_pages['settings']['bp-settings'] = $bp_settings_page; 297 $hooks[] = $bp_settings_page; 298 299 // Credits. 300 $bp_credits_page = add_submenu_page( 301 $this->settings_page, 302 __( 'BuddyPress Credits', 'buddypress' ), 303 __( 'BuddyPress Credits', 'buddypress' ), 304 $this->capability, 305 'bp-credits', 306 array( $this, 'credits_screen' ) 307 ); 308 309 $this->submenu_pages['settings']['bp-credits'] = $bp_credits_page; 310 $hooks[] = $bp_credits_page; 311 312 // For consistency with non-Multisite, we add a Tools menu in 313 // the Network Admin as a home for our Tools panel. 314 if ( is_multisite() && bp_core_do_network_admin() ) { 315 $tools_parent = 'network-tools'; 316 317 $hooks[] = add_menu_page( 318 __( 'Tools', 'buddypress' ), 319 __( 'Tools', 'buddypress' ), 320 $this->capability, 321 $tools_parent, 322 'bp_core_tools_top_level_item', 323 '', 324 24 // Just above Settings. 325 ); 326 327 $hooks[] = add_submenu_page( 328 $tools_parent, 329 __( 'Available Tools', 'buddypress' ), 330 __( 'Available Tools', 'buddypress' ), 331 $this->capability, 332 'available-tools', 333 'bp_core_admin_available_tools_page' 334 ); 335 } else { 336 $tools_parent = 'tools.php'; 337 } 338 339 // Init the Tools submenu pages global. 340 $this->submenu_pages['tools'] = array(); 341 342 $bp_repair_tools = add_submenu_page( 343 $tools_parent, 344 __( 'BuddyPress Tools', 'buddypress' ), 345 __( 'BuddyPress', 'buddypress' ), 346 $this->capability, 347 'bp-tools', 348 'bp_core_admin_tools' 349 ); 350 351 $this->submenu_pages['tools']['bp-tools'] = $bp_repair_tools; 352 $hooks[] = $bp_repair_tools; 353 354 $bp_optouts_tools = add_submenu_page( 355 $tools_parent, 356 __( 'Manage Opt-outs', 'buddypress' ), 357 __( 'Manage Opt-outs', 'buddypress' ), 358 $this->capability, 359 'bp-optouts', 360 'bp_core_optouts_admin' 361 ); 362 363 $this->submenu_pages['tools']['bp-optouts'] = $bp_optouts_tools; 364 $hooks[] = $bp_optouts_tools; 365 366 // For network-wide configs, add a link to (the root site's) Emails screen. 367 if ( is_network_admin() && bp_is_network_activated() ) { 368 $email_labels = bp_get_email_post_type_labels(); 369 $email_url = get_admin_url( bp_get_root_blog_id(), 'edit.php?post_type=' . bp_get_email_post_type() ); 370 371 $hooks[] = add_menu_page( 372 $email_labels['name'], 373 $email_labels['menu_name'], 374 $this->capability, 375 '', 376 '', 377 'dashicons-email', 378 26 379 ); 380 381 // Hack: change the link to point to the root site's admin, not the network admin. 382 $GLOBALS['menu'][26][2] = esc_url_raw( $email_url ); 383 } 384 385 foreach( $hooks as $hook ) { 386 add_action( "admin_head-$hook", 'bp_core_modify_admin_menu_highlight' ); 387 } 388 389 /** 390 * Fires before adding inline styles for BP Admin tabs. 391 * 392 * @since 10.0.0 393 * 394 * @param array $submenu_pages The BP_Admin submenu pages passed by reference. 395 */ 396 do_action_ref_array( 'bp_admin_submenu_pages', array( &$this->submenu_pages ) ); 397 398 foreach( $this->submenu_pages as $subpage_type => $subpage_hooks ) { 399 foreach ( $subpage_hooks as $subpage_hook ) { 400 add_action( "admin_print_styles-{$subpage_hook}", array( $this, 'add_inline_styles' ), 20 ); 401 402 // When BuddyPress is activated on the network, the settings screens need an admin notice when settings have been updated. 403 if ( is_network_admin() && bp_is_network_activated() && 'settings' === $subpage_type && 'settings_page_bp-credits' !== $subpage_hook ) { 404 add_action( "load-{$subpage_hook}", array( $this, 'admin_load' ) ); 405 } 406 } 407 } 408 } 409 410 /** 411 * Register site-admin nav menu elements. 412 * 413 * @since 2.5.0 414 */ 415 public function site_admin_menus() { 416 if ( ! bp_current_user_can( 'manage_options' ) ) { 417 return; 418 } 419 420 $hooks = array(); 421 422 // Appearance > Emails. 423 $hooks[] = add_theme_page( 424 _x( 'Emails', 'screen heading', 'buddypress' ), 425 _x( 'Emails', 'screen heading', 'buddypress' ), 426 $this->capability, 427 'bp-emails-customizer-redirect', 428 'bp_email_redirect_to_customizer' 429 ); 430 431 // Emails > Customize. 432 $hooks[] = add_submenu_page( 433 'edit.php?post_type=' . bp_get_email_post_type(), 434 _x( 'Customize', 'email menu label', 'buddypress' ), 435 _x( 'Customize', 'email menu label', 'buddypress' ), 436 $this->capability, 437 'bp-emails-customizer-redirect', 438 'bp_email_redirect_to_customizer' 439 ); 440 441 foreach( $hooks as $hook ) { 442 add_action( "admin_head-$hook", 'bp_core_modify_admin_menu_highlight' ); 443 } 444 } 445 446 /** 447 * Register the settings. 448 * 449 * @since 1.6.0 450 * 451 */ 452 public function register_admin_settings() { 453 454 /* Main Section ******************************************************/ 455 456 // Add the main section. 457 add_settings_section( 'bp_main', __( 'Main Settings', 'buddypress' ), 'bp_admin_setting_callback_main_section', 'buddypress' ); 458 459 // Hide toolbar for logged out users setting. 460 add_settings_field( 'hide-loggedout-adminbar', __( 'Toolbar', 'buddypress' ), 'bp_admin_setting_callback_admin_bar', 'buddypress', 'bp_main' ); 461 register_setting( 'buddypress', 'hide-loggedout-adminbar', 'intval' ); 462 463 // Allow account deletion. 464 add_settings_field( 'bp-disable-account-deletion', __( 'Account Deletion', 'buddypress' ), 'bp_admin_setting_callback_account_deletion', 'buddypress', 'bp_main' ); 465 register_setting( 'buddypress', 'bp-disable-account-deletion', 'intval' ); 466 467 // Template pack picker. 468 add_settings_field( '_bp_theme_package_id', __( 'Template Pack', 'buddypress' ), 'bp_admin_setting_callback_theme_package_id', 'buddypress', 'bp_main', array( 'label_for' => '_bp_theme_package_id' ) ); 469 register_setting( 'buddypress', '_bp_theme_package_id', 'sanitize_text_field' ); 470 471 /* Members Section **************************************************/ 472 473 // Add the main section. 474 add_settings_section( 'bp_members', _x( 'Members Settings', 'BuddyPress setting tab', 'buddypress' ), 'bp_admin_setting_callback_members_section', 'buddypress' ); 475 476 // Avatars. 477 add_settings_field( 'bp-disable-avatar-uploads', __( 'Profile Photo Uploads', 'buddypress' ), 'bp_admin_setting_callback_avatar_uploads', 'buddypress', 'bp_members' ); 478 register_setting( 'buddypress', 'bp-disable-avatar-uploads', 'intval' ); 479 480 // Cover images. 481 if ( bp_is_active( 'members', 'cover_image' ) ) { 482 add_settings_field( 'bp-disable-cover-image-uploads', __( 'Cover Image Uploads', 'buddypress' ), 'bp_admin_setting_callback_cover_image_uploads', 'buddypress', 'bp_members' ); 483 register_setting( 'buddypress', 'bp-disable-cover-image-uploads', 'intval' ); 484 } 485 486 // Community Invitations. 487 if ( bp_is_active( 'members', 'invitations' ) ) { 488 add_settings_field( 'bp-enable-members-invitations', __( 'Invitations', 'buddypress' ), 'bp_admin_setting_callback_members_invitations', 'buddypress', 'bp_members' ); 489 register_setting( 'buddypress', 'bp-enable-members-invitations', 'intval' ); 490 } 491 492 // Membership requests. 493 if ( bp_is_active( 'members', 'membership_requests' ) ) { 494 add_settings_field( 'bp-enable-membership-requests', __( 'Membership Requests', 'buddypress' ), 'bp_admin_setting_callback_membership_requests', 'buddypress', 'bp_members' ); 495 register_setting( 'buddypress', 'bp-enable-membership-requests', 'intval' ); 496 } 497 498 /* XProfile Section **************************************************/ 499 500 if ( bp_is_active( 'xprofile' ) ) { 501 502 // Add the main section. 503 add_settings_section( 'bp_xprofile', _x( 'Profile Settings', 'BuddyPress setting tab', 'buddypress' ), 'bp_admin_setting_callback_xprofile_section', 'buddypress' ); 504 505 // Profile sync setting. 506 add_settings_field( 'bp-disable-profile-sync', __( 'Profile Syncing', 'buddypress' ), 'bp_admin_setting_callback_profile_sync', 'buddypress', 'bp_xprofile' ); 507 register_setting ( 'buddypress', 'bp-disable-profile-sync', 'intval' ); 508 } 509 510 /* Groups Section ****************************************************/ 511 512 if ( bp_is_active( 'groups' ) ) { 513 514 // Add the main section. 515 add_settings_section( 'bp_groups', __( 'Groups Settings', 'buddypress' ), 'bp_admin_setting_callback_groups_section', 'buddypress' ); 516 517 // Allow subscriptions setting. 518 add_settings_field( 'bp_restrict_group_creation', __( 'Group Creation', 'buddypress' ), 'bp_admin_setting_callback_group_creation', 'buddypress', 'bp_groups' ); 519 register_setting( 'buddypress', 'bp_restrict_group_creation', 'intval' ); 520 521 // Allow group avatars. 522 add_settings_field( 'bp-disable-group-avatar-uploads', __( 'Group Photo Uploads', 'buddypress' ), 'bp_admin_setting_callback_group_avatar_uploads', 'buddypress', 'bp_groups' ); 523 register_setting( 'buddypress', 'bp-disable-group-avatar-uploads', 'intval' ); 524 525 // Allow group cover images. 526 if ( bp_is_active( 'groups', 'cover_image' ) ) { 527 add_settings_field( 'bp-disable-group-cover-image-uploads', __( 'Group Cover Image Uploads', 'buddypress' ), 'bp_admin_setting_callback_group_cover_image_uploads', 'buddypress', 'bp_groups' ); 528 register_setting( 'buddypress', 'bp-disable-group-cover-image-uploads', 'intval' ); 529 } 530 } 531 532 /* Activity Section **************************************************/ 533 534 if ( bp_is_active( 'activity' ) ) { 535 536 // Add the main section. 537 add_settings_section( 'bp_activity', __( 'Activity Settings', 'buddypress' ), 'bp_admin_setting_callback_activity_section', 'buddypress' ); 538 539 // Activity commenting on post and comments. 540 add_settings_field( 'bp-disable-blogforum-comments', __( 'Post Comments', 'buddypress' ), 'bp_admin_setting_callback_blogforum_comments', 'buddypress', 'bp_activity' ); 541 register_setting( 'buddypress', 'bp-disable-blogforum-comments', 'bp_admin_sanitize_callback_blogforum_comments' ); 542 543 // Activity Heartbeat refresh. 544 add_settings_field( '_bp_enable_heartbeat_refresh', __( 'Activity auto-refresh', 'buddypress' ), 'bp_admin_setting_callback_heartbeat', 'buddypress', 'bp_activity' ); 545 register_setting( 'buddypress', '_bp_enable_heartbeat_refresh', 'intval' ); 546 547 // Allow activity akismet. 548 if ( is_plugin_active( 'akismet/akismet.php' ) && defined( 'AKISMET_VERSION' ) ) { 549 add_settings_field( '_bp_enable_akismet', __( 'Akismet', 'buddypress' ), 'bp_admin_setting_callback_activity_akismet', 'buddypress', 'bp_activity' ); 550 register_setting( 'buddypress', '_bp_enable_akismet', 'intval' ); 551 } 552 } 553 } 554 555 /** 556 * Add a link to BuddyPress Hello to the admin bar. 557 * 558 * @since 1.9.0 559 * @since 3.0.0 Hooked at priority 100 (was 15). 560 * 561 * @param WP_Admin_Bar $wp_admin_bar 562 */ 563 public function admin_bar_about_link( $wp_admin_bar ) { 564 if ( ! is_user_logged_in() ) { 565 return; 566 } 567 568 $wp_admin_bar->add_node( array( 569 'parent' => 'wp-logo', 570 'id' => 'bp-about', 571 'title' => esc_html_x( 'Hello, BuddyPress!', 'Colloquial alternative to "learn about BuddyPress"', 'buddypress' ), 572 'href' => bp_get_admin_url( '?hello=buddypress' ), 573 'meta' => array( 574 'class' => 'say-hello-buddypress', 575 ), 576 ) ); 577 } 578 579 /** 580 * Add Settings link to plugins area. 581 * 582 * @since 1.6.0 583 * 584 * @param array $links Links array in which we would prepend our link. 585 * @param string $file Current plugin basename. 586 * @return array Processed links. 587 */ 588 public function modify_plugin_action_links( $links, $file ) { 589 590 // Return normal links if not BuddyPress. 591 if ( plugin_basename( buddypress()->basename ) != $file ) { 592 return $links; 593 } 594 595 // Add a few links to the existing links array. 596 return array_merge( $links, array( 597 'settings' => '<a href="' . esc_url( add_query_arg( array( 'page' => 'bp-components' ), bp_get_admin_url( $this->settings_page ) ) ) . '">' . esc_html__( 'Settings', 'buddypress' ) . '</a>', 598 'about' => '<a href="' . esc_url( bp_get_admin_url( '?hello=buddypress' ) ) . '">' . esc_html_x( 'Hello, BuddyPress!', 'Colloquial alternative to "learn about BuddyPress"', 'buddypress' ) . '</a>' 599 ) ); 600 } 601 602 /** 603 * Displays an admin notice to inform settings have been saved. 604 * 605 * The notice is only displayed inside the Network Admin when 606 * BuddyPress is network activated. 607 * 608 * @since 10.0.0 609 */ 610 public function admin_load() { 611 if ( ! isset( $_GET['updated'] ) ) { 612 return; 613 } 614 615 bp_core_add_admin_notice( __( 'Settings saved.', 'buddypress' ), 'updated' ); 616 } 617 618 /** 619 * Add some general styling to the admin area. 620 * 621 * @since 1.6.0 622 */ 623 public function admin_head() { 624 625 // Settings pages. 626 remove_submenu_page( $this->settings_page, 'bp-page-settings' ); 627 remove_submenu_page( $this->settings_page, 'bp-settings' ); 628 remove_submenu_page( $this->settings_page, 'bp-credits' ); 629 630 // Network Admin Tools. 631 remove_submenu_page( 'network-tools', 'network-tools' ); 632 633 // About and Credits pages. 634 remove_submenu_page( 'index.php', 'bp-about' ); 635 remove_submenu_page( 'index.php', 'bp-credits' ); 636 637 // Nonmembers Opt-outs page. 638 if ( is_network_admin() ) { 639 remove_submenu_page( 'network-tools', 'bp-optouts' ); 640 } else { 641 remove_submenu_page( 'tools.php', 'bp-optouts' ); 642 } 643 } 644 645 /** 646 * Add some general styling to the admin area. 647 * 648 * @since 1.6.0 649 */ 650 public function enqueue_scripts() { 651 wp_enqueue_style( 'bp-admin-common-css' ); 652 653 // BuddyPress Hello. 654 if ( 0 === strpos( get_current_screen()->id, 'dashboard' ) && ! empty( $_GET['hello'] ) && $_GET['hello'] === 'buddypress' ) { 655 wp_enqueue_style( 'bp-hello-css' ); 656 wp_enqueue_script( 'bp-hello-js' ); 657 wp_localize_script( 'bp-hello-js', 'bpHelloStrings', array( 658 'pageNotFound' => __( 'Sorry, the page you requested was not found.', 'buddypress' ), 659 'modalLabel' => __( 'Hello BuddyPress', 'buddypress' ), 660 ) ); 661 } 662 } 663 664 /** 665 * Registers BuddyPress's suggested privacy policy language. 666 * 667 * @since 4.0.0 668 */ 669 public function add_privacy_policy_content() { 670 $suggested_text = '<strong class="privacy-policy-tutorial">' . esc_html__( 'Suggested text:', 'buddypress' ) . ' </strong>'; 671 $content = ''; 672 673 $content .= '<div class="wp-suggested-text">'; 674 675 $content .= '<h2>' . esc_html__( 'What personal data we collect and why we collect it', 'buddypress' ) . '</h2>'; 676 $content .= '<p class="privacy-policy-tutorial">' . esc_html__( 'Sites powered by BuddyPress rely heavily on user-provided data. In this section, you should note what data you collect, from both registered users and anonymous visitors.', 'buddypress' ) . '</p>'; 677 678 if ( bp_is_active( 'xprofile' ) ) { 679 $content .= '<h3>' . esc_html__( 'Profile Data', 'buddypress' ) . '</h3>'; 680 $content .= '<p class="privacy-policy-tutorial">' . esc_html__( 'In this section you should note what information is collected on user profiles. The suggested text gives an overview of the kinds of profile data collected by BuddyPress.', 'buddypress' ) . '</p>'; 681 682 $content .= '<p>' . $suggested_text . esc_html__( 'When you register for the site, you may be asked to provide certain personal data for display on your profile. The "Name" field is required as well as public, and user profiles are visible to any site visitor. Other profile information may be required or optional, as configured by the site administrator.', 'buddypress' ) . '</p>'; 683 $content .= '<p>' . esc_html__( 'User information provided during account registration can be modified or removed on the Profile > Edit panel. In most cases, users also have control over who is able to view a particular piece of profile content, limiting visibility on a field-by-field basis to friends, logged-in users, or administrators only. Site administrators can read and edit all profile data for all users.', 'buddypress' ) . '</p>'; 684 } 685 686 if ( bp_is_active( 'activity' ) ) { 687 $content .= '<h3>' . esc_html__( 'Activity', 'buddypress' ) . '</h3>'; 688 $content .= '<p class="privacy-policy-tutorial">' . esc_html__( 'In this section you should describe the kinds of information collected in the activity stream, how and whether it can be edited or deleted, and to whom the activity is visible.', 'buddypress' ) . '</p>'; 689 690 $content .= '<p>' . $suggested_text . esc_html__( 'This site records certain user actions, in the form of "activity" data. Activity includes updates and comments posted directly to activity streams, as well as descriptions of other actions performed while using the site, such as new friendships, newly joined groups, and profile updates.', 'buddypress' ) . '</p>'; 691 $content .= '<p>' . esc_html__( 'The content of activity items obey the same privacy rules as the contexts in which the activity items are created. For example, activity updates created in a user\'s profile is publicly visible, while activity items generated in a private group are visible only to members of that group. Site administrators can view all activity items, regardless of context.', 'buddypress' ) . '</p>'; 692 $content .= '<p>' . esc_html__( 'Activity items may be deleted at any time by users who created them. Site administrators can edit all activity items.', 'buddypress' ) . '</p>'; 693 } 694 695 if ( bp_is_active( 'messages' ) ) { 696 $content .= '<h3>' . esc_html__( 'Messages', 'buddypress' ) . '</h3>'; 697 $content .= '<p class="privacy-policy-tutorial">' . esc_html__( 'In this section you should describe any personal data related to private messages.', 'buddypress' ) . '</p>'; 698 699 $content .= '<p>' . $suggested_text . esc_html__( 'The content of private messages is visible only to the sender and the recipients of the message. With the exception of site administrators, who can read all private messages, private message content is never visible to other users or site visitors. Site administrators may delete the content of any message.', 'buddypress' ) . '</p>'; 700 } 701 702 $content .= '<h3>' . esc_html__( 'Cookies', 'buddypress' ) . '</h3>'; 703 $content .= '<p class="privacy-policy-tutorial">' . esc_html__( 'In this section you should describe the BuddyPress-specific cookies that your site collects. The suggested text describes the default cookies.', 'buddypress' ) . '</p>'; 704 705 $content .= '<p>' . $suggested_text . esc_html__( 'We use a cookie to show success and failure messages to logged-in users, in response to certain actions, like joining a group. These cookies contain no personal data, and are deleted immediately after the next page load.', 'buddypress' ) . '</p>'; 706 707 $content .= '<p>' . esc_html__( 'We use cookies on group, member, and activity directories to keep track of a user\'s browsing preferences. These preferences include the last-selected values of the sort and filter dropdowns, as well as pagination information. These cookies contain no personal data, and are deleted after 24 hours.', 'buddypress' ) . '</p>'; 708 709 if ( bp_is_active( 'groups' ) ) { 710 $content .= '<p>' . esc_html__( 'When a logged-in user creates a new group, we use a number of cookies to keep track of the group creation process. These cookies contain no personal data, and are deleted either upon the successful creation of the group or after 24 hours.', 'buddypress' ) . '</p>'; 711 } 712 713 $content .= '</div><!-- .wp-suggested-text -->'; 714 715 wp_add_privacy_policy_content( 716 'BuddyPress', 717 wp_kses_post( wpautop( $content, false ) ) 718 ); 719 } 720 721 /** About *****************************************************************/ 722 723 /** 724 * Output the BuddyPress Hello template. 725 * 726 * @since 1.7.0 Screen content. 727 * @since 3.0.0 Now outputs BuddyPress Hello template. 728 */ 729 public function about_screen() { 730 if ( 0 !== strpos( get_current_screen()->id, 'dashboard' ) || empty( $_GET['hello'] ) || $_GET['hello'] !== 'buddypress' ) { 731 return; 732 } 733 734 // Get BuddyPress stable version. 735 $version = self::display_version(); 736 $version_slug = 'version-' . str_replace( '.', '-', $version ); 737 ?> 738 739 <div id="bp-hello-container"> 740 <div id="plugin-information-scrollable" role="document"> 741 <div id='plugin-information-title' class="with-banner"> 742 <div class='vignette'></div> 743 <h1> 744 <?php printf( 745 /* translators: %s is the placeholder for the BuddyPress version number. */ 746 esc_html__( 'BuddyPress %s', 'buddypress' ), 747 $version 748 ); ?> 749 </h1> 750 </div> 751 <div id="plugin-information-tabs"> 752 <a name="whats-new" href="#whats-new" class="current"><?php esc_html_e( 'What\'s new?', 'buddypress' ); ?></a> 753 <a name="changelog" href="#changelog" class="dynamic" data-slug="<?php echo esc_attr( $version_slug ); ?>" data-endpoint="https://codex.buddypress.org/wp-json/wp/v2/pages"><?php esc_html_e( 'Changelog', 'buddypress' ); ?></a> 754 <a name="get-involved" href="#get-involved" class="dynamic" data-slug="participate-and-contribute" data-endpoint="https://codex.buddypress.org/wp-json/wp/v2/pages"><?php esc_html_e( 'Get involved', 'buddypress' ); ?></a> 755 </div> 756 757 <div class="bp-hello-content"> 758 <div id="dynamic-content"></div> 759 <div id="top-features"> 760 <h2><?php esc_html_e( 'Site Membership Requests', 'buddypress' ); ?></h2> 761 <figure class="bp-hello-aligncenter"> 762 <img src="<?php echo esc_url( buddypress()->plugin_url . 'bp-core/images/prevent-spammer-registration.png' ); ?>" alt="<?php esc_attr_e( 'Illustration showing the Site Membership Requests list.', 'buddypress' ); ?>" /> 763 </figure> 764 <p> 765 <?php esc_html_e( 'Take control of your site’s membership! With site membership requests, new in BuddyPress 10.0.0, administrators can significantly reduce the number of spam users trolling their sites.', 'buddypress' ); ?> 766 </p> 767 <p> 768 <?php esc_html_e( 'When requests are enabled, visitors may submit a membership request, which must be manually approved by a site administrator.', 'buddypress' ); ?> 769 <?php 770 printf( 771 /* translators: %s is the placeholder for the link to the BuddyPress Codex documentation page. */ 772 esc_html__( '%s about this feature.', 'buddypress' ), 773 sprintf( 774 '<a href="%1$s">%2$s</a>', 775 esc_url( 'https://codex.buddypress.org/administrator-guide/alternative-registration-workflows/#membership-requests-available-in-buddypress-10' ), 776 esc_html__( 'Read more', 'buddypress' ) 777 ) 778 ); 779 ?> 780 </p> 781 782 <hr class="bp-hello-divider"/> 783 784 <h2><?php esc_html_e( 'More engaging logging activities', 'buddypress' ); ?></h2> 785 <p> 786 <?php esc_html_e( 'These simple activities about specific user interactions or events (e.g.: you and me are now friends) are more visually attractive to improve user engagement in your community.', 'buddypress' ); ?> 787 </p> 788 <figure class="bp-hello-aligncenter"> 789 <img src="<?php echo esc_url( buddypress()->plugin_url . 'bp-core/images/logging-activities.png' ); ?>" alt="<?php esc_attr_e( 'Illustration showing the new avatar secondary activity.', 'buddypress' ); ?>" /> 790 </figure> 791 <p> 792 <?php esc_html_e( 'The most impressive new activity is that which is generated when a user updates their profile photo: it will include the profile photo that spurred the creation of the activity item, even if it has been updated since.', 'buddypress' ); ?> 793 <?php 794 printf( 795 /* translators: %s is the placeholder for the link to the BuddyPress Development blog. */ 796 esc_html__( 'Learn more about it reading this %s.', 'buddypress' ), 797 sprintf( 798 '<a href="%1$s">%2$s</a>', 799 esc_url( 'https://bpdevel.wordpress.com/2022/01/06/more-engaging-logging-activities-in-10-0-0/' ), 800 esc_html__( 'Developer note', 'buddypress' ) 801 ) 802 ); 803 ?> 804 </p> 805 806 <hr class="bp-hello-divider"/> 807 808 <h2><?php esc_html_e( 'Administration: improved BuddyPress management experience', 'buddypress' ); ?></h2> 809 <figure class="bp-hello-aligncenter"> 810 <img src="<?php echo esc_url( buddypress()->plugin_url . 'bp-core/images/bp-settings-screen.png' ); ?>" alt="<?php esc_attr_e( 'Illustration showing the BuddyPress settings screen.', 'buddypress' ); ?>" /> 811 </figure> 812 <p> 813 <?php esc_html_e( 'As shown in the image above, the BuddyPress administration screens are now using the layout WordPress uses for its tabbed administration screens such as the Site-Health or Privacy ones.', 'buddypress' ); ?> 814 </p> 815 <figure class="bp-hello-aligncenter"> 816 <img src="<?php echo esc_url( buddypress()->plugin_url . 'bp-core/images/edit-pages-screen.png' ); ?>" alt="<?php esc_attr_e( 'Illustration showing the Edit Pages screen.', 'buddypress' ); ?>" /> 817 </figure> 818 <p> 819 <?php esc_html_e( 'Knowing the WordPress pages BuddyPress uses for its front-end directory screens is easier, a status information informs you about the role of all BuddyPress pages.', 'buddypress' ); ?> 820 </p> 821 822 <hr class="bp-hello-divider"/> 823 824 <h2><?php esc_html_e( 'A new area to discover our current and future BuddyPress Add-ons.', 'buddypress' ); ?></h2> 825 <p> 826 <?php esc_html_e( 'BuddyPress Add-ons are experimental plugins, beta features packaged as plugins, that will be made available into the official WordPress.org plugins directory so that it’s easier for you to test them and give the development team your feedback.', 'buddypress' ); ?> 827 </p> 828 <p> 829 <?php esc_html_e( 'The more we are to get involved into the future of our open source project, the brighter it will be and the faster we’ll be able to include great new features!', 'buddypress' ); ?> 830 </p> 831 832 <figure class="bp-hello-aligncenter"> 833 <img src="<?php echo esc_url( buddypress()->plugin_url . 'bp-core/images/hello-buddypress-addons.png' ); ?>" alt="<?php esc_attr_e( 'Illustration showing the Edit Pages screen.', 'buddypress' ); ?>" /> 834 </figure> 835 836 <p> 837 <?php esc_html_e( 'BuddyPress Add-ons are also stable complementary BP Components or BP Blocks, we choose to keep independent from the core of BuddyPress to leave you the choice to use it or not.', 'buddypress' ); ?> 838 <?php 839 printf( 840 /* translators: %s is the placeholder for the link to the BuddyPress Add-ons administration page. */ 841 esc_html__( 'The BP Search Block is a first example of this second category of add-ons, give it a try installing it from your %s administration screen.', 'buddypress' ), 842 sprintf( 843 '<a href="%1$s">%2$s</a>', 844 esc_url( add_query_arg( 'tab', 'bp-add-ons', network_admin_url( 'plugin-install.php' ) ) ), 845 esc_html__( 'BuddyPress Add-ons', 'buddypress' ) 846 ) 847 ); 848 ?> 849 </p> 850 851 <hr class="bp-hello-divider"/> 852 853 <h2><?php esc_html_e( 'Ready for Twenty Twenty-Two!', 'buddypress' ); ?></h2> 854 <p> 855 <?php esc_html_e( 'WordPress 5.9 will introduce Full Site Editing featuring the new default theme Twenty Twenty-Two.', 'buddypress' ); ?> 856 </p> 857 <p> 858 <?php esc_html_e( 'The needed adjustments to our BP Theme Compatibility API were made so that you can enjoy this amazing feature making sure the BuddyPress generated content integrates optimally within themes supporting it.', 'buddypress' ); ?> 859 </p> 860 861 <hr class="bp-hello-divider"/> 862 863 <h2><?php esc_html_e( 'Under the hood', 'buddypress' ); ?></h2> 864 <p> 865 <?php esc_html_e( '10.0.0 comes with more than 70 changes including performance improvements to the BP Notifications, the BP Activity & the BP Signups API; Date Queries support for Members, Groups and Sites loops; new BP Avatar UI Recycle tab, improved inline documentation/translators comments and code formatting.', 'buddypress' ); ?> 866 <?php esc_html_e( 'Click on the "Changelog" tab to discover them all!', 'buddypress' ); ?> 867 </p> 868 <figure class="bp-hello-aligncenter"> 869 <div class="dashicons dashicons-buddicons-buddypress-logo big"></div> 870 </figure> 871 872 <hr class="bp-hello-divider"/> 873 874 <h2><?php echo esc_html( _x( 'Your feedback', 'screen heading', 'buddypress' ) ); ?></h2> 875 <p> 876 <?php esc_html_e( 'How are you using BuddyPress? Receiving your feedback and suggestions for future versions of BuddyPress genuinely motivates and encourages our contributors.', 'buddypress' ); ?> 877 <?php 878 printf( 879 /* translators: %s is the placeholder for the link to BuddyPress support forums. */ 880 esc_html__( 'Please %s about this version of BuddyPress on our website.', 'buddypress' ), 881 sprintf( 882 '<a href="%1$s">%2$s</a>', 883 esc_url( 'https://buddypress.org/support/' ), 884 esc_html__( 'share your feedback', 'buddypress' ) 885 ) 886 ); 887 ?> 888 </p> 889 <p> 890 <?php 891 printf( 892 /* Translators: %s is a hugging face emoji. */ 893 esc_html__( 'Thank you for using BuddyPress! %s', 'buddypress' ), 894 wp_staticize_emoji( '🤗' ) 895 ); 896 ?> 897 </p> 898 899 <br /><br /> 900 </div> 901 </div> 902 </div> 903 <div id="plugin-information-footer"> 904 <div class="bp-hello-social-cta"> 905 <p> 906 <?php 907 printf( 908 /* translators: 1: heart dashicons. 2: BP Credits screen url. 3: number of BuddyPress contributors to this version. */ 909 _n( 'Built with %1$s by <a href="%2$s">%3$d volunteer</a>.', 'Built with %1$s by <a href="%2$s">%3$d volunteers</a>.', 39, 'buddypress' ), 910 '<span class="dashicons dashicons-heart"></span>', 911 esc_url( bp_get_admin_url( 'admin.php?page=bp-credits' ) ), 912 number_format_i18n( 39 ) 913 ); 914 ?> 915 </p> 916 </div> 917 918 <div class="bp-hello-social-links"> 919 <ul class="bp-hello-social"> 920 <li> 921 <?php 922 printf( 923 '<a class="twitter bp-tooltip" data-bp-tooltip="%1$s" href="%2$s"><span class="screen-reader-text">%3$s</span></a>', 924 esc_attr__( 'Follow BuddyPress on Twitter', 'buddypress' ), 925 esc_url( 'https://twitter.com/buddypress' ), 926 esc_html__( 'Follow BuddyPress on Twitter', 'buddypress' ) 927 ); 928 ?> 929 </li> 930 931 <li> 932 <?php 933 printf( 934 '<a class="support bp-tooltip" data-bp-tooltip="%1$s" href="%2$s"><span class="screen-reader-text">%3$s</span></a>', 935 esc_attr__( 'Visit the Support Forums', 'buddypress' ), 936 esc_url( 'https://buddypress.org/support/' ), 937 esc_html__( 'Visit the Support Forums', 'buddypress' ) 938 ); 939 ?> 940 </li> 941 </ul> 942 </div> 943 </div> 944 </div> 945 946 <?php 947 } 948 949 /** 950 * Output the credits screen. 951 * 952 * Hardcoding this in here is pretty janky. It's fine for now, but we'll 953 * want to leverage api.wordpress.org eventually. 954 * 955 * @since 1.7.0 956 */ 957 public function credits_screen() { 958 bp_core_admin_tabbed_screen_header( __( 'BuddyPress Settings', 'buddypress' ), __( 'Credits', 'buddypress' ) ); 959 ?> 960 961 <div class="buddypress-body bp-about-wrap"> 962 963 <p class="about-description"><?php esc_html_e( 'Meet the contributors behind BuddyPress:', 'buddypress' ); ?></p> 964 965 <h3 class="wp-people-group"><?php esc_html_e( 'Project Leaders', 'buddypress' ); ?></h3> 966 <ul class="wp-people-group " id="wp-people-group-project-leaders"> 967 <li class="wp-person" id="wp-person-johnjamesjacoby"> 968 <a class="web" href="https://profiles.wordpress.org/johnjamesjacoby"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/7a2644fb53ae2f7bfd7143b504af396c?s=120"> 969 John James Jacoby</a> 970 <span class="title"><?php esc_html_e( 'Project Lead', 'buddypress' ); ?></span> 971 </li> 972 <li class="wp-person" id="wp-person-boonebgorges"> 973 <a class="web" href="https://profiles.wordpress.org/boonebgorges"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/9cf7c4541a582729a5fc7ae484786c0c?s=120"> 974 Boone B. Gorges</a> 975 <span class="title"><?php esc_html_e( 'Lead Developer', 'buddypress' ); ?></span> 976 </li> 977 <li class="wp-person" id="wp-person-djpaul"> 978 <a class="web" href="https://profiles.wordpress.org/djpaul"><img alt="" class="gravatar" src="https://avatars2.githubusercontent.com/u/1275914?s=120"> 979 Paul Gibbs</a> 980 <span class="title"><?php esc_html_e( 'Lead Developer', 'buddypress' ); ?></span> 981 </li> 982 <li class="wp-person" id="wp-person-r-a-y"> 983 <a class="web" href="https://profiles.wordpress.org/r-a-y"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/3bfa556a62b5bfac1012b6ba5f42ebfa?s=120"> 984 Ray</a> 985 <span class="title"><?php esc_html_e( 'Lead Developer', 'buddypress' ); ?></span> 986 </li> 987 <li class="wp-person" id="wp-person-imath"> 988 <a class="web" href="https://profiles.wordpress.org/imath"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/8b208ca408dad63888253ee1800d6a03?s=120"> 989 Mathieu Viet</a> 990 <span class="title"><?php esc_html_e( 'Lead Developer', 'buddypress' ); ?></span> 991 </li> 992 <li class="wp-person" id="wp-person-mercime"> 993 <a class="web" href="https://profiles.wordpress.org/mercime"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/fae451be6708241627983570a1a1817a?s=120"> 994 Mercime</a> 995 <span class="title"><?php esc_html_e( 'Lead Developer', 'buddypress' ); ?></span> 996 </li> 997 </ul> 998 999 <h3 class="wp-people-group"><?php esc_html_e( 'BuddyPress Team', 'buddypress' ); ?></h3> 1000 <ul class="wp-people-group " id="wp-people-group-core-team"> 1001 <li class="wp-person" id="wp-person-hnla"> 1002 <a class="web" href="https://profiles.wordpress.org/hnla"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/3860c955aa3f79f13b92826ae47d07fe?s=120"> 1003 Hugo Ashmore</a> 1004 <span class="title"><?php esc_html_e( 'Core Developer', 'buddypress' ); ?></span> 1005 </li> 1006 <li class="wp-person" id="wp-person-dcavins"> 1007 <a class="web" href="https://profiles.wordpress.org/dcavins"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/a5fa7e83d59cb45ebb616235a176595a?s=120"> 1008 David Cavins</a> 1009 <span class="title"><?php esc_html_e( 'Core Developer', 'buddypress' ); ?></span> 1010 </li> 1011 <li class="wp-person" id="wp-person-tw2113"> 1012 <a class="web" href="https://profiles.wordpress.org/tw2113"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/a5d7c934621fa1c025b83ee79bc62366?s=120"> 1013 Michael Beckwith</a> 1014 <span class="title"><?php esc_html_e( 'Core Developer', 'buddypress' ); ?></span> 1015 </li> 1016 <li class="wp-person" id="wp-person-henry-wright"> 1017 <a class="web" href="https://profiles.wordpress.org/henry.wright"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/0da2f1a9340d6af196b870f6c107a248?s=120"> 1018 Henry Wright</a> 1019 <span class="title"><?php esc_html_e( 'Community Support', 'buddypress' ); ?></span> 1020 </li> 1021 <li class="wp-person" id="wp-person-danbp"> 1022 <a class="web" href="https://profiles.wordpress.org/danbp"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/0deae2e7003027fbf153500cd3fa5501?s=120"> 1023 danbp</a> 1024 <span class="title"><?php esc_html_e( 'Community Support', 'buddypress' ); ?></span> 1025 </li> 1026 <li class="wp-person" id="wp-person-shanebp"> 1027 <a class="web" href="https://profiles.wordpress.org/shanebp"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/ffd294ab5833ba14aaf175f9acc71cc4?s=120"> 1028 shanebp</a> 1029 <span class="title"><?php esc_html_e( 'Community Support', 'buddypress' ); ?></span> 1030 </li> 1031 <li class="wp-person" id="wp-person-slaffik"> 1032 <a class="web" href="https://profiles.wordpress.org/r-a-y"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/61fb07ede3247b63f19015f200b3eb2c?s=120"> 1033 Slava Abakumov</a> 1034 <span class="title"><?php esc_html_e( 'Core Developer', 'buddypress' ); ?></span> 1035 </li> 1036 <li class="wp-person" id="wp-person-offereins"> 1037 <a class="web" href="https://profiles.wordpress.org/Offereins"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/2404ed0a35bb41aedefd42b0a7be61c1?s=120"> 1038 Laurens Offereins</a> 1039 <span class="title"><?php esc_html_e( 'Core Developer', 'buddypress' ); ?></span> 1040 </li> 1041 <li class="wp-person" id="wp-person-netweb"> 1042 <a class="web" href="https://profiles.wordpress.org/netweb"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/97e1620b501da675315ba7cfb740e80f?s=120"> 1043 Stephen Edgar</a> 1044 <span class="title"><?php esc_html_e( 'Core Developer', 'buddypress' ); ?></span> 1045 </li> 1046 <li class="wp-person" id="wp-person-espellcaste"> 1047 <a class="web" href="https://profiles.wordpress.org/espellcaste"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/b691e67be0ba5cad6373770656686bc3?s=120"> 1048 Renato Alves</a> 1049 <span class="title"><?php esc_html_e( 'Core Developer', 'buddypress' ); ?></span> 1050 </li> 1051 <li class="wp-person" id="wp-person-venutius"> 1052 <a class="web" href="https://profiles.wordpress.org/venutius"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/6a7c42a77fd94b82b217a7a97afdddbc?s=120"> 1053 Venutius</a> 1054 <span class="title"><?php esc_html_e( 'Community Support', 'buddypress' ); ?></span> 1055 </li> 1056 </ul> 1057 1058 <h3 class="wp-people-group"> 1059 <?php 1060 printf( 1061 /* translators: %s: BuddyPress version number */ 1062 esc_html__( 'Noteworthy Contributors to %s', 'buddypress' ), 1063 self::display_version() 1064 ); 1065 ?> 1066 </h3> 1067 <ul class="wp-people-group " id="wp-people-group-noteworthy"> 1068 <li class="wp-person" id="wp-person-vapvarun"> 1069 <a class="web" href="https://profiles.wordpress.org/vapvarun"><img alt="" class="gravatar" src="//gravatar.com/avatar/78a3bf7eb3a1132fc667f96f2631e448?s=120"> 1070 Varun Dubey</a> 1071 </li> 1072 <li class="wp-person" id="wp-person-oztaser"> 1073 <a class="web" href="https://profiles.wordpress.org/oztaser/"><img alt="" class="gravatar" src="//gravatar.com/avatar/06eb4dd13c0113bf826968ae16a13e52?s=120"> 1074 Adil Ă–ztaĹźer</a> 1075 </li> 1076 </ul> 1077 1078 <h3 class="wp-people-group"> 1079 <?php 1080 printf( 1081 /* translators: %s: BuddyPress version number */ 1082 esc_html__( 'All Contributors to BuddyPress %s', 'buddypress' ), 1083 self::display_version() 1084 ); 1085 ?> 1086 </h3> 1087 <p class="wp-credits-list"> 1088 <a href="https://github.com/Achilles4400">Achilles4400</a>, 1089 <a href="https://profiles.wordpress.org/oztaser/">Adil Ă–ztaĹźer (oztaser)</a>, 1090 <a href="https://profiles.wordpress.org/boonebgorges/">Boone B Gorges (boonebgorges)</a>, 1091 <a href="https://profiles.wordpress.org/sbrajesh/">Brajesh Singh (sbrajesh)</a>, 1092 <a href="https://profiles.wordpress.org/needle/">Christian Wach (needle)</a>, 1093 <a href="https://profiles.wordpress.org/comminski/">comminski</a>, 1094 <a href="https://profiles.wordpress.org/dancaragea/">Dan Caragea (dancaragea)</a>, 1095 <a href="https://profiles.wordpress.org/dcavins/">David Cavins (dcavins)</a>, 1096 <a href="https://profiles.wordpress.org/dhavalkasvala/">Dhaval Kasavala (dhavalkasvala)</a>, 1097 <a href="https://profiles.wordpress.org/dd32/">Dion Hulse (dd32)</a>, 1098 <a href="https://github.com/durdenx">durdenx</a>, 1099 <a href="https://profiles.wordpress.org/ellucinda/">ellucinda</a>, 1100 <a href="https://profiles.wordpress.org/vanpop/">Evan Stein (vanpop)</a>, 1101 <a href="https://profiles.wordpress.org/garyj/">Gary Jones (garyj)</a>, 1102 <a href="https://profiles.wordpress.org/hasanuzzamanshamim/">Hasanuzzaman (hasanuzzamanshamim)</a>, 1103 <a href="https://github.com/jakubrak">jakubrak</a>, 1104 <a href="https://profiles.wordpress.org/jean-david/">Jean-David Daviet (Jean-David)</a>, 1105 <a href="https://profiles.wordpress.org/jenfraggle/">Jennifer Burnett (jenfraggle)</a> 1106 <a href="https://profiles.wordpress.org/johnjamesjacoby/">John James Jacoby (johnjamesjacoby)</a>, 1107 <a href="https://profiles.wordpress.org/josett225/">josett225</a>, 1108 <a href="https://profiles.wordpress.org/ketan_chawda/">Ketan Chawda (ketan_chawda)</a>, 1109 <a href="https://profiles.wordpress.org/konnektiv/">konnektiv</a>, 1110 <a href="https://profiles.wordpress.org/offereins/">Laurens Offereins (Offereins)</a>, 1111 <a href="https://profiles.wordpress.org/magland/">magland</a>, 1112 <a href="https://profiles.wordpress.org/mandro/">mandro</a>, 1113 <a href="https://github.com/marioshtika">marioshtika</a>, 1114 <a href="https://profiles.wordpress.org/markscottrobson/">Mark Robson (markscottrobson)</a>, 1115 <a href="https://profiles.wordpress.org/imath/">Mathieu Viet (imath)</a>, 1116 <a href="https://profiles.wordpress.org/niftythree/">Nifty (niftythree)</a>, 1117 <a href="https://profiles.wordpress.org/nunks/">nunks</a>, 1118 <a href="https://profiles.wordpress.org/oddev56/">oddev56</a>, 1119 <a href="https://profiles.wordpress.org/DJPaul/">Paul Gibbs (DJPaul)</a>, 1120 <a href="https://profiles.wordpress.org/r-a-y/">r-a-y</a>, 1121 <a href="https://profiles.wordpress.org/espellcaste/">Renato Alves (espellcaste)</a>, 1122 <a href="https://profiles.wordpress.org/rigsbyx/">rigsbyx</a>, 1123 <a href="https://profiles.wordpress.org/thomaslhotta/">thomaslhotta</a>, 1124 <a href="https://profiles.wordpress.org/vapvarun/">Varun Dubey (vapvarun)</a>, 1125 <a href="https://profiles.wordpress.org/venutius/">venutius</a>, 1126 <a href="https://profiles.wordpress.org/yesbutmaybeno/">yesbutmaybeno</a>. 1127 </p> 1128 1129 <h3 class="wp-people-group"><?php esc_html_e( 'With our thanks to these Open Source projects', 'buddypress' ); ?></h3> 1130 <p class="wp-credits-list"> 1131 <a href="https://github.com/ichord/At.js">At.js</a>, 1132 <a href="https://bbpress.org">bbPress</a>, 1133 <a href="https://github.com/ichord/Caret.js">Caret.js</a>, 1134 <a href="https://tedgoas.github.io/Cerberus/">Cerberus</a>, 1135 <a href="https://ionicons.com/">Ionicons</a>, 1136 <a href="https://github.com/carhartl/jquery-cookie">jquery.cookie</a>, 1137 <a href="https://mattbradley.github.io/livestampjs/">Livestamp.js</a>, 1138 <a href="https://www.mediawiki.org/wiki/MediaWiki">MediaWiki</a>, 1139 <a href="https://momentjs.com/">Moment.js</a>, 1140 <a href="https://wordpress.org">WordPress</a>. 1141 </p> 1142 1143 <h3 class="wp-people-group"><?php esc_html_e( 'Contributor Emeriti', 'buddypress' ); ?></h3> 1144 <ul class="wp-people-group " id="wp-people-group-emeriti"> 1145 <li class="wp-person" id="wp-person-apeatling"> 1146 <a class="web" href="https://profiles.wordpress.org/apeatling/"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/bb29d699b5cba218c313b61aa82249da?s=120"> 1147 Andy Peatling</a> 1148 <span class="title"><?php esc_html_e( 'Project Founder', 'buddypress' ); ?></span> 1149 </li> 1150 <li class="wp-person" id="wp-person-burtadsit"> 1151 <a class="web" href="https://profiles.wordpress.org/burtadsit"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/185e1d3e2d653af9d49a4e8e4fc379df?s=120"> 1152 Burt Adsit</a> 1153 </li> 1154 <li class="wp-person" id="wp-person-dimensionmedia"> 1155 <a class="web" href="https://profiles.wordpress.org/dimensionmedia"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/7735aada1ec39d0c1118bd92ed4551f1?s=120"> 1156 David Bisset</a> 1157 </li> 1158 <li class="wp-person" id="wp-person-jeffsayre"> 1159 <a class="web" href="https://profiles.wordpress.org/jeffsayre"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/8e009a84ff5d245c22a69c7df6ab45f7?s=120"> 1160 Jeff Sayre</a> 1161 </li> 1162 <li class="wp-person" id="wp-person-karmatosed"> 1163 <a class="web" href="https://profiles.wordpress.org/karmatosed"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/ca7d4273a689cdbf524d8332771bb1ca?s=120"> 1164 Tammie Lister</a> 1165 </li> 1166 <li class="wp-person" id="wp-person-modemlooper"> 1167 <a class="web" href="https://profiles.wordpress.org/modemlooper"><img alt="" class="gravatar" src="//www.gravatar.com/avatar/1c07be1016e845de514931477c939307?s=120"> 1168 modemlooper</a> 1169 </li> 1170 </ul> 1171 </div> 1172 1173 <?php 1174 } 1175 1176 /** Emails ****************************************************************/ 1177 1178 /** 1179 * Registers 'Situations' column on Emails dashboard page. 1180 * 1181 * @since 2.6.0 1182 * 1183 * @param array $columns Current column data. 1184 * @return array 1185 */ 1186 public function emails_register_situation_column( $columns = array() ) { 1187 $situation = array( 1188 'situation' => _x( 'Situations', 'Email post type', 'buddypress' ) 1189 ); 1190 1191 // Inject our 'Situations' column just before the last 'Date' column. 1192 return array_slice( $columns, 0, -1, true ) + $situation + array_slice( $columns, -1, null, true ); 1193 } 1194 1195 /** 1196 * Output column data for our custom 'Situations' column. 1197 * 1198 * @since 2.6.0 1199 * 1200 * @param string $column Current column name. 1201 * @param int $post_id Current post ID. 1202 */ 1203 public function emails_display_situation_column_data( $column = '', $post_id = 0 ) { 1204 if ( 'situation' !== $column ) { 1205 return; 1206 } 1207 1208 // Grab email situations for the current post. 1209 $terms = get_the_terms( $post_id, bp_get_email_tax_type() ); 1210 $taxonomy_object = get_taxonomy( bp_get_email_tax_type() ); 1211 1212 if ( is_wp_error( $terms ) || ! $terms ) { 1213 printf( '<span aria-hidden="true">—</span><span class="screen-reader-text">%s</span>', $taxonomy_object->labels->no_terms ); 1214 } else { 1215 $situations = wp_list_pluck( $terms, 'description' ); 1216 1217 // Output each situation as a list item. 1218 echo '<ul><li>'; 1219 echo implode( '</li><li>', $situations ); 1220 echo '</li></ul>'; 1221 } 1222 } 1223 1224 /** Helpers ***************************************************************/ 1225 1226 /** 1227 * Return true/false based on whether a query argument is set. 1228 * 1229 * @see bp_do_activation_redirect() 1230 * 1231 * @since 2.2.0 1232 * 1233 * @return bool 1234 */ 1235 public static function is_new_install() { 1236 return (bool) isset( $_GET['is_new_install'] ); 1237 } 1238 1239 /** 1240 * Return a user-friendly version-number string, for use in translations. 1241 * 1242 * @since 2.2.0 1243 * 1244 * @return string 1245 */ 1246 public static function display_version() { 1247 1248 // Use static variable to prevent recalculations. 1249 static $display = ''; 1250 1251 // Only calculate on first run. 1252 if ( '' === $display ) { 1253 1254 // Get current version. 1255 $version = bp_get_version(); 1256 1257 // Check for prerelease hyphen. 1258 $pre = strpos( $version, '-' ); 1259 1260 // Strip prerelease suffix. 1261 $display = ( false !== $pre ) 1262 ? substr( $version, 0, $pre ) 1263 : $version; 1264 } 1265 1266 // Done! 1267 return $display; 1268 } 1269 1270 /** 1271 * Add Emails menu item to custom menus array. 1272 * 1273 * Several BuddyPress components have top-level menu items in the Dashboard, 1274 * which all appear together in the middle of the Dashboard menu. This function 1275 * adds the Emails screen to the array of these menu items. 1276 * 1277 * @since 2.4.0 1278 * 1279 * @param array $custom_menus The list of top-level BP menu items. 1280 * @return array $custom_menus List of top-level BP menu items, with Emails added. 1281 */ 1282 public function emails_admin_menu_order( $custom_menus = array() ) { 1283 array_push( $custom_menus, 'edit.php?post_type=' . bp_get_email_post_type() ); 1284 1285 if ( is_network_admin() && bp_is_network_activated() ) { 1286 array_push( 1287 $custom_menus, 1288 get_admin_url( bp_get_root_blog_id(), 'edit.php?post_type=' . bp_get_email_post_type() ) 1289 ); 1290 } 1291 1292 return $custom_menus; 1293 } 1294 1295 /** 1296 * Register styles commonly used by BuddyPress wp-admin screens. 1297 * 1298 * @since 2.5.0 1299 */ 1300 public function admin_register_styles() { 1301 $min = bp_core_get_minified_asset_suffix(); 1302 $url = $this->css_url; 1303 1304 /** 1305 * Filters the BuddyPress Core Admin CSS file path. 1306 * 1307 * @since 1.6.0 1308 * 1309 * @param string $file File path for the admin CSS. 1310 */ 1311 $common_css = apply_filters( 'bp_core_admin_common_css', "{$url}common{$min}.css" ); 1312 1313 /** 1314 * Filters the BuddyPress admin stylesheet files to register. 1315 * 1316 * @since 2.5.0 1317 * 1318 * @param array $value Array of admin stylesheet file information to register. 1319 */ 1320 $styles = apply_filters( 'bp_core_admin_register_styles', array( 1321 // Legacy. 1322 'bp-admin-common-css' => array( 1323 'file' => $common_css, 1324 'dependencies' => array(), 1325 ), 1326 1327 // 2.5 1328 'bp-customizer-controls' => array( 1329 'file' => "{$url}customizer-controls{$min}.css", 1330 'dependencies' => array(), 1331 ), 1332 1333 // 3.0 1334 'bp-hello-css' => array( 1335 'file' => "{$url}hello{$min}.css", 1336 'dependencies' => array( 'bp-admin-common-css', 'thickbox' ), 1337 ), 1338 ) ); 1339 1340 $version = bp_get_version(); 1341 1342 foreach ( $styles as $id => $style ) { 1343 wp_register_style( $id, $style['file'], $style['dependencies'], $version ); 1344 wp_style_add_data( $id, 'rtl', 'replace' ); 1345 1346 if ( $min ) { 1347 wp_style_add_data( $id, 'suffix', $min ); 1348 } 1349 } 1350 } 1351 1352 /** 1353 * Register JS commonly used by BuddyPress wp-admin screens. 1354 * 1355 * @since 2.5.0 1356 */ 1357 public function admin_register_scripts() { 1358 $min = bp_core_get_minified_asset_suffix(); 1359 $url = $this->js_url; 1360 1361 /** 1362 * Filters the BuddyPress admin JS files to register. 1363 * 1364 * @since 2.5.0 1365 * 1366 * @param array $value Array of admin JS file information to register. 1367 */ 1368 $scripts = apply_filters( 'bp_core_admin_register_scripts', array( 1369 // 2.5 1370 'bp-customizer-controls' => array( 1371 'file' => "{$url}customizer-controls{$min}.js", 1372 'dependencies' => array( 'jquery' ), 1373 'footer' => true, 1374 ), 1375 1376 // 10.0 1377 'bp-thickbox' => array( 1378 'file' => "{$url}bp-thickbox{$min}.js", 1379 'dependencies' => array( 'thickbox' ), 1380 'footer' => true, 1381 ), 1382 1383 // 3.0 1384 'bp-hello-js' => array( 1385 'file' => "{$url}hello{$min}.js", 1386 'dependencies' => array( 'bp-thickbox', 'wp-api-request' ), 1387 'footer' => true, 1388 ), 1389 1390 // 10.0 1391 'bp-dismissible-admin-notices' => array( 1392 'file' => "{$url}dismissible-admin-notices.js", 1393 'dependencies' => array(), 1394 'footer' => true, 1395 'extra' => array( 1396 'name' => 'bpDismissibleAdminNoticesSettings', 1397 'data' => array( 1398 'url' => bp_core_ajax_url(), 1399 'nonce' => wp_create_nonce( 'bp_dismiss_admin_notice' ), 1400 ), 1401 ), 1402 ), 1403 ) ); 1404 1405 $version = bp_get_version(); 1406 1407 foreach ( $scripts as $id => $script ) { 1408 wp_register_script( $id, $script['file'], $script['dependencies'], $version, $script['footer'] ); 1409 1410 if ( isset( $script['extra'] ) ) { 1411 // List the block specific props. 1412 wp_add_inline_script( 1413 $id, 1414 sprintf( 'var %1$s = %2$s;', $script['extra']['name'], wp_json_encode( $script['extra']['data'] ) ), 1415 'before' 1416 ); 1417 } 1418 } 1419 } 1420 1421 /** 1422 * Adds inline styles to adapt the number of grid columns according to the number of BP Admin tabs. 1423 * 1424 * @since 10.0.0 1425 */ 1426 public function add_inline_styles() { 1427 $screen = get_current_screen(); 1428 1429 if ( ! isset( $screen->id ) ) { 1430 return; 1431 } 1432 1433 // We might need to edit this id, see below code. 1434 $screen_id = $screen->id; 1435 1436 // Multisite configs adds a '-network' suffix to page hooknames inside the Network Admin screens. 1437 if ( is_multisite() && is_network_admin() && bp_is_network_activated() ) { 1438 $screen_id = str_replace( '-network', '', $screen_id ); 1439 } 1440 1441 $current_settings_tab_id = array_search( $screen_id, $this->submenu_pages['settings'], true ); 1442 $current_tools_tab_id = array_search( $screen_id, $this->submenu_pages['tools'], true ); 1443 $current_tab_id = ''; 1444 $tabs = array(); 1445 $context = ''; 1446 1447 if ( $current_settings_tab_id ) { 1448 $current_tab_id = $current_settings_tab_id; 1449 $tabs = wp_list_pluck( bp_core_get_admin_settings_tabs(), 'name', 'id' ); 1450 $context = 'settings'; 1451 } elseif ( $current_tools_tab_id ) { 1452 $current_tab_id = $current_tools_tab_id; 1453 $tabs = wp_list_pluck( bp_core_get_admin_tools_tabs(), 'name', 'id' ); 1454 $context = 'tools'; 1455 } 1456 1457 if ( $current_tab_id && isset( $tabs[ $current_tab_id ] ) ) { 1458 $this->nav_tabs = bp_core_admin_tabs( $tabs[ $current_tab_id ], $context, false ); 1459 $grid_columns = array_fill( 0, count( $this->nav_tabs ), '1fr'); 1460 $help_tab_css = ''; 1461 1462 if ( $screen->get_help_tabs() ) { 1463 $help_tab_css = '#screen-meta { margin-right: 0; } #screen-meta-links { position: absolute; right: 0; }'; 1464 } 1465 1466 wp_add_inline_style( 1467 'bp-admin-common-css', 1468 sprintf( 1469 '.buddypress-tabs-wrapper { 1470 -ms-grid-columns: %1$s; 1471 grid-template-columns: %1$s; 1472 } 1473 %2$s', 1474 implode( " ", $grid_columns ), 1475 $help_tab_css 1476 ) 1477 ); 1478 } 1479 } 1480 1481 /** 1482 * Add a "BuddyPress Add-ons" tab to the Add Plugins Admin screen. 1483 * 1484 * @since 10.0.0 1485 * 1486 * @param array $tabs The list of "Add Plugins" Tabs (Featured, Recommended, etc..). 1487 * @return array The same list including the "BuddyPress Add-ons" tab. 1488 */ 1489 public function addons_tab( $tabs = array() ) { 1490 $keys = array_keys( $tabs ); 1491 $index = array_search( 'favorites', $keys, true ); 1492 1493 // Makes sure the "BuddyPress Add-ons" tab is right after the "Favorites" one. 1494 $new_tabs = array_merge( 1495 array_slice( $tabs, 0, $index + 1, true ), 1496 array( 1497 'bp-add-ons' => __( 'BuddyPress Add-ons', 'buddypress' ), 1498 ), 1499 $tabs 1500 ); 1501 1502 return $new_tabs; 1503 } 1504 1505 /** 1506 * Customize the Plugins API query arguments. 1507 * 1508 * The most important argument is the $user one which is set to "buddypress". 1509 * Using this key and value will fetch the plugins the w.org "buddypress" user favorited. 1510 * 1511 * @since 10.0.0 1512 * 1513 * @global int $paged The current page of the Plugin results. 1514 * @param false|array $args `false` by default. 1515 * @return array The "BuddyPress add-ons" args. 1516 */ 1517 public function addons_args( $args = false ) { 1518 global $paged; 1519 1520 return array( 1521 'page' => $paged, 1522 'per_page' => 10, 1523 'locale' => get_user_locale(), 1524 'user' => 'buddypress', 1525 ); 1526 } 1527 1528 /** 1529 * Displays the list of "BuddyPress Add-ons". 1530 * 1531 * @since 10.0.0 1532 */ 1533 public function display_addons_table() { 1534 $notice_id = 'bp100-welcome-addons'; 1535 $dismissed = bp_get_option( "bp-dismissed-notice-{$notice_id}", false ); 1536 1537 if ( ! $dismissed ) { 1538 // Enqueue the Script to Ajax Dismiss an Admin notice. 1539 wp_enqueue_script( 'bp-dismissible-admin-notices' ); 1540 1541 ?> 1542 <div class="bp-welcome-panel bp-notice-container"> 1543 <a class="bp-welcome-panel-close bp-is-dismissible" href="#" data-notice_id="<?php echo esc_attr( $notice_id ); ?>" aria-label="<?php esc_attr_e( 'Dismiss the welcome panel', 'buddypress' ); ?>"><?php esc_html_e( 'Dismiss', 'buddypress' ); ?></a> 1544 <div class="bp-welcome-panel-content"> 1545 <h2><span class="bp-badge"></span> <?php esc_html_e( 'Hello BuddyPress Add-ons!', 'buddypress' ); ?></h2> 1546 <p class="about-description"> 1547 <?php esc_html_e( 'Add-ons are features as Plugins or Blocks maintained by the BuddyPress development team & hosted on the WordPress.org plugins directory.', 'buddypress' ); ?> 1548 <?php esc_html_e( 'Thanks to this new tab inside your Dashboard screen to add plugins, you’ll be able to find them faster and eventually contribute to beta features early to give the BuddyPress development team your feedbacks.', 'buddypress' ); ?> 1549 </p> 1550 </div> 1551 </div> 1552 <?php 1553 } 1554 1555 // Display the "buddypress" favorites. 1556 display_plugins_table(); 1557 } 1558 } 1559 endif; // End class_exists check.
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Dec 5 01:00:58 2024 | Cross-referenced by PHPXref 0.7.1 |