BP 11: bp_has_profile() Now Accepts an Array of Profile Group IDs

In the upcoming BuddyPress 11.0 release, we’ve added some developer frosting 🧁 to make working with profile groups more straightforward. The template function bp_has_profile() and its underlying function BP_XProfile_Group::get() now accept a single profile group ID or an array of profile group IDs, making it easier to loop through your members’ profile data.

For example, the following code:

<?php
$profile_args = array(
    'user_id'          => 1,
    'profile_group_id' => array( 1, 2 ),
);

if ( bp_has_profile( $profile_args ) ) :
    while ( bp_profile_groups() ) : bp_the_profile_group();
        if ( bp_profile_group_has_fields() ) : ?>
            <h2><?php bp_the_profile_group_name(); ?></h2>

            <table class="profile-fields">

                <?php while ( bp_profile_fields() ) : bp_the_profile_field(); ?>

                    <?php if ( bp_field_has_data() ) : ?>

                        <tr<?php bp_field_css_class(); ?>>

                            <td class="label"><?php bp_the_profile_field_name(); ?></td>

                            <td class="data"><?php bp_the_profile_field_value(); ?></td>

                        </tr>

                    <?php endif; ?>

                <?php endwhile; ?>

            </table>

        <?php
        endif;
    endwhile;
endif;

produces the following output:

Without having to add an extra profile group loop! You can test this new functionality out in the most recent BuddyPress v11 release beta.

BP 11: Fetch Activities for or Excluding a Group of Users

Coming soon in 11.0, we’ve made it possible to fetch activity items for a specific group of users, or to fetch activity items excluding a group of users. The new parameters are user_id__in and user_id__not_in, following a familiar WordPress naming convention.

<?php 
// A couple of users are so cool I would like to do something
// featuring just their updates 
$activity_args = array(
	'user_id__in' => array( 3, 7 ),
);

$activity_items = bp_activity_get( $activity_args );

foreach ( $activity_items as $activity ) {
	// Do soemthing interesting with these activities...
}
?>

Or to find activities, excluding updates from users with the ID 3 and 7, simply use the other new option.

<?php 
// I'd like to block updates from a couple of annoying users. 😮
$activity_args = array(
	'user_id__not_in' => array( 3, 7 ),
);

$activity_items = bp_activity_get( $activity_args );

foreach ( $activity_items as $activity ) {
	// Do soemthing interesting with these activities...
}
?>

This change is simple but powerful! For instance, you could create custom interest activity streams, or build a mute feature to let your members take a break from other, too-chatty users!. 🙂

BP 8.0 Introduces Site Membership Invitations

With the release of BuddyPress 8.0, your BuddyPress community can grow organically by referral, attracting new members with personalized invitations from existing members. This feature is deactivated by default but can easily be enabled by visiting the BuddyPress Options screen at WP Admin > Settings > BuddyPress > Options. Enable membership invitations by ticking the checkbox labeled “Allow registered members to invite people to join this network.”

The BuddyPress Options screen, with the new invitations option highlighted.

When invitations are enabled, users can accept an invitation and register for your site even if “Anyone can register” is disabled. This means you can disable public registration and enable invitations to create a site with membership by invitation only. Or, enable public registration and use invitations as just another way to spread the word about your community.

Once invitations are enabled, your members will have access to an Invitations tab in their member profiles. Simply enter a valid email address and optionally add a personalized message to send an invitation to the new potential member via email.

The new member invitations "send invites" screen in a member's profile.

Once invitations are sent, a member can view a list of pending invitations and resend the email or cancel the invitation.

The new member invitations "pending invites" screen in a member's profile.

The invitee receives an email that includes a link to the registration form (with a customized acceptance key that allows access even if public registration is disabled). The message also includes the personalized message from the inviting user and an unsubscribe link which allows the invitee to opt out from future invitations from your site. The email’s content is customizable via the BuddyPress Emails admin interface.

The email sent to the invited user containing a personalized message and acceptance and opt-out links.

If the invitee chooses to accept the invitation, he or she can follow the customized link to the registration form.

The customized registration form that is reached by accepting an invitation.

When a new membership is the result of an invitation, the activity item will be expanded to include the name of the inviter.

The expanded activity item when a new membership is the result of an invitation.

Administration Tools

BuddyPress site admins can also view a list of all invitations and opt-outs from the WP Admin dashboard. The new screens are available at Tools > BuddyPress.

On the “Manage Invitations” screen, site admins can view pending and accepted invitations and choose to resend the email or cancel the invitation.

