PluginProbe
ActivityPub / 3.2.5
ActivityPub v3.2.5
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/class-scheduler.php +212 -22 1.3.03.2.5 View file →
@@ -1,12 +1,17 @@
1 1 <?php
2 2
3 3 namespace Activitypub;
4 4
5 +use Activitypub\Transformer\Post;
5 6 use Activitypub\Collection\Users;
6 7 use Activitypub\Collection\Followers;
7 -use Activitypub\Transformer\Post;
8 8
9 +use function Activitypub\was_comment_sent;
10 +use function Activitypub\is_user_type_disabled;
11 +use function Activitypub\should_comment_be_federated;
12 +use function Activitypub\get_remote_metadata_by_actor;
13 +
9 14 /**
10 15 * ActivityPub Scheduler Class
11 16 *
12 17 * @author Matthias Pfefferle
@@ -11,18 +16,70 @@
11 16 *
12 17 * @author Matthias Pfefferle
13 18 */
14 19 class Scheduler {
20 +
15 21 /**
16 22 * Initialize the class, registering WordPress hooks
17 23 */
18 24 public static function init() {
25 + // Post transitions
19 26 \add_action( 'transition_post_status', array( self::class, 'schedule_post_activity' ), 33, 3 );
27 + \add_action(
28 + 'edit_attachment',
29 + function ( $post_id ) {
30 + self::schedule_post_activity( 'publish', 'publish', $post_id );
31 + }
32 + );
33 + \add_action(
34 + 'add_attachment',
35 + function ( $post_id ) {
36 + self::schedule_post_activity( 'publish', '', $post_id );
37 + }
38 + );
39 + \add_action(
40 + 'delete_attachment',
41 + function ( $post_id ) {
42 + self::schedule_post_activity( 'trash', '', $post_id );
43 + }
44 + );
20 45
46 + if ( ! ACTIVITYPUB_DISABLE_OUTGOING_INTERACTIONS ) {
47 + // Comment transitions
48 + \add_action( 'transition_comment_status', array( self::class, 'schedule_comment_activity' ), 20, 3 );
49 + \add_action(
50 + 'edit_comment',
51 + function ( $comment_id ) {
52 + self::schedule_comment_activity( 'approved', 'approved', $comment_id );
53 + }
54 + );
55 + \add_action(
56 + 'wp_insert_comment',
57 + function ( $comment_id ) {
58 + self::schedule_comment_activity( 'approved', '', $comment_id );
59 + }
60 + );
61 + }
62 +
63 + // Follower Cleanups
21 64 \add_action( 'activitypub_update_followers', array( self::class, 'update_followers' ) );
22 65 \add_action( 'activitypub_cleanup_followers', array( self::class, 'cleanup_followers' ) );
23 66
24 - \add_action( 'admin_init', array( self::class, 'schedule_migration' ) );
67 + // profile updates for blog options
68 + if ( ! is_user_type_disabled( 'blog' ) ) {
69 + \add_action( 'update_option_site_icon', array( self::class, 'blog_user_update' ) );
70 + \add_action( 'update_option_blogdescription', array( self::class, 'blog_user_update' ) );
71 + \add_action( 'update_option_blogname', array( self::class, 'blog_user_update' ) );
72 + \add_filter( 'pre_set_theme_mod_custom_logo', array( self::class, 'blog_user_update' ) );
73 + \add_filter( 'pre_set_theme_mod_header_image', array( self::class, 'blog_user_update' ) );
74 + }
75 +
76 + // profile updates for user options
77 + if ( ! is_user_type_disabled( 'user' ) ) {
78 + \add_action( 'wp_update_user', array( self::class, 'user_update' ) );
79 + \add_action( 'updated_user_meta', array( self::class, 'user_meta_update' ), 10, 3 );
80 + // @todo figure out a feasible way of updating the header image since it's not unique to any user.
81 + }
25 82 }
26 83
27 84 /**
28 85 * Schedule all ActivityPub schedules.
@@ -57,8 +114,24 @@
57 114 * @param string $old_status Old post status.
58 115 * @param WP_Post $post Post object.
59 116 */
60 117 public static function schedule_post_activity( $new_status, $old_status, $post ) {
118 + $post = get_post( $post );
119 +
120 + if ( ! $post ) {
121 + return;
122 + }
123 +
124 + if ( 'ap_extrafield' === $post->post_type ) {
125 + self::schedule_profile_update( $post->post_author );
126 + return;
127 + }
128 +
129 + if ( 'ap_extrafield_blog' === $post->post_type ) {
130 + self::schedule_profile_update( 0 );
131 + return;
132 + }
133 +
61 134 // Do not send activities if post is password protected.
62 135 if ( \post_password_required( $post ) ) {
63 136 return;
64 137 }
@@ -70,37 +143,90 @@
70 143 }
71 144
72 145 $type = false;
73 146
74 - if ( 'publish' === $new_status && 'publish' !== $old_status ) {
147 + if (
148 + 'publish' === $new_status &&
149 + 'publish' !== $old_status
150 + ) {
75 151 $type = 'Create';
76 - } elseif ( 'publish' === $new_status ) {
152 + } elseif (
153 + 'publish' === $new_status ||
154 + // We want to send updates for posts that are published and then moved to draft.
155 + ( 'draft' === $new_status &&
156 + 'publish' === $old_status )
157 + ) {
77 158 $type = 'Update';
78 159 } elseif ( 'trash' === $new_status ) {
79 160 $type = 'Delete';
80 161 }
81 162
82 - if ( ! $type ) {
163 + if ( empty( $type ) ) {
83 164 return;
84 165 }
85 166
86 - \wp_schedule_single_event(
87 - \time(),
88 - 'activitypub_send_activity',
89 - array( $post, $type )
90 - );
167 + $hook = 'activitypub_send_post';
168 + $args = array( $post->ID, $type );
91 169
92 - \wp_schedule_single_event(
93 - \time(),
94 - sprintf(
95 - 'activitypub_send_%s_activity',
96 - \strtolower( $type )
97 - ),
98 - array( $post )
99 - );
170 + if ( false === wp_next_scheduled( $hook, $args ) ) {
171 + set_wp_object_state( $post, 'federate' );
172 + \wp_schedule_single_event( \time(), $hook, $args );
173 + }
100 174 }
101 175
102 176 /**
177 + * Schedule Comment Activities
178 + *
179 + * transition_comment_status()
180 + *
181 + * @param string $new_status New comment status.
182 + * @param string $old_status Old comment status.
183 + * @param WP_Comment $comment Comment object.
184 + */
185 + public static function schedule_comment_activity( $new_status, $old_status, $comment ) {
186 + $comment = get_comment( $comment );
187 +
188 + // federate only comments that are written by a registered user.
189 + if ( ! $comment || ! $comment->user_id ) {
190 + return;
191 + }
192 +
193 + $type = false;
194 +
195 + if (
196 + 'approved' === $new_status &&
197 + 'approved' !== $old_status
198 + ) {
199 + $type = 'Create';
200 + } elseif ( 'approved' === $new_status ) {
201 + $type = 'Update';
202 + \update_comment_meta( $comment->comment_ID, 'activitypub_comment_modified', time(), true );
203 + } elseif (
204 + 'trash' === $new_status ||
205 + 'spam' === $new_status
206 + ) {
207 + $type = 'Delete';
208 + }
209 +
210 + if ( empty( $type ) ) {
211 + return;
212 + }
213 +
214 + // check if comment should be federated or not
215 + if ( ! should_comment_be_federated( $comment ) ) {
216 + return;
217 + }
218 +
219 + $hook = 'activitypub_send_comment';
220 + $args = array( $comment->comment_ID, $type );
221 +
222 + if ( false === wp_next_scheduled( $hook, $args ) ) {
223 + set_wp_object_state( $comment, 'federate' );
224 + \wp_schedule_single_event( \time(), $hook, $args );
225 + }
226 + }
227 +
228 + /**
103 229 * Update followers
104 230 *
105 231 * @return void
106 232 */
@@ -110,8 +236,9 @@
110 236 if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
111 237 $number = 50;
112 238 }
113 239
240 + $number = apply_filters( 'activitypub_update_followers_number', $number );
114 241 $followers = Followers::get_outdated_followers( $number );
115 242
116 243 foreach ( $followers as $follower ) {
117 244 $meta = get_remote_metadata_by_actor( $follower->get_id(), false );
@@ -136,8 +263,9 @@
136 263 if ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) {
137 264 $number = 50;
138 265 }
139 266
267 + $number = apply_filters( 'activitypub_update_followers_number', $number );
140 268 $followers = Followers::get_faulty_followers( $number );
141 269
142 270 foreach ( $followers as $follower ) {
143 271 $meta = get_remote_metadata_by_actor( $follower->get_url(), false );
@@ -146,8 +274,13 @@
146 274 $follower->delete();
147 275 } elseif ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) {
148 276 if ( $follower->count_errors() >= 5 ) {
149 277 $follower->delete();
278 + \wp_schedule_single_event(
279 + \time(),
280 + 'activitypub_delete_actor_interactions',
281 + array( $follower->get_id() )
282 + );
150 283 } else {
151 284 Followers::add_error( $follower->get__id(), $meta );
152 285 }
153 286 } else {
@@ -156,14 +289,71 @@
156 289 }
157 290 }
158 291
159 292 /**
160 - * Schedule migration if DB-Version is not up to date.
293 + * Send a profile update when relevant user meta is updated.
161 294 *
295 + * @param int $meta_id Meta ID being updated.
296 + * @param int $user_id User ID being updated.
297 + * @param string $meta_key Meta key being updated.
298 + *
162 299 * @return void
163 300 */
164 - public static function schedule_migration() {
165 - if ( ! \wp_next_scheduled( 'activitypub_schedule_migration' ) && ! Migration::is_latest_version() ) {
166 - \wp_schedule_single_event( \time(), 'activitypub_schedule_migration' );
301 + public static function user_meta_update( $meta_id, $user_id, $meta_key ) {
302 + // don't bother if the user can't publish
303 + if ( ! \user_can( $user_id, 'activitypub' ) ) {
304 + return;
167 305 }
306 + // the user meta fields that affect a profile.
307 + $fields = array(
308 + 'activitypub_description',
309 + 'activitypub_header_image',
310 + 'description',
311 + 'user_url',
312 + 'display_name',
313 + );
314 + if ( in_array( $meta_key, $fields, true ) ) {
315 + self::schedule_profile_update( $user_id );
316 + }
317 + }
318 +
319 + /**
320 + * Send a profile update when a user is updated.
321 + *
322 + * @param int $user_id User ID being updated.
323 + *
324 + * @return void
325 + */
326 + public static function user_update( $user_id ) {
327 + // don't bother if the user can't publish
328 + if ( ! \user_can( $user_id, 'activitypub' ) ) {
329 + return;
330 + }
331 +
332 + self::schedule_profile_update( $user_id );
333 + }
334 +
335 + /**
336 + * Theme mods only have a dynamic filter so we fudge it like this.
337 + *
338 + * @param mixed $value
339 + *
340 + * @return mixed
341 + */
342 + public static function blog_user_update( $value = null ) {
343 + self::schedule_profile_update( 0 );
344 + return $value;
345 + }
346 +
347 + /**
348 + * Send a profile update to all followers. Gets hooked into all relevant options/meta etc.
349 + *
350 + * @param int $user_id The user ID to update (Could be 0 for Blog-User).
351 + */
352 + public static function schedule_profile_update( $user_id ) {
353 + \wp_schedule_single_event(
354 + \time(),
355 + 'activitypub_send_update_profile_activity',
356 + array( $user_id )
357 + );
168 358 }
169 359 }