PluginProbe
ActivityPub / 4.0.2
ActivityPub v4.0.2
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-activity-dispatcher.php

class-activity-dispatcher.php in ActivityPub 4.0.2, at includes/class-activity-dispatcher.php

341 lines 9.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ActivityPub Activity_Dispatcher Class.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub;
9
10 use WP_Post;
11 use WP_Comment;
12 use Activitypub\Collection\Users;
13 use Activitypub\Activity\Activity;
14 use Activitypub\Collection\Followers;
15 use Activitypub\Transformer\Factory;
16
17 /**
18 * ActivityPub Activity_Dispatcher Class.
19 *
20 * @author Matthias Pfefferle
21 *
22 * @see https://www.w3.org/TR/activitypub/
23 */
24 class Activity_Dispatcher {
25 /**
26 * Initialize the class, registering WordPress hooks.
27 */
28 public static function init() {
29 \add_action( 'activitypub_send_post', array( self::class, 'send_post' ), 10, 2 );
30 \add_action( 'activitypub_send_comment', array( self::class, 'send_comment' ), 10, 2 );
31
32 \add_action( 'activitypub_send_activity', array( self::class, 'send_activity' ), 10, 2 );
33 \add_action( 'activitypub_send_activity', array( self::class, 'send_activity_or_announce' ), 10, 2 );
34 \add_action( 'activitypub_send_update_profile_activity', array( self::class, 'send_profile_update' ) );
35
36 // Default filters to add Inboxes to sent to.
37 \add_filter( 'activitypub_send_to_inboxes', array( self::class, 'add_inboxes_of_follower' ), 10, 2 );
38 \add_filter( 'activitypub_send_to_inboxes', array( self::class, 'add_inboxes_by_mentioned_actors' ), 10, 3 );
39 \add_filter( 'activitypub_send_to_inboxes', array( self::class, 'add_inboxes_of_replied_urls' ), 10, 3 );
40 }
41
42 /**
43 * Send Activities to followers and mentioned users or `Announce` (boost) a blog post.
44 *
45 * @param mixed $wp_object The ActivityPub Post.
46 * @param string $type The Activity-Type.
47 */
48 public static function send_activity_or_announce( $wp_object, $type ) {
49 if ( is_user_type_disabled( 'blog' ) ) {
50 return;
51 }
52
53 if ( is_single_user() ) {
54 self::send_activity( $wp_object, $type, Users::BLOG_USER_ID );
55 } else {
56 self::send_announce( $wp_object, $type );
57 }
58 }
59
60 /**
61 * Send Activities to followers and mentioned users.
62 *
63 * @param mixed $wp_object The ActivityPub Post.
64 * @param string $type The Activity-Type.
65 * @param int $user_id Optional. The WordPress User-ID.
66 */
67 public static function send_activity( $wp_object, $type, $user_id = null ) {
68 $transformer = Factory::get_transformer( $wp_object ); // Could potentially return a `\WP_Error` instance.
69
70 if ( \is_wp_error( $transformer ) ) {
71 return;
72 }
73
74 if ( null !== $user_id ) {
75 $transformer->change_wp_user_id( $user_id );
76 }
77
78 $user_id = $transformer->get_wp_user_id();
79
80 if ( is_user_disabled( $user_id ) ) {
81 return;
82 }
83
84 $activity = $transformer->to_activity( $type );
85
86 self::send_activity_to_followers( $activity, $user_id, $wp_object );
87 }
88
89 /**
90 * Send Announces to followers and mentioned users.
91 *
92 * @param mixed $wp_object The ActivityPub Post.
93 * @param string $type The Activity-Type.
94 */
95 public static function send_announce( $wp_object, $type ) {
96 if ( ! in_array( $type, array( 'Create', 'Update', 'Delete' ), true ) ) {
97 return;
98 }
99
100 if ( is_user_disabled( Users::BLOG_USER_ID ) ) {
101 return;
102 }
103
104 $transformer = Factory::get_transformer( $wp_object );
105
106 if ( \is_wp_error( $transformer ) ) {
107 return;
108 }
109
110 $user_id = Users::BLOG_USER_ID;
111 $activity = $transformer->to_activity( $type );
112 $user = Users::get_by_id( Users::BLOG_USER_ID );
113
114 $announce = new Activity();
115 $announce->set_type( 'Announce' );
116 $announce->set_object( $activity );
117 $announce->set_actor( $user->get_id() );
118
119 self::send_activity_to_followers( $announce, $user_id, $wp_object );
120 }
121
122 /**
123 * Send a "Update" Activity when a user updates their profile.
124 *
125 * @param int $user_id The user ID to send an update for.
126 */
127 public static function send_profile_update( $user_id ) {
128 $user = Users::get_by_various( $user_id );
129
130 // Bail if that's not a good user.
131 if ( is_wp_error( $user ) ) {
132 return;
133 }
134
135 // Build the update.
136 $activity = new Activity();
137 $activity->set_type( 'Update' );
138 $activity->set_actor( $user->get_id() );
139 $activity->set_object( $user->get_id() );
140 $activity->set_to( array( 'https://www.w3.org/ns/activitystreams#Public' ) );
141
142 // Send the update.
143 self::send_activity_to_followers( $activity, $user_id, $user );
144 }
145
146 /**
147 * Send an Activity to all followers and mentioned users.
148 *
149 * @param Activity $activity The ActivityPub Activity.
150 * @param int $user_id The user ID.
151 * @param \WP_User|WP_Post|WP_Comment $wp_object The WordPress object.
152 */
153 private static function send_activity_to_followers( $activity, $user_id, $wp_object ) {
154 /**
155 * Filter to prevent sending an Activity to followers.
156 *
157 * @param bool $send_activity_to_followers Whether to send the Activity to followers.
158 * @param Activity $activity The ActivityPub Activity.
159 * @param int $user_id The user ID.
160 * @param \WP_User|WP_Post|WP_Comment $wp_object The WordPress object.
161 */
162 if ( ! apply_filters( 'activitypub_send_activity_to_followers', true, $activity, $user_id, $wp_object ) ) {
163 return;
164 }
165
166 /**
167 * Filter to modify the Activity before sending it to followers.
168 *
169 * @param Activity $activity The ActivityPub Activity.
170 * @param int $user_id The user ID.
171 * @param \WP_User|WP_Post|WP_Comment $wp_object The WordPress object.
172 */
173 $inboxes = apply_filters( 'activitypub_send_to_inboxes', array(), $user_id, $activity );
174 $inboxes = array_unique( $inboxes );
175
176 if ( empty( $inboxes ) ) {
177 return;
178 }
179
180 $json = $activity->to_json();
181
182 foreach ( $inboxes as $inbox ) {
183 safe_remote_post( $inbox, $json, $user_id );
184 }
185
186 set_wp_object_state( $wp_object, 'federated' );
187 }
188
189 /**
190 * Send a "Create" or "Update" Activity for a WordPress Post.
191 *
192 * @param int $id The WordPress Post ID.
193 * @param string $type The Activity-Type.
194 */
195 public static function send_post( $id, $type ) {
196 $post = get_post( $id );
197
198 if ( ! $post || is_post_disabled( $post ) ) {
199 return;
200 }
201
202 /**
203 * Action to send an Activity for a Post.
204 *
205 * @param WP_Post $post The WordPress Post.
206 * @param string $type The Activity-Type.
207 */
208 do_action( 'activitypub_send_activity', $post, $type );
209
210 /**
211 * Action to send a specific Activity for a Post.
212 *
213 * @param WP_Post $post The WordPress Post.
214 */
215 do_action( sprintf( 'activitypub_send_%s_activity', \strtolower( $type ) ), $post );
216 }
217
218 /**
219 * Send a "Create" or "Update" Activity for a WordPress Comment.
220 *
221 * @param int $id The WordPress Comment ID.
222 * @param string $type The Activity-Type.
223 */
224 public static function send_comment( $id, $type ) {
225 $comment = get_comment( $id );
226
227 if ( ! $comment ) {
228 return;
229 }
230
231 /**
232 * Action to send an Activity for a Comment.
233 *
234 * @param WP_Comment $comment The WordPress Comment.
235 * @param string $type The Activity-Type.
236 */
237 do_action( 'activitypub_send_activity', $comment, $type );
238
239 /**
240 * Action to send a specific Activity for a Comment.
241 *
242 * @param WP_Comment $comment The WordPress Comment.
243 */
244 do_action( sprintf( 'activitypub_send_%s_activity', \strtolower( $type ) ), $comment );
245 }
246
247 /**
248 * Default filter to add Inboxes of Followers.
249 *
250 * @param array $inboxes The list of Inboxes.
251 * @param int $user_id The WordPress User-ID.
252 *
253 * @return array The filtered Inboxes
254 */
255 public static function add_inboxes_of_follower( $inboxes, $user_id ) {
256 $follower_inboxes = Followers::get_inboxes( $user_id );
257
258 return array_merge( $inboxes, $follower_inboxes );
259 }
260
261 /**
262 * Default filter to add Inboxes of Mentioned Actors
263 *
264 * @param array $inboxes The list of Inboxes.
265 * @param int $user_id The WordPress User-ID.
266 * @param array $activity The ActivityPub Activity.
267 *
268 * @return array The filtered Inboxes.
269 */
270 public static function add_inboxes_by_mentioned_actors( $inboxes, $user_id, $activity ) {
271 $cc = $activity->get_cc() ?? array();
272 $to = $activity->get_to() ?? array();
273
274 $audience = array_merge( $cc, $to );
275
276 // Remove "public placeholder" and "same domain" from the audience.
277 $audience = array_filter(
278 $audience,
279 function ( $actor ) {
280 return 'https://www.w3.org/ns/activitystreams#Public' !== $actor && ! is_same_domain( $actor );
281 }
282 );
283
284 if ( $audience ) {
285 $mentioned_inboxes = Mention::get_inboxes( $audience );
286
287 return array_merge( $inboxes, $mentioned_inboxes );
288 }
289
290 return $inboxes;
291 }
292
293 /**
294 * Default filter to add Inboxes of Posts that are set as `in-reply-to`
295 *
296 * @param array $inboxes The list of Inboxes.
297 * @param int $user_id The WordPress User-ID.
298 * @param array $activity The ActivityPub Activity.
299 *
300 * @return array The filtered Inboxes
301 */
302 public static function add_inboxes_of_replied_urls( $inboxes, $user_id, $activity ) {
303 $in_reply_to = $activity->get_in_reply_to();
304
305 if ( ! $in_reply_to ) {
306 return $inboxes;
307 }
308
309 if ( ! is_array( $in_reply_to ) ) {
310 $in_reply_to = array( $in_reply_to );
311 }
312
313 foreach ( $in_reply_to as $url ) {
314 $object = Http::get_remote_object( $url );
315
316 if (
317 ! $object ||
318 \is_wp_error( $object ) ||
319 empty( $object['attributedTo'] )
320 ) {
321 continue;
322 }
323
324 $actor = object_to_uri( $object['attributedTo'] );
325 $actor = Http::get_remote_object( $actor );
326
327 if ( ! $actor || \is_wp_error( $actor ) ) {
328 continue;
329 }
330
331 if ( ! empty( $actor['endpoints']['sharedInbox'] ) ) {
332 $inboxes[] = $actor['endpoints']['sharedInbox'];
333 } elseif ( ! empty( $actor['inbox'] ) ) {
334 $inboxes[] = $actor['inbox'];
335 }
336 }
337
338 return $inboxes;
339 }
340 }
341