A BuddyPress component is the perfect approach to adding custom functionality to your BuddyPress installation.
These components are actually the same components used to provide Groups, Activities, Blogs, Forums, Profile Extensions, etc. to BuddyPress out of the box. Other than the code snippet thrown on the codex, there currently wasn’t any tutorials to guide a developer when getting started.
For that reason I’m posting my discoveries here, although I don’t claim to have all the answers myself, I’m simply trying to fill in the gaps while I attempt my first custom component. Most of my findings came from digging through the “BuddyPress Skeleton Component” plugin, as advised from the forums.
First off, we must hook and include our custom class:
function bp_example_load_core_component() { global $bp; $bp->example = new BP_Example_Component; } add_action( 'bp_loaded', 'bp_example_load_core_component' );
Our custom class must extend the BP_Component
class:
“BP_Component is the base class that all BuddyPress components use to set up their basic structure, including global data, navigation elements, and admin bar information. If there’s a particular aspect of this class that is not relevant to your plugin, just leave it out.”
The Constructor
When constructing a BP_Component
, although many things can happen here, at minimum you should invoke the parent::start()
function in order to begin setup routine. This function receives 3 parameters:
- $id – A unique identifier for the component. Letters, numbers, and underscores only.
- $name – This is a translatable name for your component, which will be used in various places through the BuddyPress admin screens to identify it.
- $path – The path to your plugin directory. Primarily, this is used by
BP_Component::includes()
, to include your plugin’s files.
Next you’ll want to add any include files, depending on your components needs, this can include the following suggestions from the skeleton component plugin:
- actions.php – Functions hooked to bp_actions, mainly used to catch action requests (save, delete, etc)
- screens.php – Functions hooked to bp_screens. These are the screen functions responsible for the display of your plugin’s content.
- filters.php – Functions that are hooked via
apply_filters()
- classes.php – Your plugin’s classes. Depending on how you organize your plugin, this could mean: a database query class, a custom post type data schema, and so forth
activity.php – Functions related to the BP Activity Component. This is where you put functions responsible for creating, deleting, and modifying activity items related to your component - template.php – Template tags. These are functions that are called from your templates, or from your screen functions. If your plugin contains its own version of the WordPress Loop (such asbp_example_has_items()), those functions should go in this file.
- functions.php – Miscellaneous utility functions required by your component.
- notifications.php – Functions related to email notification, as well as the BuddyPress notifications that show up in the admin bar.
- widgets.php – If your plugin includes any sidebar widgets, define them in this file.
- buddybar.php – Functions related to the BuddyBar.
- adminbar.php – Functions related to the WordPress Admin Bar.
- cssjs.php – Here is where you set up and enqueue your CSS and JS.
- ajax.php – Functions used in the process of AJAX requests.
Add to Active Components Array
Put your component into the active components array, so that bp_is_active( 'wizard');
returns true when appropriate. We have to do this manually, because non-core components are not saved as active components in the database.
$bp->active_components[$this->id] = '1';
Register Custom Post Type (Optional)
Hook the register_post_types() method. If you’re using custom post types to store data (which is recommended), you will need to hook your function manually to init
.
add_action( 'init', array( $this, 'register_post_types' ) );
Setup Navigation Tabs (Optional)
If you intend to set up screens for your component and you would like navigation tabs then you will need to configure a setup_nav()
method (see class-bp-component.php
for details). Here is a quick example
/** * Setup BuddyBar navigation */ function setup_nav( $main_nav = array(), $sub_nav = array() ) { // Add 'Example' to the main navigation $main_nav = array( 'name' => __( 'Example', 'bp-example' ), 'slug' => bp_get_example_slug(), // setup in bp-{component}-template file 'position' => 80, 'screen_function' => 'bp_example_step_1', 'default_subnav_slug' => 'example-step-1' ); $example_link = trailingslashit( bp_loggedin_user_domain() . bp_get_example_slug() ); // Add a few subnav items under the main Wizard tab $sub_nav[] = array( 'name' => __( 'Example', 'bp-example' ), 'slug' => 'example-step-1', 'parent_url' => $example_link , 'parent_slug' => bp_get_example_slug(), 'screen_function' => 'bp_example_step_1', 'position' => 10 ); parent::setup_nav( $main_nav, $sub_nav ); // If your component needs additional navigation menus that are not handled by // BP_Component::setup_nav(), you can register them manually here. For wizard, // if your component needs a subsection under a user's Settings menu, add // it like this. See bp_wizard_screen_settings_menu() for more info bp_core_new_subnav_item( array( 'name' => __( 'Example', 'bp-example' ), 'slug' => 'example-admin', 'parent_slug' => bp_get_settings_slug(), 'parent_url' => trailingslashit( bp_loggedin_user_domain() . bp_get_settings_slug() ), 'screen_function' => 'bp_example_screen_settings_menu', 'position' => 40, 'user_has_access' => bp_is_my_profile() // Only the logged in user can access this on his/her profile ) ); }
Register Component
Add the component to the registered buddypress components in order to be activated and deactivated like the core BP components by hooking into bp_core_get_components
filter.
/** * Register component information in the buddypress settings */ add_filter( 'bp_core_get_components', array( $this, 'register_component' ), 10, 2 ); /** * Register the component * @param array $components * @param string $type * @return array */ function register_component( $components, $type ) { if( $type == 'optional'){ $component = array( 'wizard' => array( 'title' => __( 'Profile Wizard', 'buddypress' ), 'description' => __( 'Create a process to encourage new members to fill out their profiles on first login', 'buddypress' ) ), ); /* Add this component to registered optional components array */ $components = array_merge( $components, $component ); } /* Return component */ return $components; }
Custom Template Page (Optional)
If you do not wish to keep you content within the buddypress screen container you can replace the template with the following filter hooks:
/* Setup the component's page template */ add_filter( 'bp_template_include', array( $this, 'set_template' ), 10, 2 ); /* Setup a template hierarchy for the component */ add_filter( 'bp_located_template', array( $this, 'add_template_directory' ), 10, 2 );
These will first include your component template
/** * Setup the component's page template * * @param string $template Path to template (probably single.php). * @return string */ function set_template( $template ){ /* If this is not an example page than don't filter the template */ if ( !bp_is_current_component( 'example' ) ) return $template; if( bp_is_example_component() ){ // defined in bp-example-templates.php /* This is going to look in theme/buddypress/example/index.php */ bp_core_load_template( apply_filters( 'example_directory_template', 'example/index' ) ); } return ''; } /** * Setup a template hierarchy for the component * * @param string $found_template * @param array $templates * @return string */ function add_template_directory( $found_template, $templates ){ /* If this is not an example page than don't filter the template */ if ( !bp_is_current_component( 'example' ) ) return $found_template; foreach ( (array) $templates as $template ) { if ( file_exists( STYLESHEETPATH . '/buddypress/' . $template ) ) $filtered_templates[] = STYLESHEETPATH . '/buddypress/' . $template; elseif( file_exists( TEMPLATEPATH . '/buddypress/' . $template ) ) $filtered_templates[] = TEMPLATEPATH . '/buddypress/' . $template; elseif ( file_exists( dirname( __FILE__ ) . '/' . $template ) ) $filtered_templates[] = file_exists( dirname( __FILE__ ) . '/' . $template ); } $found_template = $filtered_templates[0]; return $found_template; }