The WP Admin "Manage Invitation" screen available to BP site admins.

On the “Manage Opt-outs” screen, site admins can see opt-out requests, with a record of what type of email resulted in the opt-out request, and who sent the email. This screen can be used to see if any particular component or plugin or user is abusing the system to send unwanted emails that result in many opt-outs. It is also possible find a specific opt-out by searching for an email address, which is useful, for example, in the case where a user who has previously opted out changes his or her mind and would like to have the opt-out request deleted. Note that the email addresses associated with an opt-out request are hashed before being stored in the database.

The WP Admin "Manage Opt-outs" screen available to BP site admins.

We hope this new feature enriches your BuddyPress commmunity by attracting new, engaged members!

#8-0-0, #invitations, #members

New Invitations API Coming in BuddyPress 5.0

As part of BuddyPress 5.0, we’ve included a new core API for managing invitations. This API stores data in a new table, bp_invitations, and introduces new classes to handle working with invitations stored in the new table. The API clears the way for the development of useful  features like site invitations (hopefully coming in 5.1) but starts by handling group invitations and membership requests.

For most users and developers, the changes will be subtle. Existing group invitations will be migrated to the invitations table, and the current behaviors have been maintained. Managing invitations and requests will still be accomplished using familiar functions like groups_invite_user() or groups_accept_membership_request(). Queries made using BP_Group_Member_Query will continue to work as expected.

However, if you are directly querying the bp_groups_members table to find invitations and membership requests, these queries will no longer work, since the pending memberships will be stored in the new bp_invitations table. Happily, we’ve introduced several new functions, like groups_get_invites() and groups_get_requests(), that make finding invitations easier and more reliable.

The signatures of several functions have changed from accepting one or two parameters to accepting an array of parameters to support the new flexibility of the underlying API. The following functions now accept an array of parameters and will issue a deprecation notice if standard parameters are passed into them:

  • groups_send_invites()
  • groups_send_membership_request()

Three membership request management functions have also changed from accepting a membership_id as the first parameter to relying on the user_id and group_id parameters to find the correct request to change:

  • groups_accept_membership_request()
  • groups_reject_membership_request()
  • groups_delete_membership_request()

Other improvements include the following:

  • BP_Invitation objects are cached
  • Queries made via the BP_Invitation class are cached
  • Extension is straightforward; see BP_Groups_Invitation_Manager for an example
  • Many scattered direct queries have been replaced by calls to the API
  • Messages included in invitations and requests are now included in the notice email

If you have any questions or comments, please let us know.

BuddyPress 2.6.0 Release Candidate 1…

BuddyPress 2.6.0 Release Candidate 1 is now available for testing. Please let us know of any issues via our issues tracker or on the BuddyPress support forums.

Thanks in advance for your help!

Changes to Some Extended Profile Input Types in BP 2.6.0

For BuddyPress 2.6.0, the core team worked to improve the structure of several extended profile input field types to improve the accessibility of the fields and also make them easier for developers to style. The field types that have been updated are checkboxes, radio buttons, and date boxes.

All three types have been restructured as <fieldset>s with the label for the field residing in the field set’s <legend>.

Checkboxes and radio buttons options have been wrapped in a new <div> with the class input-options and either checkbox-options or radio-button-options. Additionally, the labels for the individual options have been given the class option-label. These changes taken together should make it much easier to target option labels to apply styling. (Goodbye .selector > label + label to catch option labels!)

Date boxes have similarly gained a wrapper <div> with the classes input-options and datebox-selects around the three selects.

Here are some examples of how the code output for these fields has changed:

<!-- Checkbox inputs, before changes -->
<div class="editfield field_2 field_core-makeup optional-field visibility-public alt field_type_checkbox">
  <div class="checkbox">
    <label for="field_2">Core makeup</label>
    <label for="field_11_0"><input name="field_2[]" id="field_11_0" value="Goat" type="checkbox">Goat</label>
    <label for="field_12_1"><input name="field_2[]" id="field_12_1" value="Rhinoceros" type="checkbox">Rhinoceros</label>
    <label for="field_13_2"><input name="field_2[]" id="field_13_2" value="Slow Loris" type="checkbox">Slow Loris</label>
  </div>
</div>

