Developer Documentation – BuddyPress Edit Activity

Get Started

Core Features

  • Front-end Editing: Users can edit their activity posts directly from the activity stream
  • Time-based Restrictions: Admins can set time limits for how long users can edit their posts
  • Seamless Integration: Works with standard BuddyPress themes and templates
  • Visual Feedback: Shows “(edited)” indicator on posts that have been modified
  • Security: Only post authors and admins can edit content

Technical Architecture

The plugin follows the WordPress plugin architecture pattern with separate admin and public-facing components:

buddypress-edit-activity/
├── admin/              # Admin-specific functionality
├── includes/           # Core plugin files
├── public/             # Front-end functionality
├── languages/          # Internationalization
└── edd-license/        # Licensing system

Available Hooks

Filters

  1. buddypress_edit_activity_duration
    • Purpose: Modify the duration (in minutes) during which users can edit their activities
    • Parameters: $duration (int)
    • Default: Varies based on admin settings (Forever, 30 days, 7 days, 1 day, 1 hour, or 10 minutes)
    • Example:
      function custom_edit_duration($duration) {
       return 60 * 3; // 3 hours in minutes
      }
      add_filter('buddypress_edit_activity_duration', 'custom_edit_duration');
  2. bp_editable_types_activity
    • Purpose: Define which activity types can be edited
    • Parameters: $editable_types (array)
    • Default: ['activity_update']
    • Example:
      function custom_editable_types($types) {
       $types[] = 'activity_comment';
       return $types;
      }
      add_filter('bp_editable_types_activity', 'custom_editable_types');
  3. buddypress_can_edit_activity
    • Purpose: Determine if a user can edit a specific activity
    • Parameters: $can_edit (boolean), $activity (object)
    • Example:
      function custom_edit_permissions($can_edit, $activity) {
       // Allow group moderators to edit any activity in their groups
       if (bp_is_active('groups') && $activity->component == 'groups') {
           $group_id = $activity->item_id;
           if (groups_is_user_mod(get_current_user_id(), $group_id)) {
               return true;
           }
       }
       return $can_edit;
      }
      add_filter('buddypress_can_edit_activity', 'custom_edit_permissions', 10, 2);
  4. buddypress_get_edit_activity_content
    • Purpose: Filter the activity content before displaying it in the edit form
    • Parameters: $content (string), $activity (object)
    • Example:
      function prepare_activity_for_editing($content, $activity) {
       // Remove any special formatting before editing
       $content = preg_replace('/[special_format](.*?)[/special_format]/s', '$1', $content);
       return $content;
      }
      add_filter('buddypress_get_edit_activity_content', 'prepare_activity_for_editing', 10, 2);
  5. buddypress_edit_activity_content
    • Purpose: Modify the activity content before saving the edited version
    • Parameters: $content (string), $activity_id (int)
    • Example:
      function process_edited_content($content, $activity_id) {
       // Add formatting or process hashtags
       $content = parse_hashtags($content);
       return $content;
      }
      add_filter('buddypress_edit_activity_content', 'process_edited_content', 10, 2);
  6. buddypress_bp_edit_activity_action
    • Purpose: Modify the activity action text with the “(edited)” indicator
    • Parameters: $action (string), $activity (object)
    • Example:
      function custom_edited_indicator($action, $activity) {
       // Add timestamp to edited indicator
       if (bp_activity_get_meta($activity->id, '_bp_edit_activity', true)) {
           $edit_time = bp_activity_get_meta($activity->id, '_bp_edit_timestamp', true);
           if ($edit_time) {
               $time_diff = human_time_diff($edit_time, current_time('timestamp'));
               return $action . ' <span class="bp-activity-edited-text">(edited ' . $time_diff . ' ago)</span>';
           }
       }
       return $action;
      }
      add_filter('buddypress_bp_edit_activity_action', 'custom_edited_indicator', 10, 2);

