PluginProbe
ActivityPub / 2.0.0
ActivityPub v2.0.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
activitypub / includes / class-scheduler.php

class-scheduler.php in ActivityPub 2.0.0, at includes/class-scheduler.php

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