BuddyPress menu item,
* regardless of which actual BuddyPress admin screen we are on.
*
* The conditional prevents the behavior when the user is viewing the
* backpat "Help" page, the Activity page, or any third-party plugins.
*
* @since 1.6.0
*
* @global string $plugin_page
* @global array $submenu
*/
function bp_core_modify_admin_menu_highlight() {
global $plugin_page, $submenu_file;
// This tweaks the Settings subnav menu to show only one BuddyPress menu item.
if ( ! in_array( $plugin_page, array( 'bp-activity', 'bp-general-settings' ), true ) ) {
$submenu_file = 'bp-components';
}
// Network Admin > Tools.
if ( in_array( $plugin_page, array( 'bp-tools', 'available-tools' ), true ) ) {
$submenu_file = $plugin_page;
}
// Keep the BuddyPress tools menu highlighted when using a tools tab.
if ( 'bp-optouts' === $plugin_page || 'bp-members-invitations' === $plugin_page ) {
$submenu_file = 'bp-tools';
}
}
/**
* Generates markup for a fallback top-level BuddyPress menu page, if the site is running
* a legacy plugin which hasn't been updated. If the site is up to date, this page
* will never appear.
*
* @see bp_core_admin_backpat_menu()
*
* @since 1.6.0
*
* @todo Add convenience links into the markup once new positions are finalized.
*/
function bp_core_admin_backpat_page() {
$url = bp_core_do_network_admin() ? network_admin_url( 'settings.php' ) : admin_url( 'options-general.php' );
$settings_url = add_query_arg( 'page', 'bp-components', $url ); ?>
Settings > BuddyPress. Profile Fields has been moved into the Users menu.', 'buddypress' ),
esc_url( $settings_url ),
esc_url( bp_get_admin_url( 'users.php?page=bp-profile-setup' ) )
);
?>
admin->notices as $notice ) {
$notice_types[] = $notice['type'];
}
$notice_types = array_unique( $notice_types );
foreach ( $notice_types as $type ) {
$notices = wp_list_filter( buddypress()->admin->notices, array( 'type' => $type ) );
printf( '', sanitize_html_class( $type ) );
foreach ( $notices as $notice ) {
printf(
'
%s
',
wp_kses(
$notice['message'],
array(
'strong' => true,
'code' => true,
'a' => array(
'href' => true,
),
)
)
);
}
printf( '
' );
}
}
add_action( 'admin_notices', 'bp_core_print_admin_notices' );
add_action( 'network_admin_notices', 'bp_core_print_admin_notices' );
/**
* Add an admin notice to the BP queue.
*
* Messages added with this function are displayed in BuddyPress's general purpose admin notices
* box. It is recommended that you hook this function to admin_init, so that your messages are
* loaded in time.
*
* @since 1.5.0
*
* @param string $notice Optional. The notice you are adding to the queue.
* @param string $type The notice type; optional. Usually either "updated" or "error".
*/
function bp_core_add_admin_notice( $notice = '', $type = 'updated' ) {
// Do not add if the notice is empty.
if ( empty( $notice ) ) {
return;
}
// Double check the object before referencing it.
if ( ! isset( buddypress()->admin->notices ) ) {
buddypress()->admin->notices = array();
}
// Add the notice.
buddypress()->admin->notices[] = array(
'message' => $notice,
'type' => $type,
);
}
/**
* Verify that some BP prerequisites are set up properly, and notify the admin if not.
*
* On every Dashboard page, this function checks the following:
* - that every BP component that needs a WP page for a directory has one.
* - that no WP page has multiple BP components associated with it.
* The administrator will be shown a notice for each check that fails.
*
* @since 1.2.0
*
* @global wpdb $wpdb WordPress database object.
*/
function bp_core_activation_notice() {
global $wpdb;
// Only the super admin gets warnings.
if ( ! bp_current_user_can( 'bp_moderate' ) ) {
return;
}
// Bail in user admin.
if ( is_user_admin() ) {
return;
}
// On multisite installs, don't load on a non-root blog, unless do_network_admin is overridden.
if ( is_multisite() && bp_core_do_network_admin() && ! bp_is_root_blog() ) {
return;
}
// Bail if in network admin, and BuddyPress is not network activated.
if ( is_network_admin() && ! bp_is_network_activated() ) {
return;
}
/**
* Check to make sure that the blog setup routine has run. This can't
* happen during the wizard because of the order which the components
* are loaded.
*/
if ( bp_is_active( 'blogs' ) ) {
$bp = buddypress();
$count = $wpdb->get_var( "SELECT COUNT(*) FROM {$bp->blogs->table_name}" );
if ( empty( $count ) ) {
bp_blogs_record_existing_blogs();
}
}
// Get BuddyPress instance.
$bp = buddypress();
/**
* Check for orphaned BP components (BP component is enabled, no WP page exists).
*/
$orphaned_components = array();
$wp_page_components = array();
// Only components with 'has_directory' require a WP page to function.
foreach ( $bp->loaded_components as $component_id ) {
if ( ! empty( $bp->{$component_id}->has_directory ) ) {
$wp_page_components[] = array(
'id' => $component_id,
'name' => isset( $bp->{$component_id}->name ) ? $bp->{$component_id}->name : ucwords( $bp->{$component_id}->id ),
);
}
}
// Activate and Register are special cases. They are not components but they need WP pages.
// If user registration is disabled, we can skip this step.
if ( bp_allow_access_to_registration_pages() ) {
$wp_page_components[] = array(
'id' => 'activate',
'name' => __( 'Activate', 'buddypress' ),
);
$wp_page_components[] = array(
'id' => 'register',
'name' => __( 'Register', 'buddypress' ),
);
}
// On the first admin screen after a new installation, this isn't set, so grab it to suppress
// a misleading error message.
if ( empty( $bp->pages->members ) ) {
$bp->pages = bp_core_get_directory_pages();
}
foreach ( $wp_page_components as $component ) {
if ( ! isset( $bp->pages->{$component['id']} ) ) {
$component_props = $component;
if ( isset( $bp->{$component['id']}->directory_title ) ) {
$component_props['title'] = $bp->{$component['id']}->directory_title;
} else {
$component_props['title'] = $component_props['name'];
}
if ( isset( $bp->{$component['id']}->root_slug ) ) {
$component_props['name'] = $bp->{$component['id']}->root_slug;
}
$orphaned_components[ $component['id'] ] = $component_props;
}
}
if ( ! empty( $orphaned_components ) ) {
$notice_type = 'error';
$notice = sprintf(
// Translators: %s is the comma separated list of components needing a directory page.
__( 'The following active BuddyPress Components do not have associated BuddyPress Pages: %s.', 'buddypress' ),
'' . implode( ', ', array_map( 'esc_html', wp_list_pluck( $orphaned_components, 'title' ) ) ) . ''
);
if ( 'buddypress' === bp_core_get_directory_post_type() ) {
$pages = bp_core_add_page_mappings( $orphaned_components, 'keep', true );
$orphaned_components = array_intersect_key( $orphaned_components, $pages );
$notice_type = 'updated';
$notice = sprintf(
// Translators: %s is the comma separated list of components needing a directory page.
__( 'A BuddyPress page has been added for the following active BuddyPress Components which did not have associated BuddyPress Pages yet: %s. You may need to refresh your permalink settings.', 'buddypress' ),
'' . implode( ', ', array_map( 'esc_html', wp_list_pluck( $orphaned_components, 'title' ) ) ) . ''
);
}
bp_core_add_admin_notice( $notice, $notice_type );
}
// BP components cannot share a single WP page. Check for duplicate assignments, and post a message if found.
$dupe_names = array();
$page_ids = bp_core_get_directory_page_ids();
$dupes = array_diff_assoc( $page_ids, array_unique( $page_ids ) );
if ( ! empty( $dupes ) ) {
foreach ( array_keys( $dupes ) as $dupe_component ) {
$dupe_names[] = $bp->pages->{$dupe_component}->title;
}
// Make sure that there are no duplicate duplicates :).
$dupe_names = array_unique( $dupe_names );
}
// If there are duplicates, post a message about them.
if ( ! empty( $dupe_names ) ) {
$notice = sprintf(
// Translators: %s is the list of directory pages associated to more than one component.
__( 'Each BuddyPress Component needs its own BuddyPress page. The following BuddyPress Pages have more than one component associated with them: %s.', 'buddypress' ),
'' . implode( ', ', array_map( 'esc_html', $dupe_names ) ) . ''
);
bp_core_add_admin_notice( $notice, 'error' );
}
}
/**
* Redirect user to BuddyPress's What's New page on activation.
*
* @since 1.7.0
*
* @internal Used internally to redirect BuddyPress to the about page on activation.
*/
function bp_do_activation_redirect() {
// Bail if no activation redirect.
if ( ! get_transient( '_bp_activation_redirect' ) ) {
return;
}
// Delete the redirect transient.
delete_transient( '_bp_activation_redirect' );
// Bail if activating from network, or bulk.
if ( isset( $_GET['activate-multi'] ) ) {
return;
}
$settings_page = 'options-general.php';
if ( bp_core_do_network_admin() ) {
$settings_page = 'settings.php';
}
$query_args = array(
'page' => 'bp-components',
'hello' => 'buddypress',
);
if ( get_transient( '_bp_is_new_install' ) ) {
$query_args['is_new_install'] = '1';
delete_transient( '_bp_is_new_install' );
}
// Redirect to dashboard and trigger the Hello screen.
wp_safe_redirect( add_query_arg( $query_args, bp_get_admin_url( $settings_page ) ) );
}
/** UI/Styling ****************************************************************/
/**
* Outputs the BP Admin Tabbed header.
*
* @since 10.0.0
*
* @param string $title Optional. The title of the Admin page.
* @param string $active_tab Optional. The current displayed tab.
* @param string $context Optional. The context of use for the tabs. Defaults to 'settings'.
* Possible values are 'settings' & 'tools'.
*/
function bp_core_admin_tabbed_screen_header( $title = '', $active_tab = '', $context = 'settings' ) {
$bp = buddypress();
// Globalize the active tab for backcompat purpose.
$bp->admin->active_nav_tab = $active_tab;
/**
* Fires before the output of the BP Admin tabbed screen header.
*
* @since 10.0.0
*
* @param string $active_tab The BP Admin active tab.
* @param string $context The context of use for the tabs.
*/
do_action( 'bp_core_admin_tabbed_screen_header', $active_tab, $context );
?>
' . esc_html( $tab_data['name'] ) . '';
}
if ( ! $echo_tabs ) {
return $tabs_html;
}
// phpcs:ignore WordPress.Security.EscapeOutput
echo implode( "\n", $tabs_html );
/**
* Fires after the output of tabs for the admin area.
*
* @since 1.5.0
* @since 8.0.0 Adds the `$context` parameter.
* @since 10.0.0 Adds the `$active_tab` parameter.
*
* @param string $context The context of use for the tabs.
* @param string $active_tab The active tab.
*/
do_action( 'bp_admin_tabs', $context, $active_tab );
}
/**
* Returns the BP Admin settings tabs.
*
* @since 10.0.0
*
* @param bool $apply_filters Optional. Whether to apply filters or not.
* @return array The BP Admin settings tabs.
*/
function bp_core_get_admin_settings_tabs( $apply_filters = true ) {
$settings_tabs = array(
'0' => array(
'id' => 'bp-components',
'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-components' ), 'admin.php' ) ),
'name' => __( 'Components', 'buddypress' ),
),
'2' => array(
'id' => 'bp-settings',
'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-settings' ), 'admin.php' ) ),
'name' => __( 'Options', 'buddypress' ),
),
'4' => array(
'id' => 'bp-credits',
'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-credits' ), 'admin.php' ) ),
'name' => __( 'Credits', 'buddypress' ),
),
);
if ( 'rewrites' === bp_core_get_query_parser() ) {
$settings_tabs['1'] = array(
'id' => 'bp-rewrites',
'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-rewrites' ), 'admin.php' ) ),
'name' => __( 'URLs', 'buddypress' ),
);
}
if ( bp_core_get_unread_admin_notifications() || ( isset( $_GET['page'] ) && 'bp-admin-notifications' === $_GET['page'] ) ) {
$settings_tabs['3'] = array(
'id' => 'bp-admin-notifications',
'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-admin-notifications' ), 'admin.php' ) ),
'name' => __( 'Notifications', 'buddypress' ),
);
}
if ( ! $apply_filters ) {
return $settings_tabs;
}
/**
* Filter here to edit the BP Admin settings tabs.
*
* @since 10.0.0
*
* @param array $settings_tabs The BP Admin settings tabs.
*/
$settings_tabs = apply_filters( 'bp_core_get_admin_settings_tabs', $settings_tabs );
// Sort tabs before returning it.
ksort( $settings_tabs );
return $settings_tabs;
}
/**
* Returns the BP Admin tools tabs.
*
* @since 10.0.0
*
* @param bool $apply_filters Optional. Whether to apply filters or not.
* @return array The BP Admin tools tabs.
*/
function bp_core_get_admin_tools_tabs( $apply_filters = true ) {
$tools_page = 'tools.php';
if ( bp_core_do_network_admin() ) {
$tools_page = 'admin.php';
}
$tools_tabs = array(
'0' => array(
'id' => 'bp-tools',
'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-tools' ), $tools_page ) ),
'name' => __( 'Repair', 'buddypress' ),
),
'1' => array(
'id' => 'bp-members-invitations',
'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-members-invitations' ), $tools_page ) ),
'name' => __( 'Manage Invitations', 'buddypress' ),
),
'2' => array(
'id' => 'bp-optouts',
'href' => bp_get_admin_url( add_query_arg( array( 'page' => 'bp-optouts' ), $tools_page ) ),
'name' => __( 'Manage Opt-outs', 'buddypress' ),
),
);
if ( ! $apply_filters ) {
return $tools_tabs;
}
/**
* Filter here to edit the BP Admin tools tabs.
*
* @since 10.0.0
*
* @param array $tools_tabs The BP Admin tools tabs.
*/
$tools_tabs = apply_filters( 'bp_core_get_admin_tools_tabs', $tools_tabs );
// Sort tabs before returning it.
ksort( $tools_tabs );
return $tools_tabs;
}
/**
* Get the data for the tabs in the admin area.
*
* @since 2.2.0
* @since 8.0.0 Adds the `$context` parameter.
*
* @param string $active_tab Name of the tab that is active. Optional.
* @param string $context Optional. The context of use for the tabs. Defaults to 'settings'.
* Possible values are 'settings' & 'tools'.
* @return string
*/
function bp_core_get_admin_tabs( $active_tab = '', $context = 'settings' ) {
$tabs = array();
if ( 'settings' === $context ) {
$tabs = bp_core_get_admin_settings_tabs();
} elseif ( 'tools' === $context ) {
$tabs = bp_core_get_admin_tools_tabs();
}
/**
* Filters the tab data used in our wp-admin screens.
*
* @since 2.2.0
* @since 8.0.0 Adds the `$context` parameter.
*
* @param array $tabs Tab data.
* @param string $context The context of use for the tabs.
*/
return apply_filters( 'bp_core_get_admin_tabs', $tabs, $context );
}
/**
* Makes sure plugins using `bp_core_admin_tabs()` to output their custom BP Admin Tabs are well displayed
* inside the 10.0.0 tabbed header.
*
* @since 10.0.0
*
* @param string $context Optional. The context of use for the tabs.
* @param string $active_tab Optional. The active tab.
*/
function bp_backcompat_admin_tabs( $context = '', $active_tab = '' ) {
$bp = buddypress();
// Only add the back compat for Settings or Tools sub pages.
if ( 'settings' !== $context && 'tools' !== $context ) {
return;
}
// Globalize the active tab for backcompat purpose.
if ( ! $bp->admin->active_nav_tab || $active_tab !== $bp->admin->active_nav_tab ) {
_doing_it_wrong(
'bp_core_admin_tabs()',
esc_html__( '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' ),
'10.0.0'
);
// Let's try to use JavaScript to force the use of the 10.0.0 Admin tabbed screen header.
wp_enqueue_script(
'bp-backcompat-admin-tabs',
sprintf( '%1$sbackcompat-admin-tabs%2$s.js', $bp->admin->js_url, bp_core_get_minified_asset_suffix() ),
array(),
bp_get_version(),
true
);
}
}
add_action( 'bp_admin_tabs', 'bp_backcompat_admin_tabs', 1, 2 );
/** Help **********************************************************************/
/**
* Adds contextual help to BuddyPress admin pages.
*
* @since 1.7.0
* @todo Make this part of the BP_Component class and split into each component.
*
* @param string $screen Optional. Current screen.
*/
function bp_core_add_contextual_help( $screen = '' ) {
$screen = get_current_screen();
$documentation_link = '';
switch ( $screen->id ) {
// Component page.
case 'settings_page_bp-components':
case 'settings_page_bp-components-network':
// Help tabs.
$screen->add_help_tab(
array(
'id' => 'bp-comp-overview',
'title' => __( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-comp-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/settings/components.md' ),
esc_html__( 'Managing Components', 'buddypress' )
);
break;
// Rewrites page.
case 'settings_page_bp-rewrites':
case 'settings_page_bp-rewrites-network':
// Help tabs.
$screen->add_help_tab(
array(
'id' => 'bp-rewrites-overview',
'title' => esc_html__( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-rewrites-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/settings/urls.md' ),
esc_html__( 'Managing URLs', 'buddypress' )
);
break;
// Settings page.
case 'settings_page_bp-settings':
case 'settings_page_bp-settings-network':
// Help tabs.
$screen->add_help_tab(
array(
'id' => 'bp-settings-overview',
'title' => esc_html__( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-settings-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/settings/options.md' ),
esc_html__( 'Managing Settings', 'buddypress' )
);
break;
// Profile fields page.
case 'users_page_bp-profile-setup':
case 'users_page_bp-profile-setup-network':
// Help tabs.
$screen->add_help_tab(
array(
'id' => 'bp-profile-overview',
'title' => __( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-profile-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/users/xprofile.md' ),
esc_html__( 'Managing Profile Fields', 'buddypress' )
);
break;
case 'edit-bp_member_type':
// Help tab.
$screen->add_help_tab(
array(
'id' => 'bp-member-types-overview',
'title' => __( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-member-types-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/users/member-types.md' ),
esc_html__( 'Managing Member Types', 'buddypress' )
);
break;
case 'edit-bp_group_type':
// Help tab.
$screen->add_help_tab(
array(
'id' => 'bp-group-types-overview',
'title' => __( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-group-types-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/groups/group-types.md' ),
esc_html__( 'Managing Group Types', 'buddypress' )
);
break;
case 'edit-bp-email':
// Help tab.
$screen->add_help_tab(
array(
'id' => 'bp-emails-overview',
'title' => __( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-emails-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/emails/README.md' ),
esc_html__( 'Managing BP Emails', 'buddypress' )
);
break;
case 'bp-email':
// Help tab.
$screen->add_help_tab(
array(
'id' => 'bp-email-overview',
'title' => __( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-email-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/emails/tokens.md' ),
esc_html__( 'BP Email tokens usage', 'buddypress' )
);
break;
case 'tools_page_bp-tools':
// Help tab.
$screen->add_help_tab(
array(
'id' => 'bp-tools-repair-overview',
'title' => __( 'Overview', 'buddypress' ),
'content' => bp_core_add_contextual_help_content( 'bp-tools-repair-overview' ),
)
);
$documentation_link = sprintf(
'%2$s',
esc_url( 'https://github.com/buddypress/buddypress/blob/master/docs/user/administration/tools/repair.md' ),
esc_html__( 'Using repair tools', 'buddypress' )
);
break;
}
if ( $documentation_link ) {
$bp_forum = sprintf(
'%2$s',
esc_url( 'https://buddypress.org/support/' ),
esc_html__( 'Support Forums', 'buddypress' )
);
// Help panel - sidebar links.
$screen->set_help_sidebar(
'' . esc_html__( 'For more information:', 'buddypress' ) . '
' .
'' . $documentation_link . '
' .
'' . $bp_forum . '
'
);
}
}
add_action( 'load-settings_page_bp-components', 'bp_core_add_contextual_help' );
add_action( 'load-settings_page_bp-rewrites', 'bp_core_add_contextual_help' );
add_action( 'load-settings_page_bp-settings', 'bp_core_add_contextual_help' );
add_action( 'load-users_page_bp-profile-setup', 'bp_core_add_contextual_help' );
add_action( 'bp_admin_load_bp_member_type', 'bp_core_add_contextual_help' );
add_action( 'bp_admin_load_bp_group_type', 'bp_core_add_contextual_help' );
add_action( 'admin_head-tools_page_bp-tools', 'bp_core_add_contextual_help' );
/**
* Renders contextual help content to contextual help tabs.
*
* @since 1.7.0
*
* @param string $tab Optional. Current help content tab.
* @return string
*/
function bp_core_add_contextual_help_content( $tab = '' ) {
switch ( $tab ) {
case 'bp-comp-overview':
$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' );
break;
case 'bp-settings-overview':
$retval = __( 'Extra configuration settings are provided and activated. You can selectively enable or disable any setting by using the form on this screen.', 'buddypress' );
break;
case 'bp-profile-overview':
$retval = __( 'Your users will distinguish themselves through their profile page. Create relevant profile fields that will show on each users profile.', 'buddypress' ) . '
' . __( 'Note: Drag fields from other groups and drop them on the "Signup Fields" tab to include them into your registration form.', 'buddypress' );
break;
case 'bp-debug-settings':
$retval = __( 'Find all the details about your BuddyPress configuration opening the BuddyPress panel of your Site Health info accordion panels. If you need to ask for support, this information will help the BuddyPress community in giving you the right reply to your issue.', 'buddypress' );
break;
case 'bp-rewrites-overview':
$retval = __( 'Customize the page titles and URL slugs for the BuddyPress screens on your site.', 'buddypress' ) . '
' . __( 'The title is the page title displayed above the BuddyPress content. For example, the page title "Members" is shown above the members directory.', 'buddypress' ) . '
' . __( 'A slug is a portion of the URL itself. For instance, "members" is the members directory slug in the following example URL: https://mysite.org/members. Slugs should only include lowercase letters, numbers, and hyphens.', 'buddypress' );
break;
case 'bp-member-types-overview':
$retval = __( 'Member Types in BuddyPress provide a powerful way to classify users within your community. By defining various member types, such as "Students", "Teachers", or "Alumni", you can create a more organized and tailored community environment. This feature is especially useful for communities with diverse user groups, allowing customized interactions, content access, and privileges.', 'buddypress' );
break;
case 'bp-group-types-overview':
$retval = __( 'The Group Types feature categorizes community groups into distinct categories, enhancing the management and personalization of group experiences within the community.', 'buddypress' );
break;
case 'bp-emails-overview':
$retval = __( 'This screen provides access to all BP Emails. Hovering over a row in the BP Emails list will display action links that allow you to manage the corresponding BP Email.', 'buddypress' );
break;
case 'bp-email-overview':
$retval = sprintf(
/* Translators: %s contains braces within a code tag. */
__( 'Phrases wrapped in braces %s are email tokens. Tokens are variable strings that will get replaced with dynamic content when the email gets sent.', 'buddypress' ),
'{{ }}'
);
break;
case 'bp-tools-repair-overview':
$retval = __( 'This is the administration screen to help you perform an assortment of repair tasks when your BuddyPress relationships are out of sync or conduct other bulk operations.', 'buddypress' );
break;
default:
$retval = false;
break;
}
// Wrap text in a paragraph tag.
if ( ! empty( $retval ) ) {
$allowed_tags = array(
'br' => true,
'code' => true,
'strong' => true,
);
$retval = '' . wp_kses( $retval, $allowed_tags ) . '
';
}
return $retval;
}
/** Separator *****************************************************************/
/**
* Add a separator to the WordPress admin menus.
*
* @since 1.7.0
* @since 14.0.0 Added 'bp_admin_separator' filter.
*
* @global array $menu
*/
function bp_admin_separator() {
// Default to always adding.
$add = true;
// Skip if BuddyPress is not network activated and viewing network admin.
if ( is_network_admin() && ! bp_is_network_activated() ) {
$add = false;
}
// Skip if BuddyPress is network activated and viewing site admin.
if ( ! is_network_admin() && bp_is_network_activated() ) {
$add = false;
}
// Prevent duplicate separators when no core menu items exist.
if ( ! bp_current_user_can( 'bp_moderate' ) ) {
$add = false;
}
// Bail if there are no components with admin UI's.
if ( ! bp_is_active( 'activity' ) && ! bp_is_active( 'groups' ) ) {
$add = false;
}
// Force on Site Admin if BuddyPress Core post-types are registered.
if ( is_blog_admin() && bp_current_user_can( 'bp_moderate' ) ) {
// See: BP_Core::register_post_types().
if ( post_type_exists( bp_get_email_post_type() ) || post_type_exists( 'buddypress' ) ) {
$add = true;
}
}
/**
* Filters whether a top-level admin menu separator is added.
*
* @since 14.0.0
*
* @param bool $add Default true. May be false if nothing to separate.
*/
$add = (bool) apply_filters( 'bp_admin_separator', $add );
// Bail if a separator is not necessary.
if ( false === $add ) {
return;
}
global $menu;
// Append a separator to the end of the global menu array.
$menu[] = array( '', 'read', 'separator-buddypress', '', 'wp-menu-separator buddypress' );
}
/**
* Tell WordPress we have a custom menu order.
*
* @since 1.7.0
*
* @param bool $menu_order Optional. Menu order. Default: false.
* @return bool False if user cannot see admin pages, otherwise true.
*/
function bp_admin_custom_menu_order( $menu_order = false ) {
// Bail if user cannot see admin pages.
if ( ! bp_current_user_can( 'bp_moderate' ) ) {
return $menu_order;
}
return true;
}
/**
* Move our custom separator above our custom post types.
*
* @since 1.7.0
*
* @param array $menu_order Optional. Menu Order.
* @return array Modified menu order.
*/
function bp_admin_menu_order( $menu_order = array() ) {
// Bail if user cannot see admin pages.
if ( empty( $menu_order ) || ! bp_current_user_can( 'bp_moderate' ) ) {
return $menu_order;
}
// Initialize our custom order array.
$bp_menu_order = array();
// Menu values.
$last_sep = is_network_admin() ? 'separator1' : 'separator2';
/**
* Filters the custom admin menus.
*
* @since 1.7.0
*
* @param array $value Empty array.
*/
$custom_menus = (array) apply_filters( 'bp_admin_menu_order', array() );
// Bail if no components have top level admin pages.
if ( empty( $custom_menus ) ) {
return $menu_order;
}
// Add our separator to beginning of array.
array_unshift( $custom_menus, 'separator-buddypress' );
// Loop through menu order and do some rearranging.
foreach ( (array) $menu_order as $item ) {
// Position BuddyPress menus above appearance.
if ( $last_sep === $item ) {
// Add our custom menus.
foreach ( (array) $custom_menus as $custom_menu ) {
if ( array_search( $custom_menu, $menu_order, true ) ) {
$bp_menu_order[] = $custom_menu;
}
}
// Add the appearance separator.
$bp_menu_order[] = $last_sep;
// Skip our menu items.
} elseif ( ! in_array( $item, $custom_menus, true ) ) {
$bp_menu_order[] = $item;
}
}
// Return our custom order.
return $bp_menu_order;
}
/** Utility *****************************************************************/
/**
* When using a WP_List_Table, get the currently selected bulk action.
*
* WP_List_Tables have bulk actions at the top and at the bottom of the tables,
* and the inputs have different keys in the $_REQUEST array. This function
* reconciles the two values and returns a single action being performed.
*
* @since 1.7.0
*
* @return string
*/
function bp_admin_list_table_current_bulk_action() {
$action = ! empty( $_REQUEST['action'] ) ? $_REQUEST['action'] : '';
// If the bottom is set, let it override the action.
if ( ! empty( $_REQUEST['action2'] ) && '-1' !== $_REQUEST['action2'] ) {
$action = $_REQUEST['action2'];
}
return $action;
}
/** Menus *********************************************************************/
/**
* Register meta box and associated JS for BuddyPress WP Nav Menu.
*
* @since 1.9.0
*/
function bp_admin_wp_nav_menu_meta_box() {
if ( ! bp_is_root_blog() ) {
return;
}
add_meta_box( 'add-buddypress-nav-menu', __( 'BuddyPress Member', 'buddypress' ), 'bp_admin_do_wp_nav_menu_meta_box', 'nav-menus', 'side', 'default' );
add_action( 'admin_print_footer_scripts', 'bp_admin_wp_nav_menu_restrict_items' );
}
/**
* BP Member nav menu filter to short-circuit WP's query.
*
* @since 7.0.0
*
* @param null $nil A null value.
* @param WP_Query $wp_query The WP_Query instance (passed by reference).
* @return array The BP Member nav items to short-circuit WP's query,
*/
function bp_admin_get_wp_nav_menu_items( $nil, $wp_query ) {
if ( isset( $wp_query->query['orderby'], $wp_query->query['order'] ) && 'post_date' === $wp_query->query['orderby'] && 'DESC' === $wp_query->query['order'] ) {
return bp_nav_menu_get_loggedin_pages();
} elseif ( isset( $wp_query->query['nopaging'] ) && true === $wp_query->query['nopaging'] ) {
return array_merge( bp_nav_menu_get_loggedin_pages(), bp_nav_menu_get_loggedout_pages() );
}
return bp_nav_menu_get_loggedout_pages();
}
/**
* Build and populate the BuddyPress accordion on Appearance > Menus.
*
* @since 1.9.0
* @since 7.0.0 Uses wp_nav_menu_item_post_type_meta_box()
*
* @global int|string $nav_menu_selected_id
*
* @param WP_Post $post Optional. The current post object.
* @param array $box Optional. The meta box arguments.
*/
function bp_admin_do_wp_nav_menu_meta_box( $post = '', $box = array() ) {
global $nav_menu_selected_id;
$box['args'] = (object) array(
'name' => 'bp_nav_menu_item',
'_default_query' => array(),
);
// Temporarly register a post type.
register_post_type(
'bp_nav_menu_item',
array(
'label' => 'BuddyPress',
'labels' => array(
'search_items' => __( 'Search BuddyPress member menu items', 'buddypress' ),
'all_items' => __( 'All BuddyPress Member menu items', 'buddypress' ),
),
'public' => true,
'hierarchical' => false,
'has_archive' => false,
'rewrite' => false,
)
);
// Temporarly override the posts query results.
add_filter( 'posts_pre_query', 'bp_admin_get_wp_nav_menu_items', 10, 2 );
ob_start();
wp_nav_menu_item_post_type_meta_box( 'buddypress', $box );
$output = ob_get_clean();
$get_bp_items = new WP_Query();
$all_bp_items = $get_bp_items->query( array( 'nopaging' => true ) );
$walker = new Walker_Nav_Menu_Checklist();
$all_bp_tabs = sprintf(
'',
esc_html__( 'All BuddyPress Member menu items', 'buddypress' ),
walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $all_bp_items ), 0, (object) array( 'walker' => $walker ) )
);
// Remove temporary post type and filter.
unregister_post_type( 'bp_nav_menu_item' );
remove_filter( 'posts_pre_query', 'bp_admin_get_wp_nav_menu_items' );
$tab_name = 'bp_nav_menu_item-tab';
$current_tab = 'logged-in';
$tabs = array(
'logged-in' => __( 'Logged-In', 'buddypress' ),
'logged-out' => __( 'Logged-Out', 'buddypress' ),
'all' => __( 'All', 'buddypress' ),
);
$tab_urls = array(
'all' => '',
'logged-in' => '',
'logged-out' => '',
);
if ( isset( $_REQUEST[ $tab_name ] ) && in_array( $_REQUEST[ $tab_name ], array_keys( $tabs ), true ) ) {
$current_tab = $_REQUEST[ $tab_name ];
}
$removed_args = array(
'action',
'customlink-tab',
'edit-menu-item',
'menu-item',
'page-tab',
'_wpnonce',
);
if ( $nav_menu_selected_id ) {
$tab_urls['all'] = esc_url( add_query_arg( $tab_name, 'all', remove_query_arg( $removed_args ) ) );
$tab_urls['logged-in'] = esc_url( add_query_arg( $tab_name, 'logged-in', remove_query_arg( $removed_args ) ) );
$tab_urls['logged-out'] = esc_url( add_query_arg( $tab_name, 'logged-out', remove_query_arg( $removed_args ) ) );
}
$bp_tabs_nav = '';
foreach ( $tabs as $tab => $tab_text ) {
$class = '';
$datatype = 'bp_nav_menu_item-' . $tab;
if ( $current_tab === $tab ) {
$class = ' class="tabs"';
}
if ( 'all' !== $tab ) {
$datatype = 'tabs-panel-posttype-bp_nav_menu_item-' . $tab;
}
$bp_tabs_nav .= sprintf(
'
%4$s
',
$class,
$datatype,
esc_url( $tab_urls[ $tab ] ) . '#' . $datatype,
esc_html( $tab_text )
);
}
$output = str_replace(
array(
'tabs-panel-posttype-bp_nav_menu_item-most-recent',
'bp_nav_menu_itemchecklist-most-recent',
'bp_nav_menu_item-all',
'bp_nav_menu_itemchecklist',
),
array(
'tabs-panel-posttype-bp_nav_menu_item-logged-in',
'bp_nav_menu_itemchecklist-logged-in',
'tabs-panel-posttype-bp_nav_menu_item-logged-out',
'bp_nav_menu_itemchecklist-logged-out',
),
$output
);
preg_match( '/\