BuddyPress does a great job integrating new users who register through your WordPress site into the community — optionally synchronizing profile information between BP and WP, and creating an activity feed item for new user signups.
But what about users who login against an external authentication provider, and whose accounts are created and managed by such a system? Today we’re going to look at how to bring those users into the community in the same way as those who registered locally. Be warned — this is a fairly dense piece, especially if you haven’t worked with an authenticate
filter before.
A crash course on authenticate
If you are using (or writing) an external authentication plugin, you’ll need a function hooked to the authenticate
filter. This function is where your plugin gets a chance to authenticate users against your outside system. It is also where your users will have subordinate WordPress accounts made and managed by the external system.
A very quick example:
function my_func_to_authenticate( $user, $username, $password ) { // if $user is a valid WP_User, authenticated by an upstream filter // pass these params to the external auth source for verification // proceed if user is logged in, otherwise return a WP_Error } add_filter( 'authenticate', 'my_func_to_authenticate', 10, 3 ); |
The first login
The first time your users log in to your WordPress install using their external credentials, you’ll probably want to create a WP account for them. You may skip this if you’re just trying to restrict read access, but this is about BuddyPress, so I’m assuming you want them to post and contribute to the site.
Here’s a rundown of the process:
- Suppress the BuddyPress activation email
- Create WP user account
- Update user meta and, optionally, xprofile data
- Activate user and set proper
display_name
- Publish activity stream message about new user, with properly-formatted display name
Suppress the BuddyPress activation email
These users are already verified by virtue of being in our external auth system, so an activation email would just be confusing.
/** Suppress activation key email for users logging in with external auth */ add_filter( 'bp_core_signup_send_activation_key', create_function('','return false;') ); |
Create WordPress user account
Normally, you’d use wp_create_user
(or wp_insert_user
if you want access to the full set of user properties).
But BuddyPress comes with a wrapper function that can be used to do a lot of the heavy lifting for us.
$new_user = bp_core_signup_user( $user_login, $user_password, $user_email, array() ); if( is_wp_error( $new_user ) ) { return $new_user; } |
Update user meta and, optionally, xprofile data
There are actually a few ways to handle this, ranging from bull-in-a-china-shop overwriting to graceful but more complicated filtering. Which one you choose may depend on your comfort with WP or PHP, which BuddyPress features you have enabled, or the structure of your authentication script.
Easiest
$display_name = $first_name . ' ' . $last_name; update_user_meta( $new_user, 'nickname', $display_name ); update_user_meta( $new_user, 'first_name', $first_name ); update_user_meta( $new_user, 'last_name', $last_name ); if( bp_is_active( 'xprofile' ) ) xprofile_set_field_data( bp_xprofile_fullname_field_name(), $new_user, $display_name ); // Even though setting the xprofile value, above, should take care of this, // testing revealed that we needed to prime the cache with the right value wp_cache_set( 'bp_user_fullname_' . $new_user, $display_name, 'bp' ); |
PROS:
- Very straightforward and procedural — no objects or data sharing needed
- Complete control over format of display_name and BP fullname field
- Control over any other BP xprofile values you want to set
- Does not require xprofile or WP-BP profile sync in order to operate
CONS:
- Will ultimately drift out of sync with BP development
- Still need to set the display_name property below
- Might as well use
wp_insert_user
, since we’re manually adding so much
Shortest
Replace the bp_core_signup_user
call above with this:
$new_user = bp_core_signup_user( $login_name, $password, $email, array( 'profile_field_ids' => bp_xprofile_fullname_field_name(), "field_{bp_xprofile_fullname_field_name()}" => $display_name ) ); |
PROS:
- Uses BP to eliminate the need for additional filters or processing
- Least code redundancy of all
- Can supply additional xprofile fields to be added to the new user
- Most natural method in terms of program flow
CONS:
- Complex meta parameter structure can be difficult to read
- Parameter or data structure may change in future BP releases
- Requires xprofile and WP-BP profile sync to update WP display_name and usermeta
Fanciest
function my_display_name_filter( $user_id, $user_login, $user_password, $user_email, $usermeta ) { // must get $display_name from another part of the authentication process if ( bp_is_active( 'xprofile' ) ) { xprofile_set_field_data( bp_xprofile_fullname_field_name(), $new_user, $display_name ); } } |
Change your authenticate function to look like this:
function my_func_to_authenticate( $user, $username, $password ) { // ... authenticate user add_action( 'bp_core_signup_user', 'my_display_name_filter', 9, 5 ); $new_user = bp_core_signup_user( $login_name, $password, $email, array() ); } |
PROS:
- Uses BP filters for forward compatibility
- Reduces the amount of repeated code
CONS:
- Requires an object or data-sharing infrastructure to get user details to the filter
- Requires xprofile and WP-BP profile sync to update WP display_name and usermeta
Now that the xprofile and usermeta data are set up, it’s time to activate the user! This is done by simply setting the
user_status
column to 0
.
Activate user (and set proper display_name, if needed)
Update 08-06-2012: I used to recommend wp_update_user
for this, but that has proven unreliable on a recent project. So to be safe, just use a direct query.
// activate user and set display name appropriately $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->users SET display_name=%s, user_status=0 WHERE ID=%d", $display_name, $new_user ) ); |
And if you set $display_name
above, use the shortened version:
// activate user $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->users SET user_status=0 WHERE ID=%d", $new_user ) ); |
Publish an activity stream message about the new user and notify the site admin
Since the display_name property and associated xprofile field are finally set the way we want them, it’s time to trigger the activity stream message and administrator notification.
bp_core_new_user_activity( $new_user ); wp_new_user_notification( $new_user ); |
And you’re done!
Return a WP_User
object to let other authentication filters know you’ve handled this user.
return new WP_User( $new_user ); |
A complete example
function my_func_to_authenticate( $user, $username, $password ) { // if $user is a valid WP_User, authenticated by an upstream filter if( is_a( $user, 'WP_User' ) ) return $user; // pass these params to the external auth source for verification // proceed if user is logged in, otherwise return a WP_Error if( $user_details = my_external_auth( $username, $password ) ) { // for simplicity's sake, I'm assuming that $user_details is an array with all the right keys // in practice, more checks would be required extract( $user_details ); // this function returns the new user account ID if successful $new_user = bp_core_signup_user( $username, $password, $user_email, array() ); // If signup returned an error, skip the rest if( is_wp_error( $new_user ) ) { return $new_user; } $display_name = $first_name . ' ' . $last_name; update_user_meta( $new_user, 'nickname', $display_name ); update_user_meta( $new_user, 'first_name', $first_name ); update_user_meta( $new_user, 'last_name', $last_name ); if( bp_is_active( 'xprofile' ) ) xprofile_set_field_data( bp_xprofile_fullname_field_name(), $new_user, $display_name ); // Even though setting the xprofile value, above, should take care of this, // testing revealed that we needed to prime the cache with the right value wp_cache_set( 'bp_user_fullname_' . $new_user, $display_name, 'bp' ); // activate user and set display name appropriately $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->users SET display_name=%s, user_status=0 WHERE ID=%d", $display_name, $new_user ) ); bp_core_new_user_activity( $new_user ); wp_new_user_notification( $new_user ); return new WP_User( $new_user ); } // you can return FALSE, or a WP_Error if you have something specific to say return new WP_Error( 'login_failed', __( 'Could not authenticate user' ) ); } add_filter( 'authenticate', 'my_func_to_authenticate', 10, 3 ); |
If you have questions, or if you put this to use in your next project, feel free to drop me a line in the comments!
2 Responses