Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions includes/class-activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,18 @@ public static function theme_compat() {
/**
* Add the 'activitypub' capability to users who can publish posts.
*
* New users get the capability by default unless the site was previously in
* blog-only mode (indicated by activitypub_disable_users_by_default option).
*
* @param int $user_id User ID.
*/
public static function user_register( $user_id ) {
// Check if site was previously in blog-only mode.
if ( \get_option( 'activitypub_disable_users_by_default' ) ) {
return;
}

// Add capability to users who can publish posts.
if ( \user_can( $user_id, 'publish_posts' ) ) {
$user = \get_user_by( 'id', $user_id );
$user->add_cap( 'activitypub' );
Expand Down
31 changes: 28 additions & 3 deletions includes/class-migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ public static function maybe_migrate() {
}

if ( \version_compare( $version_from_db, 'unreleased', '<' ) ) {
self::migrate_actor_mode_to_capabilities();
self::clean_up_inbox();
\wp_schedule_single_event( \time(), 'activitypub_migrate_avatar_to_remote_actors' );
}
Expand Down Expand Up @@ -478,6 +479,30 @@ public static function migrate_to_4_7_2() {
}
}

/**
* Migrate from actor mode settings to capability-based system.
*
* Blog actors are now always enabled and user actors are controlled
* solely via the 'activitypub' capability. This migration handles sites that
* were previously in blog-only mode by setting a flag to prevent new users
* from automatically getting the activitypub capability.
*/
public static function migrate_actor_mode_to_capabilities() {
$actor_mode = \get_option( 'activitypub_actor_mode', 'actor' );

// If site was in blog-only mode, set flag to disable users by default.
if ( 'blog' === $actor_mode ) {
\update_option( 'activitypub_disable_users_by_default', true );
}

// Clean up old actor mode option.
\delete_option( 'activitypub_actor_mode' );

// Clean up legacy options if they still exist.
\delete_option( 'activitypub_enable_blog_user' );
\delete_option( 'activitypub_enable_users' );
}

/**
* Update comment counts for posts in batches.
*
Expand Down Expand Up @@ -857,17 +882,17 @@ public static function migrate_actor_mode() {
'1' === $blog_profile &&
'1' === $author_profiles
) {
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE );
\update_option( 'activitypub_actor_mode', 'actor_blog' );
} elseif (
'1' === $blog_profile &&
'1' !== $author_profiles
) {
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE );
\update_option( 'activitypub_actor_mode', 'blog' );
} elseif (
'1' !== $blog_profile &&
'1' === $author_profiles
) {
\update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE );
\update_option( 'activitypub_actor_mode', 'actor' );
}
}

Expand Down
24 changes: 0 additions & 24 deletions includes/class-options.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class Options {
* Initialize the options.
*/
public static function init() {
\add_filter( 'pre_option_activitypub_actor_mode', array( self::class, 'pre_option_activitypub_actor_mode' ) );
\add_filter( 'pre_option_activitypub_authorized_fetch', array( self::class, 'pre_option_activitypub_authorized_fetch' ) );
\add_filter( 'pre_option_activitypub_vary_header', array( self::class, 'pre_option_activitypub_vary_header' ) );

Expand All @@ -39,29 +38,6 @@ public static function delete() {
$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'activitypub_%'" );
}

/**
* Pre-get option filter for the Actor-Mode.
*
* @param string|false $pre The pre-get option value.
*
* @return string|false The actor mode or false if it should not be filtered.
*/
public static function pre_option_activitypub_actor_mode( $pre ) {
if ( \defined( 'ACTIVITYPUB_SINGLE_USER_MODE' ) && ACTIVITYPUB_SINGLE_USER_MODE ) {
return ACTIVITYPUB_BLOG_MODE;
}

if ( \defined( 'ACTIVITYPUB_DISABLE_USER' ) && ACTIVITYPUB_DISABLE_USER ) {
return ACTIVITYPUB_BLOG_MODE;
}

if ( \defined( 'ACTIVITYPUB_DISABLE_BLOG_USER' ) && ACTIVITYPUB_DISABLE_BLOG_USER ) {
return ACTIVITYPUB_ACTOR_MODE;
}

return $pre;
}

/**
* Pre-get option filter for the Authorized Fetch.
*
Expand Down
5 changes: 0 additions & 5 deletions includes/class-scheduler.php
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,6 @@ public static function is_locked( $key ) {
* @param int $content_visibility The content visibility.
*/
public static function schedule_announce_activity( $outbox_activity_id, $activity, $actor_id, $content_visibility ) {
// Only if we're in both Blog and User modes.
if ( ACTIVITYPUB_ACTOR_AND_BLOG_MODE !== \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ) {
return;
}

// Only if this isn't the Blog Actor.
if ( Actors::BLOG_USER_ID === $actor_id ) {
return;
Expand Down
38 changes: 10 additions & 28 deletions includes/collection/class-actors.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use Activitypub\Model\Blog;
use Activitypub\Model\User;

use function Activitypub\is_user_type_disabled;
use function Activitypub\normalize_host;
use function Activitypub\normalize_url;
use function Activitypub\object_to_uri;
Expand Down Expand Up @@ -104,19 +103,11 @@ public static function get_by_username( $username ) {
* @return int|\WP_Error Actor id or WP_Error if not found.
*/
public static function get_id_by_username( $username ) {
// Check for blog user.
// Check for blog user (always enabled).
if (
Blog::get_default_username() === $username ||
\get_option( 'activitypub_blog_identifier' ) === $username
) {
if ( is_user_type_disabled( 'blog' ) ) {
return new \WP_Error(
'activitypub_user_not_found',
\__( 'Actor not found', 'activitypub' ),
array( 'status' => 404 )
);
}

return self::BLOG_USER_ID;
}

Expand Down Expand Up @@ -342,10 +333,6 @@ public static function get_id_by_various( $id ) {
* @return Actor[] Array of User actor objects.
*/
public static function get_collection() {
if ( is_user_type_disabled( 'user' ) ) {
return array();
}

$users = \get_users(
array(
'capability__in' => array( 'activitypub' ),
Expand Down Expand Up @@ -373,21 +360,16 @@ public static function get_collection() {
* @return int[] Array of User and Blog actor IDs.
*/
public static function get_all_ids() {
$user_ids = array();

if ( ! is_user_type_disabled( 'user' ) ) {
$user_ids = \get_users(
array(
'fields' => 'ID',
'capability__in' => array( 'activitypub' ),
)
);
}
// Get all users with activitypub capability.
$user_ids = \get_users(
array(
'fields' => 'ID',
'capability__in' => array( 'activitypub' ),
)
);

// Also include the blog actor if active.
if ( ! is_user_type_disabled( 'blog' ) ) {
$user_ids[] = self::BLOG_USER_ID;
}
// Always include the blog actor (always enabled).
$user_ids[] = self::BLOG_USER_ID;

return array_map( 'intval', $user_ids );
}
Expand Down
4 changes: 0 additions & 4 deletions includes/collection/class-followers.php
Original file line number Diff line number Diff line change
Expand Up @@ -426,10 +426,6 @@ public static function get_inboxes_for_activity( $json, $actor_id, $batch_size =
public static function maybe_add_inboxes_of_blog_user( $json, $actor_id ) {
\_deprecated_function( __METHOD__, '7.3.0' );

// Only if we're in both Blog and User modes.
if ( ACTIVITYPUB_ACTOR_AND_BLOG_MODE !== \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ) {
return false;
}
// Only if this isn't the Blog Actor.
if ( Actors::BLOG_USER_ID === $actor_id ) {
return false;
Expand Down
6 changes: 1 addition & 5 deletions includes/collection/class-replies.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use function Activitypub\get_rest_url_by_path;
use function Activitypub\is_local_comment;
use function Activitypub\is_post_disabled;
use function Activitypub\is_user_type_disabled;

/**
* Class containing code for getting replies Collections and CollectionPages of posts and comments.
Expand Down Expand Up @@ -171,10 +170,7 @@ public static function get_context_collection( $post_id ) {

$author = Actors::get_by_id( $post->post_author );
if ( is_wp_error( $author ) ) {
if ( is_user_type_disabled( 'blog' ) ) {
return false;
}

// Fallback to blog actor (always enabled).
$author = new Blog();
}

Expand Down
5 changes: 0 additions & 5 deletions includes/constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@

define( 'ACTIVITYPUB_DATE_TIME_RFC3339', 'Y-m-d\TH:i:s\Z' );

// Define Actor-Modes for the plugin.
define( 'ACTIVITYPUB_ACTOR_MODE', 'actor' );
define( 'ACTIVITYPUB_BLOG_MODE', 'blog' );
define( 'ACTIVITYPUB_ACTOR_AND_BLOG_MODE', 'actor_blog' );

// Post visibility constants.
define( 'ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC', '' );
define( 'ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC', 'quiet_public' );
Expand Down
82 changes: 20 additions & 62 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ function user_can_activitypub( $user_id ) {
break;

case Actors::BLOG_USER_ID:
$enabled = ! is_user_type_disabled( 'blog' );
$enabled = true; // Blog user is always enabled.
break;

default:
Expand All @@ -377,11 +377,7 @@ function user_can_activitypub( $user_id ) {
break;
}

if ( is_user_type_disabled( 'user' ) ) {
$enabled = false;
break;
}

// Check only the capability.
$enabled = \user_can( $user_id, 'activitypub' );
}

Expand All @@ -400,64 +396,30 @@ function user_can_activitypub( $user_id ) {
* This function is used to check if the 'blog' or 'user'
* type is disabled for ActivityPub.
*
* Note: As of version 4.6.0, blog actors are always enabled and user actors
* are controlled via the 'activitypub' capability. This function now always
* returns false but is maintained for backward compatibility and filter support.
*
* @param string $type User type. 'blog' or 'user'.
*
* @return boolean True if the user type is disabled, false otherwise.
* @return boolean Always returns false (no types are globally disabled).
*/
function is_user_type_disabled( $type ) {
switch ( $type ) {
case 'blog':
if ( \defined( 'ACTIVITYPUB_SINGLE_USER_MODE' ) ) {
if ( ACTIVITYPUB_SINGLE_USER_MODE ) {
$disabled = false;
break;
}
}

if ( \defined( 'ACTIVITYPUB_DISABLE_BLOG_USER' ) ) {
$disabled = ACTIVITYPUB_DISABLE_BLOG_USER;
break;
}

if ( ACTIVITYPUB_ACTOR_MODE === \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ) {
$disabled = true;
break;
}

$disabled = false;
break;
case 'user':
if ( \defined( 'ACTIVITYPUB_SINGLE_USER_MODE' ) ) {
if ( ACTIVITYPUB_SINGLE_USER_MODE ) {
$disabled = true;
break;
}
}

if ( \defined( 'ACTIVITYPUB_DISABLE_USER' ) ) {
$disabled = ACTIVITYPUB_DISABLE_USER;
break;
}

if ( ACTIVITYPUB_BLOG_MODE === \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ) {
$disabled = true;
break;
}
$disabled = false;

$disabled = false;
break;
default:
$disabled = new \WP_Error(
'activitypub_wrong_user_type',
__( 'Wrong user type', 'activitypub' ),
array( 'status' => 400 )
);
break;
if ( ! in_array( $type, array( 'blog', 'user' ), true ) ) {
$disabled = new \WP_Error(
'activitypub_wrong_user_type',
__( 'Wrong user type', 'activitypub' ),
array( 'status' => 400 )
);
}

/**
* Allow plugins to disable user types for ActivityPub.
*
* Note: This filter is deprecated. Use capability management instead.
*
* @param boolean $disabled True if the user type is disabled, false otherwise.
* @param string $type The User-Type.
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

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

The filter documentation indicates deprecation, but there's no @deprecated tag. Consider adding a proper @deprecated tag with version number to follow WordPress documentation standards and make it clear to developers when this was deprecated (e.g., '@deprecated unreleased').

Suggested change
* @param string $type The User-Type.
* @param string $type The User-Type.
* @deprecated unreleased

Copilot uses AI. Check for mistakes.
*/
Expand Down Expand Up @@ -1311,16 +1273,12 @@ function get_content_warning( $post_id ) {
* @return string|false The ActivityPub ID (a URL) of the User or false if not found.
*/
function get_user_id( $id ) {
$mode = \get_option( 'activitypub_actor_mode', 'default' );
// Try to get the user actor first.
$user = Actors::get_by_id( $id );

if ( ACTIVITYPUB_BLOG_MODE === $mode ) {
// Fallback to blog actor if user not found.
if ( \is_wp_error( $user ) ) {
$user = Actors::get_by_id( Actors::BLOG_USER_ID );
} else {
$user = Actors::get_by_id( $id );

if ( \is_wp_error( $user ) ) {
$user = Actors::get_by_id( Actors::BLOG_USER_ID );
}
}

if ( \is_wp_error( $user ) ) {
Expand Down
Loading
Loading