PluginProbe
Assistant – Every Day Productivity Apps / 1.3
Assistant – Every Day Productivity Apps v1.3
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 +669 -703 trunk1.3 View file →
@@ -1,703 +1,669 @@
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 + '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 + '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 + $data = $this->get_save_data( $request, $post );
289 +
290 + return $client->libraries->update_item(
291 + $item_id,
292 + $data
293 + );
294 + }
295 +
296 + /**
297 + * Imports a post from a library to the site.
298 + *
299 + * @param object $request
300 + * @return array
301 + */
302 + public function import_from_library( $request ) {
303 + $data = $request->get_param( 'item' );
304 + $item = $data ? json_decode( $data ) : null;
305 +
306 + if ( ! $item ) {
307 + return rest_ensure_response(
308 + [
309 + 'error' => true,
310 + ]
311 + );
312 + }
313 +
314 + $client = new CloudClient;
315 + $item = $client->libraries->get_item( $item->id );
316 + $post_data = $item->data->post;
317 + $meta_data = $item->data->meta;
318 + $term_data = $item->data->terms;
319 +
320 + $new_post_id = wp_insert_post(
321 + [
322 + 'comment_status' => $post_data->comment_status,
323 + 'menu_order' => $post_data->menu_order,
324 + 'ping_status' => $post_data->ping_status,
325 + 'post_author' => wp_get_current_user()->ID,
326 + 'post_content' => $post_data->post_content ? $post_data->post_content : '',
327 + 'post_excerpt' => $post_data->post_excerpt ? $post_data->post_excerpt : '',
328 + 'post_mime_type' => $post_data->post_mime_type,
329 + 'post_name' => $post_data->post_name,
330 + 'post_status' => 'publish',
331 + 'post_title' => $post_data->post_title,
332 + 'post_type' => $post_data->post_type,
333 + ]
334 + );
335 +
336 + if ( is_wp_error( $new_post_id ) ) {
337 + return rest_ensure_response(
338 + [
339 + 'error' => true,
340 + ]
341 + );
342 + }
343 +
344 + $this->import_post_meta_from_library( $new_post_id, $meta_data );
345 + $this->import_post_terms_from_library( $new_post_id, $term_data );
346 + $this->regenerate_builder_cache( $new_post_id, $item );
347 +
348 + return rest_ensure_response(
349 + $this->posts->transform(
350 + get_post( $new_post_id )
351 + )
352 + );
353 + }
354 +
355 + /**
356 + * Replaces a post on this site with a post from a library.
357 + *
358 + * @param object $request
359 + * @return array
360 + */
361 + public function sync_from_library( $request ) {
362 + $post_id = $request->get_param( 'id' );
363 + $data = $request->get_param( 'item' );
364 + $item = $data ? json_decode( $data ) : null;
365 +
366 + if ( ! $item ) {
367 + return rest_ensure_response(
368 + [
369 + 'error' => true,
370 + ]
371 + );
372 + }
373 +
374 + $client = new CloudClient;
375 + $item = $client->libraries->get_item( $item->id );
376 + $post_data = $item->data->post;
377 + $meta_data = $item->data->meta;
378 + $term_data = $item->data->terms;
379 +
380 + $updated = wp_update_post(
381 + [
382 + 'ID' => $post_id,
383 + 'post_content' => $post_data->post_content,
384 + ]
385 + );
386 +
387 + if ( is_wp_error( $updated ) ) {
388 + return rest_ensure_response(
389 + [
390 + 'error' => true,
391 + ]
392 + );
393 + }
394 +
395 + $this->import_post_meta_from_library( $post_id, $meta_data );
396 + $this->import_post_terms_from_library( $post_id, $term_data );
397 + $this->regenerate_builder_cache( $post_id, $item );
398 +
399 + return rest_ensure_response(
400 + $this->posts->transform(
401 + get_post( $post_id )
402 + )
403 + );
404 + }
405 +
406 + /**
407 + * Imports meta for a library post to the site.
408 + *
409 + * @param int $post_id
410 + * @param object $meta
411 + * @return void
412 + */
413 + public function import_post_meta_from_library( $post_id, $meta ) {
414 + global $wpdb;
415 +
416 + if ( ! $meta || ! is_object( $meta ) ) {
417 + return;
418 + }
419 +
420 + if ( isset( $meta->_fl_builder_data ) ) {
421 + $meta->_fl_builder_draft = $meta->_fl_builder_data;
422 + $meta->_fl_builder_draft_settings = $meta->_fl_builder_data_settings;
423 + }
424 +
425 + foreach ( $meta as $meta_key => $meta_value ) {
426 + if ( metadata_exists( 'post', $post_id, $meta_key ) ) {
427 + delete_metadata( 'post', $post_id, $meta_key );
428 + }
429 + if ( is_array( $meta_value ) && count( $meta_value ) !== 0 ) {
430 + foreach ( $meta_value as $value ) {
431 + $value = addslashes( $value );
432 + // @codingStandardsIgnoreStart
433 + $wpdb->query( "INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) values ({$post_id}, '{$meta_key}', '{$value}')" );
434 + // @codingStandardsIgnoreEnd
435 + }
436 + }
437 + }
438 + }
439 +
440 + /**
441 + * Imports terms for a library post to the site.
442 + *
443 + * @param int $post_id
444 + * @param array $terms
445 + * @return void
446 + */
447 + public function import_post_terms_from_library( $post_id, $terms ) {
448 + $terms = is_object( $terms ) ? [ $terms ] : $terms;
449 +
450 + if ( ! $terms || ! is_array( $terms ) || 0 === count( $terms ) ) {
451 + return;
452 + }
453 +
454 + $taxonomies = get_taxonomies( '', 'objects' );
455 + $taxonomy_terms = [];
456 +
457 + foreach ( $terms as $term ) {
458 + if ( ! isset( $term->name ) || ! isset( $term->taxonomy ) ) {
459 + continue;
460 + } elseif ( ! taxonomy_exists( $term->taxonomy ) ) {
461 + continue;
462 + } elseif ( ! isset( $taxonomy_terms ) ) {
463 + $taxonomy_terms[ $term->taxonomy ] = [];
464 + }
465 +
466 + $existing_term = term_exists( $term->slug, $term->taxonomy );
467 + $is_hierarchical = ! ! $taxonomies[ $term->taxonomy ]->hierarchical;
468 +
469 + if ( is_array( $existing_term ) ) {
470 + $term_id = $is_hierarchical ? $existing_term['term_taxonomy_id'] : $term->name;
471 + } else {
472 + $new_term = wp_insert_term(
473 + $term->name,
474 + $term->taxonomy,
475 + [
476 + 'description' => $term->description,
477 + 'slug' => $term->slug,
478 + ]
479 + );
480 + $term_id = $is_hierarchical ? $new_term['term_taxonomy_id'] : $term->name;
481 + }
482 +
483 + $taxonomy_terms[ $term->taxonomy ][] = $term_id;
484 + }
485 +
486 + foreach ( $taxonomy_terms as $taxonomy => $terms ) {
487 + wp_delete_object_term_relationships( $post_id, $taxonomy );
488 + wp_set_post_terms( $post_id, $terms, $taxonomy, true );
489 + }
490 + }
491 +
492 + /**
493 + * Returns an array of all terms for a post.
494 + *
495 + * @param object $post
496 + * @return array
497 + */
498 + public function get_post_terms( $post ) {
499 + $taxonomies = get_taxonomies( '', 'names' );
500 + $object_terms = wp_get_object_terms( $post->ID, $taxonomies );
501 + $terms = [];
502 +
503 + foreach ( $object_terms as $term ) {
504 + $terms[] = [
505 + 'description' => $term->description,
506 + 'name' => $term->name,
507 + 'slug' => $term->slug,
508 + 'taxonomy' => $term->taxonomy,
509 + ];
510 + }
511 +
512 + return $terms;
513 + }
514 +
515 + /**
516 + * Returns the screenshot data for a post.
517 + *
518 + * @param object $request
519 + * @param object $post
520 + * @return array
521 + */
522 + public function get_post_screenshot( $request, $post ) {
523 + $url = PreviewHelper::get_post_preview_url( $post );
524 + $url = add_query_arg( 'fl_asst_screenshot', '1', $url );
525 + return ScreenshotHelper::get_for_rest_request( $request, $url );
526 + }
527 +
528 + /**
529 + * Imports the featured image for a post.
530 + *
531 + * @param object $request
532 + * @return array
533 + */
534 + public function import_post_thumb_from_library( $request ) {
535 + $post_id = $request->get_param( 'post_id' );
536 + $thumb = $request->get_param( 'thumb' );
537 + $service = new MediaLibraryService();
538 +
539 + if ( ! preg_match( '/screenshot\.(png|jpg|gif)/', $thumb['file_name'] ) ) {
540 + $response = $service->import_cloud_media( $thumb, $post_id );
541 + set_post_thumbnail( $post_id, $response['id'] );
542 + }
543 +
544 + return [ 'success' => true ];
545 + }
546 +
547 + /**
548 + * Imports a media item for a post.
549 + *
550 + * @param object $request
551 + * @return array
552 + */
553 + public function import_post_media_from_library( $request ) {
554 + $post_id = $request->get_param( 'post_id' );
555 + $media = $request->get_param( 'media' );
556 + $service = new MediaLibraryService();
557 +
558 + $imported = [];
559 + $response = $service->import_cloud_media( $media, $post_id );
560 + $imported[ $media['file_name'] ] = wp_get_attachment_metadata( $response['id'] );
561 + $imported[ $media['file_name'] ]['id'] = $response['id'];
562 +
563 + $this->replace_imported_attachment_urls_in_content( $post_id, $imported );
564 + $this->replace_imported_attachment_urls_in_meta( $post_id, $imported );
565 +
566 + return [ 'success' => true ];
567 + }
568 +
569 + /**
570 + * Replace attachment urls with urls from the cloud.
571 + *
572 + * @param object $item
573 + * @param int $post_id
574 + * @return void
575 + */
576 + public function replace_attachment_urls_with_cloud_urls( $item, $post_id ) {
577 + if ( isset( $item->media->attachments ) ) {
578 + $imported = [];
579 +
580 + foreach ( $item->media->attachments as $attachment ) {
581 + $imported[ $attachment->file_name ] = $attachment;
582 + }
583 +
584 + $this->replace_imported_attachment_urls_in_content( $post_id, $imported );
585 + $this->replace_imported_attachment_urls_in_meta( $post_id, $imported );
586 + }
587 + }
588 +
589 + /**
590 + * Replaces the imported attachment urls in post content.
591 + *
592 + * @param int $post_id
593 + * @param array $imported
594 + * @return void
595 + */
596 + public function replace_imported_attachment_urls_in_content( $post_id, $imported ) {
597 + $content = get_post_field( 'post_content', $post_id );
598 + $content = MediaPathHelper::replace_imported_attachment_urls_in_string( $content, $imported );
599 +
600 + wp_update_post(
601 + [
602 + 'ID' => $post_id,
603 + 'post_content' => $content,
604 + ]
605 + );
606 + }
607 +
608 + /**
609 + * Replaces the imported attachment urls in post meta.
610 + *
611 + * @param int $post_id
612 + * @param array $imported
613 + * @return void
614 + */
615 + public function replace_imported_attachment_urls_in_meta( $post_id, $imported ) {
616 + $meta = get_post_meta( $post_id );
617 +
618 + foreach ( $meta as $key => $val ) {
619 + $val = maybe_unserialize( $val[0] );
620 +
621 + if ( is_object( $val ) || is_array( $val ) ) {
622 + $val = MediaPathHelper::replace_imported_attachment_urls_in_data( $val, $imported );
623 + } elseif ( JsonHelper::is_string_json( $val ) ) {
624 + $val = json_decode( $val );
625 + $val = MediaPathHelper::replace_imported_attachment_urls_in_data( $val, $imported );
626 + $val = wp_slash( json_encode( $val ) );
627 + } else {
628 + $val = MediaPathHelper::replace_imported_attachment_urls_in_string( $val, $imported );
629 + }
630 +
631 + update_post_meta( $post_id, $key, $val );
632 + }
633 + }
634 +
635 + /**
636 + * Get the server paths to all images associated with a post.
637 + *
638 + * @param object $post
639 + * @return array
640 + */
641 + public function get_post_image_paths( $post ) {
642 + $content_paths = MediaPathHelper::get_image_paths_from_string( $post->post_content );
643 + $meta = get_post_meta( $post->ID );
644 + $meta_paths = [];
645 +
646 + if ( $meta && count( $meta ) > 0 ) {
647 + $meta_paths = MediaPathHelper::get_image_paths_from_data( $meta );
648 + }
649 +
650 + return array_unique( array_merge( $content_paths, $meta_paths ) );
651 + }
652 +
653 + /**
654 + * Regenerate the asset cache for posts created with a builder.
655 + *
656 + * @param object $item
657 + * @return void
658 + */
659 + public function regenerate_builder_cache( $post_id, $item ) {
660 + $meta = (array) $item->data->meta;
661 +
662 + if ( isset( $meta['_fl_builder_data'] ) && class_exists( 'FLBuilderModel' ) ) {
663 + \FLBuilderModel::delete_all_asset_cache( $post_id );
664 + }
665 + if ( isset( $meta['_elementor_data'] ) && class_exists( 'Elementor\Plugin' ) ) {
666 + \Elementor\Plugin::$instance->files_manager->clear_cache();
667 + }
668 + }
669 +}