Actions

  1. bp_before_edit_activity_template
    • Purpose: Add content before the edit activity form
    • Example:
      function add_edit_form_notice() {
       echo '<div class="bp-edit-notice">Editing your post will notify all participants.</div>';
      }
      add_action('bp_before_edit_activity_template', 'add_edit_form_notice');
  2. bp_after_edit_activity_template
    • Purpose: Add content after the edit activity form
    • Example:
      function add_edit_form_guidelines() {
       echo '<div class="bp-edit-guidelines">Please follow community guidelines when editing.</div>';
      }
      add_action('bp_after_edit_activity_template', 'add_edit_form_guidelines');
  3. bp_edit_activity_fields
    • Purpose: Add custom fields to the edit activity form
    • Example:
      function add_custom_edit_fields() {
       ?>
       <div class="custom-activity-field">
           <label for="activity-category">Category:</label>
           <select name="activity_category" id="activity-category">
               <option value="general">General</option>
               <option value="question">Question</option>
               <option value="announcement">Announcement</option>
           </select>
       </div>
       <?php
      }
      add_action('bp_edit_activity_fields', 'add_custom_edit_fields');
  4. bp_get_addition_activity_content
    • Purpose: Add additional content to the activity when retrieving it for editing
    • Parameters: $activity (object)
    • Example:
      function load_custom_activity_data($activity) {
       // Get saved category
       $category = bp_activity_get_meta($activity->id, 'activity_category', true);
       if ($category) {
           ?>
           <script>
           jQuery(document).ready(function($) {
               $('#activity-category').val('<?php echo esc_js($category); ?>');
           });
           </script>
           <?php
       }
      }
      add_action('bp_get_addition_activity_content', 'load_custom_activity_data');
  5. buddypress_edit_activity_before_save_activity_content
    • Purpose: Execute actions before saving the edited activity content
    • Parameters: $activity_id (int)
    • Example:
      function before_save_activity($activity_id) {
       // Log edit action
       bp_activity_add_meta($activity_id, '_edit_started', time());
      }
      add_action('buddypress_edit_activity_before_save_activity_content', 'before_save_activity');
  6. buddypress_edit_activity_after_save_activity_content
    • Purpose: Execute actions after saving the edited activity content
    • Parameters: $activity_id (int), $activity (object)
    • Example:
      function after_save_activity($activity_id, $activity) {
       // Save edit timestamp
       bp_activity_update_meta($activity_id, '_bp_edit_timestamp', time());
      
       // Save custom fields
       if (isset($_POST['activity_category'])) {
           $category = sanitize_text_field($_POST['activity_category']);
           bp_activity_update_meta($activity_id, 'activity_category', $category);
       }
      
       // Create notification about edit
       if (function_exists('bp_notifications_add_notification')) {
           // Notify original mentioned users about update
           $mentioned_users = bp_activity_get_meta($activity_id, 'mentioned_users', true);
           if (!empty($mentioned_users) && is_array($mentioned_users)) {
               foreach ($mentioned_users as $user_id) {
                   bp_notifications_add_notification(array(
                       'user_id'           => $user_id,
                       'item_id'           => $activity_id,
                       'component_name'    => 'activity',
                       'component_action'  => 'activity_edited',
                   ));
               }
           }
       }
      }
      add_action('buddypress_edit_activity_after_save_activity_content', 'after_save_activity', 10, 2);

Implementation Examples

1. Add Character Counter to Edit Form

function add_character_counter() {
    ?>
    <div class="character-count">
        <span id="char-count">0</span> characters
    </div>
    <script>
    jQuery(document).ready(function($) {
        var textarea = $('#whats-new');
        var counter = $('#char-count');

        // Update on load
        counter.text(textarea.val().length);

        // Update on keyup
        textarea.on('keyup', function() {
            counter.text($(this).val().length);
        });
    });
    </script>
    <?php
}
add_action('bp_before_edit_activity_template', 'add_character_counter');

2. Extend Editing Time for Certain Groups

function extend_edit_time_for_groups($duration, $activity) {
    // Check if activity is from specific groups
    if (!empty($activity->component) && $activity->component === 'groups') {
        // Get array of group IDs with extended edit time
        $extended_groups = [5, 10, 15]; // Replace with your group IDs

        if (in_array($activity->item_id, $extended_groups)) {
            // Allow 7 days for these groups instead of default
            return 60 * 24 * 7; // 7 days in minutes
        }
    }
    return $duration;
}
add_filter('buddypress_edit_activity_duration', 'extend_edit_time_for_groups', 10, 2);

