updated plugin ActivityPub version 9.1.0
This commit is contained in:
@ -49,6 +49,10 @@ class Actor {
|
||||
\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' ) );
|
||||
|
||||
// The Starter Kit policy is part of every actor profile.
|
||||
\add_action( 'add_option_activitypub_default_feature_policy', array( self::class, 'schedule_all_profile_updates' ) );
|
||||
\add_action( 'update_option_activitypub_default_feature_policy', array( self::class, 'schedule_all_profile_updates' ) );
|
||||
|
||||
\add_action( 'transition_post_status', array( self::class, 'schedule_post_activity' ), 33, 3 );
|
||||
|
||||
\add_action( 'post_stuck', array( self::class, 'sticky_post_update' ) );
|
||||
@ -84,7 +88,7 @@ class Actor {
|
||||
'user_url',
|
||||
);
|
||||
|
||||
if ( in_array( $meta_key, $fields, true ) ) {
|
||||
if ( \in_array( $meta_key, $fields, true ) ) {
|
||||
self::schedule_profile_update( $user_id );
|
||||
}
|
||||
}
|
||||
@ -132,13 +136,28 @@ class Actor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send profile updates for all local actors.
|
||||
*
|
||||
* Used when a site-wide setting that is part of every actor profile
|
||||
* changes, like the Starter Kit policy (FEP-7aa9 `canFeature`), so
|
||||
* followers of the blog actor and of every author receive the change.
|
||||
*
|
||||
* @since 9.0.1
|
||||
*/
|
||||
public static function schedule_all_profile_updates() {
|
||||
foreach ( Actors::get_all_ids() as $user_id ) {
|
||||
self::schedule_profile_update( $user_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a profile update to all followers. Gets hooked into all relevant options/meta etc.
|
||||
*
|
||||
* @param int $user_id The user ID to update (Could be 0 for Blog-User).
|
||||
*/
|
||||
public static function schedule_profile_update( $user_id ) {
|
||||
if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
|
||||
if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -148,7 +167,7 @@ class Actor {
|
||||
return;
|
||||
}
|
||||
|
||||
$actor->set_updated( gmdate( ACTIVITYPUB_DATE_TIME_RFC3339, time() ) );
|
||||
$actor->set_updated( \gmdate( ACTIVITYPUB_DATE_TIME_RFC3339, \time() ) );
|
||||
|
||||
add_to_outbox( $actor, 'Update', $user_id );
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ class Collection_Sync {
|
||||
public static function schedule_reconciliation( $type, $user_id, $actor_url, $params ) {
|
||||
// Schedule async processing to avoid blocking the inbox.
|
||||
\wp_schedule_single_event(
|
||||
time() + MINUTE_IN_SECONDS,
|
||||
\time() + MINUTE_IN_SECONDS,
|
||||
"activitypub_{$type}_sync_reconcile",
|
||||
array( $user_id, $actor_url, $params )
|
||||
);
|
||||
@ -70,7 +70,7 @@ class Collection_Sync {
|
||||
|
||||
$accepted = Following::get_by_authority( $user_id, $home_authority );
|
||||
foreach ( $accepted as $following ) {
|
||||
$key = array_search( $following->guid, $remote_followers, true );
|
||||
$key = \array_search( $following->guid, $remote_followers, true );
|
||||
if ( false === $key ) {
|
||||
Following::reject( $following, $user_id );
|
||||
} else {
|
||||
@ -78,11 +78,11 @@ class Collection_Sync {
|
||||
}
|
||||
}
|
||||
|
||||
$remote_followers = array_values( $remote_followers ); // Reindex.
|
||||
$remote_followers = \array_values( $remote_followers ); // Reindex.
|
||||
|
||||
$pending = Following::get_by_authority( $user_id, $home_authority, Following::PENDING_META_KEY );
|
||||
foreach ( $pending as $following ) {
|
||||
$key = array_search( $following->guid, $remote_followers, true );
|
||||
$key = \array_search( $following->guid, $remote_followers, true );
|
||||
if ( false === $key ) {
|
||||
Following::reject( $following, $user_id );
|
||||
} else {
|
||||
|
||||
@ -40,11 +40,11 @@ class Comment {
|
||||
* @param \WP_Comment $comment Comment object.
|
||||
*/
|
||||
public static function schedule_comment_activity( $new_status, $old_status, $comment ) {
|
||||
if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
|
||||
if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$comment = get_comment( $comment );
|
||||
$comment = \get_comment( $comment );
|
||||
|
||||
// Federate only comments that are written by a registered user.
|
||||
if ( ! $comment || ! $comment->user_id ) {
|
||||
@ -65,7 +65,7 @@ class Comment {
|
||||
$allowed_types[] = 'comment'; // Add core WordPress comment types.
|
||||
|
||||
// Check if comment type is in allowed list.
|
||||
if ( ! in_array( $comment_type, $allowed_types, true ) ) {
|
||||
if ( ! \in_array( $comment_type, $allowed_types, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ class Comment {
|
||||
$type = 'Create';
|
||||
} elseif ( 'approved' === $new_status ) {
|
||||
$type = 'Update';
|
||||
\update_comment_meta( $comment->comment_ID, 'activitypub_comment_modified', time(), true );
|
||||
\update_comment_meta( $comment->comment_ID, 'activitypub_comment_modified', \time(), true );
|
||||
} elseif (
|
||||
'trash' === $new_status ||
|
||||
( 'delete' === $new_status && '' === $old_status ) || // Went through schedule_comment_delete_activity().
|
||||
|
||||
@ -11,10 +11,10 @@ use Activitypub\Activity\Activity;
|
||||
use Activitypub\Collection\Actors;
|
||||
|
||||
use function Activitypub\add_to_outbox;
|
||||
use function Activitypub\get_content_visibility;
|
||||
use function Activitypub\get_post_id;
|
||||
use function Activitypub\get_wp_object_state;
|
||||
use function Activitypub\is_post_disabled;
|
||||
use function Activitypub\is_post_publicly_queryable;
|
||||
|
||||
/**
|
||||
* Post scheduler class.
|
||||
@ -55,7 +55,7 @@ class Post {
|
||||
* @param \WP_Post $post_before Post object before the update.
|
||||
*/
|
||||
public static function triage( $post_id, $post, $update, $post_before ) {
|
||||
if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
|
||||
if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -64,12 +64,10 @@ class Post {
|
||||
}
|
||||
|
||||
$object_status = get_wp_object_state( $post );
|
||||
$is_queryable = is_post_publicly_queryable( $post );
|
||||
|
||||
// If the post is already soft-deleted, do not create any more activities.
|
||||
if (
|
||||
ACTIVITYPUB_OBJECT_STATE_DELETED === $object_status &&
|
||||
in_array( get_content_visibility( $post ), array( ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL, ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE ), true )
|
||||
) {
|
||||
// If the post is already soft-deleted and still non-public, do not create any more activities.
|
||||
if ( ACTIVITYPUB_OBJECT_STATE_DELETED === $object_status && ! $is_queryable ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -78,8 +76,8 @@ class Post {
|
||||
return;
|
||||
}
|
||||
|
||||
$new_status = get_post_status( $post );
|
||||
$old_status = $post_before ? get_post_status( $post_before ) : null;
|
||||
$new_status = \get_post_status( $post );
|
||||
$old_status = $post_before ? \get_post_status( $post_before ) : null;
|
||||
|
||||
switch ( $new_status ) {
|
||||
case 'publish':
|
||||
@ -90,17 +88,36 @@ class Post {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'future':
|
||||
/*
|
||||
* A (re-)scheduled post is not a deletion: it becomes public again
|
||||
* when it publishes, at which point the publish transition federates
|
||||
* it. Treating `future` as a soft delete would fan out a Delete that
|
||||
* remotely tombstones the object id — e.g. when a content edit reverts
|
||||
* a future-dated published post back to `future` — after which the
|
||||
* post can never re-federate. Emit nothing instead.
|
||||
*/
|
||||
$type = false;
|
||||
break;
|
||||
|
||||
case 'draft':
|
||||
case 'pending':
|
||||
$type = ( 'publish' === $old_status ) ? 'Update' : false;
|
||||
break;
|
||||
|
||||
case 'private':
|
||||
case 'trash':
|
||||
$type = ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_status ? 'Delete' : false;
|
||||
break;
|
||||
|
||||
default:
|
||||
$type = false;
|
||||
/*
|
||||
* Soft delete for federated posts (FEP-4f05).
|
||||
*
|
||||
* A previously-federated post transitioning to any non-public
|
||||
* status (built-in or custom) emits a Delete so federated
|
||||
* copies are torn down. Without this, draft/pending would
|
||||
* broadcast a placeholder Update, private/trash would silently
|
||||
* leave the federated copy stale, and a custom status would
|
||||
* fall through without notifying followers at all.
|
||||
*/
|
||||
$type = ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_status && ! $is_queryable
|
||||
? 'Delete'
|
||||
: false;
|
||||
}
|
||||
|
||||
// Do not send Activities if `$type` is not set or unknown.
|
||||
@ -121,8 +138,20 @@ class Post {
|
||||
$type = 'Create';
|
||||
}
|
||||
|
||||
// If the post was federated before but is now local or private, it should be a Delete activity.
|
||||
if ( ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_status && in_array( get_content_visibility( $post ), array( ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL, ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE ), true ) ) {
|
||||
/*
|
||||
* Resurrection: a soft-deleted post that is back in a publicly
|
||||
* queryable state must emit Create, not Update. Remote followers
|
||||
* either dropped the original Create on the Delete fan-out (so
|
||||
* they need to learn about the post again) or had it cancelled
|
||||
* before fanning out (so the supersession logic invalidates the
|
||||
* pending Delete and Create is the correct re-introduction).
|
||||
*/
|
||||
if ( ACTIVITYPUB_OBJECT_STATE_DELETED === $object_status && 'Update' === $type && $is_queryable ) {
|
||||
$type = 'Create';
|
||||
}
|
||||
|
||||
// If the post was federated before but is now non-public, it should be a Delete activity.
|
||||
if ( ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_status && ! $is_queryable ) {
|
||||
$type = 'Delete';
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
namespace Activitypub\Scheduler;
|
||||
|
||||
use Activitypub\Collection\Actors;
|
||||
use Activitypub\Mailer;
|
||||
use Activitypub\Statistics as Statistics_Collector;
|
||||
|
||||
@ -320,7 +321,7 @@ class Statistics {
|
||||
}
|
||||
|
||||
// Check user preference.
|
||||
if ( $user_id > \Activitypub\Collection\Actors::BLOG_USER_ID ) {
|
||||
if ( $user_id > Actors::BLOG_USER_ID ) {
|
||||
if ( ! \get_user_option( $option_name, $user_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user