PluginProbe
ActivityPub / trunk
ActivityPub vtrunk
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-collections-controller.php

class-collections-controller.php in ActivityPub trunk, at includes/rest/class-collections-controller.php

266 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Collections_Controller file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Rest;
9
10 use Activitypub\Activity\Base_Object;
11 use Activitypub\Collection\Actors;
12 use Activitypub\Transformer\Factory;
13
14 use function Activitypub\esc_hashtag;
15 use function Activitypub\get_rest_url_by_path;
16 use function Activitypub\is_single_user;
17
18 /**
19 * Collections_Controller class.
20 *
21 * @author Matthias Pfefferle
22 *
23 * @see https://docs.joinmastodon.org/spec/activitypub/#featured
24 * @see https://docs.joinmastodon.org/spec/activitypub/#featuredTags
25 * @see https://www.w3.org/TR/activitypub/#collections
26 */
27 class Collections_Controller extends Actors_Controller {
28 use Collection;
29
30 /**
31 * Register routes.
32 */
33 public function register_routes() {
34 \register_rest_route(
35 $this->namespace,
36 '/' . $this->rest_base . '/collections/(?P<type>[\w\-\.]+)',
37 array(
38 'args' => array(
39 'user_id' => array(
40 'description' => 'The user ID or username.',
41 'type' => 'integer',
42 'required' => true,
43 'validate_callback' => array( $this, 'validate_user_id' ),
44 ),
45 'type' => array(
46 'description' => 'The type of collection to query.',
47 'type' => 'string',
48 'enum' => array( 'tags', 'featured' ),
49 'required' => true,
50 ),
51 ),
52 array(
53 'methods' => \WP_REST_Server::READABLE,
54 'callback' => array( $this, 'get_items' ),
55 'permission_callback' => '__return_true',
56 'args' => array(
57 'page' => array(
58 'description' => 'Current page of the collection.',
59 'type' => 'integer',
60 'minimum' => 1,
61 // No default so we can differentiate between Collection and CollectionPage requests.
62 ),
63 'per_page' => array(
64 'description' => 'Maximum number of items to be returned in result set.',
65 'type' => 'integer',
66 'default' => 20,
67 'minimum' => 1,
68 ),
69 ),
70 ),
71 'schema' => array( $this, 'get_item_schema' ),
72 )
73 );
74 }
75
76 /**
77 * Retrieves a collection of featured tags.
78 *
79 * @param \WP_REST_Request $request The request object.
80 *
81 * @return \WP_REST_Response|\WP_Error Response object or WP_Error object.
82 */
83 public function get_items( $request ) {
84 $user_id = $request->get_param( 'user_id' );
85
86 switch ( $request->get_param( 'type' ) ) {
87 case 'tags':
88 $response = $this->get_tags( $request, $user_id );
89 break;
90
91 case 'featured':
92 $response = $this->get_featured( $request, $user_id );
93 break;
94
95 default:
96 $response = new \WP_Error( 'rest_unknown_collection_type', 'Unknown collection type.', array( 'status' => 404 ) );
97 }
98
99 if ( \is_wp_error( $response ) ) {
100 return $response;
101 }
102
103 $response = \rest_ensure_response( $response );
104 $response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
105
106 return $response;
107 }
108
109 /**
110 * Retrieves a collection of featured tags.
111 *
112 * @param \WP_REST_Request $request The request object.
113 * @param int $user_id Actor ID.
114 *
115 * @return array Collection of featured tags.
116 */
117 public function get_tags( $request, $user_id ) {
118 $tags = \get_terms(
119 array(
120 'taxonomy' => 'post_tag',
121 'orderby' => 'count',
122 'order' => 'DESC',
123 'number' => 4,
124 )
125 );
126
127 if ( \is_wp_error( $tags ) ) {
128 $tags = array();
129 }
130
131 $response = array(
132 '@context' => Base_Object::JSON_LD_CONTEXT,
133 'id' => get_rest_url_by_path( \sprintf( 'actors/%d/collections/tags', $user_id ) ),
134 'type' => 'Collection',
135 'totalItems' => \is_countable( $tags ) ? \count( $tags ) : 0,
136 'items' => array(),
137 );
138
139 foreach ( $tags as $tag ) {
140 $response['items'][] = array(
141 'type' => 'Hashtag',
142 'href' => \esc_url_raw( \get_tag_link( $tag ) ),
143 'name' => esc_hashtag( $tag->name ),
144 );
145 }
146
147 return $this->prepare_collection_response( $response, $request );
148 }
149
150 /**
151 * Retrieves a collection of featured posts.
152 *
153 * @param \WP_REST_Request $request The request object.
154 * @param int $user_id Actor ID.
155 *
156 * @return array Collection of featured posts.
157 */
158 public function get_featured( $request, $user_id ) {
159 $posts = array();
160
161 if ( is_single_user() || Actors::BLOG_USER_ID !== $user_id ) {
162 $sticky_posts = \get_option( 'sticky_posts' );
163
164 if ( $sticky_posts && \is_array( $sticky_posts ) ) {
165 // Only show public posts.
166 $args = array(
167 'post__in' => $sticky_posts,
168 'ignore_sticky_posts' => 1,
169 'orderby' => 'date',
170 'order' => 'DESC',
171 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
172 'meta_query' => array(
173 array(
174 'key' => 'activitypub_content_visibility',
175 'compare' => 'NOT EXISTS',
176 ),
177 ),
178 );
179
180 if ( $user_id > 0 ) {
181 $args['author'] = $user_id;
182 }
183
184 $posts = \get_posts( $args );
185 }
186 }
187
188 $response = array(
189 '@context' => Base_Object::JSON_LD_CONTEXT,
190 'id' => get_rest_url_by_path( \sprintf( 'actors/%d/collections/featured', $user_id ) ),
191 'type' => 'OrderedCollection',
192 'totalItems' => \is_countable( $posts ) ? \count( $posts ) : 0,
193 'orderedItems' => array(),
194 );
195
196 foreach ( $posts as $post ) {
197 $transformer = Factory::get_transformer( $post );
198
199 if ( \is_wp_error( $transformer ) ) {
200 continue;
201 }
202
203 $response['orderedItems'][] = $transformer->to_object()->to_array( false );
204 }
205
206 return $this->prepare_collection_response( $response, $request );
207 }
208
209 /**
210 * Retrieves the schema for the Collections endpoint.
211 *
212 * @return array Schema data.
213 */
214 public function get_item_schema() {
215 if ( $this->schema ) {
216 return $this->add_additional_fields_schema( $this->schema );
217 }
218
219 $schema = $this->get_collection_schema();
220
221 // Add collections-specific properties.
222 $schema['title'] = 'featured';
223 $schema['properties']['generator'] = array(
224 'description' => 'The software used to generate the collection.',
225 'type' => 'string',
226 'format' => 'uri',
227 );
228 $schema['properties']['oneOf'] = array(
229 'orderedItems' => array(
230 'type' => 'array',
231 'items' => array(
232 'type' => 'object',
233 ),
234 ),
235 'items' => array(
236 'type' => 'array',
237 'items' => array(
238 'type' => 'object',
239 'properties' => array(
240 'type' => array(
241 'type' => 'string',
242 'enum' => array( 'Hashtag' ),
243 'required' => true,
244 ),
245 'href' => array(
246 'type' => 'string',
247 'format' => 'uri',
248 'required' => true,
249 ),
250 'name' => array(
251 'type' => 'string',
252 'required' => true,
253 ),
254 ),
255 ),
256 ),
257 );
258
259 unset( $schema['properties']['orderedItems'] );
260
261 $this->schema = $schema;
262
263 return $this->add_additional_fields_schema( $this->schema );
264 }
265 }
266