3. Custom Activity History Tracking

function track_activity_edit_history($activity_id, $activity) {
    // Get previous content versions
    $history = bp_activity_get_meta($activity_id, '_edit_history', true);
    if (!$history) {
        $history = array();
    }

    // Add new entry to history
    $history[] = array(
        'content' => $activity->content,
        'time' => current_time('timestamp'),
        'user_id' => bp_loggedin_user_id()
    );

    // Store up to 5 recent edits
    if (count($history) > 5) {
        $history = array_slice($history, -5);
    }

    // Save history
    bp_activity_update_meta($activity_id, '_edit_history', $history);
}
add_action('buddypress_edit_activity_after_save_activity_content', 'track_activity_edit_history', 10, 2);

4. Adding Toggle Privacy Option During Edit

function add_privacy_toggle_field() {
    ?>
    <div class="edit-activity-privacy">
        <label>
            <input type="checkbox" name="make_private" id="make-activity-private" />
            Make this activity visible only to friends
        </label>
    </div>
    <?php
}
add_action('bp_edit_activity_fields', 'add_privacy_toggle_field');

function process_privacy_toggle($activity_id, $activity) {
    if (isset($_POST['make_private']) && $_POST['make_private'] == 'on') {
        // Set activity to private (only visible to friends)
        bp_activity_update_meta($activity_id, 'privacy', 'friends');

        // This requires additional filtering of activity visibility elsewhere
    } else {
        // Set activity to public
        bp_activity_delete_meta($activity_id, 'privacy');
    }
}
add_action('buddypress_edit_activity_after_save_activity_content', 'process_privacy_toggle', 10, 2);

5. Customize Edit Button for Specific Activity Types

function customize_edit_button($buttons, $activity_id) {
    $activity = new BP_Activity_Activity($activity_id);

    // Change button text/appearance for photo updates
    if ($activity->type == 'activity_update' && strpos($activity->content, '<img') !== false) {
        $buttons['activity_bp_edit']['button_attr']['data-bp-tooltip'] = __('Edit Photo', 'my-plugin');
        $buttons['activity_bp_edit']['link_text'] = sprintf('<span class="bp-screen-reader-text">%s</span>', __('Edit Photo', 'my-plugin'));
    }

    return $buttons;
}
add_filter('bb_nouveau_get_activity_entry_dropdown_toggle_buttons', 'customize_edit_button', 20, 2);

Troubleshooting

Common Issues and Solutions

  1. Activity Not Editable When Expected
    • Check if the activity type is included in the bp_editable_types_activity filter
    • Verify user permissions with the buddypress_can_edit_activity filter
    • Ensure the edit duration hasn’t expired
  2. Custom Fields Not Saving
    • Ensure proper nonce verification in your code
    • Check that you’re hooking into buddypress_edit_activity_after_save_activity_content
    • Verify proper sanitization of form inputs
  3. Modal Dialog Styling Issues
    • Use browser developer tools to inspect the modal
    • Add specific CSS targeting the .bp-activity-edit-model-wrap and its children
    • Ensure your theme’s styles aren’t overriding the plugin’s modal styles
  4. JavaScript Not Working
    • Check browser console for JavaScript errors
    • Ensure jQuery is properly loaded
    • Verify AJAX URLs are correctly configured

Best Practices

  1. Security
    • Always sanitize and validate user inputs
    • Use nonce verification for AJAX requests
    • Check user capabilities before allowing edits
  2. Performance
    • Minimize database queries in your hooks
    • Cache expensive operations where appropriate
    • Use transients for temporary data storage
  3. Compatibility
    • Test your customizations with different BuddyPress themes
    • Ensure compatibility with popular BuddyPress plugins
    • Follow WordPress coding standards
  4. User Experience
    • Provide clear feedback when activities are edited
    • Keep the editing interface simple and intuitive
    • Consider mobile users when adding UI elements

Support

For additional support or to report issues:

Update on April 10, 2025