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