PluginProbe
ActivityPub / 4.7.1
ActivityPub v4.7.1
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 / rest / class-outbox.php

class-outbox.php in ActivityPub 4.7.1, at includes/rest/class-outbox.php

182 lines 4.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Outbox REST-Class file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Rest;
9
10 use stdClass;
11 use WP_REST_Server;
12 use WP_REST_Response;
13 use Activitypub\Activity\Activity;
14 use Activitypub\Collection\Actors;
15 use Activitypub\Transformer\Factory;
16
17 use function Activitypub\get_context;
18 use function Activitypub\get_rest_url_by_path;
19 use function Activitypub\get_masked_wp_version;
20
21 /**
22 * ActivityPub Outbox REST-Class.
23 *
24 * @author Matthias Pfefferle
25 *
26 * @see https://www.w3.org/TR/activitypub/#outbox
27 */
28 class Outbox {
29 /**
30 * Initialize the class, registering WordPress hooks.
31 */
32 public static function init() {
33 self::register_routes();
34 }
35
36 /**
37 * Register routes
38 */
39 public static function register_routes() {
40 \register_rest_route(
41 ACTIVITYPUB_REST_NAMESPACE,
42 '/(users|actors)/(?P<user_id>[\w\-\.]+)/outbox',
43 array(
44 array(
45 'methods' => WP_REST_Server::READABLE,
46 'callback' => array( self::class, 'user_outbox_get' ),
47 'args' => self::request_parameters(),
48 'permission_callback' => array( 'Activitypub\Rest\Server', 'verify_signature' ),
49 ),
50 )
51 );
52 }
53
54 /**
55 * Renders the user-outbox
56 *
57 * @param \WP_REST_Request $request The request object.
58 * @return WP_REST_Response|\WP_Error The response object or WP_Error.
59 */
60 public static function user_outbox_get( $request ) {
61 $user_id = $request->get_param( 'user_id' );
62 $user = Actors::get_by_various( $user_id );
63
64 if ( is_wp_error( $user ) ) {
65 return $user;
66 }
67
68 $post_types = \get_option( 'activitypub_support_post_types', array( 'post' ) );
69
70 $page = $request->get_param( 'page', 1 );
71
72 /**
73 * Action triggered prior to the ActivityPub profile being created and sent to the client.
74 */
75 \do_action( 'activitypub_rest_outbox_pre' );
76
77 $json = new stdClass();
78
79 // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
80 $json->{'@context'} = get_context();
81 $json->id = get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) );
82 $json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
83 $json->actor = $user->get_id();
84 $json->type = 'OrderedCollectionPage';
85 $json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) );
86 $json->totalItems = 0;
87
88 if ( $user_id > 0 ) {
89 $count_posts = \count_user_posts( $user_id, $post_types, true );
90 $json->totalItems = \intval( $count_posts );
91 } else {
92 foreach ( $post_types as $post_type ) {
93 $count_posts = \wp_count_posts( $post_type );
94 $json->totalItems += \intval( $count_posts->publish );
95 }
96 }
97
98 $json->first = \add_query_arg( 'page', 1, $json->partOf );
99 $json->last = \add_query_arg( 'page', \ceil( $json->totalItems / 10 ), $json->partOf );
100
101 if ( $page && ( ( \ceil( $json->totalItems / 10 ) ) > $page ) ) {
102 $json->next = \add_query_arg( 'page', $page + 1, $json->partOf );
103 }
104
105 if ( $page && ( $page > 1 ) ) {
106 $json->prev = \add_query_arg( 'page', $page - 1, $json->partOf );
107 }
108 // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
109
110 if ( $page ) {
111 $posts = \get_posts(
112 array(
113 'posts_per_page' => 10,
114 'author' => $user_id > 0 ? $user_id : null,
115 'paged' => $page,
116 'post_type' => $post_types,
117 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
118 'meta_query' => array(
119 'relation' => 'OR',
120 array(
121 'key' => 'activitypub_content_visibility',
122 'compare' => 'NOT EXISTS',
123 ),
124 array(
125 'key' => 'activitypub_content_visibility',
126 'value' => ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL,
127 'compare' => '!=',
128 ),
129 ),
130 )
131 );
132
133 foreach ( $posts as $post ) {
134 $transformer = Factory::get_transformer( $post );
135
136 if ( \is_wp_error( $transformer ) ) {
137 continue;
138 }
139
140 $post = $transformer->to_object();
141 $activity = new Activity();
142 $activity->set_type( 'Create' );
143 $activity->set_object( $post );
144 $json->orderedItems[] = $activity->to_array( false ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
145 }
146 }
147
148 /**
149 * Filter the ActivityPub outbox array.
150 *
151 * @param array $json The ActivityPub outbox array.
152 */
153 $json = \apply_filters( 'activitypub_rest_outbox_array', $json );
154
155 /**
156 * Action triggered after the ActivityPub profile has been created and sent to the client
157 */
158 \do_action( 'activitypub_outbox_post' );
159
160 $rest_response = new WP_REST_Response( $json, 200 );
161 $rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) );
162
163 return $rest_response;
164 }
165
166 /**
167 * The supported parameters.
168 *
169 * @return array List of parameters.
170 */
171 public static function request_parameters() {
172 $params = array();
173
174 $params['page'] = array(
175 'type' => 'integer',
176 'default' => 1,
177 );
178
179 return $params;
180 }
181 }
182