Globals ************************************************ */ // @deprecated. if ( defined( 'BP_MEMBERS_SLUG' ) ) { _doing_it_wrong( 'BP_MEMBERS_SLUG', esc_html__( 'Slug constants are deprecated.', 'buddypress' ), 'BuddyPress 12.0.0' ); $default_slug = BP_MEMBERS_SLUG; } // Fetch the default directory title. $default_directory_titles = bp_core_get_directory_page_default_titles(); $default_directory_title = $default_directory_titles[$this->id]; // Override any passed args. $args = array( 'slug' => $default_slug, 'root_slug' => isset( $bp->pages->members->slug ) ? $bp->pages->members->slug : $default_slug, 'has_directory' => true, 'rewrite_ids' => array( 'directory' => 'members', 'directory_type' => 'members_type', 'single_item' => 'member', 'single_item_component' => 'member_component', 'single_item_action' => 'member_action', 'single_item_action_variables' => 'member_action_variables', 'member_register' => 'register', 'member_activate' => 'activate', 'member_activate_key' => 'activate_key', ), 'directory_title' => isset( $bp->pages->members->title ) ? $bp->pages->members->title : $default_directory_title, 'search_string' => __( 'Search Members...', 'buddypress' ), 'global_tables' => array( 'table_name_invitations' => bp_core_get_table_prefix() . 'bp_invitations', 'table_name_last_activity' => bp_core_get_table_prefix() . 'bp_activity', 'table_name_optouts' => bp_core_get_table_prefix() . 'bp_optouts', 'table_name_signups' => $wpdb->base_prefix . 'signups', // Signups is a global WordPress table. ), 'notification_callback' => 'members_format_notifications', 'block_globals' => array( 'bp/dynamic-members' => array( 'widget_classnames' => array( 'widget_bp_core_members_widget', 'buddypress' ), ), 'bp/online-members' => array( 'widget_classnames' => array( 'widget_bp_core_whos_online_widget', 'buddypress' ), ), 'bp/active-members' => array( 'widget_classnames' => array( 'widget_bp_core_recently_active_widget', 'buddypress' ), ), ), ); parent::setup_globals( $args ); // Additional globals. $this->setup_additional_globals(); } /** * Set up canonical stack for this component. * * @since 2.1.0 */ public function setup_canonical_stack() { $bp = buddypress(); /** Default Profile Component **************************************** */ if ( bp_displayed_user_has_front_template() ) { $bp->default_component = 'front'; } elseif ( bp_is_active( 'activity' ) && isset( $bp->pages->activity ) ) { $bp->default_component = bp_get_activity_slug(); } else { $bp->default_component = ( 'xprofile' === $bp->profile->id ) ? 'profile' : $bp->profile->id; } if ( defined( 'BP_DEFAULT_COMPONENT' ) && BP_DEFAULT_COMPONENT ) { $default_component = BP_DEFAULT_COMPONENT; if ( 'profile' === $default_component ) { $default_component = 'xprofile'; } if ( bp_is_active( $default_component ) ) { $bp->default_component = BP_DEFAULT_COMPONENT; } } /** Canonical Component Stack **************************************** */ if ( bp_displayed_user_id() ) { $bp->canonical_stack['base_url'] = bp_displayed_user_url(); $action_variables = (array) bp_action_variables(); $path_chunks = bp_members_get_path_chunks( array_merge( array( bp_current_component(), bp_current_action() ), array_filter( $action_variables ) ) ); if ( isset( $path_chunks['single_item_component'] ) ) { $bp->canonical_stack['component'] = $path_chunks['single_item_component']; // The canonical URL will not contain the default component. if ( bp_is_current_component( $bp->default_component ) && ! bp_current_action() ) { unset( $bp->canonical_stack['component'] ); } elseif ( isset( $path_chunks['single_item_action'] ) ) { $bp->canonical_stack['action'] = $path_chunks['single_item_action']; if ( isset( $path_chunks['single_item_action_variables'] ) ) { $bp->canonical_stack['action_variables'] = $path_chunks['single_item_action_variables']; } } // Looking at the single member root/home, so assume the default. } else { $bp->current_component = $bp->default_component; } /* * If we're on a spammer's profile page, only users with the 'bp_moderate' cap * can view subpages on the spammer's profile. * * users without the cap trying to access a spammer's subnav page will get * redirected to the root of the spammer's profile page. this occurs by * by removing the component in the canonical stack. */ if ( bp_is_user_spammer( bp_displayed_user_id() ) && ! bp_current_user_can( 'bp_moderate' ) ) { unset( $bp->canonical_stack['component'] ); } } } /** * Get the Avatar and Cover image subnavs. * * @since 6.0.0 * @deprecated 12.0.0 * * @return array The Avatar and Cover image subnavs. */ public function get_avatar_cover_image_subnavs() { _deprecated_function( __METHOD__, '12.0.0' ); } /** * Register component navigation. * * @since 12.0.0 * * @see `BP_Component::register_nav()` for a description of arguments. * * @param array $main_nav Optional. See `BP_Component::register_nav()` for * description. * @param array $sub_nav Optional. See `BP_Component::register_nav()` for * description. */ public function register_nav( $main_nav = array(), $sub_nav = array() ) { // Set slug to profile in case the xProfile component is not active $slug = bp_get_profile_slug(); $main_nav = array( 'name' => _x( 'Profile', 'Member profile main navigation', 'buddypress' ), 'slug' => $slug, 'position' => 20, 'screen_function' => 'bp_members_screen_display_profile', 'default_subnav_slug' => 'public', 'item_css_id' => buddypress()->profile->id, 'generate' => ! bp_is_active( 'xprofile' ), ); $sub_nav[] = array( 'name' => _x( 'View', 'Member profile view', 'buddypress' ), 'slug' => 'public', 'parent_slug' => $slug, 'screen_function' => 'bp_members_screen_display_profile', 'position' => 10, 'generate' => ! bp_is_active( 'xprofile' ), ); $sub_nav[] = array( 'name' => _x( 'Change Profile Photo', 'Profile header sub menu', 'buddypress' ), 'slug' => 'change-avatar', 'parent_slug' => $slug, 'screen_function' => 'bp_members_screen_change_avatar', 'position' => 30, 'user_has_access' => false, 'user_has_access_callback' => 'bp_core_can_edit_settings', 'generate' => buddypress()->avatar->show_avatars, ); $sub_nav[] = array( 'name' => _x( 'Change Cover Image', 'Profile header sub menu', 'buddypress' ), 'slug' => 'change-cover-image', 'parent_slug' => $slug, 'screen_function' => 'bp_members_screen_change_cover_image', 'position' => 40, 'user_has_access' => false, 'user_has_access_callback' => 'bp_core_can_edit_settings', 'generate' => bp_displayed_user_use_cover_image_header(), ); parent::register_nav( $main_nav, $sub_nav ); } /** * Set up a profile nav in case the xProfile * component is not active and a front template is * used. * * @since 2.6.0 * @deprecated 12.0.0 */ public function setup_profile_nav() { _deprecated_function( __METHOD__, '12.0.0' ); } /** * Set up the xProfile nav. * * @since 6.0.0 * @deprecated 12.0.0 */ public function setup_xprofile_nav() { _deprecated_function( __METHOD__, '12.0.0' ); } /** * Get the Avatar and Cover image admin navs. * * @since 6.0.0 * * @param string $admin_bar_menu_id The Admin bar menu ID to attach sub items to. * @return array The Avatar and Cover image admin navs. */ public function get_avatar_cover_image_admin_navs( $admin_bar_menu_id = '' ) { $wp_admin_nav = array(); $profile_slug = bp_get_profile_slug(); if ( ! $admin_bar_menu_id ) { $admin_bar_menu_id = $this->id; } // Edit Avatar. if ( buddypress()->avatar->show_avatars ) { $wp_admin_nav[] = array( 'parent' => 'my-account-' . $admin_bar_menu_id, 'id' => 'my-account-' . $admin_bar_menu_id . '-change-avatar', 'title' => _x( 'Change Profile Photo', 'My Account Profile sub nav', 'buddypress' ), 'href' => bp_loggedin_user_url( bp_members_get_path_chunks( array( $profile_slug, 'change-avatar' ) ) ), 'position' => 30, ); } // Edit Cover Image if ( bp_displayed_user_use_cover_image_header() ) { $wp_admin_nav[] = array( 'parent' => 'my-account-' . $admin_bar_menu_id, 'id' => 'my-account-' . $admin_bar_menu_id . '-change-cover-image', 'title' => _x( 'Change Cover Image', 'My Account Profile sub nav', 'buddypress' ), 'href' => bp_loggedin_user_url( bp_members_get_path_chunks( array( $profile_slug, 'change-cover-image' ) ) ), 'position' => 40, ); } return $wp_admin_nav; } /** * Set up the Admin Bar. * * @since 6.0.0 * * @param array $wp_admin_nav Admin Bar items. */ public function setup_admin_bar( $wp_admin_nav = array() ) { // Menus for logged in user. if ( is_user_logged_in() ) { $profile_slug = bp_get_profile_slug(); if ( ! bp_is_active( 'xprofile' ) ) { // Add the "Profile" sub menu. $wp_admin_nav[] = array( 'parent' => buddypress()->my_account_menu_id, 'id' => 'my-account-' . $this->id, 'title' => _x( 'Profile', 'My Account Profile', 'buddypress' ), 'href' => bp_loggedin_user_url( bp_members_get_path_chunks( array( $profile_slug ) ) ), ); // View Profile. $wp_admin_nav[] = array( 'parent' => 'my-account-' . $this->id, 'id' => 'my-account-' . $this->id . '-public', 'title' => _x( 'View', 'My Account Profile sub nav', 'buddypress' ), 'href' => bp_loggedin_user_url( bp_members_get_path_chunks( array( $profile_slug, 'public' ) ) ), 'position' => 10, ); $wp_admin_nav = array_merge( $wp_admin_nav, $this->get_avatar_cover_image_admin_navs() ); /** * The xProfile is active. * * Add the Change Avatar and Change Cover Image Admin Bar items * to the xProfile Admin Bar Menu. */ } else { add_filter( 'bp_xprofile_admin_nav', array( $this, 'setup_xprofile_admin_nav' ), 2 ); } } parent::setup_admin_bar( $wp_admin_nav ); } /** * Adds "Profile > Change Avatar" & "Profile > Change Cover Image" subnav item * under the "Profile" adminbar menu. * * @since 6.0.0 * * @param array $wp_admin_nav The Profile adminbar nav array. * @return array */ public function setup_xprofile_admin_nav( $wp_admin_nav ) { $items = $this->get_avatar_cover_image_admin_navs( buddypress()->profile->id ); if ( $items ) { $wp_admin_nav = array_merge( $wp_admin_nav, $items ); } return $wp_admin_nav; } /** * Set up the title for pages and . * * @since 1.5.0 */ public function setup_title() { $bp = buddypress(); if ( bp_is_my_profile() ) { $bp->bp_options_title = __( 'You', 'buddypress' ); } elseif ( bp_is_user() ) { $bp->bp_options_title = bp_get_displayed_user_fullname(); $bp->bp_options_avatar = bp_core_fetch_avatar( array( 'item_id' => bp_displayed_user_id(), 'type' => 'thumb', /* translators: %s: member name */ 'alt' => sprintf( __( 'Profile picture of %s', 'buddypress' ), $bp->bp_options_title ) ) ); } parent::setup_title(); } /** * Setup cache groups. * * @since 2.2.0 */ public function setup_cache_groups() { // Global groups. wp_cache_add_global_groups( array( 'bp_last_activity', 'bp_member_member_type', ) ); parent::setup_cache_groups(); } /** * Adds the Members directory type, Registration and Activation rewrite tags. * * @since 12.0.0 * * @param array $rewrite_tags Optional. See BP_Component::add_rewrite_tags() for * description. */ public function add_rewrite_tags( $rewrite_tags = array() ) { $rewrite_tags = array( 'directory_type' => '([^/]+)', 'member_register' => '([1]{1,})', 'member_activate' => '([1]{1,})', 'member_activate_key' => '([^/]+)', ); parent::add_rewrite_tags( $rewrite_tags ); } /** * Adds the Registration and Activation rewrite rules. * * @since 12.0.0 * * @param array $rewrite_rules Optional. See BP_Component::add_rewrite_rules() for * description. */ public function add_rewrite_rules( $rewrite_rules = array() ) { $rewrite_rules = array( 'directory_type' => array( 'regex' => $this->root_slug . '/' . bp_get_members_member_type_base() . '/([^/]+)/?$', 'order' => 50, 'query' => 'index.php?' . $this->rewrite_ids['directory'] . '=1&' . $this->rewrite_ids['directory_type'] . '=$matches[1]', ), 'member_activate' => array( 'regex' => bp_get_activate_slug() . '/?$', 'order' => 40, 'query' => 'index.php?' . $this->rewrite_ids['member_activate'] . '=1', ), 'member_activate_key' => array( 'regex' => bp_get_activate_slug() . '/([^/]+)/?$', 'order' => 30, 'query' => 'index.php?' . $this->rewrite_ids['member_activate'] . '=1&' . $this->rewrite_ids['member_activate_key'] . '=$matches[1]', ), 'member_register' => array( 'regex' => bp_get_signup_slug() . '/?$', 'order' => 20, 'query' => 'index.php?' . $this->rewrite_ids['member_register'] . '=1', ), ); parent::add_rewrite_rules( $rewrite_rules ); } /** * Adds the Registration and Activation permastructs. * * @since 12.0.0 * * @param array $permastructs Optional. See BP_Component::add_permastructs() for * description. */ public function add_permastructs( $permastructs = array() ) { $permastructs = array( // Register permastruct. $this->rewrite_ids['member_register'] => array( 'permastruct' => $this->register_permastruct, 'args' => array(), ), // Activate permastruct. $this->rewrite_ids['member_activate'] => array( 'permastruct' => $this->activate_permastruct, 'args' => array(), ), ); parent::add_permastructs( $permastructs ); } /** * Parse the WP_Query and eventually display the component's directory or single item. * * @since 12.0.0 * * @param WP_Query $query Required. See BP_Component::parse_query() for * description. */ public function parse_query( $query ) { /* * If BP Rewrites are not in use, no need to parse BP URI globals another time. * Legacy Parser should have already set these. */ if ( 'rewrites' !== bp_core_get_query_parser() ) { return parent::parse_query( $query ); } // Init the current member and member type. $member = false; $member_type = false; $member_data = bp_rewrites_get_member_data(); if ( isset( $member_data['object'] ) && $member_data['object'] ) { bp_reset_query( trailingslashit( $this->root_slug ) . $GLOBALS['wp']->request, $query ); $member = $member_data['object']; // Make sure the Member's screen is fired. add_action( 'bp_screens', 'bp_members_screen_display_profile', 3 ); } if ( bp_is_site_home() && bp_is_directory_homepage( $this->id ) ) { $query->set( $this->rewrite_ids['directory'], 1 ); } // Which component are we displaying? $is_members_component = 1 === (int) $query->get( $this->rewrite_ids['directory'] ); $is_register_component = 1 === (int) $query->get( $this->rewrite_ids['member_register'] ); $is_activate_component = 1 === (int) $query->get( $this->rewrite_ids['member_activate'] ); // Get BuddyPress main instance. $bp = buddypress(); if ( $is_members_component ) { $bp->current_component = 'members'; $member_slug = $query->get( $this->rewrite_ids['single_item'] ); $member_type_slug = $query->get( $this->rewrite_ids['directory_type'] ); if ( $member_slug ) { /** * Filter the portion of the URI that is the displayed user's slug. * * Eg. example.com/ADMIN (when root profiles is enabled) * example.com/members/ADMIN (when root profiles isn't enabled) * * ADMIN would be the displayed user's slug. * * @since 2.6.0 * * @param string $member_slug */ $member_slug = apply_filters( 'bp_core_set_uri_globals_member_slug', $member_slug ); $bp->current_component = ''; // Unless root profiles are on, the member shouldn't be set yet. if ( ! $member ) { $member = get_user_by( $member_data['field'], $member_slug ); if ( ! $member ) { bp_do_404(); return; } } // If the member is marked as a spammer, 404 (unless logged-in user is a super admin). if ( bp_is_user_spammer( $member->ID ) ) { if ( bp_current_user_can( 'bp_moderate' ) ) { bp_core_add_message( __( 'This user has been marked as a spammer. Only site admins can view this profile.', 'buddypress' ), 'warning' ); } else { bp_do_404(); return; } } // Set the displayed user and the current item. $bp->displayed_user->id = $member->ID; $bp->current_item = $member_slug; // The core userdata of the user who is currently being displayed. if ( ! isset( $bp->displayed_user->userdata ) || ! $bp->displayed_user->userdata ) { $bp->displayed_user->userdata = bp_core_get_core_userdata( bp_displayed_user_id() ); } // Fetch the full name displayed user. if ( ! isset( $bp->displayed_user->fullname ) || ! $bp->displayed_user->fullname ) { $bp->displayed_user->fullname = ''; if ( isset( $bp->displayed_user->userdata->display_name ) ) { $bp->displayed_user->fullname = $bp->displayed_user->userdata->display_name; } } // The domain for the user currently being displayed. if ( ! isset( $bp->displayed_user->domain ) || ! $bp->displayed_user->domain ) { $bp->displayed_user->domain = bp_members_get_user_url( bp_displayed_user_id() ); } // If a user is displayed, check if there is a front template and reset navigation. if ( bp_get_displayed_user() ) { $bp->displayed_user->front_template = bp_displayed_user_get_front_template(); // Reset the nav for the members component. $this->nav = new BP_Core_Nav(); } $member_component = $query->get( $this->rewrite_ids['single_item_component'] ); if ( $member_component ) { // Check if the member's component slug has been customized. $item_component_rewrite_id = bp_rewrites_get_custom_slug_rewrite_id( 'members', $member_component ); if ( $item_component_rewrite_id ) { $member_component = str_replace( 'bp_member_', '', $item_component_rewrite_id ); } $bp->current_component = $member_component; } $current_action = $query->get( $this->rewrite_ids['single_item_action'] ); if ( $current_action ) { $context = sprintf( 'bp_member_%s_', $bp->current_component ); // Check if the member's component action slug has been customized. $item_component_action_rewrite_id = bp_rewrites_get_custom_slug_rewrite_id( 'members', $current_action, $context ); if ( $item_component_action_rewrite_id ) { $custom_action_slug = str_replace( $context, '', $item_component_action_rewrite_id ); // Make sure the action is stored as a slug: underscores need to be replaced by dashes. $current_action = str_replace( '_', '-', $custom_action_slug ); } $bp->current_action = $current_action; } $action_variables = $query->get( $this->rewrite_ids['single_item_action_variables'] ); if ( $action_variables ) { $context = sprintf( 'bp_member_%1$s_%2$s_', $bp->current_component, $bp->current_action ); if ( ! is_array( $action_variables ) ) { $action_variables = explode( '/', ltrim( $action_variables, '/' ) ); } foreach ( $action_variables as $key_variable => $action_variable ) { $item_component_action_variable_rewrite_id = bp_rewrites_get_custom_slug_rewrite_id( 'members', $action_variable, $context ); if ( $item_component_action_variable_rewrite_id ) { $action_variables[ $key_variable ] = str_replace( $context, '', $item_component_action_variable_rewrite_id ); } } $bp->action_variables = $action_variables; } // Is this a member type query? } elseif ( $member_type_slug ) { $member_type = bp_get_member_types( array( 'has_directory' => true, 'directory_slug' => $member_type_slug, ) ); if ( $member_type ) { $member_type = reset( $member_type ); $bp->current_member_type = $member_type; } else { $bp->current_component = ''; bp_do_404(); return; } } // Set the BuddyPress queried object. if ( isset( $bp->pages->members->id ) ) { $query->queried_object = get_post( $bp->pages->members->id ); $query->queried_object_id = $query->queried_object->ID; if ( $member ) { $query->queried_object->single_item_name = $member->display_name; } elseif ( $member_type ) { $query->queried_object->directory_type_name = $member_type; } } // Handle the custom registration page. } elseif ( $is_register_component ) { $bp->current_component = 'register'; // Handle the custom activation page. } elseif ( $is_activate_component ) { $bp->current_component = 'activate'; $current_action = $query->get( $this->rewrite_ids['member_activate_key'] ); if ( $current_action ) { $bp->current_action = $current_action; } } parent::parse_query( $query ); } /** * Check the parsed query is consistent with Members navigation. * * As the members’ component pages need a valid screen function to load the right BP Template, * we need to make sure the current single item action exists inside the Members navigation and * that the corresponding screen function is a valid callback. * * @since 12.0.0 */ public function check_parsed_query() { if ( bp_is_user() ) { $single_item_component = bp_current_component(); $single_item_action = ''; if ( $single_item_component ) { $single_item_action = bp_current_action(); } // Viewing a single activity. if ( 'activity' === $single_item_component && is_numeric( $single_item_action ) ) { return; } $bp = buddypress(); if ( ! bp_is_active( $single_item_component ) && ! $bp->members->nav->get_primary( array( 'slug' => $single_item_component ), false ) ) { bp_do_404(); return; } // Navigation is generated by a component. if ( isset( $bp->{$single_item_component} ) ) { $screen_function = ''; if ( isset( $bp->{$single_item_component}->sub_nav ) ) { $screen_functions = wp_list_pluck( $bp->{$single_item_component}->sub_nav, 'screen_function', 'slug' ); if ( isset( $screen_functions[ $single_item_action ] ) ) { $screen_function = $screen_functions[ $single_item_action ]; } } // Check if this nav item has been added from outside the Component's class. if ( ! $screen_function ) { $sub_nav = $this->nav->get( $single_item_component . '/' . $single_item_action ); if ( isset( $sub_nav->screen_function ) && $sub_nav->screen_function ) { $screen_function = $sub_nav->screen_function; } } if ( ! $single_item_action || ! $screen_function || ! is_callable( $screen_function ) ) { bp_do_404(); return; } // Navigation is not generated by a component. } else { $sub_nav = $bp->members->nav->get_secondary( array( 'parent_slug' => $single_item_component, 'slug' => $single_item_action, ), false ); if ( ! $sub_nav ) { bp_do_404(); return; } } } } /** * Init the BP REST API. * * @since 5.0.0 * @since 6.0.0 Adds the Member Cover and Signup REST endpoints. * @since 9.0.0 Moves the `BP_REST_Components_Endpoint` controller in `BP_Core` component. * * @param array $controllers Optional. See BP_Component::rest_api_init() for * description. */ public function rest_api_init( $controllers = array() ) { $controllers = array( 'BP_REST_Members_Endpoint', 'BP_REST_Attachments_Member_Avatar_Endpoint', ); if ( bp_is_active( 'members', 'cover_image' ) ) { $controllers[] = 'BP_REST_Attachments_Member_Cover_Endpoint'; } if ( bp_get_signup_allowed() ) { $controllers[] = 'BP_REST_Signup_Endpoint'; } parent::rest_api_init( $controllers ); } /** * Register the BP Members Blocks. * * @since 6.0.0 * @since 12.0.0 Use the WP Blocks API v2. * * @param array $blocks Optional. See BP_Component::blocks_init() for * description. */ public function blocks_init( $blocks = array() ) { parent::blocks_init( array( 'bp/member' => array( 'metadata' => trailingslashit( buddypress()->plugin_dir ) . 'bp-members/blocks/member', 'render_callback' => 'bp_members_render_member_block', ), 'bp/members' => array( 'metadata' => trailingslashit( buddypress()->plugin_dir ) . 'bp-members/blocks/members', 'render_callback' => 'bp_members_render_members_block', ), 'bp/dynamic-members' => array( 'metadata' => trailingslashit( buddypress()->plugin_dir ) . 'bp-members/blocks/dynamic-members', 'render_callback' => 'bp_members_render_dynamic_members_block', ), 'bp/online-members' => array( 'metadata' => trailingslashit( buddypress()->plugin_dir ) . 'bp-members/blocks/online-members', 'render_callback' => 'bp_members_render_online_members_block', ), 'bp/active-members' => array( 'metadata' => trailingslashit( buddypress()->plugin_dir ) . 'bp-members/blocks/active-members', 'render_callback' => 'bp_members_render_active_members_block', ), ) ); } }