[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-core/admin/ -> bp-core-admin-functions.php (source)

   1  <?php
   2  /**
   3   * BuddyPress Common Admin Functions.
   4   *
   5   * @package BuddyPress
   6   * @subpackage CoreAdministration
   7   * @since 2.3.0
   8   */
   9  
  10  // Exit if accessed directly.
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /** Menu **********************************************************************/
  14  
  15  /**
  16   * Initializes the wp-admin area "BuddyPress" menus and sub menus.
  17   */
  18  function bp_core_admin_menu_init() {
  19      add_action( bp_core_admin_hook(), 'bp_core_add_admin_menu', 9 );
  20  }
  21  
  22  /**
  23   * In BP 1.6, the top-level admin menu was removed. For backpat, this function
  24   * keeps the top-level menu if a plugin has registered a menu into the old
  25   * 'bp-general-settings' menu.
  26   *
  27   * The old "bp-general-settings" page was renamed "bp-components".
  28   *
  29   * @global array $_parent_pages
  30   * @global array $_registered_pages
  31   * @global array $submenu
  32   *
  33   * @since 1.6.0
  34   */
  35  function bp_core_admin_backpat_menu() {
  36      global $_parent_pages, $_registered_pages, $submenu;
  37  
  38      // If there's no bp-general-settings menu (perhaps because the current
  39      // user is not an Administrator), there's nothing to do here.
  40      if ( ! isset( $submenu['bp-general-settings'] ) ) {
  41          return;
  42      }
  43  
  44      /**
  45       * By default, only the core "Help" submenu is added under the top-level BuddyPress menu.
  46       * This means that if no third-party plugins have registered their admin pages into the
  47       * 'bp-general-settings' menu, it will only contain one item. Kill it.
  48       */
  49      if ( 1 != count( $submenu['bp-general-settings'] ) ) {
  50          return;
  51      }
  52  
  53      // This removes the top-level menu.
  54      remove_submenu_page( 'bp-general-settings', 'bp-general-settings' );
  55      remove_menu_page( 'bp-general-settings' );
  56  
  57      // These stop people accessing the URL directly.
  58      unset( $_parent_pages['bp-general-settings'] );
  59      unset( $_registered_pages['toplevel_page_bp-general-settings'] );
  60  }
  61  add_action( bp_core_admin_hook(), 'bp_core_admin_backpat_menu', 999 );
  62  
  63  /**
  64   * This tells WP to highlight the Settings > BuddyPress menu item,
  65   * regardless of which actual BuddyPress admin screen we are on.
  66   *
  67   * The conditional prevents the behavior when the user is viewing the
  68   * backpat "Help" page, the Activity page, or any third-party plugins.
  69   *
  70   * @global string $plugin_page
  71   * @global array $submenu
  72   *
  73   * @since 1.6.0
  74   */
  75  function bp_core_modify_admin_menu_highlight() {
  76      global $plugin_page, $submenu_file;
  77  
  78      // This tweaks the Settings subnav menu to show only one BuddyPress menu item.
  79      if ( ! in_array( $plugin_page, array( 'bp-activity', 'bp-general-settings' ) ) ) {
  80          $submenu_file = 'bp-components';
  81      }
  82  
  83      // Network Admin > Tools.
  84      if ( in_array( $plugin_page, array( 'bp-tools', 'available-tools' ) ) ) {
  85          $submenu_file = $plugin_page;
  86      }
  87  
  88      // Keep the BuddyPress tools menu highlighted when using a tools tab.
  89      if ( 'bp-optouts' === $plugin_page || 'bp-members-invitations' === $plugin_page ) {
  90          $submenu_file = 'bp-tools';
  91      }
  92  }
  93  
  94  /**
  95   * Generates markup for a fallback top-level BuddyPress menu page, if the site is running
  96   * a legacy plugin which hasn't been updated. If the site is up to date, this page
  97   * will never appear.
  98   *
  99   * @see bp_core_admin_backpat_menu()
 100   *
 101   * @since 1.6.0
 102   *
 103   * @todo Add convenience links into the markup once new positions are finalized.
 104   */
 105  function bp_core_admin_backpat_page() {
 106      $url          = bp_core_do_network_admin() ? network_admin_url( 'settings.php' ) : admin_url( 'options-general.php' );
 107      $settings_url = add_query_arg( 'page', 'bp-components', $url ); ?>
 108  
 109      <div class="wrap">
 110          <h1 class="wp-heading-inline"><?php esc_html_e( 'Why have all my BuddyPress menus disappeared?', 'buddypress' ); ?></h1>
 111          <hr class="wp-header-end">
 112  
 113          <p><?php esc_html_e( "Don't worry! We've moved the BuddyPress options into more convenient and easier to find locations. You're seeing this page because you are running a legacy BuddyPress plugin which has not been updated.", 'buddypress' ); ?></p>
 114          <p>
 115              <?php
 116              printf(
 117                  // Translators: 1: is the url to the BP Components settings screen. 2: is the url to the xProfile administration screen.
 118                  __( 'Components, Pages, Settings, and Forums, have been moved to <a href="%1$s">Settings &gt; BuddyPress</a>. Profile Fields has been moved into the <a href="%2$s">Users</a> menu.', 'buddypress' ),
 119                  esc_url( $settings_url ),
 120                  bp_get_admin_url( 'users.php?page=bp-profile-setup' )
 121              );
 122              ?>
 123          </p>
 124      </div>
 125  
 126      <?php
 127  }
 128  
 129  /** Notices *******************************************************************/
 130  
 131  /**
 132   * Print admin messages to admin_notices or network_admin_notices.
 133   *
 134   * BuddyPress combines all its messages into a single notice, to avoid a preponderance of yellow
 135   * boxes.
 136   *
 137   * @since 1.5.0
 138   */
 139  function bp_core_print_admin_notices() {
 140  
 141      // Only the super admin should see messages.
 142      if ( ! bp_current_user_can( 'bp_moderate' ) ) {
 143          return;
 144      }
 145  
 146      // On multisite installs, don't show on a non-root blog, unless
 147      // 'do_network_admin' is overridden.
 148      if ( is_multisite() && bp_core_do_network_admin() && ! bp_is_root_blog() ) {
 149          return;
 150      }
 151  
 152      $notice_types = array();
 153      foreach ( buddypress()->admin->notices as $notice ) {
 154          $notice_types[] = $notice['type'];
 155      }
 156      $notice_types = array_unique( $notice_types );
 157  
 158      foreach ( $notice_types as $type ) {
 159          $notices = wp_list_filter( buddypress()->admin->notices, array( 'type' => $type ) );
 160          printf( '<div id="message" class="fade %s notice is-dismissible">', sanitize_html_class( $type ) );
 161  
 162          foreach ( $notices as $notice ) {
 163              printf( '<p>%s</p>', $notice['message'] );
 164          }
 165  
 166          printf( '</div>' );
 167      }
 168  }
 169  add_action( 'admin_notices', 'bp_core_print_admin_notices' );
 170  add_action( 'network_admin_notices', 'bp_core_print_admin_notices' );
 171  
 172  /**
 173   * Add an admin notice to the BP queue.
 174   *
 175   * Messages added with this function are displayed in BuddyPress's general purpose admin notices
 176   * box. It is recommended that you hook this function to admin_init, so that your messages are
 177   * loaded in time.
 178   *
 179   * @since 1.5.0
 180   *
 181   * @param string $notice The notice you are adding to the queue.
 182   * @param string $type   The notice type; optional. Usually either "updated" or "error".
 183   */
 184  function bp_core_add_admin_notice( $notice = '', $type = 'updated' ) {
 185  
 186      // Do not add if the notice is empty.
 187      if ( empty( $notice ) ) {
 188          return;
 189      }
 190  
 191      // Double check the object before referencing it.
 192      if ( ! isset( buddypress()->admin->notices ) ) {
 193          buddypress()->admin->notices = array();
 194      }
 195  
 196      // Add the notice.
 197      buddypress()->admin->notices[] = array(
 198          'message' => $notice,
 199          'type'    => $type,
 200      );
 201  }
 202  
 203  /**
 204   * Verify that some BP prerequisites are set up properly, and notify the admin if not.
 205   *
 206   * On every Dashboard page, this function checks the following:
 207   *   - that pretty permalinks are enabled.
 208   *   - that every BP component that needs a WP page for a directory has one.
 209   *   - that no WP page has multiple BP components associated with it.
 210   * The administrator will be shown a notice for each check that fails.
 211   *
 212   * @global WPDB $wpdb WordPress DB object
 213   * @global WP_Rewrite $wp_rewrite
 214   *
 215   * @since 1.2.0
 216   */
 217  function bp_core_activation_notice() {
 218      global $wp_rewrite, $wpdb;
 219  
 220      // Only the super admin gets warnings.
 221      if ( ! bp_current_user_can( 'bp_moderate' ) ) {
 222          return;
 223      }
 224  
 225      // Bail in user admin.
 226      if ( is_user_admin() ) {
 227          return;
 228      }
 229  
 230      // On multisite installs, don't load on a non-root blog, unless do_network_admin is overridden.
 231      if ( is_multisite() && bp_core_do_network_admin() && ! bp_is_root_blog() ) {
 232          return;
 233      }
 234  
 235      // Bail if in network admin, and BuddyPress is not network activated.
 236      if ( is_network_admin() && ! bp_is_network_activated() ) {
 237          return;
 238      }
 239  
 240      /**
 241       * Check to make sure that the blog setup routine has run. This can't
 242       * happen during the wizard because of the order which the components
 243       * are loaded.
 244       */
 245      if ( bp_is_active( 'blogs' ) ) {
 246          $bp    = buddypress();
 247          $count = $wpdb->get_var( "SELECT COUNT(*) FROM {$bp->blogs->table_name}" );
 248  
 249          if ( empty( $count ) ) {
 250              bp_blogs_record_existing_blogs();
 251          }
 252      }
 253  
 254      // Add notice if no rewrite rules are enabled.
 255      if ( empty( $wp_rewrite->permalink_structure ) ) {
 256          bp_core_add_admin_notice(
 257              sprintf(
 258                  // Translators: %s is the url to the permalink settings.
 259                  __( '<strong>BuddyPress is almost ready</strong>. You must <a href="%s">update your permalink structure</a> to something other than the default for it to work.', 'buddypress' ),
 260                  admin_url( 'options-permalink.php' )
 261              ),
 262              'error'
 263          );
 264      }
 265  
 266      // Get BuddyPress instance.
 267      $bp = buddypress();
 268  
 269      /**
 270       * Check for orphaned BP components (BP component is enabled, no WP page exists).
 271       */
 272      $orphaned_components = array();
 273      $wp_page_components  = array();
 274  
 275      // Only components with 'has_directory' require a WP page to function.
 276      foreach ( array_keys( $bp->loaded_components ) as $component_id ) {
 277          if ( ! empty( $bp->{$component_id}->has_directory ) ) {
 278              $wp_page_components[] = array(
 279                  'id'   => $component_id,
 280                  'name' => isset( $bp->{$component_id}->name ) ? $bp->{$component_id}->name : ucwords( $bp->{$component_id}->id ),
 281              );
 282          }
 283      }
 284  
 285      // Activate and Register are special cases. They are not components but they need WP pages.
 286      // If user registration is disabled, we can skip this step.
 287      if ( bp_allow_access_to_registration_pages() ) {
 288          $wp_page_components[] = array(
 289              'id'   => 'activate',
 290              'name' => __( 'Activate', 'buddypress' ),
 291          );
 292  
 293          $wp_page_components[] = array(
 294              'id'   => 'register',
 295              'name' => __( 'Register', 'buddypress' ),
 296          );
 297      }
 298  
 299      // On the first admin screen after a new installation, this isn't set, so grab it to suppress
 300      // a misleading error message.
 301      if ( empty( $bp->pages->members ) ) {
 302          $bp->pages = bp_core_get_directory_pages();
 303      }
 304  
 305      foreach ( $wp_page_components as $component ) {
 306          if ( ! isset( $bp->pages->{$component['id']} ) ) {
 307              $orphaned_components[] = $component['name'];
 308          }
 309      }
 310  
 311      if ( ! empty( $orphaned_components ) ) {
 312          $admin_url = bp_get_admin_url( add_query_arg( array( 'page' => 'bp-page-settings' ), 'admin.php' ) );
 313          $notice    = sprintf(
 314              '%1$s <a href="%2$s">%3$s</a>',
 315              sprintf(
 316                  // Translators: %s is the comma separated list of components needing a directory page.
 317                  __( 'The following active BuddyPress Components do not have associated WordPress Pages: %s.', 'buddypress' ),
 318                  '<strong>' . implode( '</strong>, <strong>', array_map( 'esc_html', $orphaned_components ) ) . '</strong>'
 319              ),
 320              esc_url( $admin_url ),
 321              __( 'Repair', 'buddypress' )
 322          );
 323  
 324          bp_core_add_admin_notice( $notice );
 325      }
 326  
 327      // BP components cannot share a single WP page. Check for duplicate assignments, and post a message if found.
 328      $dupe_names = array();
 329      $page_ids   = bp_core_get_directory_page_ids();
 330      $dupes      = array_diff_assoc( $page_ids, array_unique( $page_ids ) );
 331  
 332      if ( ! empty( $dupes ) ) {
 333          foreach ( array_keys( $dupes ) as $dupe_component ) {
 334              $dupe_names[] = $bp->pages->{$dupe_component}->title;
 335          }
 336  
 337          // Make sure that there are no duplicate duplicates :).
 338          $dupe_names = array_unique( $dupe_names );
 339      }
 340  
 341      // If there are duplicates, post a message about them.
 342      if ( ! empty( $dupe_names ) ) {
 343          $admin_url = bp_get_admin_url( add_query_arg( array( 'page' => 'bp-page-settings' ), 'admin.php' ) );
 344          $notice    = sprintf(
 345              '%1$s <a href="%2$s">%3$s</a>',
 346              sprintf(
 347                  // Translators: %s is the list of directory pages associated to more than one component.
 348                  __( 'Each BuddyPress Component needs its own WordPress page. The following WordPress Pages have more than one component associated with them: %s.', 'buddypress' ),
 349                  '<strong>' . implode( '</strong>, <strong>', array_map( 'esc_html', $dupe_names ) ) . '</strong>'
 350              ),
 351              esc_url( $admin_url ),
 352              __( 'Repair', 'buddypress' )
 353          );
 354  
 355          bp_core_add_admin_notice( $notice );
 356      }
 357  }
 358  
 359  /**
 360   * Redirect user to BuddyPress's What's New page on activation.
 361   *
 362   * @since 1.7.0
 363   *
 364   * @internal Used internally to redirect BuddyPress to the about page on activation.
 365   */
 366  function bp_do_activation_redirect() {
 367  
 368      // Bail if no activation redirect.
 369      if ( ! get_transient( '_bp_activation_redirect' ) ) {
 370          return;
 371      }
 372  
 373      // Delete the redirect transient.
 374      delete_transient( '_bp_activation_redirect' );
 375  
 376      // Bail if activating from network, or bulk.
 377      if ( isset( $_GET['activate-multi'] ) ) {
 378          return;
 379      }
 380  
 381      $query_args = array();
 382      if ( get_transient( '_bp_is_new_install' ) ) {
 383          $query_args['is_new_install'] = '1';
 384          delete_transient( '_bp_is_new_install' );
 385      }
 386  
 387      // Redirect to dashboard and trigger the Hello screen.
 388      wp_safe_redirect( add_query_arg( $query_args, bp_get_admin_url( '?hello=buddypress' ) ) );
 389  }
 390  
 391  /** UI/Styling ****************************************************************/
 392  
 393  /**
 394   * Outputs the BP Admin Tabbed header.
 395   *
 396   * @since 10.0.0
 397   *
 398   * @param string $title      The title of the Admin page.
 399   * @param string $active_tab The current displayed tab.
 400   * @param string $context    The context of use for the tabs. Defaults to 'settings'.
 401   *                           Possible values are 'settings' & 'tools'.
 402   */
 403  function bp_core_admin_tabbed_screen_header( $title = '', $active_tab = '', $context = 'settings' ) {
 404      $bp = buddypress();
 405  
 406      // Globalize the active tab for backcompat purpose.
 407      $bp->admin->active_nav_tab = $active_tab;
 408  
 409      /**
 410       * Fires before the output of the BP Admin tabbed screen header.
 411       *
 412       * @since 10.0.0
 413       *
 414       * @param string $active_tab The BP Admin active tab.
 415       * @param string $context    The context of use for the tabs.
 416       */
 417      do_action( 'bp_core_admin_tabbed_screen_header', $active_tab, $context );
 418      ?>
 419      <div class="buddypress-header">
 420          <div class="buddypress-title-section">
 421              <h1><span class="bp-badge"></span> <?php echo esc_html( $title ); ?></h1>
 422          </div>
 423          <nav class="buddypress-tabs-wrapper">
 424              <?php if ( isset( $bp->admin->nav_tabs ) ) : ?>
 425                  <?php foreach ( $bp->admin->nav_tabs as $nav_tab ) : ?>
 426  
 427                      <?php echo $nav_tab; ?>
 428  
 429                  <?php endforeach; ?>
 430              <?php else : ?>
 431                  <?php bp_core_admin_tabs( esc_html( $active_tab ), $context ); ?>
 432              <?php endif; ?>
 433          </nav>
 434      </div>
 435  
 436      <hr class="wp-header-end">
 437      <?php
 438  }
 439  
 440  /**
 441   * Output the tabs in the admin area.
 442   *
 443   * @since 1.5.0
 444   * @since 8.0.0 Adds the `$context` parameter.
 445   *
 446   * @param string $active_tab Name of the tab that is active. Optional.
 447   * @param string $context    The context of use for the tabs. Defaults to 'settings'.
 448   *                           Possible values are 'settings' & 'tools'.
 449   */
 450  function bp_core_admin_tabs( $active_tab = '', $context = 'settings', $echo = true ) {
 451      $tabs_html    = '';
 452      $idle_class   = 'buddypress-nav-tab';
 453      $active_class = 'buddypress-nav-tab active';
 454  
 455      /**
 456       * Filters the admin tabs to be displayed.
 457       *
 458       * @since 1.9.0
 459       *
 460       * @param array $value Array of tabs to output to the admin area.
 461       */
 462      $tabs         = apply_filters( 'bp_core_admin_tabs', bp_core_get_admin_tabs( $active_tab, $context ) );
 463      $tabs_html    = array();
 464  
 465      // Loop through tabs and build navigation.
 466      foreach ( array_values( $tabs ) as $tab_data ) {
 467          $is_current     = (bool) ( $tab_data['name'] == $active_tab );
 468          $tab_class      = $is_current ? $active_class : $idle_class;
 469          $tabs_html[]    = '<a href="' . esc_url( $tab_data['href'] ) . '" class="' . esc_attr( $tab_class ) . '">' . esc_html( $tab_data['name'] ) . '</a>';
 470      }
 471  
 472      if ( ! $echo ) {
 473          return $tabs_html;
 474      }
 475  
 476      echo implode( "\n", $tabs_html );
 477      /**
 478       * Fires after the output of tabs for the admin area.
 479       *
 480       * @since 1.5.0
 481       * @since 8.0.0 Adds the `$context` parameter.
 482       * @since 10.0.0 Adds the `$active_tab` parameter.
 483       *
 484       * @param string $context The context of use for the tabs.
 485       */
 486      do_action( 'bp_admin_tabs', $context, $active_tab );
 487  }
 488  
 489  /**
 490   * Returns the BP Admin settings tabs.
 491   *
 492   * @since 10.0.0
 493   *
 494   * @param bool $apply_filters Whether to apply filters or not.
 495   * @return array              The BP Admin settings tabs.
 496   */
 497  function bp_core_get_admin_settings_tabs( $apply_filters = true ) {
 498      $settings_tabs = array(
 499          '0' => array(
 500              'id'   => 'bp-components',
 501              'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components' ), 'admin.php' ) ),
 502              'name' => __( 'Components', 'buddypress' ),
 503          ),
 504          '2' => array(
 505              'id'   => 'bp-settings',
 506              'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-settings' ), 'admin.php' ) ),
 507              'name' => __( 'Options', 'buddypress' ),
 508          ),
 509          '1' => array(
 510              'id'   => 'bp-page-settings',
 511              'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-page-settings' ), 'admin.php' ) ),
 512              'name' => __( 'Pages', 'buddypress' ),
 513          ),
 514          '3' => array(
 515              'id'   => 'bp-credits',
 516              'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-credits' ), 'admin.php' ) ),
 517              'name' => __( 'Credits', 'buddypress' ),
 518          ),
 519      );
 520  
 521      if ( ! $apply_filters ) {
 522          return $settings_tabs;
 523      }
 524  
 525      /**
 526       * Filter here to edit the BP Admin settings tabs.
 527       *
 528       * @since 10.0.0
 529       *
 530       * @param array $settings_tabs The BP Admin settings tabs.
 531       */
 532      return apply_filters( 'bp_core_get_admin_settings_tabs', $settings_tabs );
 533  }
 534  
 535  /**
 536   * Returns the BP Admin tools tabs.
 537   *
 538   * @since 10.0.0
 539   *
 540   * @param bool $apply_filters Whether to apply filters or not.
 541   * @return array              The BP Admin tools tabs.
 542   */
 543  function bp_core_get_admin_tools_tabs( $apply_filters = true ) {
 544      $tools_page = 'tools.php';
 545      if ( bp_core_do_network_admin() ) {
 546          $tools_page = 'admin.php';
 547      }
 548  
 549      $tools_tabs = array(
 550          '0' => array(
 551              'id'   => 'bp-tools',
 552              'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-tools' ), $tools_page ) ),
 553              'name' => __( 'Repair', 'buddypress' ),
 554          ),
 555          '1' => array(
 556              'id'   => 'bp-members-invitations',
 557              'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-members-invitations' ), $tools_page ) ),
 558              'name' => __( 'Manage Invitations', 'buddypress' ),
 559          ),
 560          '2' => array(
 561              'id'   => 'bp-optouts',
 562              'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-optouts' ), $tools_page ) ),
 563              'name' => __( 'Manage Opt-outs', 'buddypress' ),
 564          ),
 565      );
 566  
 567      if ( ! $apply_filters ) {
 568          return $tools_tabs;
 569      }
 570  
 571      /**
 572       * Filter here to edit the BP Admin tools tabs.
 573       *
 574       * @since 10.0.0
 575       *
 576       * @param array $tools_tabs The BP Admin tools tabs.
 577       */
 578      return apply_filters( 'bp_core_get_admin_tools_tabs', $tools_tabs );
 579  }
 580  
 581  /**
 582   * Get the data for the tabs in the admin area.
 583   *
 584   * @since 2.2.0
 585   * @since 8.0.0 Adds the `$context` parameter.
 586   *
 587   * @param string $active_tab Name of the tab that is active. Optional.
 588   * @param string $context    The context of use for the tabs. Defaults to 'settings'.
 589   *                           Possible values are 'settings' & 'tools'.
 590   * @return string
 591   */
 592  function bp_core_get_admin_tabs( $active_tab = '', $context = 'settings' ) {
 593      $tabs = array();
 594  
 595      if ( 'settings' === $context ) {
 596          $tabs = bp_core_get_admin_settings_tabs();
 597      } elseif ( 'tools' === $context ) {
 598          $tabs = bp_core_get_admin_tools_tabs();
 599      }
 600  
 601      /**
 602       * Filters the tab data used in our wp-admin screens.
 603       *
 604       * @since 2.2.0
 605       * @since 8.0.0 Adds the `$context` parameter.
 606       *
 607       * @param array  $tabs    Tab data.
 608       * @param string $context The context of use for the tabs.
 609       */
 610      return apply_filters( 'bp_core_get_admin_tabs', $tabs, $context );
 611  }
 612  
 613  /**
 614   * Makes sure plugins using `bp_core_admin_tabs()` to output their custom BP Admin Tabs are well displayed
 615   * inside the 10.0.0 tabbed header.
 616   *
 617   * @since 10.0.0
 618   *
 619   * @param string $context    The context of use for the tabs.
 620   * @param string $active_tab The active tab.
 621   */
 622  function bp_backcompat_admin_tabs( $context = '', $active_tab = '' ) {
 623      $bp = buddypress();
 624  
 625      // Only add the back compat for Settings or Tools sub pages.
 626      if ( 'settings' !== $context && 'tools' !== $context ) {
 627          return;
 628      }
 629  
 630      // Globalize the active tab for backcompat purpose.
 631      if ( ! $bp->admin->active_nav_tab || $active_tab !== $bp->admin->active_nav_tab ) {
 632          _doing_it_wrong(
 633              'bp_core_admin_tabs()',
 634              __( 'BuddyPress Settings and Tools Screens are now using a new tabbed header. Please use `bp_core_admin_tabbed_screen_header()` instead of bp_core_admin_tabs() to output tabs.', 'buddypress' ),
 635              '10.0.0'
 636          );
 637  
 638          // Let's try to use JavaScript to force the use of the 10.0.0 Admin tabbed screen header.
 639          wp_enqueue_script(
 640              'bp-backcompat-admin-tabs',
 641              sprintf( '%1$sbackcompat-admin-tabs%2$s.js', $bp->admin->js_url, bp_core_get_minified_asset_suffix() ),
 642              array(),
 643              bp_get_version(),
 644              true
 645          );
 646      }
 647  }
 648  add_action( 'bp_admin_tabs', 'bp_backcompat_admin_tabs', 1, 2 );
 649  
 650  /** Help **********************************************************************/
 651  
 652  /**
 653   * Adds contextual help to BuddyPress admin pages.
 654   *
 655   * @since 1.7.0
 656   * @todo Make this part of the BP_Component class and split into each component.
 657   *
 658   * @param string $screen Current screen.
 659   */
 660  function bp_core_add_contextual_help( $screen = '' ) {
 661  
 662      $screen = get_current_screen();
 663  
 664      switch ( $screen->id ) {
 665  
 666          // Component page.
 667          case 'settings_page_bp-components':
 668              // Help tabs.
 669              $screen->add_help_tab(
 670                  array(
 671                      'id'      => 'bp-comp-overview',
 672                      'title'   => __( 'Overview', 'buddypress' ),
 673                      'content' => bp_core_add_contextual_help_content( 'bp-comp-overview' ),
 674                  )
 675              );
 676  
 677              // Help panel - sidebar links.
 678              $screen->set_help_sidebar(
 679                  '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
 680                  '<p>' . __( '<a href="https://codex.buddypress.org/getting-started/configure-components/">Managing Components</a>', 'buddypress' ) . '</p>' .
 681                  '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
 682              );
 683              break;
 684  
 685          // Pages page.
 686          case 'settings_page_bp-page-settings':
 687              // Help tabs.
 688              $screen->add_help_tab(
 689                  array(
 690                      'id'      => 'bp-page-overview',
 691                      'title'   => __( 'Overview', 'buddypress' ),
 692                      'content' => bp_core_add_contextual_help_content( 'bp-page-overview' ),
 693                  )
 694              );
 695  
 696              // Help panel - sidebar links.
 697              $screen->set_help_sidebar(
 698                  '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
 699                  '<p>' . __( '<a href="https://codex.buddypress.org/getting-started/configure-components/#settings-buddypress-pages">Managing Pages</a>', 'buddypress' ) . '</p>' .
 700                  '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
 701              );
 702  
 703              break;
 704  
 705          // Settings page.
 706          case 'settings_page_bp-settings':
 707              // Help tabs.
 708              $screen->add_help_tab(
 709                  array(
 710                      'id'      => 'bp-settings-overview',
 711                      'title'   => __( 'Overview', 'buddypress' ),
 712                      'content' => bp_core_add_contextual_help_content( 'bp-settings-overview' ),
 713                  )
 714              );
 715  
 716              // Help panel - sidebar links.
 717              $screen->set_help_sidebar(
 718                  '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
 719                  '<p>' . __( '<a href="https://codex.buddypress.org/getting-started/configure-components/#settings-buddypress-settings">Managing Settings</a>', 'buddypress' ) . '</p>' .
 720                  '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
 721              );
 722  
 723              break;
 724  
 725          // Profile fields page.
 726          case 'users_page_bp-profile-setup':
 727              // Help tabs.
 728              $screen->add_help_tab(
 729                  array(
 730                      'id'      => 'bp-profile-overview',
 731                      'title'   => __( 'Overview', 'buddypress' ),
 732                      'content' => bp_core_add_contextual_help_content( 'bp-profile-overview' ),
 733                  )
 734              );
 735  
 736              // Help panel - sidebar links.
 737              $screen->set_help_sidebar(
 738                  '<p><strong>' . __( 'For more information:', 'buddypress' ) . '</strong></p>' .
 739                  '<p>' . __( '<a href="https://codex.buddypress.org/administrator-guide/extended-profiles/">Managing Profile Fields</a>', 'buddypress' ) . '</p>' .
 740                  '<p>' . __( '<a href="https://buddypress.org/support/">Support Forums</a>', 'buddypress' ) . '</p>'
 741              );
 742  
 743              break;
 744      }
 745  }
 746  add_action( 'load-settings_page_bp-components', 'bp_core_add_contextual_help' );
 747  add_action( 'load-settings_page_bp-page-settings', 'bp_core_add_contextual_help' );
 748  add_action( 'load-settings_page_bp-settings', 'bp_core_add_contextual_help' );
 749  add_action( 'load-users_page_bp-profile-setup', 'bp_core_add_contextual_help' );
 750  
 751  /**
 752   * Renders contextual help content to contextual help tabs.
 753   *
 754   * @since 1.7.0
 755   *
 756   * @param string $tab Current help content tab.
 757   * @return string
 758   */
 759  function bp_core_add_contextual_help_content( $tab = '' ) {
 760  
 761      switch ( $tab ) {
 762          case 'bp-comp-overview':
 763              $retval = __( 'By default, all but four of the BuddyPress components are enabled. You can selectively enable or disable any of the components by using the form below. Your BuddyPress installation will continue to function. However, the features of the disabled components will no longer be accessible to anyone using the site.', 'buddypress' );
 764              break;
 765  
 766          case 'bp-page-overview':
 767              $retval = __( 'BuddyPress Components use WordPress Pages for their root directory/archive pages. You can change the page associations for each active component by using the form below.', 'buddypress' );
 768              break;
 769  
 770          case 'bp-settings-overview':
 771              $retval = __( 'Extra configuration settings are provided and activated. You can selectively enable or disable any setting by using the form on this screen.', 'buddypress' );
 772              break;
 773  
 774          case 'bp-profile-overview':
 775              $retval = __( 'Your users will distinguish themselves through their profile page. Create relevant profile fields that will show on each users profile.', 'buddypress' ) . '<br /><br />' . __( 'Note: Drag fields from other groups and drop them on the "Signup Fields" tab to include them into your registration form.', 'buddypress' );
 776              break;
 777  
 778          default:
 779              $retval = false;
 780              break;
 781      }
 782  
 783      // Wrap text in a paragraph tag.
 784      if ( ! empty( $retval ) ) {
 785          $retval = '<p>' . $retval . '</p>';
 786      }
 787  
 788      return $retval;
 789  }
 790  
 791  /** Separator *****************************************************************/
 792  
 793  /**
 794   * Add a separator to the WordPress admin menus.
 795   *
 796   * @since 1.7.0
 797   */
 798  function bp_admin_separator() {
 799  
 800      // Bail if BuddyPress is not network activated and viewing network admin.
 801      if ( is_network_admin() && ! bp_is_network_activated() ) {
 802          return;
 803      }
 804  
 805      // Bail if BuddyPress is network activated and viewing site admin.
 806      if ( ! is_network_admin() && bp_is_network_activated() ) {
 807          return;
 808      }
 809  
 810      // Prevent duplicate separators when no core menu items exist.
 811      if ( ! bp_current_user_can( 'bp_moderate' ) ) {
 812          return;
 813      }
 814  
 815      // Bail if there are no components with admin UI's. Hardcoded for now, until
 816      // there's a real API for determining this later.
 817      if ( ! bp_is_active( 'activity' ) && ! bp_is_active( 'groups' ) ) {
 818          return;
 819      }
 820  
 821      global $menu;
 822  
 823      $menu[] = array( '', 'read', 'separator-buddypress', '', 'wp-menu-separator buddypress' );
 824  }
 825  
 826  /**
 827   * Tell WordPress we have a custom menu order.
 828   *
 829   * @since 1.7.0
 830   *
 831   * @param bool $menu_order Menu order.
 832   * @return bool Always true.
 833   */
 834  function bp_admin_custom_menu_order( $menu_order = false ) {
 835  
 836      // Bail if user cannot see admin pages.
 837      if ( ! bp_current_user_can( 'bp_moderate' ) ) {
 838          return $menu_order;
 839      }
 840  
 841      return true;
 842  }
 843  
 844  /**
 845   * Move our custom separator above our custom post types.
 846   *
 847   * @since 1.7.0
 848   *
 849   * @param array $menu_order Menu Order.
 850   * @return array Modified menu order.
 851   */
 852  function bp_admin_menu_order( $menu_order = array() ) {
 853  
 854      // Bail if user cannot see admin pages.
 855      if ( empty( $menu_order ) || ! bp_current_user_can( 'bp_moderate' ) ) {
 856          return $menu_order;
 857      }
 858  
 859      // Initialize our custom order array.
 860      $bp_menu_order = array();
 861  
 862      // Menu values.
 863      $last_sep = is_network_admin() ? 'separator1' : 'separator2';
 864  
 865      /**
 866       * Filters the custom admin menus.
 867       *
 868       * @since 1.7.0
 869       *
 870       * @param array $value Empty array.
 871       */
 872      $custom_menus = (array) apply_filters( 'bp_admin_menu_order', array() );
 873  
 874      // Bail if no components have top level admin pages.
 875      if ( empty( $custom_menus ) ) {
 876          return $menu_order;
 877      }
 878  
 879      // Add our separator to beginning of array.
 880      array_unshift( $custom_menus, 'separator-buddypress' );
 881  
 882      // Loop through menu order and do some rearranging.
 883      foreach ( (array) $menu_order as $item ) {
 884  
 885          // Position BuddyPress menus above appearance.
 886          if ( $last_sep == $item ) {
 887  
 888              // Add our custom menus.
 889              foreach ( (array) $custom_menus as $custom_menu ) {
 890                  if ( array_search( $custom_menu, $menu_order ) ) {
 891                      $bp_menu_order[] = $custom_menu;
 892                  }
 893              }
 894  
 895              // Add the appearance separator.
 896              $bp_menu_order[] = $last_sep;
 897  
 898              // Skip our menu items.
 899          } elseif ( ! in_array( $item, $custom_menus ) ) {
 900              $bp_menu_order[] = $item;
 901          }
 902      }
 903  
 904      // Return our custom order.
 905      return $bp_menu_order;
 906  }
 907  
 908  /** Utility  *****************************************************************/
 909  
 910  /**
 911   * When using a WP_List_Table, get the currently selected bulk action.
 912   *
 913   * WP_List_Tables have bulk actions at the top and at the bottom of the tables,
 914   * and the inputs have different keys in the $_REQUEST array. This function
 915   * reconciles the two values and returns a single action being performed.
 916   *
 917   * @since 1.7.0
 918   *
 919   * @return string
 920   */
 921  function bp_admin_list_table_current_bulk_action() {
 922  
 923      $action = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
 924  
 925      // If the bottom is set, let it override the action.
 926      if ( ! empty( $_REQUEST['action2'] ) && $_REQUEST['action2'] != '-1' ) {
 927          $action = $_REQUEST['action2'];
 928      }
 929  
 930      return $action;
 931  }
 932  
 933  /** Menus *********************************************************************/
 934  
 935  /**
 936   * Register meta box and associated JS for BuddyPress WP Nav Menu.
 937   *
 938   * @since 1.9.0
 939   */
 940  function bp_admin_wp_nav_menu_meta_box() {
 941      if ( ! bp_is_root_blog() ) {
 942          return;
 943      }
 944  
 945      add_meta_box( 'add-buddypress-nav-menu', __( 'BuddyPress Member', 'buddypress' ), 'bp_admin_do_wp_nav_menu_meta_box', 'nav-menus', 'side', 'default' );
 946  
 947      add_action( 'admin_print_footer_scripts', 'bp_admin_wp_nav_menu_restrict_items' );
 948  }
 949  
 950  /**
 951   * BP Member nav menu filter to short-circuit WP's query.
 952   *
 953   * @since 7.0.0
 954   *
 955   * @param null     $null     A null value.
 956   * @param WP_Query $wp_query The WP_Query instance (passed by reference).
 957   * @return array   The BP Member nav items to short-circuit WP's query,
 958   */
 959  function bp_admin_get_wp_nav_menu_items( $null, $wp_query ) {
 960      if ( isset( $wp_query->query['orderby'], $wp_query->query['order'] ) && 'post_date' === $wp_query->query['orderby'] && 'DESC' === $wp_query->query['order'] ) {
 961          return bp_nav_menu_get_loggedin_pages();
 962      } elseif ( isset( $wp_query->query['nopaging'] ) && true === $wp_query->query['nopaging'] ) {
 963          return array_merge( bp_nav_menu_get_loggedin_pages(), bp_nav_menu_get_loggedout_pages() );
 964      }
 965  
 966      return bp_nav_menu_get_loggedout_pages();
 967  }
 968  
 969  /**
 970   * Build and populate the BuddyPress accordion on Appearance > Menus.
 971   *
 972   * @since 1.9.0
 973   * @since 7.0.0 Uses wp_nav_menu_item_post_type_meta_box()
 974   *
 975   * @global $nav_menu_selected_id
 976   */
 977  function bp_admin_do_wp_nav_menu_meta_box( $object = '', $box = array() ) {
 978      global $nav_menu_selected_id;
 979  
 980      $box['args'] = (object) array(
 981          'name'           => 'bp_nav_menu_item',
 982          '_default_query' => array(),
 983      );
 984  
 985      // Temporarly register a post type.
 986      register_post_type(
 987          'bp_nav_menu_item',
 988          array(
 989              'label'  => 'BuddyPress',
 990              'labels' => array(
 991                  'search_items' => __( 'Search BuddyPress member menu items', 'buddypress' ),
 992                  'all_items'    => __( 'All BuddyPress Member menu items', 'buddypress' ),
 993              ),
 994              'public' => true,
 995              'hierarchical' => false,
 996              'has_archive'  => false,
 997              'rewrite'      => false,
 998          )
 999      );
1000  
1001      // Temporarly override the posts query results.
1002      add_filter( 'posts_pre_query', 'bp_admin_get_wp_nav_menu_items', 10, 2 );
1003  
1004      ob_start();
1005      wp_nav_menu_item_post_type_meta_box( 'buddypress', $box );
1006      $output = ob_get_clean();
1007  
1008      $get_bp_items = new WP_Query;
1009      $all_bp_items = $get_bp_items->query( array( 'nopaging' => true ) );
1010      $walker       = new Walker_Nav_Menu_Checklist();
1011      $all_bp_tabs  = sprintf(
1012          '<div id="bp_nav_menu_item-all" class="tabs-panel tabs-panel-view-all tabs-panel-inactive" role="region" aria-label="%1$s" tabindex="0">
1013              <ul id="bp_nav_menu_itemchecklist" data-wp-lists="list:bp_nav_menu_item" class="categorychecklist form-no-clear">
1014                  %2$s
1015              </ul>
1016          </div>',
1017          esc_html__( 'All BuddyPress Member menu items', 'buddypress' ),
1018          walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $all_bp_items ), 0, (object) array( 'walker' => $walker ) )
1019      );
1020  
1021      // Remove temporary post type and filter.
1022      unregister_post_type( 'bp_nav_menu_item' );
1023      remove_filter( 'posts_pre_query', 'bp_admin_get_wp_nav_menu_items', 10, 2 );
1024  
1025      $tab_name    = 'bp_nav_menu_item-tab';
1026      $current_tab = 'logged-in';
1027      $tabs        = array(
1028          'logged-in'  => __( 'Logged-In', 'buddypress' ),
1029          'logged-out' => __( 'Logged-Out', 'buddypress' ),
1030          'all'        => __( 'All', 'buddypress' ),
1031      );
1032      $tab_urls    = array(
1033          'all'        => '',
1034          'logged-in'  => '',
1035          'logged-out' => '',
1036      );
1037  
1038      if ( isset( $_REQUEST[ $tab_name ] ) && in_array( $_REQUEST[ $tab_name ], array_keys( $tabs ), true ) ) {
1039          $current_tab = $_REQUEST[ $tab_name ];
1040      }
1041  
1042      $removed_args = array(
1043          'action',
1044          'customlink-tab',
1045          'edit-menu-item',
1046          'menu-item',
1047          'page-tab',
1048          '_wpnonce',
1049      );
1050  
1051      if ( $nav_menu_selected_id ) {
1052          $tab_urls['all']        = esc_url( add_query_arg( $tab_name, 'all', remove_query_arg( $removed_args ) ) );
1053          $tab_urls['logged-in']  = esc_url( add_query_arg( $tab_name, 'logged-in', remove_query_arg( $removed_args ) ) );
1054          $tab_urls['logged-out'] = esc_url( add_query_arg( $tab_name, 'logged-out', remove_query_arg( $removed_args ) ) );
1055      }
1056  
1057      $bp_tabs_nav = '';
1058      foreach ( $tabs as $tab => $tab_text ) {
1059          $class    = '';
1060          $datatype = 'bp_nav_menu_item-' . $tab;
1061  
1062          if ( $current_tab === $tab ) {
1063              $class = ' class="tabs"';
1064          }
1065  
1066          if ( 'all' !== $tab ) {
1067              $datatype = 'tabs-panel-posttype-bp_nav_menu_item-' . $tab;
1068          }
1069  
1070          $bp_tabs_nav .= sprintf(
1071              '<li%1$s>
1072                  <a class="nav-tab-link" data-type="%2$s" href="%3$s">
1073                      %4$s
1074                  </a>
1075              </li>',
1076              $class,
1077              $datatype,
1078              esc_url( $tab_urls[ $tab ] ) . '#' . $datatype,
1079              esc_html( $tab_text )
1080          );
1081      }
1082  
1083      $output = str_replace(
1084          array(
1085              'tabs-panel-posttype-bp_nav_menu_item-most-recent',
1086              'bp_nav_menu_itemchecklist-most-recent',
1087              'bp_nav_menu_item-all',
1088              'bp_nav_menu_itemchecklist',
1089          ),
1090          array(
1091              'tabs-panel-posttype-bp_nav_menu_item-logged-in',
1092              'bp_nav_menu_itemchecklist-logged-in',
1093              'tabs-panel-posttype-bp_nav_menu_item-logged-out',
1094              'bp_nav_menu_itemchecklist-logged-out',
1095          ),
1096          $output
1097      );
1098  
1099      preg_match( '/\<ul\sid=\"posttype-bp_nav_menu_item-tabs\"[^>]*>(.*?)\<\/ul\>\<!-- \.posttype-tabs --\>/s', $output, $tabs_nav );
1100  
1101      if ( isset( $tabs_nav[1] ) ) {
1102          $output = str_replace( $tabs_nav[1], $bp_tabs_nav, $output );
1103      }
1104  
1105      echo preg_replace( '/\<div\sclass=\".*\"\sid=\"tabs-panel-posttype-bp_nav_menu_item-search\"[^>]*>(.*?)\<\/div\>/s', $all_bp_tabs, $output );
1106  }
1107  
1108  /**
1109   * In admin emails list, for non-en_US locales, add notice explaining how to reinstall emails.
1110   *
1111   * If BuddyPress installs before its translations are in place, tell people how to reinstall
1112   * the emails so they have their contents in their site's language.
1113   *
1114   * @since 2.5.0
1115   */
1116  function bp_admin_email_maybe_add_translation_notice() {
1117      if ( get_current_screen()->post_type !== bp_get_email_post_type() || get_locale() === 'en_US' ) {
1118          return;
1119      }
1120  
1121      // If user can't access BP Tools, there's no point showing the message.
1122      if ( ! current_user_can( buddypress()->admin->capability ) ) {
1123          return;
1124      }
1125  
1126      if ( bp_core_do_network_admin() ) {
1127          $admin_page = 'admin.php';
1128      } else {
1129          $admin_page = 'tools.php';
1130      }
1131  
1132      bp_core_add_admin_notice(
1133          sprintf(
1134              // Translators: %s is the url to the BuddyPress tools administration screen.
1135              __( 'Are these emails not written in your site\'s language? Go to <a href="%s">BuddyPress Tools and try the "reinstall emails"</a> tool.', 'buddypress' ),
1136              esc_url( add_query_arg( 'page', 'bp-tools', bp_get_admin_url( $admin_page ) ) )
1137          ),
1138          'updated'
1139      );
1140  }
1141  add_action( 'admin_head-edit.php', 'bp_admin_email_maybe_add_translation_notice' );
1142  
1143  /**
1144   * In emails editor, add notice linking to token documentation on Codex.
1145   *
1146   * @since 2.5.0
1147   */
1148  function bp_admin_email_add_codex_notice() {
1149      if ( get_current_screen()->post_type !== bp_get_email_post_type() ) {
1150          return;
1151      }
1152  
1153      bp_core_add_admin_notice(
1154          sprintf(
1155              // Translators: %s is the url to the BuddyPress codex page about BP Email tokens.
1156              __( 'Phrases wrapped in braces <code>{{ }}</code> are email tokens. <a href="%s">Learn about tokens on the BuddyPress Codex</a>.', 'buddypress' ),
1157              esc_url( 'https://codex.buddypress.org/emails/email-tokens/' )
1158          ),
1159          'error'
1160      );
1161  }
1162  add_action( 'admin_head-post.php', 'bp_admin_email_add_codex_notice' );
1163  
1164  /**
1165   * Display metabox for email taxonomy type.
1166   *
1167   * Shows the term description in a list, rather than the term name itself.
1168   *
1169   * @since 2.5.0
1170   *
1171   * @param WP_Post $post Post object.
1172   * @param array   $box {
1173   *     Tags meta box arguments.
1174   *
1175   *     @type string   $id       Meta box ID.
1176   *     @type string   $title    Meta box title.
1177   *     @type callable $callback Meta box display callback.
1178   * }
1179   */
1180  function bp_email_tax_type_metabox( $post, $box ) {
1181      $r = array(
1182          'taxonomy' => bp_get_email_tax_type(),
1183      );
1184  
1185      $tax_name = esc_attr( $r['taxonomy'] );
1186      $taxonomy = get_taxonomy( $r['taxonomy'] );
1187      ?>
1188      <div id="taxonomy-<?php echo $tax_name; ?>" class="categorydiv">
1189          <div id="<?php echo $tax_name; ?>-all" class="tabs-panel">
1190              <?php
1191              $name = ( $tax_name == 'category' ) ? 'post_category' : 'tax_input[' . $tax_name . ']';
1192              echo "<input type='hidden' name='{$name}[]' value='0' />"; // Allows for an empty term set to be sent. 0 is an invalid Term ID and will be ignored by empty() checks.
1193              ?>
1194              <ul id="<?php echo $tax_name; ?>checklist" data-wp-lists="list:<?php echo $tax_name; ?>" class="categorychecklist form-no-clear">
1195                  <?php
1196                  wp_terms_checklist(
1197                      $post->ID,
1198                      array(
1199                          'taxonomy' => $tax_name,
1200                          'walker'   => new BP_Walker_Category_Checklist(),
1201                      )
1202                  );
1203                  ?>
1204              </ul>
1205          </div>
1206  
1207          <p><?php esc_html_e( 'Choose when this email will be sent.', 'buddypress' ); ?></p>
1208      </div>
1209      <?php
1210  }
1211  
1212  /**
1213   * Custom metaboxes used by our 'bp-email' post type.
1214   *
1215   * @since 2.5.0
1216   */
1217  function bp_email_custom_metaboxes() {
1218      // Remove default 'Excerpt' metabox and replace with our own.
1219      remove_meta_box( 'postexcerpt', null, 'normal' );
1220      add_meta_box( 'postexcerpt', __( 'Plain text email content', 'buddypress' ), 'bp_email_plaintext_metabox', null, 'normal', 'high' );
1221  }
1222  add_action( 'add_meta_boxes_' . bp_get_email_post_type(), 'bp_email_custom_metaboxes' );
1223  
1224  /**
1225   * Customized version of the 'Excerpt' metabox for our 'bp-email' post type.
1226   *
1227   * We are using the 'Excerpt' metabox as our plain-text email content editor.
1228   *
1229   * @since 2.5.0
1230   *
1231   * @param WP_Post $post
1232   */
1233  function bp_email_plaintext_metabox( $post ) {
1234      ?>
1235  
1236      <label class="screen-reader-text" for="excerpt">
1237      <?php
1238          /* translators: accessibility text */
1239          _e( 'Plain text email content', 'buddypress' );
1240      ?>
1241      </label><textarea rows="5" cols="40" name="excerpt" id="excerpt"><?php echo $post->post_excerpt; // textarea_escaped ?></textarea>
1242  
1243      <p><?php _e( 'Most email clients support HTML email. However, some people prefer to receive plain text email. Enter a plain text alternative version of your email here.', 'buddypress' ); ?></p>
1244  
1245      <?php
1246  }
1247  
1248  /**
1249   * Restrict various items from view if editing a BuddyPress menu.
1250   *
1251   * If a person is editing a BP menu item, that person should not be able to
1252   * see or edit the following fields:
1253   *
1254   * - CSS Classes - We use the 'bp-menu' CSS class to determine if the
1255   *   menu item belongs to BP, so we cannot allow manipulation of this field to
1256   *   occur.
1257   * - URL - This field is automatically generated by BP on output, so this
1258   *   field is useless and can cause confusion.
1259   *
1260   * Note: These restrictions are only enforced if JavaScript is enabled.
1261   *
1262   * @since 1.9.0
1263   */
1264  function bp_admin_wp_nav_menu_restrict_items() {
1265      ?>
1266      <script type="text/javascript">
1267      jQuery( '#menu-to-edit').on( 'click', 'a.item-edit', function() {
1268          var settings  = jQuery(this).closest( '.menu-item-bar' ).next( '.menu-item-settings' );
1269          var css_class = settings.find( '.edit-menu-item-classes' );
1270  
1271          if( css_class.val().indexOf( 'bp-menu' ) === 0 ) {
1272              css_class.attr( 'readonly', 'readonly' );
1273              settings.find( '.field-url' ).css( 'display', 'none' );
1274          }
1275      });
1276      </script>
1277      <?php
1278  }
1279  
1280  /**
1281   * Add "Mark as Spam/Ham" button to user row actions.
1282   *
1283   * @since 2.0.0
1284   *
1285   * @param array  $actions     User row action links.
1286   * @param object $user_object Current user information.
1287   * @return array $actions User row action links.
1288   */
1289  function bp_core_admin_user_row_actions( $actions, $user_object ) {
1290  
1291      // Setup the $user_id variable from the current user object.
1292      $user_id = 0;
1293      if ( ! empty( $user_object->ID ) ) {
1294          $user_id = absint( $user_object->ID );
1295      }
1296  
1297      // Bail early if user cannot perform this action, or is looking at themselves.
1298      if ( current_user_can( 'edit_user', $user_id ) && ( bp_loggedin_user_id() !== $user_id ) ) {
1299  
1300          // Admin URL could be single site or network.
1301          $url = bp_get_admin_url( 'users.php' );
1302  
1303          // If spammed, create unspam link.
1304          if ( bp_is_user_spammer( $user_id ) ) {
1305              $url            = add_query_arg(
1306                  array(
1307                      'action' => 'ham',
1308                      'user'   => $user_id,
1309                  ),
1310                  $url
1311              );
1312              $unspam_link    = wp_nonce_url( $url, 'bp-spam-user' );
1313              $actions['ham'] = sprintf('<a href="%1$s">%2$s</a>', esc_url( $unspam_link ), esc_html__( 'Not Spam', 'buddypress' ) );
1314  
1315              // If not already spammed, create spam link.
1316          } else {
1317              $url             = add_query_arg(
1318                  array(
1319                      'action' => 'spam',
1320                      'user'   => $user_id,
1321                  ),
1322                  $url
1323              );
1324              $spam_link       = wp_nonce_url( $url, 'bp-spam-user' );
1325              $actions['spam'] = sprintf( '<a class="submitdelete" href="%1$s">%2$s</a>', esc_url( $spam_link ), esc_html__( 'Spam', 'buddypress' ) );
1326          }
1327      }
1328  
1329      // Create a "View" link.
1330      $url             = bp_core_get_user_domain( $user_id );
1331      $actions['view'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $url ), esc_html__( 'View', 'buddypress' ) );
1332  
1333      // Return new actions.
1334      return $actions;
1335  }
1336  
1337  /**
1338   * Catch requests to mark individual users as spam/ham from users.php.
1339   *
1340   * @since 2.0.0
1341   */
1342  function bp_core_admin_user_manage_spammers() {
1343  
1344      // Print our inline scripts on non-Multisite.
1345      add_action( 'admin_footer', 'bp_core_admin_user_spammed_js' );
1346  
1347      $action  = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : false;
1348      $updated = isset( $_REQUEST['updated'] ) ? $_REQUEST['updated'] : false;
1349      $mode    = isset( $_POST['mode'] ) ? $_POST['mode'] : false;
1350  
1351      // If this is a multisite, bulk request, stop now!
1352      if ( 'list' == $mode ) {
1353          return;
1354      }
1355  
1356      // Process a spam/ham request.
1357      if ( ! empty( $action ) && in_array( $action, array( 'spam', 'ham' ) ) ) {
1358  
1359          check_admin_referer( 'bp-spam-user' );
1360  
1361          $user_id = ! empty( $_REQUEST['user'] ) ? intval( $_REQUEST['user'] ) : false;
1362  
1363          if ( empty( $user_id ) ) {
1364              return;
1365          }
1366  
1367          $redirect = wp_get_referer();
1368  
1369          $status = ( $action == 'spam' ) ? 'spam' : 'ham';
1370  
1371          // Process the user.
1372          bp_core_process_spammer_status( $user_id, $status );
1373  
1374          $redirect = add_query_arg( array( 'updated' => 'marked-' . $status ), $redirect );
1375  
1376          wp_redirect( $redirect );
1377      }
1378  
1379      // Display feedback.
1380      if ( ! empty( $updated ) && in_array( $updated, array( 'marked-spam', 'marked-ham' ) ) ) {
1381  
1382          if ( 'marked-spam' === $updated ) {
1383              $notice = __( 'User marked as spammer. Spam users are visible only to site admins.', 'buddypress' );
1384          } else {
1385              $notice = __( 'User removed from spam.', 'buddypress' );
1386          }
1387  
1388          bp_core_add_admin_notice( $notice );
1389      }
1390  }
1391  
1392  /**
1393   * Inline script that adds the 'site-spammed' class to spammed users.
1394   *
1395   * @since 2.0.0
1396   */
1397  function bp_core_admin_user_spammed_js() {
1398      ?>
1399      <script type="text/javascript">
1400          jQuery( document ).ready( function($) {
1401              $( '.row-actions .ham' ).each( function() {
1402                  $( this ).closest( 'tr' ).addClass( 'site-spammed' );
1403              });
1404          });
1405      </script>
1406      <?php
1407  }
1408  
1409  /**
1410   * Catch and process an admin notice dismissal.
1411   *
1412   * @since 2.7.0
1413   */
1414  function bp_core_admin_notice_dismiss_callback() {
1415      if ( ! current_user_can( 'install_plugins' ) ) {
1416          wp_send_json_error();
1417      }
1418  
1419      $nonce_data = array();
1420      if ( isset( $_SERVER['HTTP_X_BP_NONCE'] ) ) {
1421          $nonce_data = array(
1422              'nonce'  => $_SERVER['HTTP_X_BP_NONCE'],
1423              'action' => 'bp_dismiss_admin_notice',
1424          );
1425      } elseif ( isset( $_POST['nonce'] ) ) {
1426          $nonce_data['nonce'] = $_POST['nonce'];
1427      }
1428  
1429      if ( empty( $nonce_data['nonce'] ) || empty( $_POST['notice_id'] ) ) {
1430          wp_send_json_error();
1431      }
1432  
1433      $notice_id = wp_unslash( $_POST['notice_id'] );
1434      if ( ! isset( $nonce_data['action'] ) ) {
1435          $nonce_data['action'] = 'bp-dismissible-notice-' . $notice_id;
1436      }
1437  
1438      if ( ! wp_verify_nonce( $nonce_data['nonce'], $nonce_data['action'] ) ) {
1439          wp_send_json_error();
1440      }
1441  
1442      bp_update_option( "bp-dismissed-notice-{$notice_id}", true );
1443  
1444      wp_send_json_success();
1445  }
1446  add_action( 'wp_ajax_bp_dismiss_notice', 'bp_core_admin_notice_dismiss_callback' );
1447  
1448  /**
1449   * Add a "buddypress" class to body element of wp-admin.
1450   *
1451   * @since 2.8.0
1452   *
1453   * @param string $classes CSS classes for the body tag in the admin, a space separated string.
1454   *
1455   * @return string
1456   */
1457  function bp_core_admin_body_classes( $classes ) {
1458      $bp = buddypress();
1459  
1460      $bp_class = ' buddypress';
1461      if ( isset( $bp->admin->nav_tabs ) && $bp->admin->nav_tabs ) {
1462          $bp_class .= ' bp-is-tabbed-screen';
1463      }
1464  
1465      return $classes . $bp_class;
1466  }
1467  add_filter( 'admin_body_class', 'bp_core_admin_body_classes' );
1468  
1469  /**
1470   * Adds a BuddyPress category to house BuddyPress blocks.
1471   *
1472   * @since 5.0.0
1473   * @since 8.0.0 The `bp_block_category_post_types` filter has been deprecated.
1474   *
1475   * @param array          $categories Array of block categories.
1476   * @param string|WP_Post $post       Post being loaded.
1477   */
1478  function bp_block_category( $categories = array(), $editor_name_or_post = null ) {
1479      if ( $editor_name_or_post instanceof WP_Post ) {
1480          $post_types = array( 'post', 'page' );
1481  
1482          /*
1483           * As blocks are always loaded even if the category is not available, there's no more interest
1484           * in disabling the BuddyPress category.
1485           */
1486          apply_filters_deprecated( 'bp_block_category_post_types', array( $post_types ), '8.0.0' );
1487      }
1488  
1489      return array_merge(
1490          $categories,
1491          array(
1492              array(
1493                  'slug'  => 'buddypress',
1494                  'title' => __( 'BuddyPress', 'buddypress' ),
1495                  'icon'  => 'buddicons-buddypress-logo',
1496              ),
1497          )
1498      );
1499  }
1500  
1501  /**
1502   * Select the right `block_categories` filter according to WP version.
1503   *
1504   * @since 8.0.0
1505   */
1506  function bp_block_init_category_filter() {
1507      if ( function_exists( 'get_default_block_categories' ) ) {
1508          add_filter( 'block_categories_all', 'bp_block_category', 1, 2 );
1509      } else {
1510          add_filter( 'block_categories', 'bp_block_category', 1, 2 );
1511      }
1512  }
1513  add_action( 'bp_init', 'bp_block_init_category_filter' );


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