PluginProbe
ActivityPub / 5.7.0
ActivityPub v5.7.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
← All changes | includes/scheduler/class-post.php +21 -168 9.2.05.7.0 View file →
@@ -6,16 +6,11 @@
6 6 */
7 7
8 8 namespace Activitypub\Scheduler;
9 9
10 -use Activitypub\Activity\Activity;
11 -use Activitypub\Collection\Actors;
12 -
13 10 use function Activitypub\add_to_outbox;
14 -use function Activitypub\get_post_id;
15 11 use function Activitypub\get_wp_object_state;
16 12 use function Activitypub\is_post_disabled;
17 -use function Activitypub\is_post_publicly_queryable;
18 13
19 14 /**
20 15 * Post scheduler class.
21 16 */
@@ -24,31 +19,18 @@
24 19 * Initialize the class, registering WordPress hooks.
25 20 */
26 21 public static function init() {
27 22 // Post transitions.
28 - \add_action( 'wp_after_insert_post', array( self::class, 'triage' ), 33, 4 );
23 + \add_action( 'wp_after_insert_post', array( self::class, 'schedule_post_activity' ), 33, 4 );
29 24
30 25 // Attachment transitions.
31 26 \add_action( 'add_attachment', array( self::class, 'transition_attachment_status' ) );
32 27 \add_action( 'edit_attachment', array( self::class, 'transition_attachment_status' ) );
33 28 \add_action( 'delete_attachment', array( self::class, 'transition_attachment_status' ) );
34 -
35 - /*
36 - * Sticky post transitions (featured collection).
37 - *
38 - * Note: These hooks run in addition to the legacy sticky hooks in
39 - * Actor scheduler, which send an Update activity when a post becomes
40 - * sticky or is unstuck. This means a sticky/unsticky event will cause both:
41 - * - an Add/Remove activity for the Actor's featured collection (below), and
42 - * - an Update activity (from Actor scheduler).
43 - * The Update activity is kept for backwards compatibility.
44 - */
45 - \add_action( 'post_stuck', array( self::class, 'schedule_featured_add' ) );
46 - \add_action( 'post_unstuck', array( self::class, 'schedule_featured_remove' ) );
47 29 }
48 30
49 31 /**
50 - * Triage post transitions and determine the appropriate Activity type.
32 + * Handle post updates and determine the appropriate Activity type.
51 33 *
52 34 * @param int $post_id Post ID.
53 35 * @param \WP_Post $post Post object.
54 36 * @param bool $update Whether this is an existing post being updated.
@@ -53,10 +35,10 @@
53 35 * @param \WP_Post $post Post object.
54 36 * @param bool $update Whether this is an existing post being updated.
55 37 * @param \WP_Post $post_before Post object before the update.
56 38 */
57 - public static function triage( $post_id, $post, $update, $post_before ) {
58 - if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
39 + public static function schedule_post_activity( $post_id, $post, $update, $post_before ) {
40 + if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
59 41 return;
60 42 }
61 43
62 44 if ( is_post_disabled( $post ) ) {
@@ -62,63 +44,31 @@
62 44 if ( is_post_disabled( $post ) ) {
63 45 return;
64 46 }
65 47
66 - $object_status = get_wp_object_state( $post );
67 - $is_queryable = is_post_publicly_queryable( $post );
68 -
69 - // If the post is already soft-deleted and still non-public, do not create any more activities.
70 - if ( ACTIVITYPUB_OBJECT_STATE_DELETED === $object_status && ! $is_queryable ) {
71 - return;
72 - }
73 -
74 48 // Bail on bulk edits, unless post author or post status changed.
75 - if ( isset( $_REQUEST['bulk_edit'] ) && ( ! isset( $_REQUEST['post_author'] ) || -1 === (int) $_REQUEST['post_author'] ) && -1 === (int) $_REQUEST['_status'] ) { // phpcs:ignore WordPress
49 + if ( isset( $_REQUEST['bulk_edit'] ) && -1 === (int) $_REQUEST['post_author'] && -1 === (int) $_REQUEST['_status'] ) { // phpcs:ignore WordPress
76 50 return;
77 51 }
78 52
79 - $new_status = \get_post_status( $post );
80 - $old_status = $post_before ? \get_post_status( $post_before ) : null;
53 + $new_status = get_post_status( $post );
54 + $old_status = $post_before ? get_post_status( $post_before ) : null;
81 55
82 56 switch ( $new_status ) {
83 57 case 'publish':
84 - if ( $update ) {
85 - $type = ( 'publish' === $old_status ) ? 'Update' : 'Create';
86 - } else {
87 - $type = 'Create';
88 - }
58 + $type = ( 'publish' === $old_status ) ? 'Update' : 'Create';
89 59 break;
90 60
91 - case 'future':
92 - /*
93 - * A (re-)scheduled post is not a deletion: it becomes public again
94 - * when it publishes, at which point the publish transition federates
95 - * it. Treating `future` as a soft delete would fan out a Delete that
96 - * remotely tombstones the object id — e.g. when a content edit reverts
97 - * a future-dated published post back to `future` — after which the
98 - * post can never re-federate. Emit nothing instead.
99 - */
100 - $type = false;
61 + case 'draft':
62 + $type = ( 'publish' === $old_status ) ? 'Update' : false;
101 63 break;
102 64
103 - case 'draft':
104 - case 'pending':
105 - case 'private':
106 65 case 'trash':
66 + $type = 'federated' === get_wp_object_state( $post ) ? 'Delete' : false;
67 + break;
68 +
107 69 default:
108 - /*
109 - * Soft delete for federated posts (FEP-4f05).
110 - *
111 - * A previously-federated post transitioning to any non-public
112 - * status (built-in or custom) emits a Delete so federated
113 - * copies are torn down. Without this, draft/pending would
114 - * broadcast a placeholder Update, private/trash would silently
115 - * leave the federated copy stale, and a custom status would
116 - * fall through without notifying followers at all.
117 - */
118 - $type = ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_status && ! $is_queryable
119 - ? 'Delete'
120 - : false;
70 + $type = false;
121 71 }
122 72
123 73 // Do not send Activities if `$type` is not set or unknown.
124 74 if ( empty( $type ) ) {
@@ -124,38 +74,9 @@
124 74 if ( empty( $type ) ) {
125 75 return;
126 76 }
127 77
128 - /*
129 - * If the post was already federated and this is a Create, skip.
130 - * The outbox controller already added it to the outbox.
131 - */
132 - if ( ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_status && 'Create' === $type ) {
133 - return;
134 - }
135 -
136 - // If the post was never federated before, it should be a Create activity.
137 - if ( empty( $object_status ) && 'Update' === $type ) {
138 - $type = 'Create';
139 - }
140 -
141 - /*
142 - * Resurrection: a soft-deleted post that is back in a publicly
143 - * queryable state must emit Create, not Update. Remote followers
144 - * either dropped the original Create on the Delete fan-out (so
145 - * they need to learn about the post again) or had it cancelled
146 - * before fanning out (so the supersession logic invalidates the
147 - * pending Delete and Create is the correct re-introduction).
148 - */
149 - if ( ACTIVITYPUB_OBJECT_STATE_DELETED === $object_status && 'Update' === $type && $is_queryable ) {
150 - $type = 'Create';
151 - }
152 -
153 - // If the post was federated before but is now non-public, it should be a Delete activity.
154 - if ( ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_status && ! $is_queryable ) {
155 - $type = 'Delete';
156 - }
157 -
78 + // Add the post to the outbox.
158 79 add_to_outbox( $post, $type, $post->post_author );
159 80 }
160 81
161 82 /**
@@ -171,90 +92,22 @@
171 92 if ( ! \post_type_supports( 'attachment', 'activitypub' ) ) {
172 93 return;
173 94 }
174 95
175 - if ( is_post_disabled( $post_id ) ) {
176 - return;
177 - }
178 -
179 96 $post = \get_post( $post_id );
180 97
181 - if ( ! $post instanceof \WP_Post ) {
182 - return;
183 - }
184 -
185 98 switch ( \current_action() ) {
186 99 case 'add_attachment':
187 - $type = 'Create';
100 + // Add the post to the outbox.
101 + add_to_outbox( $post, 'Create', $post->post_author );
188 102 break;
189 103 case 'edit_attachment':
190 - $type = 'Update';
104 + // Update the post to the outbox.
105 + add_to_outbox( $post, 'Update', $post->post_author );
191 106 break;
192 107 case 'delete_attachment':
193 - $type = 'Delete';
108 + // Delete the post from the outbox.
109 + add_to_outbox( $post, 'Delete', $post->post_author );
194 110 break;
195 - default:
196 - return;
197 111 }
198 -
199 - add_to_outbox( $post, $type, $post->post_author );
200 - }
201 -
202 - /**
203 - * Schedule an Add activity when a post is added to the featured collection.
204 - *
205 - * @param int $post_id The post ID.
206 - */
207 - public static function schedule_featured_add( $post_id ) {
208 - self::schedule_featured_update( $post_id, 'Add' );
209 - }
210 -
211 - /**
212 - * Schedule a Remove activity when a post is removed from the featured collection.
213 - *
214 - * @param int $post_id The post ID.
215 - */
216 - public static function schedule_featured_remove( $post_id ) {
217 - self::schedule_featured_update( $post_id, 'Remove' );
218 - }
219 -
220 - /**
221 - * Schedule an Add or Remove activity for the featured collection.
222 - *
223 - * When a post's sticky status changes, this sends an Add or Remove activity
224 - * to notify followers about the change to the actor's featured collection.
225 - *
226 - * @see https://github.com/Automattic/wordpress-activitypub/issues/2795
227 - *
228 - * @param int $post_id The post ID.
229 - * @param string $activity_type The activity type ('Add' or 'Remove').
230 - */
231 - private static function schedule_featured_update( $post_id, $activity_type ) {
232 - if ( \defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
233 - return;
234 - }
235 -
236 - $post = \get_post( $post_id );
237 -
238 - if ( ! $post ) {
239 - return;
240 - }
241 -
242 - if ( is_post_disabled( $post ) ) {
243 - return;
244 - }
245 -
246 - $actor = Actors::get_by_id( $post->post_author );
247 -
248 - if ( ! $actor || \is_wp_error( $actor ) ) {
249 - return;
250 - }
251 -
252 - $activity = new Activity();
253 - $activity->set_type( $activity_type );
254 - $activity->set_actor( $actor->get_id() );
255 - $activity->set_object( get_post_id( $post->ID ) );
256 - $activity->set_target( $actor->get_featured() );
257 -
258 - add_to_outbox( $activity, null, $post->post_author );
259 112 }
260 113 }