Skip to content

Conversation

@obenland
Copy link
Member

@obenland obenland commented Jul 29, 2025

Fixes #418.

Proposed changes:

  • Implements a new actor blocking system similar to the existing following/followers functionality
  • Uses post meta storage with _activitypub_blocked_by key on actor posts for scalable blocking
  • Provides list table interface for managing blocked actors with add/unblock functionality
  • Includes conditional menu registration that only shows if user has blocked actors
  • Adds site-wide blocking support in Settings > ActivityPub tab
  • Uses unified blocking API through add_user_block/remove_user_block methods

Other information:

  • Have you written new tests for your changes, if applicable?

Testing instructions:

  • Go to Users > Blocked Actors (only appears if you have blocked actors)
  • Try blocking an actor by entering @[email protected] or profile URL
  • Verify the actor appears in the blocked actors list
  • Test unblocking individual actors and bulk unblock functionality
  • Go to Settings > ActivityPub > Blocked Actors tab to test site-wide blocking
  • Verify blocked actors cannot interact with your content

Changelog entry

  • Automatically create a changelog entry from the details below.
Changelog Entry Details

Significance

  • Patch
  • Minor
  • Major

Type

  • Added - for new features
  • Changed - for changes in existing functionality
  • Deprecated - for soon-to-be removed features
  • Removed - for now removed features
  • Fixed - for any bug fixes
  • Security - in case of vulnerabilities

Message

Add actor blocking functionality with list table interface for managing blocked users and site-wide blocks

obenland added 19 commits July 28, 2025 15:50
Implements hierarchical blocking system (site-wide → user-specific → WordPress disallowed list) with three block types:
- Actors: Block specific ActivityPub users by URL
- Domains: Block entire instances by domain
- Keywords: Block content containing specific keywords

Features:
- Site-wide moderation for admins via Settings → ActivityPub
- User-specific blocks via user profiles
- Modern JavaScript with WordPress AJAX utilities
- Responsive UI matching WordPress standards
- Proper security with nonces and permission checks
- Integration with existing inbox controllers
Implements thorough test coverage for the ActivityPub moderation system including:

- User block management (add/remove/get) for all three types (actors, domains, keywords)
- Site-wide block management with admin controls
- Activity blocking logic with hierarchical priority testing
- Edge cases: malformed data, invalid inputs, special characters, Unicode
- Complex scenarios: duplicate blocks, array re-indexing, WordPress fallback
- Boundary testing: extremely long values, invalid user IDs, empty data
- Integration testing: WordPress comment disallowed list fallback

All 22 tests pass with 91 assertions covering core functionality,
error handling, and real-world usage scenarios.
Automated code style fixes applied by PHP_CodeSniffer including:
- Consistent spacing and indentation
- WordPress coding standards compliance
- Array formatting and alignment
- Comment formatting improvements

No functional changes, only code style improvements.
- Remove page reloads from AJAX operations for better UX
- Replace location.reload() with dynamic UI updates
- Add helper functions to manage DOM updates properly
- Fix table removal when last item is deleted
- Rename functions from 'block' to 'blockedTerm' to avoid confusion with WordPress blocks
- Fix issue where adding terms created tables in all sections
- Use specific selectors to target correct containers for each type
- Add @Covers annotations to all test methods for proper coverage tracking
- Add @coversDefaultClass to test and main Moderation classes
- Refactor activity_is_blocked_site_wide and activity_is_blocked_for_user to eliminate code duplication
- Extract common blocking logic into private check_activity_against_blocks method
- Maintain full test coverage with all 22 tests passing

Improves code maintainability and test coverage visibility.
Documents the new comprehensive moderation features including:
- User-specific blocking controls for actors, domains, and keywords
- Site-wide moderation interface for administrators
- Integration with existing WordPress disallowed list
- Modern responsive UI with WordPress utilities
Move nonce verification to the beginning of all AJAX handlers before accessing any  data, as recommended by Copilot security review. This ensures proper nonce validation occurs before any other processing.

- ajax_add_user_block: Verify nonce first
- ajax_remove_user_block: Verify nonce first
- ajax_add_site_block: Verify nonce first
- ajax_remove_site_block: Verify nonce first, remove duplicate check

All tests continue to pass (22 tests, 91 assertions).
…flict

- Dissolve separate wp-admin/class-moderation.php into main class-admin.php
- Rename AJAX action to 'activitypub_moderation_settings' for clarity
- Fix AJAX parameter conflict by changing 'action' to 'operation'
- Remove separate moderation class initialization from main plugin file
- Integrate moderation scripts and handlers into unified Admin class
- Update JavaScript to use single nonce and new parameter names

The 'action' parameter was conflicting with WordPress's internal AJAX routing
mechanism, causing "Invalid context or action" errors. Using 'operation'
resolves this conflict.

