diff --git a/includes/class-activitypub.php b/includes/class-activitypub.php index 3289643688..e336dd7a37 100644 --- a/includes/class-activitypub.php +++ b/includes/class-activitypub.php @@ -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' ); diff --git a/includes/class-comment.php b/includes/class-comment.php index ff90f6b39c..2ccae876cf 100644 --- a/includes/class-comment.php +++ b/includes/class-comment.php @@ -7,8 +7,6 @@ namespace Activitypub; -use Activitypub\Collection\Actors; - /** * ActivityPub Comment Class. * @@ -139,11 +137,6 @@ public static function are_comments_allowed( $comment ) { return false; } - if ( is_single_user() && \user_can( $current_user, 'publish_posts' ) ) { - // On a single user site, comments by users with the `publish_posts` capability will be federated as the blog user. - $current_user = Actors::BLOG_USER_ID; - } - return user_can_activitypub( $current_user ); } @@ -243,11 +236,6 @@ public static function should_be_federated( $comment ) { return false; } - if ( is_single_user() && \user_can( $user_id, 'activitypub' ) ) { - // On a single user site, comments by users with the `publish_posts` capability will be federated as the blog user. - $user_id = Actors::BLOG_USER_ID; - } - // User is not allowed to federate comments. if ( ! user_can_activitypub( $user_id ) ) { return false; diff --git a/includes/class-migration.php b/includes/class-migration.php index 639a51cc72..6b3b7395ec 100644 --- a/includes/class-migration.php +++ b/includes/class-migration.php @@ -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' ); } @@ -478,6 +479,41 @@ public static function migrate_to_4_7_2() { } } + /** + * Migrate from actor mode settings to capability-based system. + * + * 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', ACTIVITYPUB_ACTOR_MODE ); + + // If site was in blog-only mode, set flag to disable users by default. + if ( ACTIVITYPUB_BLOG_MODE === $actor_mode ) { + \update_option( 'activitypub_disable_users_by_default', true ); + + // Remove activitypub capability from all existing users. + $users = \get_users( + array( + 'capability__in' => array( 'activitypub' ), + ) + ); + + foreach ( $users as $user ) { + $user->remove_cap( 'activitypub' ); + } + } + + // 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. * diff --git a/includes/class-options.php b/includes/class-options.php index b4823f8381..7b4a2503d2 100644 --- a/includes/class-options.php +++ b/includes/class-options.php @@ -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' ) ); @@ -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. * diff --git a/includes/class-scheduler.php b/includes/class-scheduler.php index d00fc147d3..b1564e2714 100644 --- a/includes/class-scheduler.php +++ b/includes/class-scheduler.php @@ -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; diff --git a/includes/collection/class-actors.php b/includes/collection/class-actors.php index d8e324cc3e..d000aa30bb 100644 --- a/includes/collection/class-actors.php +++ b/includes/collection/class-actors.php @@ -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; @@ -109,14 +108,6 @@ public static function get_id_by_username( $username ) { 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; } @@ -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' ), @@ -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; - } + // Include the blog actor. + $user_ids[] = self::BLOG_USER_ID; return array_map( 'intval', $user_ids ); } diff --git a/includes/collection/class-followers.php b/includes/collection/class-followers.php index 3dcf833557..6067a58f08 100644 --- a/includes/collection/class-followers.php +++ b/includes/collection/class-followers.php @@ -413,37 +413,6 @@ public static function get_inboxes_for_activity( $json, $actor_id, $batch_size = return \array_slice( $inboxes, $offset, $batch_size ); } - /** - * Maybe add Inboxes of the Blog User. - * - * @deprecated 7.3.0 - * - * @param string $json The ActivityPub Activity JSON. - * @param int $actor_id The WordPress Actor ID. - * - * @return bool True if the Inboxes of the Blog User should be added, false otherwise. - */ - 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; - } - - $activity = \json_decode( $json, true ); - // Only if this is an Update or Delete. Create handles its own "Announce" in dual user mode. - if ( ! \in_array( $activity['type'] ?? null, array( 'Update', 'Delete' ), true ) ) { - return false; - } - - return true; - } - /** * Get all Followers. * diff --git a/includes/collection/class-replies.php b/includes/collection/class-replies.php index 698d22df86..7565fec586 100644 --- a/includes/collection/class-replies.php +++ b/includes/collection/class-replies.php @@ -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. @@ -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. $author = new Blog(); } diff --git a/includes/constants.php b/includes/constants.php index 886a578657..9a668e5eba 100644 --- a/includes/constants.php +++ b/includes/constants.php @@ -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' ); @@ -79,6 +74,15 @@ define( 'ACTIVITYPUB_INTERACTION_POLICY_FOLLOWERS', 'followers' ); define( 'ACTIVITYPUB_INTERACTION_POLICY_ME', 'me' ); +/* + * Actor mode constants. + * + * @deprecated unreleased The Actor Mode is no longer supported. + */ +define( 'ACTIVITYPUB_ACTOR_MODE', 'actor' ); +define( 'ACTIVITYPUB_BLOG_MODE', 'blog' ); +define( 'ACTIVITYPUB_ACTOR_AND_BLOG_MODE', 'actor_blog' ); + // Identifiers that mark an Activity as Public. define( 'ACTIVITYPUB_PUBLIC_AUDIENCE_IDENTIFIERS', diff --git a/includes/functions.php b/includes/functions.php index 52a9bb099a..d46e4e0af0 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -364,11 +364,8 @@ function user_can_activitypub( $user_id ) { switch ( $user_id ) { case Actors::APPLICATION_USER_ID: - $enabled = true; // Application user is always enabled. - break; - case Actors::BLOG_USER_ID: - $enabled = ! is_user_type_disabled( 'blog' ); + $enabled = true; // Application and Blog user is always enabled. break; default: @@ -377,11 +374,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' ); } @@ -400,64 +393,30 @@ function user_can_activitypub( $user_id ) { * This function is used to check if the 'blog' or 'user' * type is disabled for ActivityPub. * + * @since unreleased 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. * + * @deprecated unreleased Use capability management instead. + * * @param boolean $disabled True if the user type is disabled, false otherwise. * @param string $type The User-Type. */ @@ -467,15 +426,12 @@ function is_user_type_disabled( $type ) { /** * Check if the blog is in single-user mode. * - * @return boolean True if the blog is in single-user mode, false otherwise. + * @deprecated unreleased Always returns false as actor mode has been removed. + * + * @return boolean Always returns false. */ function is_single_user() { - if ( - false === is_user_type_disabled( 'blog' ) && - true === is_user_type_disabled( 'user' ) - ) { - return true; - } + \_deprecated_function( __FUNCTION__, 'unreleased' ); return false; } @@ -653,11 +609,6 @@ function get_active_users( $duration = 1 ) { return 0; } - // If single user mode. - if ( is_single_user() ) { - return 1; - } - // If blog user is disabled. if ( ! user_can_activitypub( Actors::BLOG_USER_ID ) ) { return (int) $count; @@ -673,11 +624,6 @@ function get_active_users( $duration = 1 ) { * @return int The total number of users. */ function get_total_users() { - // If single user mode. - if ( is_single_user() ) { - return 1; - } - $users = \get_users( array( 'capability__in' => array( 'activitypub' ), @@ -1311,16 +1257,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 ) ) { diff --git a/includes/model/class-blog.php b/includes/model/class-blog.php index 24030792e2..2a60f198ab 100644 --- a/includes/model/class-blog.php +++ b/includes/model/class-blog.php @@ -15,7 +15,6 @@ use function Activitypub\get_attribution_domains; use function Activitypub\get_rest_url_by_path; use function Activitypub\is_blog_public; -use function Activitypub\is_single_user; /** * Blog class. @@ -48,6 +47,20 @@ class Blog extends Actor { ), ); + /** + * The type of the Blog-Actor. + * + * @var string + */ + protected $type = 'Group'; + + /** + * Posting is restricted to moderators. + * + * @var bool|null True if posting is restricted to moderators, null if not applicable. + */ + protected $posting_restricted_to_mods = true; + /** * Constructor. */ @@ -99,21 +112,6 @@ public function get_id() { return \add_query_arg( 'author', $this->_id, \home_url( '/' ) ); } - /** - * Get the type of the object. - * - * If the Blog is in "single user" mode, return "Person" instead of "Group". - * - * @return string The type of the object. - */ - public function get_type() { - if ( is_single_user() ) { - return 'Person'; - } else { - return 'Group'; - } - } - /** * Get the Username. * @@ -303,10 +301,6 @@ public function get_canonical_url() { * @return string|null The Moderators endpoint. */ public function get_moderators() { - if ( is_single_user() || 'Group' !== $this->get_type() ) { - return null; - } - return get_rest_url_by_path( 'collections/moderators' ); } @@ -316,10 +310,6 @@ public function get_moderators() { * @return string|null The attributedTo value. */ public function get_attributed_to() { - if ( is_single_user() || 'Group' !== $this->get_type() ) { - return null; - } - return get_rest_url_by_path( 'collections/moderators' ); } @@ -336,19 +326,6 @@ public function get_public_key() { ); } - /** - * Returns whether posting is restricted to mods. - * - * @return bool|null True if posting is restricted to mods, null if not applicable. - */ - public function get_posting_restricted_to_mods() { - if ( 'Group' === $this->get_type() ) { - return true; - } - - return null; - } - /** * Returns the Inbox-API-Endpoint. * diff --git a/includes/rest/class-collections-controller.php b/includes/rest/class-collections-controller.php index b9ee7d686a..c76621772b 100644 --- a/includes/rest/class-collections-controller.php +++ b/includes/rest/class-collections-controller.php @@ -13,7 +13,6 @@ use function Activitypub\esc_hashtag; use function Activitypub\get_rest_url_by_path; -use function Activitypub\is_single_user; /** * Collections_Controller class. @@ -158,7 +157,7 @@ public function get_tags( $request, $user_id ) { public function get_featured( $request, $user_id ) { $posts = array(); - if ( is_single_user() || Actors::BLOG_USER_ID !== $user_id ) { + if ( Actors::BLOG_USER_ID !== $user_id ) { $sticky_posts = \get_option( 'sticky_posts' ); if ( $sticky_posts && is_array( $sticky_posts ) ) { diff --git a/includes/scheduler/class-actor.php b/includes/scheduler/class-actor.php index b07cfbdae6..c497965d34 100644 --- a/includes/scheduler/class-actor.php +++ b/includes/scheduler/class-actor.php @@ -13,7 +13,6 @@ use Activitypub\Collection\Outbox; use function Activitypub\add_to_outbox; -use function Activitypub\is_user_type_disabled; /** * Post scheduler class. @@ -24,30 +23,23 @@ class Actor { */ public static function init() { // Profile updates for blog options. - if ( ! is_user_type_disabled( 'blog' ) ) { - \add_action( 'update_option_site_icon', array( self::class, 'blog_user_update' ) ); - \add_action( 'update_option_blogdescription', array( self::class, 'blog_user_update' ) ); - \add_action( 'update_option_blogname', array( self::class, 'blog_user_update' ) ); - \add_action( 'add_option_activitypub_header_image', array( self::class, 'blog_user_update' ) ); - \add_action( 'update_option_activitypub_header_image', array( self::class, 'blog_user_update' ) ); - \add_action( 'add_option_activitypub_blog_identifier', array( self::class, 'blog_user_update' ) ); - \add_action( 'update_option_activitypub_blog_identifier', array( self::class, 'blog_user_update' ) ); - \add_action( 'add_option_activitypub_blog_description', array( self::class, 'blog_user_update' ) ); - \add_action( 'update_option_activitypub_blog_description', array( self::class, 'blog_user_update' ) ); - \add_filter( 'pre_set_theme_mod_custom_logo', array( self::class, 'blog_user_update' ) ); - \add_filter( 'pre_set_theme_mod_header_image', array( self::class, 'blog_user_update' ) ); - } + \add_action( 'update_option_site_icon', array( self::class, 'blog_user_update' ) ); + \add_action( 'update_option_blogdescription', array( self::class, 'blog_user_update' ) ); + \add_action( 'update_option_blogname', array( self::class, 'blog_user_update' ) ); + \add_action( 'add_option_activitypub_header_image', array( self::class, 'blog_user_update' ) ); + \add_action( 'update_option_activitypub_header_image', array( self::class, 'blog_user_update' ) ); + \add_action( 'add_option_activitypub_blog_identifier', array( self::class, 'blog_user_update' ) ); + \add_action( 'update_option_activitypub_blog_identifier', array( self::class, 'blog_user_update' ) ); + \add_action( 'add_option_activitypub_blog_description', array( self::class, 'blog_user_update' ) ); + \add_action( 'update_option_activitypub_blog_description', array( self::class, 'blog_user_update' ) ); + \add_filter( 'pre_set_theme_mod_custom_logo', array( self::class, 'blog_user_update' ) ); + \add_filter( 'pre_set_theme_mod_header_image', array( self::class, 'blog_user_update' ) ); // Profile updates for user options. - if ( ! is_user_type_disabled( 'user' ) ) { - \add_action( 'profile_update', array( self::class, 'user_update' ) ); - \add_action( 'added_user_meta', array( self::class, 'user_meta_update' ), 10, 3 ); - \add_action( 'updated_user_meta', array( self::class, 'user_meta_update' ), 10, 3 ); - // @todo figure out a feasible way of updating the header image since it's not unique to any user. - } - - \add_action( 'add_option_activitypub_actor_mode', array( self::class, 'blog_user_update' ) ); - \add_action( 'update_option_activitypub_actor_mode', array( self::class, 'blog_user_update' ) ); + \add_action( 'profile_update', array( self::class, 'user_update' ) ); + \add_action( 'added_user_meta', array( self::class, 'user_meta_update' ), 10, 3 ); + \add_action( 'updated_user_meta', array( self::class, 'user_meta_update' ), 10, 3 ); + // @todo figure out a feasible way of updating the header image since it's not unique to any user. \add_action( 'transition_post_status', array( self::class, 'schedule_post_activity' ), 33, 3 ); diff --git a/includes/scheduler/class-post.php b/includes/scheduler/class-post.php index ec4fee75b7..18edb1418f 100644 --- a/includes/scheduler/class-post.php +++ b/includes/scheduler/class-post.php @@ -31,12 +31,12 @@ public static function init() { /** * Handle post updates and determine the appropriate Activity type. * - * @param int $post_id Post ID. - * @param \WP_Post $post Post object. - * @param bool $update Whether this is an existing post being updated. - * @param \WP_Post $post_before Post object before the update. + * @param int $post_id Post ID. + * @param \WP_Post $post Post object. + * @param bool $update Whether this is an existing post being updated. + * @param \WP_Post|null $post_before Post object before the update. */ - public static function schedule_post_activity( $post_id, $post, $update, $post_before ) { + public static function schedule_post_activity( $post_id, $post, $update, $post_before = null ) { if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) { return; } diff --git a/includes/transformer/class-comment.php b/includes/transformer/class-comment.php index 338c40ae54..067260ebad 100644 --- a/includes/transformer/class-comment.php +++ b/includes/transformer/class-comment.php @@ -15,7 +15,6 @@ use function Activitypub\get_comment_ancestors; use function Activitypub\get_rest_url_by_path; -use function Activitypub\is_single_user; use function Activitypub\was_comment_received; /** @@ -208,10 +207,6 @@ protected function get_actor_object() { $blog_user = new Blog(); $this->actor_object = $blog_user; - if ( is_single_user() ) { - return $blog_user; - } - $user = Actors::get_by_id( $this->item->user_id ); if ( $user && ! is_wp_error( $user ) ) { diff --git a/includes/transformer/class-post.php b/includes/transformer/class-post.php index 5c30cde606..2fcc572b86 100644 --- a/includes/transformer/class-post.php +++ b/includes/transformer/class-post.php @@ -20,7 +20,6 @@ use function Activitypub\get_content_warning; use function Activitypub\get_enclosures; use function Activitypub\get_rest_url_by_path; -use function Activitypub\is_single_user; use function Activitypub\site_supports_blocks; /** @@ -105,10 +104,6 @@ public function get_actor_object() { $blog_user = new Blog(); $this->actor_object = $blog_user; - if ( is_single_user() ) { - return $blog_user; - } - $user = Actors::get_by_id( $this->item->post_author ); if ( $user && ! is_wp_error( $user ) ) { @@ -412,14 +407,8 @@ protected function get_type() { * @return string|null The audience. */ public function get_audience() { - $actor_mode = \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - - if ( ACTIVITYPUB_ACTOR_AND_BLOG_MODE === $actor_mode ) { - $blog = new Blog(); - return $blog->get_id(); - } - - return null; + // Posts always have the blog as audience. + return ( new Blog() )->get_id(); } /** @@ -1006,18 +995,10 @@ private function get_public_interaction_policy() { * @return string|array The actor ID(s). */ private function get_self_interaction_policy() { - switch ( \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ) { - case ACTIVITYPUB_BLOG_MODE: - return ( new Blog() )->get_id(); - - case ACTIVITYPUB_ACTOR_AND_BLOG_MODE: - return array( - $this->get_actor_object()->get_id(), - ( new Blog() )->get_id(), - ); - - default: - return $this->get_actor_object()->get_id(); - } + // Return both user and blog actor IDs. + return array( + $this->get_actor_object()->get_id(), + ( new Blog() )->get_id(), + ); } } diff --git a/includes/wp-admin/class-admin.php b/includes/wp-admin/class-admin.php index e3b4ca4cfd..3038ba446b 100644 --- a/includes/wp-admin/class-admin.php +++ b/includes/wp-admin/class-admin.php @@ -16,7 +16,6 @@ use function Activitypub\count_followers; use function Activitypub\get_content_visibility; -use function Activitypub\is_user_type_disabled; use function Activitypub\site_supports_blocks; use function Activitypub\user_can_activitypub; use function Activitypub\was_comment_received; @@ -289,7 +288,6 @@ public static function enqueue_scripts( $hook_suffix ) { 'activitypubCommandPalette', array( 'followingEnabled' => '1' === \get_option( 'activitypub_following_ui', '0' ), - 'actorMode' => \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ), 'canManageOptions' => \current_user_can( 'manage_options' ), ) ); @@ -810,7 +808,7 @@ public static function dashboard_glance_items( $items ) { ); } - if ( ! is_user_type_disabled( 'blog' ) && current_user_can( 'manage_options' ) ) { + if ( current_user_can( 'manage_options' ) ) { $follower_count = sprintf( // translators: %s: number of followers. _n( @@ -942,12 +940,11 @@ function activitypub_open_help_tab(event) { */ public static function add_dashboard_widgets() { \wp_add_dashboard_widget( 'activitypub_blog', \__( 'ActivityPub Plugin News', 'activitypub' ), array( self::class, 'blog_dashboard_widget' ) ); - if ( user_can_activitypub( \get_current_user_id() ) && ! is_user_type_disabled( 'user' ) ) { + if ( user_can_activitypub( \get_current_user_id() ) ) { \wp_add_dashboard_widget( 'activitypub_profile', \__( 'ActivityPub Author profile', 'activitypub' ), array( self::class, 'profile_dashboard_widget' ) ); } - if ( ! is_user_type_disabled( 'blog' ) ) { - \wp_add_dashboard_widget( 'activitypub_blog_profile', \__( 'ActivityPub Blog profile', 'activitypub' ), array( self::class, 'blogprofile_dashboard_widget' ) ); - } + // Add blog profile dashboard widget. + \wp_add_dashboard_widget( 'activitypub_blog_profile', \__( 'ActivityPub Blog profile', 'activitypub' ), array( self::class, 'blogprofile_dashboard_widget' ) ); } /** diff --git a/includes/wp-admin/class-blog-settings-fields.php b/includes/wp-admin/class-blog-settings-fields.php index ee96d2841d..c3895eb117 100644 --- a/includes/wp-admin/class-blog-settings-fields.php +++ b/includes/wp-admin/class-blog-settings-fields.php @@ -26,8 +26,8 @@ public static function init() { * Register all settings fields. */ public static function register_settings() { - // If we're in blog mode, and we're on the blog profile tab, mark the profile setup step as done. - if ( isset( $_GET['tab'] ) && 'blog-profile' === \sanitize_key( $_GET['tab'] ) && ACTIVITYPUB_BLOG_MODE === \get_option( 'activitypub_actor_mode' ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + // Mark the profile setup step as done when visiting the blog profile tab. + if ( isset( $_GET['tab'] ) && 'blog-profile' === \sanitize_key( $_GET['tab'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended \update_option( 'activitypub_checklist_profile_setup_visited', '1' ); } diff --git a/includes/wp-admin/class-settings-fields.php b/includes/wp-admin/class-settings-fields.php index 52dc2b52d0..07706f9bc6 100644 --- a/includes/wp-admin/class-settings-fields.php +++ b/includes/wp-admin/class-settings-fields.php @@ -27,13 +27,6 @@ public static function init() { */ public static function register_settings_fields() { // Add settings sections. - add_settings_section( - 'activitypub_profiles', - __( 'Profiles', 'activitypub' ), - '__return_empty_string', - 'activitypub_settings' - ); - add_settings_section( 'activitypub_activities', __( 'Activities', 'activitypub' ), @@ -63,14 +56,6 @@ public static function register_settings_fields() { ); // Add settings fields. - add_settings_field( - 'activitypub_actor_mode', - __( 'Enable profiles by type', 'activitypub' ), - array( self::class, 'render_actor_mode_field' ), - 'activitypub_settings', - 'activitypub_profiles' - ); - $object_type = \get_option( 'activitypub_object_type', ACTIVITYPUB_DEFAULT_OBJECT_TYPE ); if ( 'note' === $object_type ) { add_settings_field( @@ -161,70 +146,6 @@ public static function register_settings_fields() { ); } - /** - * Render actor mode field. - */ - public static function render_actor_mode_field() { - $disabled = ( \defined( 'ACTIVITYPUB_SINGLE_USER_MODE' ) && ACTIVITYPUB_SINGLE_USER_MODE ) || - ( \defined( 'ACTIVITYPUB_DISABLE_USER' ) && ACTIVITYPUB_DISABLE_USER ) || - ( \defined( 'ACTIVITYPUB_DISABLE_BLOG_USER' ) && ACTIVITYPUB_DISABLE_BLOG_USER ); - - if ( $disabled ) : - ?> -
- -
- - - 'integer', - 'description' => \__( 'Choose your preferred Actor-Mode.', 'activitypub' ), - 'default' => ACTIVITYPUB_ACTOR_MODE, - ) - ); - \register_setting( 'activitypub', 'activitypub_attribution_domains', @@ -395,22 +383,21 @@ public static function settings_page() { 'template' => ACTIVITYPUB_PLUGIN_DIR . 'templates/blocked-actors-list.php', ); - if ( user_can_activitypub( Actors::BLOG_USER_ID ) ) { - $settings_tabs['blog-profile'] = array( - 'label' => __( 'Blog Profile', 'activitypub' ), - 'template' => ACTIVITYPUB_PLUGIN_DIR . 'templates/blog-settings.php', - ); - $settings_tabs['followers'] = array( - 'label' => __( 'Followers', 'activitypub' ), - 'template' => ACTIVITYPUB_PLUGIN_DIR . 'templates/followers-list.php', - ); + // Blog profile and followers tabs. + $settings_tabs['blog-profile'] = array( + 'label' => __( 'Blog Profile', 'activitypub' ), + 'template' => ACTIVITYPUB_PLUGIN_DIR . 'templates/blog-settings.php', + ); + $settings_tabs['followers'] = array( + 'label' => __( 'Followers', 'activitypub' ), + 'template' => ACTIVITYPUB_PLUGIN_DIR . 'templates/followers-list.php', + ); - if ( '1' === \get_option( 'activitypub_following_ui', '0' ) ) { - $settings_tabs['following'] = array( - 'label' => __( 'Following', 'activitypub' ), - 'template' => ACTIVITYPUB_PLUGIN_DIR . 'templates/following-list.php', - ); - } + if ( '1' === \get_option( 'activitypub_following_ui', '0' ) ) { + $settings_tabs['following'] = array( + 'label' => __( 'Following', 'activitypub' ), + 'template' => ACTIVITYPUB_PLUGIN_DIR . 'templates/following-list.php', + ); } /** diff --git a/includes/wp-admin/class-welcome-fields.php b/includes/wp-admin/class-welcome-fields.php index 104593a841..15289c117f 100644 --- a/includes/wp-admin/class-welcome-fields.php +++ b/includes/wp-admin/class-welcome-fields.php @@ -353,14 +353,10 @@ public static function render_step_profile_setup() { - + - - diff --git a/includes/wp-admin/import/class-starter-kit.php b/includes/wp-admin/import/class-starter-kit.php index f71c2e72d4..cd87fea0b3 100644 --- a/includes/wp-admin/import/class-starter-kit.php +++ b/includes/wp-admin/import/class-starter-kit.php @@ -8,7 +8,6 @@ namespace Activitypub\WP_Admin\Import; use function Activitypub\follow; -use function Activitypub\is_user_type_disabled; use function Activitypub\object_to_uri; /** @@ -304,10 +303,7 @@ public static function import_options() { * Setup blog user filter for dropdown. */ private static function setup_blog_user_filter() { - if ( is_user_type_disabled( 'blog' ) ) { - return; - } - + // Add blog user to dropdown. self::$blog_user_filter_callback = function ( $users ) { return \preg_replace( '/<\/select>/', diff --git a/integration/class-opengraph.php b/integration/class-opengraph.php index 113e92a13b..72d78e4a07 100644 --- a/integration/class-opengraph.php +++ b/integration/class-opengraph.php @@ -8,9 +8,7 @@ namespace Activitypub\Integration; use Activitypub\Collection\Actors; -use Activitypub\Model\Blog; -use function Activitypub\is_single_user; use function Activitypub\is_user_type_disabled; /** @@ -54,16 +52,6 @@ public static function add_prefixes( $prefixes ) { * @return array the updated metadata. */ public static function add_metadata( $metadata ) { - // Always show Blog-User if the Blog is in single user mode. - if ( is_single_user() ) { - $user = new Blog(); - - // Add WebFinger resource. - $metadata['fediverse:creator'] = $user->get_webfinger(); - - return $metadata; - } - if ( \is_author() ) { // Use the Author of the Archive-Page. $user_id = \get_queried_object_id(); diff --git a/tests/phpunit/includes/class-activitypub-outbox-testcase.php b/tests/phpunit/includes/class-activitypub-outbox-testcase.php index 9f30eb2722..de107e65f1 100644 --- a/tests/phpunit/includes/class-activitypub-outbox-testcase.php +++ b/tests/phpunit/includes/class-activitypub-outbox-testcase.php @@ -57,21 +57,32 @@ public function tear_down() { /** * Retrieve the latest Outbox item to compare against. * - * @param string $title Title of the Outbox item. + * @param string $title Title of the Outbox item. + * @param string $activity_type Optional activity type to filter by (e.g., 'Create', 'Update'). * @return int|\WP_Post|null */ - protected function get_latest_outbox_item( $title = '' ) { - $outbox = \get_posts( - array( - 'post_type' => Outbox::POST_TYPE, - 'posts_per_page' => 1, - 'post_status' => 'pending', - 'post_title' => $title, - 'orderby' => 'date', - 'order' => 'DESC', - ) + protected function get_latest_outbox_item( $title = '', $activity_type = '' ) { + $args = array( + 'post_type' => Outbox::POST_TYPE, + 'posts_per_page' => 1, + 'post_status' => 'pending', + 'post_title' => $title, + 'orderby' => 'date', + 'order' => 'DESC', ); + if ( ! empty( $activity_type ) ) { + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + $args['meta_query'] = array( + array( + 'key' => '_activitypub_activity_type', + 'value' => $activity_type, + ), + ); + } + + $outbox = \get_posts( $args ); + return $outbox ? $outbox[0] : null; } } diff --git a/tests/phpunit/tests/includes/class-test-dispatcher.php b/tests/phpunit/tests/includes/class-test-dispatcher.php index c10db6f711..21ba59a0ce 100644 --- a/tests/phpunit/tests/includes/class-test-dispatcher.php +++ b/tests/phpunit/tests/includes/class-test-dispatcher.php @@ -48,7 +48,7 @@ public function tear_down() { */ public function test_send_to_followers() { $post_id = self::factory()->post->create( array( 'post_author' => self::$user_id ) ); - $outbox_item = $this->get_latest_outbox_item( \add_query_arg( 'p', $post_id, \home_url( '/' ) ) ); + $outbox_item = $this->get_latest_outbox_item( \add_query_arg( 'p', $post_id, \home_url( '/' ) ), 'Create' ); Followers::add( self::$user_id, 'https://example.org/users/username' ); Followers::add( self::$user_id, 'https://example.com/users/username' ); @@ -74,7 +74,7 @@ public function test_process_outbox() { }; add_filter( 'activitypub_send_activity_to_followers', $test_callback, 10, 2 ); - $outbox_item = $this->get_latest_outbox_item( \add_query_arg( 'p', $post_id, \home_url( '/' ) ) ); + $outbox_item = $this->get_latest_outbox_item( \add_query_arg( 'p', $post_id, \home_url( '/' ) ), 'Create' ); Dispatcher::process_outbox( $outbox_item->ID ); @@ -229,7 +229,7 @@ public function test_send_to_relays() { */ public function test_should_send_to_followers() { $post_id = self::factory()->post->create( array( 'post_author' => self::$user_id ) ); - $outbox_item = $this->get_latest_outbox_item( \add_query_arg( 'p', $post_id, \home_url( '/' ) ) ); + $outbox_item = $this->get_latest_outbox_item( \add_query_arg( 'p', $post_id, \home_url( '/' ) ), 'Create' ); $activity = Outbox::get_activity( $outbox_item ); $should_send = new \ReflectionMethod( Dispatcher::class, 'should_send_to_followers' ); diff --git a/tests/phpunit/tests/includes/class-test-functions.php b/tests/phpunit/tests/includes/class-test-functions.php index 7fd00663a2..8d12dedc42 100644 --- a/tests/phpunit/tests/includes/class-test-functions.php +++ b/tests/phpunit/tests/includes/class-test-functions.php @@ -706,23 +706,22 @@ public function get_post_summary_data() { * @covers \Activitypub\get_user_id */ public function test_get_user_id() { - $this->assertFalse( \Activitypub\get_user_id( 90210 ) ); + // Invalid user ID should fall back to blog actor. + $this->assertIsString( \Activitypub\get_user_id( 90210 ) ); $user = self::factory()->user->create_and_get(); $user->add_cap( 'activitypub' ); $this->assertIsString( \Activitypub\get_user_id( $user->ID ) ); - \add_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - + // User with capability should have ID. $this->assertIsString( \Activitypub\get_user_id( $user->ID ) ); + // Remove capability - user should fall back to blog. $user->remove_cap( 'activitypub' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); - $this->assertIsString( \Activitypub\get_user_id( $user->ID ) ); - - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - $this->assertFalse( \Activitypub\get_user_id( $user->ID ) ); + $blog_id = \Activitypub\get_user_id( $user->ID ); + $this->assertIsString( $blog_id ); + $this->assertStringContainsString( 'author=0', $blog_id, 'Should return blog actor ID' ); } /** diff --git a/tests/phpunit/tests/includes/class-test-mailer.php b/tests/phpunit/tests/includes/class-test-mailer.php index b4aa68e86c..500e386ea8 100644 --- a/tests/phpunit/tests/includes/class-test-mailer.php +++ b/tests/phpunit/tests/includes/class-test-mailer.php @@ -650,7 +650,6 @@ public function test_mention_with_disabled_option() { public function test_blog_new_follower_with_disabled_option() { // Set blog option to false (0). update_option( 'activitypub_blog_user_mailer_new_follower', '0' ); - update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); $activity = array( 'type' => 'Follow', @@ -671,7 +670,6 @@ public function test_blog_new_follower_with_disabled_option() { // Clean up. remove_all_filters( 'wp_before_load_template' ); delete_option( 'activitypub_blog_user_mailer_new_follower' ); - delete_option( 'activitypub_actor_mode' ); } /** @@ -682,7 +680,6 @@ public function test_blog_new_follower_with_disabled_option() { public function test_blog_direct_message_with_disabled_option() { // Set blog option to false (0). update_option( 'activitypub_blog_user_mailer_new_dm', '0' ); - update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); $activity = array( 'actor' => 'https://example.com/author', @@ -706,7 +703,6 @@ public function test_blog_direct_message_with_disabled_option() { // Clean up. remove_all_filters( 'wp_before_load_template' ); delete_option( 'activitypub_blog_user_mailer_new_dm' ); - delete_option( 'activitypub_actor_mode' ); } /** @@ -717,7 +713,6 @@ public function test_blog_direct_message_with_disabled_option() { public function test_blog_mention_with_disabled_option() { // Set blog option to false (0). update_option( 'activitypub_blog_user_mailer_new_mention', '0' ); - update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); $activity = array( 'actor' => 'https://example.com/author', @@ -741,7 +736,6 @@ public function test_blog_mention_with_disabled_option() { // Clean up. remove_all_filters( 'wp_before_load_template' ); delete_option( 'activitypub_blog_user_mailer_new_mention' ); - delete_option( 'activitypub_actor_mode' ); } /** diff --git a/tests/phpunit/tests/includes/class-test-migration.php b/tests/phpunit/tests/includes/class-test-migration.php index cb3ab8159f..0c77d20008 100644 --- a/tests/phpunit/tests/includes/class-test-migration.php +++ b/tests/phpunit/tests/includes/class-test-migration.php @@ -132,7 +132,7 @@ public function test_migrate_actor_mode() { Migration::migrate_actor_mode(); - $this->assertEquals( ACTIVITYPUB_ACTOR_MODE, \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ); + $this->assertEquals( 'actor', \get_option( 'activitypub_actor_mode', 'actor' ) ); \update_option( 'activitypub_enable_blog_user', '0' ); \update_option( 'activitypub_enable_users', '1' ); @@ -140,7 +140,7 @@ public function test_migrate_actor_mode() { Migration::migrate_actor_mode(); - $this->assertEquals( ACTIVITYPUB_ACTOR_MODE, \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ); + $this->assertEquals( 'actor', \get_option( 'activitypub_actor_mode', 'actor' ) ); \update_option( 'activitypub_enable_blog_user', '1' ); \update_option( 'activitypub_enable_users', '1' ); @@ -148,7 +148,7 @@ public function test_migrate_actor_mode() { Migration::migrate_actor_mode(); - $this->assertEquals( ACTIVITYPUB_ACTOR_AND_BLOG_MODE, \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ); + $this->assertEquals( 'actor_blog', \get_option( 'activitypub_actor_mode', 'actor' ) ); \update_option( 'activitypub_enable_blog_user', '1' ); \update_option( 'activitypub_enable_users', '0' ); @@ -156,7 +156,7 @@ public function test_migrate_actor_mode() { Migration::migrate_actor_mode(); - $this->assertEquals( ACTIVITYPUB_BLOG_MODE, \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ); + $this->assertEquals( 'blog', \get_option( 'activitypub_actor_mode', 'actor' ) ); \delete_option( 'activitypub_enable_blog_user' ); \update_option( 'activitypub_enable_users', '0' ); @@ -164,7 +164,7 @@ public function test_migrate_actor_mode() { Migration::migrate_actor_mode(); - $this->assertEquals( ACTIVITYPUB_ACTOR_MODE, \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ); + $this->assertEquals( 'actor', \get_option( 'activitypub_actor_mode', 'actor' ) ); \update_option( 'activitypub_enable_blog_user', '0' ); \delete_option( 'activitypub_enable_users' ); @@ -172,7 +172,7 @@ public function test_migrate_actor_mode() { Migration::migrate_actor_mode(); - $this->assertEquals( ACTIVITYPUB_ACTOR_MODE, \get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ) ); + $this->assertEquals( 'actor', \get_option( 'activitypub_actor_mode', 'actor' ) ); } /** diff --git a/tests/phpunit/tests/includes/class-test-move.php b/tests/phpunit/tests/includes/class-test-move.php index 3b09fcaa86..aa3dd9a22c 100644 --- a/tests/phpunit/tests/includes/class-test-move.php +++ b/tests/phpunit/tests/includes/class-test-move.php @@ -118,7 +118,7 @@ public function test_account_with_duplicate_moves() { */ public function test_account_with_blog_author_as_actor() { // Change user mode to blog author. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'blog' ); $from = Actors::get_by_id( Actors::BLOG_USER_ID )->get_id(); $to = 'https://newsite.com/user/0'; @@ -194,7 +194,7 @@ public function test_internally_activity_object_properties() { */ public function test_change_domain_with_valid_input() { // Enable blog actor. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $old_domain = home_url(); $new_domain = 'http://newdomain.com'; diff --git a/tests/phpunit/tests/includes/class-test-query.php b/tests/phpunit/tests/includes/class-test-query.php index 70d3eccc70..379524bc4b 100644 --- a/tests/phpunit/tests/includes/class-test-query.php +++ b/tests/phpunit/tests/includes/class-test-query.php @@ -485,16 +485,17 @@ public function test_maybe_get_stamp_invalid_meta() { } /** - * Test maybe_get_stamp with invalid post author. + * Test maybe_get_stamp with author fallback to blog actor. + * With actor mode removal, all posts have an actor (user or blog). * * @covers ::maybe_get_stamp */ - public function test_maybe_get_stamp_invalid_author() { - // Create a post with invalid author. + public function test_maybe_get_stamp_with_blog_actor_fallback() { + // Create a post with an invalid author that will fall back to blog actor. $post_id = self::factory()->post->create( array( 'post_author' => 999999, // Non-existent user ID. - 'post_title' => 'Test Post Invalid Author', + 'post_title' => 'Test Post with Blog Fallback', 'post_content' => 'Test Content', 'post_status' => 'publish', ) @@ -513,20 +514,19 @@ public function test_maybe_get_stamp_invalid_author() { $query = Query::get_instance(); $result = $method->invoke( $query ); - $this->assertFalse( $result, 'Should return false for invalid post author' ); + // Should successfully fall back to blog actor and return a stamp object. + $this->assertNotFalse( $result, 'Should fall back to blog actor and return valid stamp' ); // Clean up. \wp_delete_post( $post_id, true ); } /** - * Test get_activitypub_object method for home page in Actor mode. + * Test get_activitypub_object method for home page. * * @covers ::get_activitypub_object */ - public function test_home_page_actor_mode() { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - + public function test_home_page_blog_actor() { $actor_queries = array(); // Track database queries using the 'query' filter. @@ -550,7 +550,7 @@ public function test_home_page_actor_mode() { $message .= ' Found queries: ' . wp_json_encode( $actor_queries ); } - $this->assertNull( $object, 'Home page should return null, because the Blog user is disabled.' ); + $this->assertInstanceOf( 'Activitypub\Model\Blog', $object, 'Home page should return Blog actor.' ); $this->assertEmpty( $actor_queries, $message ); \delete_option( 'activitypub_actor_mode' ); @@ -562,7 +562,7 @@ public function test_home_page_actor_mode() { * @covers ::get_activitypub_object */ public function test_home_page_actor_and_blog_mode() { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $actor_queries = array(); // Track database queries using the 'query' filter. diff --git a/tests/phpunit/tests/includes/class-test-scheduler.php b/tests/phpunit/tests/includes/class-test-scheduler.php index d9f40bf292..0d5170940c 100644 --- a/tests/phpunit/tests/includes/class-test-scheduler.php +++ b/tests/phpunit/tests/includes/class-test-scheduler.php @@ -457,9 +457,6 @@ public function test_async_batch_with_invalid_callback() { * @covers ::schedule_announce_activity */ public function test_schedule_announce_activity() { - // Set the actor mode to both blog and user mode. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); - $activity = new Activity(); $activity->set_type( 'Create' ); $activity->set_id( 'https://example.com/test-id' ); diff --git a/tests/phpunit/tests/includes/collection/class-test-actors.php b/tests/phpunit/tests/includes/collection/class-test-actors.php index ce496a403d..d662b8e680 100644 --- a/tests/phpunit/tests/includes/collection/class-test-actors.php +++ b/tests/phpunit/tests/includes/collection/class-test-actors.php @@ -21,7 +21,6 @@ class Test_Actors extends \WP_UnitTestCase { public function set_up() { parent::set_up(); - update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); add_option( 'activitypub_blog_identifier', 'blog' ); add_user_meta( 1, 'activitypub_user_identifier', 'admin' ); } @@ -39,7 +38,6 @@ public function tear_down() { \delete_option( 'activitypub_blog_user_private_key' ); \delete_option( 'activitypub_application_user_public_key' ); \delete_option( 'activitypub_application_user_private_key' ); - \delete_option( 'activitypub_actor_mode' ); \delete_user_meta( 1, 'magic_sig_public_key' ); \delete_user_meta( 1, 'magic_sig_private_key' ); } @@ -135,20 +133,15 @@ public function test_get_type_by_id() { } /** - * Test if Actor mode will be respected properly + * Test that blog profile is available. * - * @covers ::get_type_by_id + * @covers ::get_by_resource */ - public function test_disabled_blog_profile() { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); - + public function test_blog_profile_available() { $resource = 'http://example.org/@blog'; + // Blog profile should be available. $this->assertEquals( 'Activitypub\Model\Blog', get_class( Actors::get_by_resource( $resource ) ) ); - - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - - $this->assertWPError( Actors::get_by_resource( $resource ) ); } /** @@ -202,9 +195,6 @@ public function test_signature_legacy() { $this->assertEquals( $key_pair['private_key'], $private_key ); // Check blog user. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); - \delete_option( 'activitypub_actor_mode' ); - $public_key = 'public key ' . Actors::BLOG_USER_ID; $private_key = 'private key ' . Actors::BLOG_USER_ID; diff --git a/tests/phpunit/tests/includes/collection/class-test-followers.php b/tests/phpunit/tests/includes/collection/class-test-followers.php index 801cb2ee26..1eb1987247 100644 --- a/tests/phpunit/tests/includes/collection/class-test-followers.php +++ b/tests/phpunit/tests/includes/collection/class-test-followers.php @@ -533,81 +533,6 @@ public function test_get_all_followers() { $this->assertCount( 30, $followers ); } - /** - * Data provider for test_maybe_add_inboxes_of_blog_user. - * - * @return array[] Test data. - */ - public function data_maybe_add_inboxes_of_blog_user() { - return array( - 'actor mode' => array( - 'actor_mode' => ACTIVITYPUB_ACTOR_MODE, - 'json' => '{"type":"Update","id":"test"}', - 'actor_id' => 123, - 'expected' => false, - 'message' => 'Should return false when not in blog and user mode.', - ), - 'blog actor' => array( - 'actor_mode' => ACTIVITYPUB_ACTOR_AND_BLOG_MODE, - 'json' => '{"type":"Update","id":"test"}', - 'actor_id' => Actors::BLOG_USER_ID, - 'expected' => false, - 'message' => 'Should return false when using blog actor.', - ), - 'create activity' => array( - 'actor_mode' => ACTIVITYPUB_ACTOR_AND_BLOG_MODE, - 'json' => '{"type":"Create","id":"test"}', - 'actor_id' => 123, - 'expected' => false, - 'message' => 'Should return false for non-Update/Delete activity types.', - ), - 'update activity' => array( - 'actor_mode' => ACTIVITYPUB_ACTOR_AND_BLOG_MODE, - 'json' => '{"type":"Update","id":"test"}', - 'actor_id' => 123, - 'expected' => true, - 'message' => 'Should return true for Update activity in dual mode.', - ), - 'delete activity' => array( - 'actor_mode' => ACTIVITYPUB_ACTOR_AND_BLOG_MODE, - 'json' => '{"type":"Delete","id":"test"}', - 'actor_id' => 123, - 'expected' => true, - 'message' => 'Should return true for Delete activity in dual mode.', - ), - 'invalid json' => array( - 'actor_mode' => ACTIVITYPUB_ACTOR_AND_BLOG_MODE, - 'json' => 'invalid json', - 'actor_id' => 123, - 'expected' => false, - 'message' => 'Should return false for invalid JSON.', - ), - ); - } - - /** - * Test maybe_add_inboxes_of_blog_user method. - * - * @covers ::maybe_add_inboxes_of_blog_user - * @dataProvider data_maybe_add_inboxes_of_blog_user - * - * @expectedDeprecated Activitypub\Collection\Followers::maybe_add_inboxes_of_blog_user - * - * @param string $actor_mode The actor mode to test with. - * @param string $json The JSON to test with. - * @param int $actor_id The actor ID to test with. - * @param boolean $expected The expected result. - * @param string $message The assertion message. - */ - public function test_maybe_add_inboxes_of_blog_user( $actor_mode, $json, $actor_id, $expected, $message ) { - update_option( 'activitypub_actor_mode', $actor_mode ); - $this->assertSame( - $expected, - Followers::maybe_add_inboxes_of_blog_user( $json, $actor_id ), - $message - ); - } - /** * Tests get_inboxes_for_activity method. * @@ -650,7 +575,7 @@ public function test_get_inboxes_for_activity() { $this->assertCount( 1, $inboxes, 'Should retrieve exactly 1 inbox with batch size 1.' ); // Test with blog user in dual mode. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); Followers::add( Actors::BLOG_USER_ID, self::$actors['sally@example.org']['id'] ); $inboxes = Followers::get_inboxes_for_activity( diff --git a/tests/phpunit/tests/includes/collection/class-test-inbox.php b/tests/phpunit/tests/includes/collection/class-test-inbox.php index a135f33423..bdda098e55 100644 --- a/tests/phpunit/tests/includes/collection/class-test-inbox.php +++ b/tests/phpunit/tests/includes/collection/class-test-inbox.php @@ -24,7 +24,7 @@ class Test_Inbox extends \WP_UnitTestCase { public function set_up() { parent::set_up(); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); } /** diff --git a/tests/phpunit/tests/includes/collection/class-test-outbox.php b/tests/phpunit/tests/includes/collection/class-test-outbox.php index 9fd076c6a6..8a3eebe462 100644 --- a/tests/phpunit/tests/includes/collection/class-test-outbox.php +++ b/tests/phpunit/tests/includes/collection/class-test-outbox.php @@ -30,7 +30,7 @@ class Test_Outbox extends \Activitypub\Tests\ActivityPub_Outbox_TestCase { * @param string $json The JSON representation of the data. */ public function test_add( $data, $type, $user_id, $json ) { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $id = \Activitypub\add_to_outbox( $data, $type, $user_id ); @@ -173,17 +173,15 @@ public function activity_object_provider() { /** * Test add an item to the outbox with a user. + * With actor mode removal, invalid users always fall back to blog. * * @covers ::add * @dataProvider author_object_provider * - * @param string $mode The actor mode. * @param int $user_id The user ID. * @param string $expected_actor The expected actor. */ - public function test_author_fallbacks( $mode, $user_id, $expected_actor ) { - \update_option( 'activitypub_actor_mode', $mode ); - + public function test_author_fallbacks( $user_id, $expected_actor ) { $user_id = $user_id ?? self::$user_id; $data = array( '@context' => 'https://www.w3.org/ns/activitystreams', @@ -203,10 +201,8 @@ public function test_author_fallbacks( $mode, $user_id, $expected_actor ) { */ public function author_object_provider() { return array( - array( ACTIVITYPUB_ACTOR_AND_BLOG_MODE, null, 'user' ), - array( ACTIVITYPUB_ACTOR_AND_BLOG_MODE, 90210, 'blog' ), - array( ACTIVITYPUB_BLOG_MODE, 90210, 'blog' ), - array( ACTIVITYPUB_ACTOR_MODE, 90210, false ), + array( null, 'user' ), + array( 90210, 'blog' ), // Invalid user falls back to blog. ); } diff --git a/tests/phpunit/tests/includes/collection/class-test-replies.php b/tests/phpunit/tests/includes/collection/class-test-replies.php index c4a4ae78c1..97a2a24712 100644 --- a/tests/phpunit/tests/includes/collection/class-test-replies.php +++ b/tests/phpunit/tests/includes/collection/class-test-replies.php @@ -149,16 +149,9 @@ public function test_get_context_collection_disabled_author() { $context_post_id = self::factory()->post->create( array( 'post_author' => $user_id ) ); get_user_by( 'id', $user_id )->remove_cap( 'activitypub' ); - // Author disabled, Blog user disabled. - $this->assertFalse( Replies::get_context_collection( $context_post_id ) ); - - // Enable Blog user. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); - + // Author has no capability, should fall back to blog actor. $context = Replies::get_context_collection( $context_post_id ); - + $this->assertNotFalse( $context, 'Should fall back to blog actor' ); $this->assertSame( \get_author_posts_url( Actors::BLOG_USER_ID ), $context['attributedTo'] ); - - \delete_option( 'activitypub_actor_mode' ); } } diff --git a/tests/phpunit/tests/includes/model/class-test-blog.php b/tests/phpunit/tests/includes/model/class-test-blog.php index 400fda7dcd..d30c07fd0c 100644 --- a/tests/phpunit/tests/includes/model/class-test-blog.php +++ b/tests/phpunit/tests/includes/model/class-test-blog.php @@ -24,7 +24,7 @@ public static function set_up_before_class() { parent::set_up_before_class(); // Enable blog actor. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); } /** diff --git a/tests/phpunit/tests/includes/rest/class-test-followers-controller.php b/tests/phpunit/tests/includes/rest/class-test-followers-controller.php index 1575a3c7e6..7ee79d9351 100644 --- a/tests/phpunit/tests/includes/rest/class-test-followers-controller.php +++ b/tests/phpunit/tests/includes/rest/class-test-followers-controller.php @@ -87,7 +87,7 @@ public function test_get_item_schema() { */ public function test_get_items() { $actor_mode = \get_option( 'activitypub_actor_mode' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'blog' ); $request = new \WP_REST_Request( 'GET', '/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/0/followers' ); $request->set_param( 'page', 1 ); @@ -121,7 +121,7 @@ public function test_get_items() { */ public function test_get_items_full_context() { $actor_mode = \get_option( 'activitypub_actor_mode' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'blog' ); $request = new \WP_REST_Request( 'GET', '/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/0/followers' ); $request->set_param( 'page', 1 ); @@ -146,7 +146,7 @@ public function test_get_items_full_context() { */ public function test_get_items_pagination() { $actor_mode = \get_option( 'activitypub_actor_mode' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'blog' ); $request = new \WP_REST_Request( 'GET', '/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/0/followers' ); $request->set_param( 'page', 2 ); diff --git a/tests/phpunit/tests/includes/rest/class-test-following-controller.php b/tests/phpunit/tests/includes/rest/class-test-following-controller.php index 65e809611d..d6023710ea 100644 --- a/tests/phpunit/tests/includes/rest/class-test-following-controller.php +++ b/tests/phpunit/tests/includes/rest/class-test-following-controller.php @@ -106,7 +106,7 @@ public function test_get_item_schema() { */ public function test_get_items() { $actor_mode = \get_option( 'activitypub_actor_mode' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'blog' ); $request = new \WP_REST_Request( 'GET', '/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/0/following' ); $request->set_param( 'page', 1 ); @@ -141,7 +141,7 @@ public function test_get_items() { */ public function test_get_items_full_context() { $actor_mode = \get_option( 'activitypub_actor_mode' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'blog' ); $request = new \WP_REST_Request( 'GET', '/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/0/following' ); $request->set_param( 'page', 1 ); @@ -166,7 +166,7 @@ public function test_get_items_full_context() { */ public function test_get_items_pagination() { $actor_mode = \get_option( 'activitypub_actor_mode' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'blog' ); $request = new \WP_REST_Request( 'GET', '/' . ACTIVITYPUB_REST_NAMESPACE . '/actors/0/following' ); $request->set_param( 'page', 2 ); diff --git a/tests/phpunit/tests/includes/rest/class-test-inbox-controller.php b/tests/phpunit/tests/includes/rest/class-test-inbox-controller.php index e16bb23a49..76b87d637e 100644 --- a/tests/phpunit/tests/includes/rest/class-test-inbox-controller.php +++ b/tests/phpunit/tests/includes/rest/class-test-inbox-controller.php @@ -197,7 +197,7 @@ public function test_get_item_schema() { public function test_create_item_with_blog_user() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'blog' ); $blog_actor = \Activitypub\Collection\Actors::get_by_id( \Activitypub\Collection\Actors::BLOG_USER_ID ); @@ -242,7 +242,7 @@ public function test_create_item_with_blog_user() { public function test_create_item_with_multiple_recipients() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $user_actor = \Activitypub\Collection\Actors::get_by_id( self::$user_id ); $blog_actor = \Activitypub\Collection\Actors::get_by_id( \Activitypub\Collection\Actors::BLOG_USER_ID ); @@ -288,7 +288,7 @@ public function test_create_item_with_multiple_recipients() { public function test_create_item_with_multiple_recipients_and_invalid_recipient() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $user_actor = \Activitypub\Collection\Actors::get_by_id( self::$user_id ); $blog_actor = \Activitypub\Collection\Actors::get_by_id( \Activitypub\Collection\Actors::BLOG_USER_ID ); @@ -334,7 +334,7 @@ public function test_create_item_with_multiple_recipients_and_invalid_recipient( public function test_create_item_with_multiple_recipients_and_inactive_recipient() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $user_actor = \Activitypub\Collection\Actors::get_by_id( self::$user_id ); $blog_actor = \Activitypub\Collection\Actors::get_by_id( \Activitypub\Collection\Actors::BLOG_USER_ID ); @@ -357,7 +357,7 @@ public function test_create_item_with_multiple_recipients_and_inactive_recipient 'to' => array( $user_actor->get_id(), $blog_actor->get_id() ), ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); + \update_option( 'activitypub_actor_mode', 'actor' ); $request = new \WP_REST_Request( 'POST', '/' . ACTIVITYPUB_REST_NAMESPACE . '/inbox' ); $request->set_header( 'Content-Type', 'application/activity+json' ); @@ -382,7 +382,7 @@ public function test_create_item_with_multiple_recipients_and_inactive_recipient public function test_create_item_with_different_activity_types() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); + \update_option( 'activitypub_actor_mode', 'actor' ); $user_actor = \Activitypub\Collection\Actors::get_by_id( self::$user_id ); $activity_types = array( 'Update', 'Delete', 'Follow', 'Accept', 'Reject', 'Announce', 'Like' ); @@ -555,9 +555,6 @@ public function test_get_local_recipients_with_malformed_urls() { * @covers ::get_local_recipients */ public function test_get_local_recipients_public_activity() { - // Enable actor mode to allow user actors. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - // Create additional test users (authors have activitypub capability by default). $user_id_1 = self::factory()->user->create( array( 'role' => 'author' ) ); $user_id_2 = self::factory()->user->create( array( 'role' => 'author' ) ); @@ -617,16 +614,15 @@ function ( $pre, $url ) use ( $remote_actor_url ) { $this->assertContains( $user_id_3, $result, 'Should contain user 3' ); // Verify it returns exactly the followers we added. - // Note: May include blog user (0) if blog mode is enabled. + // Note: Blog user (0) is now always included. $this->assertGreaterThanOrEqual( 4, count( $result ), 'Should return at least 4 followers' ); - $this->assertLessThanOrEqual( 5, count( $result ), 'Should return at most 5 followers (4 users + optional blog)' ); + $this->assertLessThanOrEqual( 6, count( $result ), 'Should return at most 6 followers (4 users + blog + application)' ); // Clean up. \wp_delete_post( $remote_actor->ID, true ); \wp_delete_user( $user_id_1 ); \wp_delete_user( $user_id_2 ); \wp_delete_user( $user_id_3 ); - \delete_option( 'activitypub_actor_mode' ); \remove_all_filters( 'activitypub_pre_http_get_remote_object' ); } @@ -636,9 +632,6 @@ function ( $pre, $url ) use ( $remote_actor_url ) { * @covers ::get_local_recipients */ public function test_get_local_recipients_public_activity_in_cc() { - // Enable actor mode to allow user actors. - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - // Create a test user (authors have activitypub capability by default). $user_id = self::factory()->user->create( array( 'role' => 'author' ) ); @@ -692,14 +685,13 @@ function ( $pre, $url ) use ( $remote_actor_url ) { $this->assertContains( $user_id, $result, 'Should contain new test user' ); // Verify it returns exactly the followers we added. - // Note: May include blog user (0) if blog mode is enabled. + // Note: Blog user (0) is now always included. $this->assertGreaterThanOrEqual( 2, count( $result ), 'Should return at least 2 followers' ); - $this->assertLessThanOrEqual( 3, count( $result ), 'Should return at most 3 followers (2 users + optional blog)' ); + $this->assertLessThanOrEqual( 4, count( $result ), 'Should return at most 4 followers (2 users + blog + application)' ); // Clean up. \wp_delete_post( $remote_actor->ID, true ); \wp_delete_user( $user_id ); - \delete_option( 'activitypub_actor_mode' ); \remove_all_filters( 'activitypub_pre_http_get_remote_object' ); } @@ -710,7 +702,7 @@ function ( $pre, $url ) use ( $remote_actor_url ) { */ public function test_shared_inbox_context_parameter() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $user_actor = \Activitypub\Collection\Actors::get_by_id( self::$user_id ); $blog_actor = \Activitypub\Collection\Actors::get_by_id( \Activitypub\Collection\Actors::BLOG_USER_ID ); @@ -762,7 +754,7 @@ function ( $data, $user_ids, $type, $activity, $context ) use ( &$captured_conte */ public function test_shared_inbox_action_hook_fires() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $user_actor = \Activitypub\Collection\Actors::get_by_id( self::$user_id ); $blog_actor = \Activitypub\Collection\Actors::get_by_id( \Activitypub\Collection\Actors::BLOG_USER_ID ); @@ -820,7 +812,7 @@ function ( $data, $user_ids ) use ( &$shared_inbox_fired, &$captured_recipients */ public function test_inbox_persistence_with_shared_inbox() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $user_actor = \Activitypub\Collection\Actors::get_by_id( self::$user_id ); $blog_actor = \Activitypub\Collection\Actors::get_by_id( \Activitypub\Collection\Actors::BLOG_USER_ID ); @@ -881,7 +873,7 @@ function ( $data, $user_ids, $type, $activity, $item_id ) use ( &$inbox_id ) { */ public function test_regular_inbox_action_with_shared_inbox_context() { \add_filter( 'activitypub_defer_signature_verification', '__return_true' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); $user_actor = \Activitypub\Collection\Actors::get_by_id( self::$user_id ); $blog_actor = \Activitypub\Collection\Actors::get_by_id( \Activitypub\Collection\Actors::BLOG_USER_ID ); diff --git a/tests/phpunit/tests/includes/rest/class-test-outbox-controller.php b/tests/phpunit/tests/includes/rest/class-test-outbox-controller.php index 88b871d64d..e1ab79b9ce 100644 --- a/tests/phpunit/tests/includes/rest/class-test-outbox-controller.php +++ b/tests/phpunit/tests/includes/rest/class-test-outbox-controller.php @@ -72,27 +72,25 @@ public function test_register_routes() { /** * Test user ID validation. + * With actor mode removal, both blog and user actors are available. * * @covers ::validate_user_id */ public function test_validate_user_id() { - $actor_mode = \get_option( 'activitypub_actor_mode' ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); - $controller = new Outbox_Controller(); + + // Blog actor (ID 0) should be valid. $this->assertTrue( $controller->validate_user_id( 0 ) ); - $this->assertTrue( $controller->validate_user_id( '1' ) ); - $this->assertWPError( $controller->validate_user_id( 'user-1' ) ); + $this->assertTrue( $controller->validate_user_id( '0' ) ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - $this->assertWPError( $controller->validate_user_id( 0 ) ); - $this->assertTrue( $controller->validate_user_id( 1 ) ); + // User actor (ID 1) should be valid if user exists. + $this->assertTrue( $controller->validate_user_id( '1' ) ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); - $this->assertTrue( $controller->validate_user_id( '0' ) ); - $this->assertWPError( $controller->validate_user_id( 1 ) ); + // Invalid format should return WP_Error. + $this->assertWPError( $controller->validate_user_id( 'user-1' ) ); - \update_option( 'activitypub_actor_mode', $actor_mode ); + // Non-existent user ID should return WP_Error. + $this->assertWPError( $controller->validate_user_id( 99999 ) ); } /** @@ -500,7 +498,7 @@ public function test_get_items_content_visibility( $visibility, $public_visible, * @covers ::get_items */ public function test_get_items_actor_type_filtering() { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', 'actor_blog' ); // Create a post with blog actor type. $blog_post_id = self::factory()->post->create( diff --git a/tests/phpunit/tests/includes/scheduler/class-test-actor.php b/tests/phpunit/tests/includes/scheduler/class-test-actor.php index e9245b0161..55229b2d53 100644 --- a/tests/phpunit/tests/includes/scheduler/class-test-actor.php +++ b/tests/phpunit/tests/includes/scheduler/class-test-actor.php @@ -132,7 +132,6 @@ public function test_user_update() { * @covers ::blog_user_update */ public function test_blog_user_update() { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); $test_value = 'test value'; $result = \Activitypub\Scheduler\Actor::blog_user_update( $test_value ); @@ -165,7 +164,6 @@ public function blog_user_images_provider() { * @param string $option Option to test. */ public function test_blog_user_image_updates( $field, $option ) { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); Actor::init(); $attachment_id = self::factory()->attachment->create_upload_object( AP_TESTS_DIR . '/data/assets/test.jpg' ); @@ -209,7 +207,6 @@ public function blog_user_text_provider() { * @param string $value Value to test. */ public function test_blog_user_text_updates( $field, $option, $value ) { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); Actor::init(); \update_option( $option, $value ); @@ -287,7 +284,6 @@ public function test_schedule_post_activity_extra_fields() { * @covers ::schedule_post_activity */ public function test_schedule_post_activity_extra_field_blog() { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); $blog_post_id = self::factory()->post->create( array( 'post_type' => Extra_Fields::BLOG_POST_TYPE ) ); $activitpub_id = Actors::get_by_id( Actors::BLOG_USER_ID )->get_id(); diff --git a/tests/phpunit/tests/includes/scheduler/class-test-post.php b/tests/phpunit/tests/includes/scheduler/class-test-post.php index 7180713c6a..1dc03bd23d 100644 --- a/tests/phpunit/tests/includes/scheduler/class-test-post.php +++ b/tests/phpunit/tests/includes/scheduler/class-test-post.php @@ -28,7 +28,7 @@ public function test_transition_attachment_status() { // Create. $post_id = self::factory()->attachment->create_upload_object( AP_TESTS_DIR . '/data/assets/test.jpg' ); $activitypub_id = \add_query_arg( 'p', $post_id, \home_url( '/' ) ); - $outbox_item = $this->get_latest_outbox_item( $activitypub_id ); + $outbox_item = $this->get_latest_outbox_item( $activitypub_id, 'Create' ); $this->assertNotNull( $outbox_item ); $this->assertSame( 'Create', \get_post_meta( $outbox_item->ID, '_activitypub_activity_type', true ) ); @@ -36,13 +36,13 @@ public function test_transition_attachment_status() { // Update. self::factory()->attachment->update_object( $post_id, array( 'post_title' => 'Updated title' ) ); - $outbox_item = $this->get_latest_outbox_item( $activitypub_id ); + $outbox_item = $this->get_latest_outbox_item( $activitypub_id, 'Update' ); $this->assertSame( 'Update', \get_post_meta( $outbox_item->ID, '_activitypub_activity_type', true ) ); // Delete. \wp_delete_attachment( $post_id, true ); - $outbox_item = $this->get_latest_outbox_item( $activitypub_id ); + $outbox_item = $this->get_latest_outbox_item( $activitypub_id, 'Delete' ); $this->assertSame( 'Delete', \get_post_meta( $outbox_item->ID, '_activitypub_activity_type', true ) ); remove_post_type_support( 'attachment', 'activitypub' ); @@ -100,7 +100,7 @@ public function test_activity_type_on_publish() { \wp_publish_post( $post_id ); - $post = $this->get_latest_outbox_item( $activitypub_id ); + $post = $this->get_latest_outbox_item( $activitypub_id, 'Create' ); $type = \get_post_meta( $post->ID, '_activitypub_activity_type', true ); $this->assertSame( 'Create', $type ); diff --git a/tests/phpunit/tests/includes/transformer/class-test-base.php b/tests/phpunit/tests/includes/transformer/class-test-base.php index af0c236cbc..a2a21b83cf 100644 --- a/tests/phpunit/tests/includes/transformer/class-test-base.php +++ b/tests/phpunit/tests/includes/transformer/class-test-base.php @@ -127,8 +127,27 @@ function ( $k ) { $transformed_object = $method->invoke( $transformer, new Generic_Object() ); - $this->assertEquals( $expected_audience['to'], $transformed_object->get_to() ); - $this->assertEquals( $expected_audience['cc'], $transformed_object->get_cc() ); + // For TO field, check that it contains at least the expected items. + // (blog followers URL may also be present with actor mode removal). + $actual_to = $transformed_object->get_to(); + if ( null !== $expected_audience['to'] ) { + foreach ( $expected_audience['to'] as $expected_item ) { + $this->assertContains( $expected_item, $actual_to, "TO should contain $expected_item" ); + } + } else { + $this->assertNull( $actual_to, 'TO should be null' ); + } + + // For CC field, check that it contains at least the expected items. + // (blog followers URL will also be present for public posts). + $actual_cc = $transformed_object->get_cc(); + if ( null !== $expected_audience['cc'] ) { + foreach ( $expected_audience['cc'] as $expected_item ) { + $this->assertContains( $expected_item, $actual_cc, "CC should contain $expected_item" ); + } + } else { + $this->assertNull( $actual_cc, 'CC should be null' ); + } \wp_delete_post( $post_id ); \remove_filter( 'activitypub_pre_http_get_remote_object', $function ); diff --git a/tests/phpunit/tests/includes/transformer/class-test-factory.php b/tests/phpunit/tests/includes/transformer/class-test-factory.php index c45be26722..fa23863ce5 100644 --- a/tests/phpunit/tests/includes/transformer/class-test-factory.php +++ b/tests/phpunit/tests/includes/transformer/class-test-factory.php @@ -105,6 +105,7 @@ public function test_get_transformer_invalid_input() { /** * Test get_transformer with post. + * With actor mode removal, posts have an actor (user or blog). * * @covers ::get_transformer */ @@ -112,20 +113,7 @@ public function test_get_transformer_post() { $post = get_post( self::$post_id ); $transformer = Factory::get_transformer( $post ); - $this->assertInstanceOf( \WP_Error::class, $transformer ); - - \add_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); - - $post = get_post( self::$post_id ); - $transformer = Factory::get_transformer( $post ); - - $this->assertInstanceOf( Post::class, $transformer ); - - \add_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); - - $post = get_post( self::$post_id ); - $transformer = Factory::get_transformer( $post ); - + // Should return a Post transformer (blog actor fallback available). $this->assertInstanceOf( Post::class, $transformer ); } diff --git a/tests/phpunit/tests/includes/transformer/class-test-post.php b/tests/phpunit/tests/includes/transformer/class-test-post.php index 5b5418fee5..8ba3a7412f 100644 --- a/tests/phpunit/tests/includes/transformer/class-test-post.php +++ b/tests/phpunit/tests/includes/transformer/class-test-post.php @@ -413,15 +413,25 @@ public function test_get_attachments_with_zero_max_media_attachments() { $method = $reflection->getMethod( 'get_attachment' ); $method->setAccessible( true ); - $result = $method->invoke( $transformer ); + // Track filter count before and after to detect if filter was called. + $filter_count_before = \did_filter( 'activitypub_attachment_ids' ); + $result = $method->invoke( $transformer ); + $filter_count_after = \did_filter( 'activitypub_attachment_ids' ); $this->assertEmpty( $result ); - $this->assertFalse( (bool) \did_filter( 'activitypub_attachment_ids' ) ); + $this->assertEquals( $filter_count_before, $filter_count_after, 'Filter should not be called when max_media is 0' ); \delete_post_meta( $post_id, 'activitypub_max_image_attachments' ); - $result = $method->invoke( $transformer ); - $this->assertTrue( (bool) \did_filter( 'activitypub_attachment_ids' ) ); + // Need to recreate transformer to pick up new meta value. + $post = get_post( $post_id ); + $transformer = new Post( $post ); + + $filter_count_before = \did_filter( 'activitypub_attachment_ids' ); + $result = $method->invoke( $transformer ); + $filter_count_after = \did_filter( 'activitypub_attachment_ids' ); + + $this->assertGreaterThan( $filter_count_before, $filter_count_after, 'Filter should be called when max_media is default' ); \wp_delete_post( $post_id ); } @@ -977,38 +987,21 @@ public function test_get_interaction_policy_followers() { * * @covers ::get_interaction_policy */ - public function test_get_interaction_policy_me_actor_modes() { + public function test_get_interaction_policy_me() { $post = $this->create_test_post(); update_post_meta( $post->ID, 'activitypub_interaction_policy_quote', ACTIVITYPUB_INTERACTION_POLICY_ME ); - $actor_modes = array( - ACTIVITYPUB_ACTOR_MODE, - ACTIVITYPUB_BLOG_MODE, - ACTIVITYPUB_ACTOR_AND_BLOG_MODE, - ); + $transformer = new Post( get_post( $post->ID ) ); + $policy = $transformer->get_interaction_policy(); - foreach ( $actor_modes as $mode ) { - update_option( 'activitypub_actor_mode', $mode ); - $transformer = new Post( get_post( $post->ID ) ); // fresh instance. - $policy = $transformer->get_interaction_policy(); - - $this->assertIsArray( $policy, 'Policy should be array for mode ' . $mode ); - $this->assertArrayHasKey( 'canQuote', $policy ); - $this->assertArrayHasKey( 'automaticApproval', $policy['canQuote'] ); - - $auto = $policy['canQuote']['automaticApproval']; - if ( ACTIVITYPUB_ACTOR_AND_BLOG_MODE === $mode ) { - $this->assertIsArray( $auto, 'Actor+Blog mode should return an array of IDs.' ); - $this->assertCount( 2, $auto, 'Actor+Blog mode should supply two IDs.' ); - } else { - $this->assertIsString( $auto, 'Single mode should return a single ID string.' ); - } - } + $this->assertIsArray( $policy, 'Policy should be array' ); + $this->assertArrayHasKey( 'canQuote', $policy ); + $this->assertArrayHasKey( 'automaticApproval', $policy['canQuote'] ); - // Cleanup. - delete_option( 'activitypub_actor_mode' ); + $auto = $policy['canQuote']['automaticApproval']; + $this->assertIsArray( $auto, 'Should return an array of IDs (both user and blog).' ); + $this->assertCount( 2, $auto, 'Should supply two IDs (user and blog).' ); } - /** * Ensure invalid permission values fall back to 'anyone' policy. * diff --git a/tests/phpunit/tests/integration/class-test-webfinger.php b/tests/phpunit/tests/integration/class-test-webfinger.php index a7a957385d..ca704c8b0e 100644 --- a/tests/phpunit/tests/integration/class-test-webfinger.php +++ b/tests/phpunit/tests/integration/class-test-webfinger.php @@ -136,6 +136,7 @@ public function test_add_user_discovery() { /** * Test add_user_discovery with invalid user. + * With actor mode removal, invalid users fall back to blog actor. * * @covers ::add_user_discovery */ @@ -153,8 +154,10 @@ public function test_add_user_discovery_with_invalid_user() { $result = Webfinger::add_user_discovery( $initial_jrd, 'acct:invalid@example.com', $user ); - // Should return original jrd unchanged. - $this->assertEquals( $initial_jrd, $result ); + // Should fall back to blog actor instead of returning unchanged. + $this->assertNotEquals( $initial_jrd, $result, 'Should add blog actor info for invalid user' ); + $this->assertStringContainsString( wp_parse_url( home_url(), PHP_URL_HOST ), $result['subject'], 'Subject should be blog actor' ); + $this->assertNotEmpty( $result['aliases'], 'Should have aliases for blog actor' ); } /**