PluginProbe
ActivityPub / 7.7.0
ActivityPub v7.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
activitypub / includes / class-post-types.php

class-post-types.php in ActivityPub 7.7.0, at includes/class-post-types.php

602 lines 17.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Post Types class for consolidating all custom post type and related meta registrations.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub;
9
10 use Activitypub\Activity\Activity;
11 use Activitypub\Collection\Extra_Fields;
12 use Activitypub\Collection\Followers;
13 use Activitypub\Collection\Inbox;
14 use Activitypub\Collection\Outbox;
15 use Activitypub\Collection\Posts;
16 use Activitypub\Collection\Remote_Actors;
17
18 /**
19 * Post Types class.
20 */
21 class Post_Types {
22 /**
23 * Initialize the class, registering all custom post types and post meta.
24 */
25 public static function init() {
26 \add_action( 'init', array( self::class, 'register_remote_actors_post_type' ), 11 );
27 \add_action( 'init', array( self::class, 'register_inbox_post_type' ), 11 );
28 \add_action( 'init', array( self::class, 'register_outbox_post_type' ), 11 );
29 \add_action( 'init', array( self::class, 'register_post_post_type' ), 11 );
30 \add_action( 'init', array( self::class, 'register_extra_fields_post_types' ), 11 );
31 \add_action( 'init', array( self::class, 'register_activitypub_post_meta' ), 11 );
32
33 \add_action( 'rest_api_init', array( self::class, 'register_ap_actor_rest_field' ) );
34
35 \add_filter( 'activitypub_get_actor_extra_fields', array( Extra_Fields::class, 'default_actor_extra_fields' ), 10, 2 );
36
37 \add_filter( 'add_post_metadata', array( self::class, 'prevent_empty_post_meta' ), 10, 4 );
38 \add_filter( 'update_post_metadata', array( self::class, 'prevent_empty_post_meta' ), 10, 4 );
39
40 // Add support for ActivityPub to custom post types.
41 foreach ( \get_option( 'activitypub_support_post_types', array( 'post' ) ) as $post_type ) {
42 \add_post_type_support( $post_type, 'activitypub' );
43 }
44 }
45
46 /**
47 * Register the Remote Actors post type and its meta.
48 */
49 public static function register_remote_actors_post_type() {
50 \register_post_type(
51 Remote_Actors::POST_TYPE,
52 array(
53 'labels' => array(
54 'name' => \_x( 'Followers', 'post_type plural name', 'activitypub' ),
55 'singular_name' => \_x( 'Follower', 'post_type single name', 'activitypub' ),
56 ),
57 'public' => false,
58 'show_in_rest' => true,
59 'hierarchical' => false,
60 'rewrite' => false,
61 'query_var' => false,
62 'delete_with_user' => false,
63 'can_export' => true,
64 'supports' => array(),
65 )
66 );
67
68 // Register meta for Remote Actors post type.
69 \register_post_meta(
70 Remote_Actors::POST_TYPE,
71 '_activitypub_inbox',
72 array(
73 'type' => 'string',
74 'single' => true,
75 'sanitize_callback' => 'sanitize_url',
76 )
77 );
78
79 \register_post_meta(
80 Remote_Actors::POST_TYPE,
81 '_activitypub_errors',
82 array(
83 'type' => 'string',
84 'single' => false,
85 'sanitize_callback' => 'sanitize_text_field',
86 )
87 );
88
89 \register_post_meta(
90 Remote_Actors::POST_TYPE,
91 Followers::FOLLOWER_META_KEY,
92 array(
93 'type' => 'string',
94 'single' => false,
95 'sanitize_callback' => 'sanitize_text_field',
96 )
97 );
98 }
99
100 /**
101 * Register the Inbox post type and its meta.
102 */
103 public static function register_inbox_post_type() {
104 \register_post_type(
105 Inbox::POST_TYPE,
106 array(
107 'labels' => array(
108 'name' => \_x( 'Inbox', 'post_type plural name', 'activitypub' ),
109 'singular_name' => \_x( 'Inbox Item', 'post_type single name', 'activitypub' ),
110 ),
111 'capabilities' => array(
112 'create_posts' => false,
113 ),
114 'map_meta_cap' => true,
115 'public' => false,
116 'show_in_rest' => false,
117 'rewrite' => false,
118 'query_var' => false,
119 'supports' => array( 'title', 'editor', 'author', 'custom-fields' ),
120 'delete_with_user' => true,
121 'can_export' => true,
122 'exclude_from_search' => true,
123 )
124 );
125
126 // Register meta for Inbox post type.
127 \register_post_meta(
128 Inbox::POST_TYPE,
129 '_activitypub_object_id',
130 array(
131 'type' => 'string',
132 'single' => true,
133 'description' => 'The ID (ActivityPub URI) of the object that the inbox item is about.',
134 'sanitize_callback' => 'sanitize_url',
135 )
136 );
137
138 \register_post_meta(
139 Inbox::POST_TYPE,
140 '_activitypub_activity_type',
141 array(
142 'type' => 'string',
143 'description' => 'The type of the activity',
144 'single' => true,
145 'show_in_rest' => true,
146 'sanitize_callback' => function ( $value ) {
147 $schema = array(
148 'type' => 'string',
149 'enum' => Activity::TYPES,
150 'default' => 'Create',
151 );
152
153 if ( \is_wp_error( \rest_validate_enum( $value, $schema, '' ) ) ) {
154 return $schema['default'];
155 }
156
157 return $value;
158 },
159 )
160 );
161
162 \register_post_meta(
163 Inbox::POST_TYPE,
164 '_activitypub_activity_remote_actor',
165 array(
166 'type' => 'string',
167 'single' => true,
168 'description' => 'The ID (ActivityPub URI) of the remote actor that sent the activity.',
169 'sanitize_callback' => 'sanitize_url',
170 )
171 );
172
173 \register_post_meta(
174 Inbox::POST_TYPE,
175 'activitypub_content_visibility',
176 array(
177 'type' => 'string',
178 'single' => true,
179 'show_in_rest' => true,
180 'sanitize_callback' => function ( $value ) {
181 $schema = array(
182 'type' => 'string',
183 'enum' => array( ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC, ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC, ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE, ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL ),
184 'default' => ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC,
185 );
186
187 if ( \is_wp_error( \rest_validate_enum( $value, $schema, '' ) ) ) {
188 return $schema['default'];
189 }
190
191 return $value;
192 },
193 )
194 );
195
196 \register_post_meta(
197 Inbox::POST_TYPE,
198 '_activitypub_user_id',
199 array(
200 'type' => 'integer',
201 'single' => false, // Allow multiple values - one per recipient.
202 'description' => 'User ID of a recipient of this activity. Multiple entries allowed.',
203 'sanitize_callback' => 'absint',
204 'show_in_rest' => true,
205 )
206 );
207 }
208
209 /**
210 * Register the Outbox post type and its meta.
211 */
212 public static function register_outbox_post_type() {
213 \register_post_type(
214 Outbox::POST_TYPE,
215 array(
216 'labels' => array(
217 'name' => \_x( 'Outbox', 'post_type plural name', 'activitypub' ),
218 'singular_name' => \_x( 'Outbox Item', 'post_type single name', 'activitypub' ),
219 ),
220 'capabilities' => array(
221 'create_posts' => false,
222 ),
223 'map_meta_cap' => true,
224 'public' => false,
225 'show_in_rest' => false,
226 'rewrite' => false,
227 'query_var' => false,
228 'supports' => array( 'title', 'editor', 'author', 'custom-fields' ),
229 'delete_with_user' => true,
230 'can_export' => true,
231 'exclude_from_search' => true,
232 )
233 );
234
235 // Register meta for Outbox post type.
236 /**
237 * Register Activity Type meta for Outbox items.
238 *
239 * @see https://www.w3.org/TR/activitystreams-vocabulary/#activity-types
240 */
241 \register_post_meta(
242 Outbox::POST_TYPE,
243 '_activitypub_activity_type',
244 array(
245 'type' => 'string',
246 'description' => 'The type of the activity',
247 'single' => true,
248 'show_in_rest' => true,
249 'sanitize_callback' => function ( $value ) {
250 $schema = array(
251 'type' => 'string',
252 'enum' => Activity::TYPES,
253 'default' => 'Announce',
254 );
255
256 if ( \is_wp_error( \rest_validate_enum( $value, $schema, '' ) ) ) {
257 return $schema['default'];
258 }
259
260 return $value;
261 },
262 )
263 );
264
265 \register_post_meta(
266 Outbox::POST_TYPE,
267 '_activitypub_activity_actor',
268 array(
269 'type' => 'string',
270 'single' => true,
271 'show_in_rest' => true,
272 'sanitize_callback' => function ( $value ) {
273 $schema = array(
274 'type' => 'string',
275 'enum' => array( 'application', 'blog', 'user' ),
276 'default' => 'user',
277 );
278
279 if ( \is_wp_error( \rest_validate_enum( $value, $schema, '' ) ) ) {
280 return $schema['default'];
281 }
282
283 return $value;
284 },
285 )
286 );
287
288 \register_post_meta(
289 Outbox::POST_TYPE,
290 '_activitypub_outbox_offset',
291 array(
292 'type' => 'integer',
293 'single' => true,
294 'description' => 'Keeps track of the followers offset when processing outbox items.',
295 'sanitize_callback' => 'absint',
296 'default' => 0,
297 )
298 );
299
300 \register_post_meta(
301 Outbox::POST_TYPE,
302 '_activitypub_object_id',
303 array(
304 'type' => 'string',
305 'single' => true,
306 'description' => 'The ID (ActivityPub URI) of the object that the outbox item is about.',
307 'sanitize_callback' => 'sanitize_url',
308 )
309 );
310
311 \register_post_meta(
312 Outbox::POST_TYPE,
313 'activitypub_content_visibility',
314 array(
315 'type' => 'string',
316 'single' => true,
317 'show_in_rest' => true,
318 'sanitize_callback' => function ( $value ) {
319 $schema = array(
320 'type' => 'string',
321 'enum' => array( ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC, ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC, ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE, ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL ),
322 'default' => ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC,
323 );
324
325 if ( \is_wp_error( \rest_validate_enum( $value, $schema, '' ) ) ) {
326 return $schema['default'];
327 }
328
329 return $value;
330 },
331 )
332 );
333 }
334
335 /**
336 * Register the Post post type.
337 */
338 public static function register_post_post_type() {
339 \register_post_type(
340 Posts::POST_TYPE,
341 array(
342 'labels' => array(
343 'name' => \_x( 'Posts', 'post_type plural name', 'activitypub' ),
344 'singular_name' => \_x( 'Post', 'post_type single name', 'activitypub' ),
345 ),
346 'capabilities' => array(
347 'create_posts' => false,
348 ),
349 'map_meta_cap' => true,
350 'public' => false,
351 'show_in_rest' => false,
352 'rewrite' => false,
353 'query_var' => false,
354 'supports' => array( 'title', 'editor', 'author', 'custom-fields', 'excerpt', 'comments' ),
355 'delete_with_user' => true,
356 'can_export' => true,
357 'exclude_from_search' => true,
358 'taxonomies' => array( 'ap_tag', 'ap_object_type' ),
359 )
360 );
361
362 \register_taxonomy(
363 'ap_tag',
364 array( Posts::POST_TYPE ),
365 array(
366 'public' => false,
367 'query_var' => true,
368 'show_in_rest' => true,
369 )
370 );
371
372 \register_taxonomy(
373 'ap_object_type',
374 array( Posts::POST_TYPE ),
375 array(
376 'public' => false,
377 'query_var' => true,
378 'show_in_rest' => true,
379 )
380 );
381
382 \register_post_meta(
383 Posts::POST_TYPE,
384 '_activitypub_remote_actor_id',
385 array(
386 'type' => 'integer',
387 'single' => true,
388 'description' => 'The local ID of the remote actor that created the object.',
389 'sanitize_callback' => 'absint',
390 )
391 );
392
393 \register_post_meta(
394 Posts::POST_TYPE,
395 '_activitypub_user_id',
396 array(
397 'type' => 'integer',
398 'single' => true,
399 'description' => 'The ID of the local user that received the activity.',
400 'sanitize_callback' => 'absint',
401 )
402 );
403 }
404
405 /**
406 * Register the Extra Fields post types.
407 */
408 public static function register_extra_fields_post_types() {
409 $extra_field_args = array(
410 'labels' => array(
411 'name' => \_x( 'Extra fields', 'post_type plural name', 'activitypub' ),
412 'singular_name' => \_x( 'Extra field', 'post_type single name', 'activitypub' ),
413 'add_new' => \__( 'Add new', 'activitypub' ),
414 'add_new_item' => \__( 'Add new extra field', 'activitypub' ),
415 'new_item' => \__( 'New extra field', 'activitypub' ),
416 'edit_item' => \__( 'Edit extra field', 'activitypub' ),
417 'view_item' => \__( 'View extra field', 'activitypub' ),
418 'all_items' => \__( 'All extra fields', 'activitypub' ),
419 ),
420 'public' => false,
421 'hierarchical' => false,
422 'query_var' => false,
423 'has_archive' => false,
424 'publicly_queryable' => false,
425 'show_in_menu' => false,
426 'delete_with_user' => true,
427 'can_export' => true,
428 'exclude_from_search' => true,
429 'show_in_rest' => true,
430 'map_meta_cap' => true,
431 'show_ui' => true,
432 'supports' => array( 'title', 'editor', 'page-attributes', 'author' ),
433 'capabilities' => array(
434 'edit_others_posts' => 'do_not_allow', // Disallow editing others' Extra Fields (only own ones).
435 ),
436 );
437
438 \register_post_type( Extra_Fields::USER_POST_TYPE, $extra_field_args );
439
440 unset( $extra_field_args['capabilities'] ); // Allow editing the Blog's Extra Fields.
441 \register_post_type( Extra_Fields::BLOG_POST_TYPE, $extra_field_args );
442
443 /**
444 * Fires after ActivityPub custom post types have been registered.
445 */
446 \do_action( 'activitypub_after_register_post_type' );
447 }
448
449 /**
450 * Register post meta for ActivityPub supported post types.
451 */
452 public static function register_activitypub_post_meta() {
453 $ap_post_types = \get_post_types_by_support( 'activitypub' );
454 foreach ( $ap_post_types as $post_type ) {
455 \register_post_meta(
456 $post_type,
457 'activitypub_content_warning',
458 array(
459 'show_in_rest' => true,
460 'single' => true,
461 'type' => 'string',
462 'sanitize_callback' => 'sanitize_text_field',
463 )
464 );
465
466 \register_post_meta(
467 $post_type,
468 'activitypub_content_visibility',
469 array(
470 'type' => 'string',
471 'single' => true,
472 'show_in_rest' => true,
473 'sanitize_callback' => function ( $value ) {
474 $schema = array(
475 'type' => 'string',
476 'enum' => array( ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC, ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC, ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE, ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL ),
477 'default' => ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC,
478 );
479
480 if ( \is_wp_error( \rest_validate_enum( $value, $schema, '' ) ) ) {
481 return $schema['default'];
482 }
483
484 return $value;
485 },
486 )
487 );
488
489 \register_post_meta(
490 $post_type,
491 'activitypub_max_image_attachments',
492 array(
493 'type' => 'integer',
494 'single' => true,
495 'show_in_rest' => true,
496 'default' => \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ),
497 'sanitize_callback' => 'absint',
498 )
499 );
500
501 \register_post_meta(
502 $post_type,
503 'activitypub_interaction_policy_quote',
504 array(
505 'type' => 'string',
506 'single' => true,
507 'show_in_rest' => true,
508 'sanitize_callback' => function ( $value ) {
509 $schema = array(
510 'type' => 'string',
511 'enum' => array( ACTIVITYPUB_INTERACTION_POLICY_ANYONE, ACTIVITYPUB_INTERACTION_POLICY_FOLLOWERS, ACTIVITYPUB_INTERACTION_POLICY_ME ),
512 'default' => ACTIVITYPUB_INTERACTION_POLICY_ANYONE,
513 );
514
515 if ( \is_wp_error( \rest_validate_enum( $value, $schema, '' ) ) ) {
516 return $schema['default'];
517 }
518
519 return $value;
520 },
521 )
522 );
523
524 \register_post_meta(
525 $post_type,
526 'activitypub_status',
527 array(
528 'type' => 'string',
529 'single' => true,
530 'show_in_rest' => true,
531 'sanitize_callback' => function ( $value ) {
532 $schema = array(
533 'type' => 'string',
534 'enum' => array( 'pending', 'federated', 'failed' ),
535 'default' => 'pending',
536 );
537
538 if ( \is_wp_error( \rest_validate_enum( $value, $schema, '' ) ) ) {
539 return $schema['default'];
540 }
541
542 return $value;
543 },
544 )
545 );
546 }
547 }
548
549 /**
550 * Register REST field for ap_actor posts.
551 */
552 public static function register_ap_actor_rest_field() {
553 \register_rest_field(
554 Remote_Actors::POST_TYPE,
555 'activitypub_json',
556 array(
557 /**
558 * Get the raw post content without WordPress content filtering.
559 *
560 * @param array $response Prepared response array.
561 * @return string The raw post content.
562 */
563 'get_callback' => function ( $response ) {
564 return \get_post_field( 'post_content', $response['id'] );
565 },
566 'schema' => array(
567 'description' => 'Raw ActivityPub JSON data without WordPress content filtering',
568 'type' => 'string',
569 'context' => array( 'view', 'edit' ),
570 ),
571 )
572 );
573 }
574
575 /**
576 * Prevent empty or default meta values.
577 *
578 * @param null|bool $check Whether to allow updating metadata for the given type.
579 * @param int $object_id ID of the object metadata is for.
580 * @param string $meta_key Metadata key.
581 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
582 */
583 public static function prevent_empty_post_meta( $check, $object_id, $meta_key, $meta_value ) {
584 $post_metas = array(
585 'activitypub_content_visibility' => '',
586 'activitypub_content_warning' => '',
587 'activitypub_interaction_policy_quote' => ACTIVITYPUB_INTERACTION_POLICY_ANYONE,
588 'activitypub_max_image_attachments' => (string) \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ),
589 );
590
591 if ( isset( $post_metas[ $meta_key ] ) && $post_metas[ $meta_key ] === (string) $meta_value ) {
592 if ( 'update_post_metadata' === current_action() ) {
593 \delete_post_meta( $object_id, $meta_key );
594 }
595
596 $check = true;
597 }
598
599 return $check;
600 }
601 }
602