PluginProbe
Assistant – Every Day Productivity Apps / trunk
Assistant – Every Day Productivity Apps vtrunk
1.5.5 trunk 0.1.0 0.2.0 0.2.1 0.2.2 0.3.0 0.3.1 0.4 0.4.1 0.4.2 0.5.0 0.5.1 0.6.0 0.7.0 0.7.0.2 0.7.0.3 0.7.0.4 0.7.0.5 0.7.0.6 0.7.0.7 0.7.0.8 0.7.0.9 0.7.1 1.0 All 71 releases
assistant / backend / src / Controllers / PostsController.php

PostsController.php in Assistant – Every Day Productivity Apps trunk, at backend/src/Controllers/PostsController.php

462 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FL\Assistant\Controllers;
4
5 use FL\Assistant\Data\Repository\LabelsRepository;
6 use FL\Assistant\Data\Repository\PostsRepository;
7 use FL\Assistant\Data\Transformers\PostTransformer;
8 use FL\Assistant\System\Contracts\ControllerAbstract;
9
10 use WP_REST_Request;
11 use WP_REST_Server;
12
13 /**
14 * REST API logic for posts.
15 */
16 class PostsController extends ControllerAbstract {
17
18 protected $labels;
19 protected $posts;
20 protected $transformer;
21
22 public function __construct(
23 LabelsRepository $labels,
24 PostsRepository $posts,
25 PostTransformer $transformer
26 ) {
27 $this->labels = $labels;
28 $this->posts = $posts;
29 $this->transformer = $transformer;
30 }
31
32 /**
33 * Register routes.
34 */
35 public function register_routes() {
36 $this->route(
37 '/posts',
38 [
39 [
40 'methods' => WP_REST_Server::READABLE,
41 'callback' => [ $this, 'posts' ],
42 'permission_callback' => function () {
43 return current_user_can( 'edit_others_posts' );
44 },
45 ],
46 [
47 'methods' => WP_REST_Server::CREATABLE,
48 'callback' => [ $this, 'create_post' ],
49 'permission_callback' => function () {
50 return current_user_can( 'edit_others_posts' );
51 },
52 ],
53 ]
54 );
55
56 $this->route(
57 '/posts/hierarchical',
58 [
59 [
60 'methods' => WP_REST_Server::READABLE,
61 'callback' => [ $this, 'hierarchical_posts' ],
62 'permission_callback' => function () {
63 return current_user_can( 'edit_others_posts' );
64 },
65 ],
66 ]
67 );
68
69 $this->route(
70 '/posts/count',
71 [
72 [
73 'methods' => WP_REST_Server::READABLE,
74 'callback' => [ $this, 'posts_count' ],
75 'permission_callback' => function () {
76 return current_user_can( 'edit_others_posts' );
77 },
78 ],
79 ]
80 );
81
82 $this->route(
83 '/posts/(?P<id>\d+)',
84 [
85 [
86 'methods' => WP_REST_Server::READABLE,
87 'callback' => [ $this, 'post' ],
88 'args' => [
89 'id' => [
90 'required' => true,
91 'type' => 'number',
92 ],
93 ],
94 'permission_callback' => function () {
95 return current_user_can( 'edit_others_posts' );
96 },
97 ],
98 [
99 'methods' => WP_REST_Server::CREATABLE,
100 'callback' => [ $this, 'update_post' ],
101 'args' => [
102 'id' => [
103 'required' => true,
104 'type' => 'number',
105 ],
106 'action' => [
107 'required' => true,
108 'type' => 'string',
109 ],
110 ],
111 'permission_callback' => function () {
112 return current_user_can( 'edit_others_posts' );
113 },
114 ],
115 [
116 'methods' => WP_REST_Server::DELETABLE,
117 'callback' => [ $this, 'delete_post' ],
118 'args' => [
119 'id' => [
120 'required' => true,
121 'type' => 'number',
122 ],
123 ],
124 'permission_callback' => function () {
125 return current_user_can( 'edit_others_posts' );
126 },
127 ],
128 ]
129 );
130
131 $this->route(
132 '/posts/(?P<id>\d+)/clone',
133 [
134 [
135 'methods' => WP_REST_Server::CREATABLE,
136 'callback' => [ $this, 'clone_post' ],
137 'args' => [
138 'id' => [
139 'required' => true,
140 'type' => 'number',
141 ],
142 ],
143 'permission_callback' => function () {
144 return current_user_can( 'edit_others_posts' );
145 },
146 ],
147 ]
148 );
149 }
150
151 /**
152 * Returns an array of posts and related data.
153 */
154 public function posts( WP_REST_Request $request ) {
155
156 $params = $request->get_params();
157 $params['perm'] = 'editable';
158
159 if ( isset( $params['label'] ) && $params['label'] ) {
160 $params['post__in'] = $this->labels->get_object_ids( 'post', $params['label'] );
161 if ( ! count( $params['post__in'] ) ) {
162 $params['post__in'][] = -1; // post__in returns all posts if empty.
163 }
164 }
165
166 $pager = $this->posts->paginate( $params, $this->transformer );
167
168 return rest_ensure_response( $pager->to_array() );
169 }
170
171 /**
172 * Returns an array of posts and related data
173 * with child posts contained in the parent
174 * post's data array.
175 */
176 public function hierarchical_posts( $request ) {
177 $response = [];
178 $children = [];
179 $params = $request->get_params();
180 $posts = get_posts(
181 array_merge(
182 $params,
183 [
184 'perm' => 'editable',
185 ]
186 )
187 );
188
189 foreach ( $posts as $post ) {
190 if ( $post->post_parent ) {
191 if ( ! isset( $children[ $post->post_parent ] ) ) {
192 $children[ $post->post_parent ] = [];
193 }
194 $children [ $post->post_parent ][] = $post;
195 }
196 }
197
198 foreach ( $posts as $post ) {
199 if ( ! $post->post_parent ) {
200 $parent = $this->transform( $post );
201 $parent['children'] = $this->get_child_posts( $post, $children );
202 $response[] = $parent;
203 }
204 }
205
206 return rest_ensure_response( $response );
207 }
208
209 /**
210 * Returns an array of response data for a single post.
211 */
212 public function transform( $post ) {
213 return call_user_func( $this->transformer, $post );
214 }
215
216 /**
217 * Returns an array of child posts for the given post.
218 * A $children array must be passed to search for children.
219 */
220 public function get_child_posts( $post, $children ) {
221 if ( isset( $children[ $post->ID ] ) ) {
222 $post_children = $children[ $post->ID ];
223 foreach ( $post_children as $i => $child ) {
224 $post_children[ $i ] = $this->transform( $child );
225 $post_children[ $i ]['children'] = $this->get_child_posts( $child, $children );
226 }
227
228 return $post_children;
229 }
230
231 return [];
232 }
233
234 /**
235 * Returns an array of counts by post type.
236 */
237 public function posts_count( $request ) {
238
239 $post_types = $this->posts->get_types();
240 $response = [];
241
242 foreach ( $post_types as $slug => $label ) {
243 $counts = wp_count_posts( $slug );
244 $counts->total = $counts->publish + $counts->draft + $counts->pending + $counts->private + $counts->future;
245 $response[ $slug ] = $counts;
246 }
247
248 return rest_ensure_response( $response );
249 }
250
251 /**
252 * Returns data for a single post.
253 */
254 public function post( $request ) {
255 $id = $request->get_param( 'id' );
256
257 if ( current_user_can( 'edit_post', $id ) ) {
258 $post = get_post( $id );
259 return $this->transform( $post );
260 }
261
262 return [];
263 }
264
265 /**
266 * Creates a single post.
267 */
268 public function create_post( $request ) {
269 global $wpdb;
270
271 $params = $request->get_params();
272 $meta_inputs = isset( $params['meta_input'] ) ? $params['meta_input'] : [];
273 unset( $params['meta_input'] );
274 $id = wp_insert_post( $params );
275
276 if ( isset( $meta_inputs ) && is_array( $meta_inputs ) && ! empty( $meta_inputs ) ) {
277
278 foreach ( $meta_inputs as $meta_key => $meta_value ) {
279 $meta_key = sanitize_key( $meta_key );
280 if ( null !== $meta_value ) {
281 $meta_value = addslashes( $meta_value );
282 }
283 $wpdb->query( "INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) values ({$id}, '{$meta_key}', '{$meta_value}')" );
284 }
285 }
286
287 if ( ! $id || is_wp_error( $id ) ) {
288 return [
289 'error' => true,
290 ];
291 }
292
293 return $this->transform( get_post( $id ) );
294 }
295
296 /**
297 * Clones a single post.
298 */
299 public function clone_post( $request ) {
300 global $wpdb;
301
302 $post_id = absint( $request->get_param( 'id' ) );
303 $post = get_post( $post_id );
304 $current_user = wp_get_current_user();
305 $post_data = [
306 'comment_status' => $post->comment_status,
307 'ping_status' => $post->ping_status,
308 'post_author' => $current_user->ID,
309 'post_content' => $post->post_content,
310 'post_excerpt' => $post->post_excerpt,
311 'post_name' => $post->post_name . '-copy',
312 'post_parent' => $post->post_parent,
313 'post_password' => $post->post_password,
314 'post_status' => 'draft',
315 /* translators: %s: post/page title */
316 'post_title' => sprintf( _x( '%s - Copy', '%s stands for post/page title.', 'assistant' ), $post->post_title ),
317 'post_type' => $post->post_type,
318 'to_ping' => $post->to_ping,
319 'menu_order' => $post->menu_order,
320 ];
321
322 $new_post_id = wp_insert_post( $post_data );
323 $post_meta = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM {$wpdb->postmeta} WHERE post_id = %d", $post_id ) );
324 $taxonomies = get_object_taxonomies( $post->post_type );
325
326 if ( count( $post_meta ) !== 0 ) {
327 foreach ( $post_meta as $meta_info ) {
328 $meta_key = $meta_info->meta_key;
329 $meta_value = addslashes( $meta_info->meta_value );
330 $wpdb->query( "INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) values ({$new_post_id}, '{$meta_key}', '{$meta_value}')" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
331 }
332 }
333
334 foreach ( $taxonomies as $taxonomy ) {
335 $post_terms = wp_get_object_terms( $post_id, $taxonomy );
336 for ( $i = 0; $i < count( $post_terms ); $i++ ) {
337 wp_set_object_terms( $new_post_id, $post_terms[ $i ]->slug, $taxonomy, true );
338 }
339 }
340
341 return $this->transform( get_post( $new_post_id ) );
342 }
343
344 /**
345 * Updates a single post based on the specified action.
346 */
347 public function update_post( $request ) {
348 $id = $request->get_param( 'id' );
349 $action = $request->get_param( 'action' );
350
351 if ( ! current_user_can( 'edit_post', $id ) ) {
352 return rest_ensure_response(
353 [
354 'error' => true,
355 ]
356 );
357 }
358
359 switch ( $action ) {
360 case 'data':
361 $data = (array) $request->get_param( 'data' );
362 if ( isset( $data['meta'] ) ) {
363 $this->update_post_meta( $id, $data['meta'] );
364 unset( $data['meta'] );
365 }
366 if ( isset( $data['terms'] ) ) {
367 $this->update_post_terms( $id, $data['terms'] );
368 unset( $data['terms'] );
369 }
370 if ( isset( $data['thumbnail'] ) ) {
371 if ( '0' === $data['thumbnail'] ) {
372 delete_post_meta( $id, '_thumbnail_id' );
373 } else {
374 set_post_thumbnail( $id, $data['thumbnail'] );
375 }
376
377 unset( $data['thumbnail'] );
378 }
379 wp_update_post(
380 array_merge(
381 $data,
382 [
383 'ID' => $id,
384 ]
385 )
386 );
387 break;
388 case 'meta':
389 $data = (array) $request->get_param( 'data' );
390 $this->update_post_meta( $id, $data );
391 break;
392 case 'terms':
393 $data = (array) $request->get_param( 'data' );
394 $this->update_post_terms( $id, $data );
395 break;
396 case 'trash':
397 if ( ! EMPTY_TRASH_DAYS ) {
398 wp_delete_post( $id );
399 } else {
400 wp_trash_post( $id );
401 }
402 break;
403 case 'untrash':
404 wp_untrash_post( $id );
405 break;
406
407 }
408
409 $updated_post = get_post( $id );
410
411 return rest_ensure_response(
412 [
413 'success' => true,
414 'post' => $updated_post ? $this->transform( $updated_post ) : null,
415 ]
416 );
417 }
418
419 /**
420 * Updates post meta values for a post.
421 */
422 public function update_post_meta( $id, $meta ) {
423 foreach ( $meta as $key => $value ) {
424 update_post_meta( $id, $key, $value );
425 }
426 }
427
428 /**
429 * Updates terms for a post.
430 */
431 public function update_post_terms( $id, $terms ) {
432 foreach ( $terms as $taxonomy => $ids ) {
433 wp_set_post_terms( $id, $ids, $taxonomy, false );
434 }
435 }
436
437 /**
438 * Deletes a single post based on the specified ID.
439 */
440 public function delete_post( $request ) {
441 $params = $request->get_params();
442 $id = $params['id'];
443 $force = isset( $params['force'] ) && $params['force'];
444
445 if ( ! current_user_can( 'edit_post', $id ) ) {
446 return rest_ensure_response(
447 [
448 'error' => true,
449 ]
450 );
451 }
452
453 wp_delete_post( $id, $force );
454
455 return rest_ensure_response(
456 [
457 'success' => true,
458 ]
459 );
460 }
461 }
462