Benefits:
- Reduces codebase by 70 lines while maintaining full functionality
- More descriptive AJAX action name clearly indicates purpose
- Simplified admin architecture with fewer files to maintain
- All 22 moderation tests continue to pass with 91 assertions
Introduces user meta and site-wide settings for blocking ActivityPub actors, domains, and keywords. This enables more granular moderation capabilities for both individual users and the entire site.
Adjusted whitespace for variable assignments in the ajax_moderation_settings method to improve code readability and maintain consistent formatting.
This commit removes the ability to block specific ActivityPub actors (users) by their actor URL from both site-wide and user moderation settings. The related UI elements, JavaScript logic, and server-side validation have been updated to only support domain and keyword blocks.
Replaced calls to array_map and do_action with their namespaced versions for consistency and performance. Updated moderation-related labels and descriptions to use esc_html__ for proper escaping. Renamed Moderation::activity_is_blocked to Moderation::activity_is_blocked_for_user for clarity.
Actor-level block functionality has been removed from the Moderation class and related tests. Blocking is now only supported for domains and keywords, simplifying the blocklist logic and data structures. Tests and settings have been updated to reflect this change, and duplicate domain entries are now prevented via array_unique in sanitization.
Implements a new actor blocking system similar to following/followers with:
- Post meta storage using _activitypub_blocked_by key on actor posts
- List table interface for managing blocked actors with add/unblock functionality
- Conditional menu registration (only shows if user has blocked actors)
- Site-wide blocking support in Settings > ActivityPub tab
- Unified blocking API through add_user_block/remove_user_block methods
- Full admin interface with templates, screen options, and action handlers
@obenland obenland self-assigned this Jul 29, 2025
@obenland obenland requested a review from pfefferle July 29, 2025 20:19
@obenland obenland changed the base branch from trunk to add/block-lists July 29, 2025 20:19
Base automatically changed from add/block-lists to trunk August 1, 2025 14:51
obenland and others added 3 commits August 26, 2025 08:14
Updated Moderation to resolve actor IDs that are not URLs using Webfinger before checking against blocked actors. Added unit tests to verify that actors in webfinger format are correctly resolved and blocked if their resolved URL matches a blocked domain.
@obenland
Copy link
Member Author

There’s an edge case where an incoming Activity might use the WebFinger handle as its Actor-ID. Should we address that in this PR, treat it as an improvement for later, or just wait until the case actually comes up?

Fixed in 3c43505.

- Create new Blocked_Actors collection class for better code organization
- Move get_blocked_actors_with_count() and get_blocked_actors() methods from Moderation class
- Update all references to use the new collection methods
- Maintain consistent naming with other collection classes (Followers, Following)
- Improve separation of concerns by grouping blocked actor functionality
- Move add_block() and remove_block() methods from Moderation to Blocked_Actors collection
- Update Moderation class to delegate actor operations to the collection
- Keep Moderation as the top-level API while improving code organization
- Maintain all existing functionality including action hooks and cache clearing
- Improve separation of concerns with actor-specific logic in dedicated collection
- Remove extra blank line after class closing brace in Moderation class
- Resolve class name conflict by aliasing Blocked_Actors collection import
- Use Blocked_Actors_Collection alias in admin table to avoid namespace conflicts
- All composer lint checks now pass without errors
- Add TYPE_ACTOR, TYPE_DOMAIN, TYPE_KEYWORD constants
- Update all switch statements to use constants instead of strings
- Replace array keys in USER_META_KEYS and OPTION_KEYS with constants
- Update blocked actors table to use Moderation::TYPE_ACTOR constant
- Maintain string literals for plural array keys where constants don't fit
@obenland obenland requested review from Copilot and pfefferle August 26, 2025 14:54
@obenland
Copy link
Member Author

@pfefferle This should be ready for another look.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds comprehensive actor blocking functionality to the ActivityPub plugin, implementing a complete blocking system with both user-level and site-wide capabilities. The implementation follows the existing patterns used for followers and following functionality.

  • Implements actor blocking using post meta storage with _activitypub_blocked_by key for scalable blocking
  • Adds admin interface for managing blocked actors with list table views and search functionality
  • Integrates blocking with existing moderation system and automatically removes blocked actors from following lists

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/includes/class-test-moderation.php Updates test mocking and adds webfinger actor resolution tests
templates/following-list.php Updates label accessibility for profile input field
templates/blocked-actors-list.php New template for blocked actors management interface
includes/wp-admin/table/class-blocked-actors.php New list table class for displaying and managing blocked actors
includes/wp-admin/class-settings.php Adds blocked actors tab to settings page
includes/wp-admin/class-screen-options.php Adds screen options support for blocked actors list
includes/wp-admin/class-menu.php Adds blocked actors menu item to Users menu
includes/wp-admin/class-admin.php Adds blocked actors page handler and table initialization
includes/collection/class-following.php Adds method to remove blocked actors from following list
includes/collection/class-blocked-actors.php New collection class for blocked actors data management
includes/class-moderation.php Extends moderation system with actor blocking support and webfinger resolution
includes/class-activitypub.php Integrates blocked actor removal from following list
.github/changelog/2027-from-description Changelog entry for the new feature

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@pfefferle
Copy link
Member

pfefferle commented Aug 26, 2025

@obenland what about

If I block someone I follow or who follows me, unblocking them doesn’t restore that previous connection—it only removes them from my block list. If I had been following them, I can choose to follow again, but if they were following me, that connection is lost. It could be helpful to have an option to restore a follow in case a block was made by mistake.

???

@obenland
Copy link
Member Author

Ah, sorry, I missed replying to that.

Can that be a follow-up? I'm not even sure that's something that's desired or that we'd need to worry too much about.

@pfefferle
Copy link
Member

We should be at least sure about it, before we release it ;)

@obenland
Copy link
Member Author

I think for a v1 it's good enough to not support automatic re-following.

A lot of assumptions here, just as a heads up:
Blocking an actor is a pretty serious action that is probably not done lightly and relatively rare. Unblocking a blocked actor is probably even rarer, since there'll have been strong reasons to block in the first place and they would not have to be in place anymore. And then I'm not sure I'd consider unblocking the same as "everything is fine and normal again" and go back to the way it was.

Blocking is a pretty disruptive and destructive action, I think it's fine for it to be reflected in that way for the time being.

Store the original profile value before resolving email-based profiles to URIs. Use the original value in error redirects to ensure the user sees the input they provided, improving clarity in error messages.
@obenland obenland merged commit 5d3301a into trunk Aug 26, 2025
13 checks passed
@obenland obenland deleted the feature/new-actor-blocks branch August 26, 2025 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Question: How does this plugin interact with moderation and trust & safety on the fediverse?

4 participants