<!-- Checkbox inputs, after changes -->
<div class="editfield field_2 field_core-makeup optional-field visibility-public alt field_type_checkbox">  
  <fieldset class="checkbox">
    <legend>Core makeup</legend>
    <div id="field_2" class="input-options checkbox-options">
      <label for="field_11_0" class="option-label"><input name="field_2[]" id="field_11_0" value="Goat" type="checkbox">Goat</label>
      <label for="field_12_1" class="option-label"><input name="field_2[]" id="field_12_1" value="Rhinoceros" type="checkbox">Rhinoceros</label>
      <label for="field_13_2" class="option-label"><input name="field_2[]" id="field_13_2" value="Slow Loris" type="checkbox">Slow Loris</label>
    </div>
  </fieldset>
</div>

<!-- Radio button inputs, before changes -->
<div class="editfield field_6 field_home-turf optional-field visibility-public field_type_radio">
  <div class="radio">
    <label for="field_6">Home turf</label>
    <div id="field_6">
      <label for="option_7"><input name="field_6" id="option_7" value="Honali" type="radio">Honali</label>
      <label for="option_8"><input name="field_6" id="option_8" value="Fantastica" type="radio">Fantastica</label>
      <label for="option_9"><input name="field_6" id="option_9" value="Toledo" type="radio">Toledo</label>
    </div>
  </div>
</div>

<!-- Radio button inputs, after changes -->
<div class="editfield field_6 field_home-turf optional-field visibility-public field_type_radio">
  <fieldset class="radio">
    <legend>Home turf</legend>
    <div id="field_6" class="input-options radio-button-options">
      <label for="option_7" class="option-label"><input name="field_6" id="option_7" value="Honali" type="radio">Honali</label>
      <label for="option_8" class="option-label"><input name="field_6" id="option_8" value="Fantastica" type="radio">Fantastica</label>
      <label for="option_9" class="option-label"><input name="field_6" id="option_9" value="Toledo" type="radio">Toledo</label>
    </div>      
  </fieldset>
</div>

<!-- Date box inputs, before changes -->
<div class="editfield field_10 field_birth-date optional-field visibility-public alt field_type_datebox">
  <div class="datebox">
    <label for="field_10_day">Birth date</label>
      
    <label for="field_10_day" class="bp-screen-reader-text">Select day</label>
    <select id="field_10_day" name="field_10_day">
      ...Day options...
    </select>

    <label for="field_10_month" class="bp-screen-reader-text">Select month</label>
    <select id="field_10_month" name="field_10_month">
      ...Month options...
    </select>

    <label for="field_10_year" class="bp-screen-reader-text">Select year</label>
    <select id="field_10_year" name="field_10_year">
      ...Year options...    
    </select>
  </div>
</div>

<!-- Date box inputs, after changes -->
<div class="editfield field_10 field_birth-date optional-field visibility-public alt field_type_datebox">
  <fieldset class="datebox">
    <legend>Birth date</legend>

    <div class="input-options datebox-selects">
      <label for="field_10_day" class="bp-screen-reader-text">Select day</label>
      <select id="field_10_day" name="field_10_day">
        ...Day options...
      </select>

      <label for="field_10_month" class="bp-screen-reader-text">Select month</label>
      <select id="field_10_month" name="field_10_month">
        ...Month options...
      </select>

      <label for="field_10_year" class="bp-screen-reader-text">Select year</label>
      <select id="field_10_year" name="field_10_year">
        ...Year options...
      </select>
    </div>
  </fieldset>
</div>

These changes represent a continued effort to update and improve BP templates and the markup they use. In this case we’ve aimed for improved accessibility by structuring our form markup using meaningful groupings of semantic elements and homogenized rendering across browsers and devices. If you have styled the above-mentioned form controls, please review your styles and make the necessary changes, if any.

Read more about these changes at #7083 and #6678.

#6678, #7083

BuddyPress 2.6.0 Beta 1

BuddyPress 2.6.0 Beta 1 is now available. Thanks in advance for helping us find problems by testing the beta on your weird multi-network setups!

BuddyPress Work Parties

At the end of the 2.5 development cycle, a rare event occurred: many friends of BuddyPress happened to be working together (I mean at the same time and in the same Slack channel–we always work together in spirit 🙂 ). It was super productive and entertaining, to boot. Let’s try to harness the magic again.

If you’d like to help out, please join us at these times:

  • Tuesday, April 5, 1400–1700
  • Thursday, April 14, 1900–2200

You can help out by adding new tickets, commenting on tickets, testing patches, writing patches, writing content for the Codex, answering questions on the BuddyPress support forum, or offering moral support. We’d love to have you.

#work-party