PluginProbe
Assistant – Every Day Productivity Apps / 0.6.0
Assistant – Every Day Productivity Apps v0.6.0
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 / Cloud / Libraries / LibraryItemPostController.php

LibraryItemPostController.php in Assistant – Every Day Productivity Apps 0.6.0, at backend/src/Controllers/Cloud/Libraries/LibraryItemPostController.php

775 lines 19.3 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\Cloud\Libraries;
4
5 use FL\Assistant\System\Contracts\ControllerAbstract;
6 use FL\Assistant\Data\Transformers\PostTransformer;
7 use FL\Assistant\Helpers\PostHelper;
8 use FL\Assistant\Helpers\JsonHelper;
9 use FL\Assistant\Services\MediaLibraryService;
10 use FL\Assistant\Clients\Cloud\CloudClient;
11
12 class LibraryItemPostController extends ControllerAbstract {
13
14 protected $posts;
15
16 /**
17 * Controller constructor.
18 *
19 * @return void
20 */
21 public function __construct( PostTransformer $posts ) {
22 $this->posts = $posts;
23 }
24
25 /**
26 * Register routes.
27 *
28 * @return void
29 */
30 public function register_routes() {
31
32 $this->route(
33 '/posts/preview_library_post/(?P<item_id>\d+)',
34 [
35 [
36 'methods' => \WP_REST_Server::CREATABLE,
37 'callback' => [ $this, 'preview_library_post' ],
38 'args' => [
39 'item_id' => [
40 'required' => true,
41 'type' => 'number',
42 ],
43 ],
44 'permission_callback' => function () {
45 return current_user_can( 'edit_others_posts' );
46 },
47 ],
48 ]
49 );
50
51 $this->route(
52 '/posts/(?P<id>\d+)/library/(?P<library_id>\d+)',
53 [
54 [
55 'methods' => \WP_REST_Server::CREATABLE,
56 'callback' => [ $this, 'save_to_library' ],
57 'args' => [
58 'id' => [
59 'required' => true,
60 'type' => 'number',
61 ],
62 'library_id' => [
63 'required' => true,
64 'type' => 'number',
65 ],
66 ],
67 'permission_callback' => function () {
68 return current_user_can( 'edit_others_posts' );
69 },
70 ],
71 ]
72 );
73
74 $this->route(
75 '/posts/import_from_library/(?P<item_id>\d+)',
76 [
77 [
78 'methods' => \WP_REST_Server::CREATABLE,
79 'callback' => [ $this, 'import_from_library' ],
80 'args' => [
81 'item_id' => [
82 'required' => true,
83 'type' => 'number',
84 ],
85 'import_media' => [
86 'type' => 'number',
87 'default' => 1,
88 ],
89 ],
90 'permission_callback' => function () {
91 return current_user_can( 'edit_others_posts' );
92 },
93 ],
94 ]
95 );
96
97 $this->route(
98 '/posts/(?P<id>\d+)/sync_from_library/(?P<item_id>\d+)',
99 [
100 [
101 'methods' => \WP_REST_Server::CREATABLE,
102 'callback' => [ $this, 'sync_from_library' ],
103 'args' => [
104 'id' => [
105 'required' => true,
106 'type' => 'number',
107 ],
108 'item_id' => [
109 'required' => true,
110 'type' => 'number',
111 ],
112 'import_media' => [
113 'type' => 'number',
114 'default' => 1,
115 ],
116 ],
117 'permission_callback' => function () {
118 return current_user_can( 'edit_others_posts' );
119 },
120 ],
121 ]
122 );
123 }
124
125 /**
126 * Handles previewing a post from a cloud library.
127 *
128 * @param object $request
129 * @return array
130 */
131 public function preview_library_post( $request ) {
132 global $wpdb;
133
134 $item_id = $request->get_param( 'item_id' );
135
136 $meta = $wpdb->get_row(
137 $wpdb->prepare(
138 "SELECT * FROM $wpdb->postmeta
139 WHERE meta_key = '_fl_asst_preview_library_item_id'
140 AND meta_value = %s",
141 $item_id
142 )
143 );
144
145 if ( $meta ) {
146 $request->set_param( 'id', $meta->post_id );
147 $response = $this->sync_from_library( $request );
148 } else {
149 $response = $this->import_from_library( $request );
150 }
151
152 if ( isset( $response->data['error'] ) ) {
153 return $response;
154 }
155
156 $post_id = $response->data['id'];
157
158 wp_update_post(
159 [
160 'ID' => $post_id,
161 'post_status' => 'auto-draft',
162 ]
163 );
164
165 update_post_meta( $post_id, '_fl_asst_preview_library_item_id', $item_id );
166
167 return rest_ensure_response(
168 [
169 'url' => PostHelper::get_preview_url( $post_id ),
170 ]
171 );
172 }
173
174 /**
175 * Saves a post to a cloud library.
176 *
177 * @param object $request
178 * @return array
179 */
180 public function save_to_library( $request ) {
181 $id = $request->get_param( 'id' );
182 $library_id = $request->get_param( 'library_id' );
183 $post = get_post( $id );
184 $client = new CloudClient;
185
186 return $client->libraries->create_item(
187 $library_id,
188 [
189 'name' => $post->post_title,
190 'type' => 'post',
191 'data' => [
192 'post' => [
193 'comment_status' => $post->comment_status,
194 'menu_order' => $post->menu_order,
195 'ping_status' => $post->ping_status,
196 'post_content' => $post->post_content,
197 'post_excerpt' => $post->post_excerpt,
198 'post_mime_type' => $post->post_mime_type,
199 'post_name' => $post->post_name,
200 'post_title' => $post->post_title,
201 'post_type' => $post->post_type,
202 ],
203 'meta' => get_post_meta( $id ),
204 'terms' => $this->get_post_terms( $post ),
205
206 ],
207 'media' => [
208 'thumb' => get_attached_file( get_post_thumbnail_id( $post ) ),
209 'attachments' => $this->get_post_image_paths( $post ),
210 ],
211 'screenshot' => $this->get_post_screenshot( $request, $post ),
212 ]
213 );
214 }
215
216 /**
217 * Imports a post from a library to the site.
218 *
219 * @param object $request
220 * @return array
221 */
222 public function import_from_library( $request ) {
223 $item_id = $request->get_param( 'item_id' );
224 $import_media = ! ! $request->get_param( 'import_media' );
225 $client = new CloudClient;
226 $response = $client->libraries->get_item( $item_id );
227 $post_data = $response->data->post;
228
229 $new_post_id = wp_insert_post(
230 [
231 'comment_status' => $post_data->comment_status,
232 'menu_order' => $post_data->menu_order,
233 'ping_status' => $post_data->ping_status,
234 'post_author' => wp_get_current_user()->ID,
235 'post_content' => $post_data->post_content ? $post_data->post_content : '',
236 'post_excerpt' => $post_data->post_excerpt ? $post_data->post_excerpt : '',
237 'post_mime_type' => $post_data->post_mime_type,
238 'post_name' => $post_data->post_name,
239 'post_status' => 'draft',
240 'post_title' => $post_data->post_title,
241 'post_type' => $post_data->post_type,
242 ]
243 );
244
245 if ( is_wp_error( $new_post_id ) ) {
246 return rest_ensure_response(
247 [
248 'error' => true,
249 ]
250 );
251 }
252
253 $this->import_post_meta_from_library( $new_post_id, $response->data->meta );
254 $this->import_post_terms_from_library( $new_post_id, $response->data->terms );
255 $this->import_post_media_from_library( $new_post_id, $response->media, $import_media );
256 $this->regenerate_builder_cache( $response );
257
258 return rest_ensure_response(
259 $this->posts->transform(
260 get_post( $new_post_id )
261 )
262 );
263 }
264
265 /**
266 * Syncs a library post with a post on the site.
267 *
268 * @param object $request
269 * @return array
270 */
271 public function sync_from_library( $request ) {
272 $post_id = $request->get_param( 'id' );
273 $item_id = $request->get_param( 'item_id' );
274 $import_media = ! ! $request->get_param( 'import_media' );
275 $client = new CloudClient;
276 $response = $client->libraries->get_item( $item_id );
277
278 $updated = wp_update_post(
279 [
280 'ID' => $post_id,
281 'post_content' => $response->data->post->post_content,
282 ]
283 );
284
285 if ( is_wp_error( $updated ) ) {
286 return rest_ensure_response(
287 [
288 'error' => true,
289 ]
290 );
291 }
292
293 $this->import_post_meta_from_library( $post_id, $response->data->meta );
294 $this->import_post_terms_from_library( $post_id, $response->data->terms );
295 $this->import_post_media_from_library( $post_id, $response->media, $import_media );
296 $this->regenerate_builder_cache( $response );
297
298 return rest_ensure_response(
299 $this->posts->transform(
300 get_post( $post_id )
301 )
302 );
303 }
304
305 /**
306 * Imports meta for a library post to the site.
307 *
308 * @param int $post_id
309 * @param object $meta
310 * @return void
311 */
312 public function import_post_meta_from_library( $post_id, $meta ) {
313 global $wpdb;
314
315 if ( ! $meta || ! is_object( $meta ) ) {
316 return;
317 }
318
319 foreach ( $meta as $meta_key => $meta_value ) {
320 if ( metadata_exists( 'post', $post_id, $meta_key ) ) {
321 delete_metadata( 'post', $post_id, $meta_key );
322 }
323
324 foreach ( $meta_value as $value ) {
325 $value = addslashes( $value );
326 // @codingStandardsIgnoreStart
327 $wpdb->query( "INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) values ({$post_id}, '{$meta_key}', '{$value}')" );
328 // @codingStandardsIgnoreEnd
329 }
330 }
331 }
332
333 /**
334 * Imports terms for a library post to the site.
335 *
336 * @param int $post_id
337 * @param array $terms
338 * @return void
339 */
340 public function import_post_terms_from_library( $post_id, $terms ) {
341 if ( ! $terms || ! is_array( $terms ) || 0 === count( $terms ) ) {
342 return;
343 }
344
345 $taxonomies = get_taxonomies( '', 'objects' );
346
347 foreach ( $terms as $term ) {
348 if ( ! taxonomy_exists( $term->taxonomy ) ) {
349 continue;
350 }
351
352 $existing_term = term_exists( $term->slug, $term->taxonomy );
353 $is_hierarchical = ! ! $taxonomies[ $term->taxonomy ]->hierarchical;
354
355 if ( is_array( $existing_term ) ) {
356 $term_id = $is_hierarchical ? $existing_term['term_taxonomy_id'] : $term->name;
357 wp_set_post_terms( $post_id, [ $term_id ], $term->taxonomy, true );
358 } else {
359 $new_term = wp_insert_term(
360 $term->name,
361 $term->taxonomy,
362 [
363 'description' => $term->description,
364 'slug' => $term->slug,
365 ]
366 );
367 $term_id = $is_hierarchical ? $new_term['term_taxonomy_id'] : $term->name;
368 wp_set_post_terms( $post_id, [ $new_term['term_taxonomy_id'] ], $term->taxonomy, true );
369 }
370 }
371 }
372
373 /**
374 * Returns an array of all terms for a post.
375 *
376 * @param object $post
377 * @return array
378 */
379 public function get_post_terms( $post ) {
380 $taxonomies = get_taxonomies( '', 'names' );
381 $object_terms = wp_get_object_terms( $post->ID, $taxonomies );
382 $terms = [];
383
384 foreach ( $object_terms as $term ) {
385 $terms[] = [
386 'description' => $term->description,
387 'name' => $term->name,
388 'slug' => $term->slug,
389 'taxonomy' => $term->taxonomy,
390 ];
391 }
392
393 return $terms;
394 }
395
396 /**
397 * Returns the screenshot data for a post.
398 *
399 * @param object $request
400 * @param object $post
401 * @return array
402 */
403 public function get_post_screenshot( $request, $post ) {
404 $screenshot = $request->get_param( 'screenshot' );
405
406 if ( $screenshot ) {
407 return [
408 'type' => 'base64',
409 'data' => $screenshot,
410 ];
411 }
412
413 $url = PostHelper::get_preview_url( $post );
414 $response = wp_remote_get(
415 $url, [
416 'cookies' => $_COOKIE,
417 ]
418 );
419
420 return [
421 'type' => 'html',
422 'html' => wp_remote_retrieve_body( $response ),
423 ];
424 }
425
426 /**
427 * Imports the media for a post.
428 *
429 * @param int $post_id
430 * @param object $media
431 * @param bool $import
432 * @return void
433 */
434 public function import_post_media_from_library( $post_id, $media, $import = true ) {
435 $service = new MediaLibraryService();
436
437 // Import post thumbnail
438 if ( $import && isset( $media->thumb ) && 'screenshot.png' !== $media->thumb->file_name ) {
439 $response = $service->import_cloud_media( $media->thumb, $post_id );
440 set_post_thumbnail( $post_id, $response['id'] );
441 }
442
443 // Import post attachments
444 if ( isset( $media->attachments ) ) {
445 $imported = [];
446
447 foreach ( $media->attachments as $attachment ) {
448 if ( $import ) {
449 $response = $service->import_cloud_media( $attachment, $post_id );
450 $imported[ $attachment->file_name ] = wp_get_attachment_metadata( $response['id'] );
451 $imported[ $attachment->file_name ]['id'] = $response['id'];
452 } else {
453 $imported[ $attachment->file_name ] = $attachment;
454 }
455 }
456
457 $this->replace_imported_attachment_urls_in_content( $post_id, $imported );
458 $this->replace_imported_attachment_urls_in_meta( $post_id, $imported );
459 }
460 }
461
462 /**
463 * Replaces the imported attachment urls in post content.
464 *
465 * @param int $post_id
466 * @param array $imported
467 * @return void
468 */
469 public function replace_imported_attachment_urls_in_content( $post_id, $imported ) {
470 $content = get_post_field( 'post_content', $post_id );
471 $content = $this->replace_imported_attachment_urls_in_string( $content, $imported );
472
473 wp_update_post(
474 [
475 'ID' => $post_id,
476 'post_content' => $content,
477 ]
478 );
479 }
480
481 /**
482 * Replaces the imported attachment urls in post meta.
483 *
484 * @param int $post_id
485 * @param array $imported
486 * @return void
487 */
488 public function replace_imported_attachment_urls_in_meta( $post_id, $imported ) {
489 $meta = get_post_meta( $post_id );
490
491 foreach ( $meta as $key => $val ) {
492 $val = maybe_unserialize( $val[0] );
493
494 if ( is_object( $val ) || is_array( $val ) ) {
495 $val = $this->replace_imported_attachment_urls_in_data( $val, $imported );
496 } elseif ( JsonHelper::is_string_json( $val ) ) {
497 $val = json_decode( $val );
498 $val = $this->replace_imported_attachment_urls_in_data( $val, $imported );
499 $val = wp_slash( json_encode( $val ) );
500 } else {
501 $val = $this->replace_imported_attachment_urls_in_string( $val, $imported );
502 }
503
504 update_post_meta( $post_id, $key, $val );
505 }
506 }
507
508 /**
509 * Replaces the imported attachment in an object or array.
510 *
511 * @param object|array|string $data
512 * @param array $imported
513 * @return object|array|string
514 */
515 public function replace_imported_attachment_urls_in_data( $data, $imported ) {
516 if ( is_object( $data ) || is_array( $data ) ) {
517 foreach ( $data as $key => $val ) {
518 if ( is_object( $val ) || is_array( $val ) ) {
519 $new_val = $this->replace_imported_attachment_urls_in_data( $val, $imported );
520 } else {
521 $new_val = $this->replace_imported_attachment_urls_in_string( $val, $imported );
522 }
523
524 if ( is_object( $data ) ) {
525 $data->$key = $new_val;
526 } else {
527 $data[ $key ] = $new_val;
528 }
529 }
530 } else {
531 $data = $this->replace_imported_attachment_urls_in_string( $data, $imported );
532 }
533
534 return $data;
535 }
536
537 /**
538 * Replaces the imported attachment in a string.
539 *
540 * @param string $string
541 * @param array $imported
542 * @return string
543 */
544 public function replace_imported_attachment_urls_in_string( $string, $imported ) {
545 $urls = $this->get_image_urls_from_string( $string );
546
547 foreach ( $urls as $url ) {
548 $url_info = $this->get_image_info_from_url( $url );
549
550 if ( ! isset( $imported[ $url_info['file_name'] ] ) ) {
551 continue;
552 }
553
554 $import_data = (array) $imported[ $url_info['file_name'] ];
555 $sizes = $this->get_ordered_image_sizes( (array) $import_data['sizes'] );
556 $new_url = null;
557
558 if ( $url_info['width'] && $url_info['height'] ) {
559 foreach ( $sizes as $size => $size_data ) {
560 $size_data = (array) $size_data;
561 if ( $url_info['width'] <= $size_data['width'] && $url_info['height'] <= $size_data['height'] ) {
562 if ( isset( $size_data['url'] ) ) {
563 $new_url = $size_data['url'];
564 break;
565 } elseif ( isset( $import_data['id'] ) ) {
566 $size_src = wp_get_attachment_image_src( $import_data['id'], $size );
567 if ( $size_src ) {
568 $new_url = $size_src[0];
569 break;
570 }
571 }
572 }
573 }
574 }
575
576 if ( ! $new_url ) {
577 if ( isset( $import_data['url'] ) ) {
578 $new_url = $import_data['url'];
579 } elseif ( isset( $import_data['id'] ) ) {
580 $new_url = wp_get_attachment_url( $import_data['id'] );
581 }
582 }
583
584 if ( $new_url ) {
585 $string = str_replace( $url, $new_url, $string );
586 }
587 }
588
589 return $string;
590 }
591
592 /**
593 * Returns an array or ordered image sizes.
594 *
595 * @param array $sizes
596 * @return array
597 */
598 public function get_ordered_image_sizes( $sizes ) {
599 $keys = [];
600 $ordered = [];
601
602 foreach ( $sizes as $size => $data ) {
603 if ( 'thumb' === $size || 'thumbnail' === $size ) {
604 continue;
605 }
606 $data = (array) $data;
607 $key = $data['width'] + $data['height'];
608 $keys[ $key ] = $size;
609 }
610
611 ksort( $keys );
612
613 foreach ( $keys as $key ) {
614 $ordered[ $key ] = $sizes[ $key ];
615 }
616
617 return $ordered;
618 }
619
620 /**
621 * Get the server paths to all images associated with a post.
622 *
623 * @param object $post
624 * @return array
625 */
626 public function get_post_image_paths( $post ) {
627 $content_urls = $this->get_image_urls_from_string( $post->post_content );
628 $content_paths = $this->get_image_paths_from_urls( $content_urls );
629 $meta = get_post_meta( $post->ID );
630 $meta_paths = [];
631
632 if ( $meta && count( $meta ) > 0 ) {
633 $meta_urls = $this->get_image_urls_from_meta( $meta );
634 $meta_paths = $this->get_image_paths_from_urls( $meta_urls );
635 }
636
637 return array_unique( array_merge( $content_paths, $meta_paths ) );
638 }
639
640 /**
641 * Get the server paths to all images in an array of urls.
642 *
643 * @param array $urls
644 * @return array
645 */
646 public function get_image_paths_from_urls( $urls = [] ) {
647 $paths = [];
648
649 foreach ( $urls as $url ) {
650 $path = $this->get_image_path_from_url( $url );
651 if ( $path ) {
652 $paths[] = $path;
653 }
654 }
655
656 return $paths;
657 }
658
659 /**
660 * Converts a media library URL to the server path of the full size image.
661 *
662 * @param string $url
663 * @return string
664 */
665 public function get_image_path_from_url( $url ) {
666 $upload_dir = wp_get_upload_dir();
667 $base_url = preg_replace( '/https?:\/\//', '', $upload_dir['baseurl'] );
668 $url_info = $this->get_image_info_from_url( $url );
669 $url = preg_replace( '/https?:\/\//', '', $url_info['full_size_url'] );
670 $path = null;
671
672 if ( stristr( $url, $base_url ) ) {
673 $path = $upload_dir['basedir'] . str_ireplace( $base_url, '', $url );
674 }
675
676 return $path;
677 }
678
679 /**
680 * Get the urls to all images in a post meta object.
681 *
682 * @param mixed $meta
683 * @return array
684 */
685 public function get_image_urls_from_meta( $meta ) {
686 $urls = [];
687
688 foreach ( $meta as $key => $val ) {
689 $val = maybe_unserialize( $val );
690
691 if ( is_object( $val ) || is_array( $val ) ) {
692 $urls = array_merge( $urls, $this->get_image_urls_from_meta( $val ) );
693 } elseif ( JsonHelper::is_string_json( $val ) ) {
694 $val = wp_unslash( $val );
695 $urls = array_merge( $urls, $this->get_image_urls_from_string( $val ) );
696 } else {
697 $urls = array_merge( $urls, $this->get_image_urls_from_string( $val ) );
698 }
699 }
700
701 return $urls;
702 }
703
704 /**
705 * Get the urls to all images in a string.
706 *
707 * @param string $string
708 * @return array
709 */
710 public function get_image_urls_from_string( $string ) {
711 $pattern = '#https?://[^,\s()<>]+(?:\([\w\d]+\)|([^,[:punct:]\s]|/)\.(jpg|jpeg|png|gif))#';
712 $urls = [];
713
714 if ( preg_match_all( $pattern, $string, $matches ) ) {
715 if ( isset( $matches[0] ) && ! empty( $matches[0] ) ) {
716 $urls = $matches[0];
717 }
718 }
719
720 return $urls;
721 }
722
723 /**
724 * Get the info for a media library image from a url.
725 *
726 * @param string $url
727 * @return array
728 */
729 public function get_image_info_from_url( $url ) {
730 $info = [
731 'url' => $url,
732 'full_size_url' => $url,
733 'file_name' => null,
734 'width' => null,
735 'height' => null,
736 'ext' => null,
737 ];
738
739 preg_match_all( '/(-(\d+)x(\d+))\.(jpg|jpeg|png|gif)/', $url, $matches );
740
741 if ( isset( $matches[1] ) && ! empty( $matches[1] ) ) {
742 $info['full_size_url'] = str_replace( $matches[1], '', $url );
743 }
744
745 $parts = explode( '/', $info['full_size_url'] );
746 $info['file_name'] = array_pop( $parts );
747
748 if ( isset( $matches[2] ) && ! empty( $matches[2] ) ) {
749 $info['width'] = $matches[2][0];
750 }
751 if ( isset( $matches[3] ) && ! empty( $matches[3] ) ) {
752 $info['height'] = $matches[3][0];
753 }
754 if ( isset( $matches[4] ) && ! empty( $matches[4] ) ) {
755 $info['ext'] = $matches[4][0];
756 }
757
758 return $info;
759 }
760
761 /**
762 * Regenerate the asset cache for posts created with a builder.
763 *
764 * @param object $item
765 * @return void
766 */
767 public function regenerate_builder_cache( $item ) {
768 $meta = (array) $item->data->meta;
769
770 if ( isset( $meta['_elementor_data'] ) && class_exists( 'Elementor\Plugin' ) ) {
771 \Elementor\Plugin::$instance->files_manager->clear_cache();
772 }
773 }
774 }
775