PluginProbe
Photo Engine (Media Organizer & Lightroom) / trunk
Photo Engine (Media Organizer & Lightroom) vtrunk
6.5.5 6.5.4 6.5.3 6.5.2 trunk 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.8.2 0.8.3 0.8.4 0.8.6 0.8.8 1.2.4 1.3.0 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 All 157 releases
wplr-sync / classes / rest.php

rest.php in Photo Engine (Media Organizer & Lightroom) trunk, at classes/rest.php

1,251 lines 41.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Meow_WPLR_Sync_Rest
4 {
5 private $core = null;
6 private $admin = null;
7 private $namespace = 'wplr-sync/v1';
8
9 public function __construct( $core, $admin ) {
10 if ( !current_user_can( 'upload_files' ) ) {
11 return;
12 }
13 $this->core = $core;
14 $this->admin = $admin;
15 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
16 }
17
18 function rest_api_init() {
19 try {
20 // SETTINGS
21 register_rest_route( $this->namespace, '/update_option', array(
22 'methods' => 'POST',
23 'permission_callback' => array( $this->core, 'can_access_settings' ),
24 'callback' => array( $this, 'rest_update_option' )
25 ) );
26 register_rest_route( $this->namespace, '/all_settings', array(
27 'methods' => 'GET',
28 'permission_callback' => array( $this->core, 'can_access_settings' ),
29 'callback' => array( $this, 'rest_all_settings' ),
30 ) );
31 register_rest_route( $this->namespace, '/generate_auth_token', array(
32 'methods' => 'POST',
33 'permission_callback' => array( $this->core, 'can_access_settings' ),
34 'callback' => array( $this, 'rest_generate_auth_token' ),
35 ) );
36 register_rest_route( $this->namespace, '/regenerate_user_token', array(
37 'methods' => 'POST',
38 'permission_callback' => array( $this->core, 'can_access_settings' ),
39 'callback' => array( $this, 'rest_regenerate_user_token' ),
40 ) );
41 register_rest_route( $this->namespace, '/entries', array(
42 'methods' => 'GET',
43 'permission_callback' => array( $this->core, 'can_access_settings' ),
44 'callback' => array( $this, 'rest_entries' ),
45 'args' => array(
46 'show' => array( 'required' => true, 'default' => 'unlinked' ),
47 )
48 ) );
49 register_rest_route( $this->namespace, '/wp_hierarchy', array(
50 'methods' => 'GET',
51 'permission_callback' => array( $this->core, 'can_access_features' ),
52 'callback' => array( $this, 'rest_wp_hierarchy' ),
53 ) );
54 register_rest_route( $this->namespace, '/lr_hierarchy', array(
55 'methods' => 'GET',
56 'permission_callback' => array( $this->core, 'can_access_features' ),
57 'callback' => array( $this, 'rest_lr_hierarchy' ),
58 ) );
59 register_rest_route( $this->namespace, '/all_media', array(
60 'methods' => 'GET',
61 'permission_callback' => array( $this->core, 'can_access_features' ),
62 'callback' => array( $this, 'rest_all_media' ),
63 'args' => array(
64 'limit' => array( 'required' => false, 'default' => 20 ),
65 'skip' => array( 'required' => false, 'default' => 0 ),
66 'orderBy' => array( 'required' => false, 'default' => 'id' ),
67 'order' => array( 'required' => false, 'default' => 'desc' ),
68 )
69 ) );
70 register_rest_route( $this->namespace, '/unassigned_entries', array(
71 'methods' => 'GET',
72 'permission_callback' => array( $this->core, 'can_access_features' ),
73 'callback' => array( $this, 'rest_unassigned_entries' ),
74 'args' => array(
75 'limit' => array( 'required' => false, 'default' => 20 ),
76 'skip' => array( 'required' => false, 'default' => 0 ),
77 'orderBy' => array( 'required' => false, 'default' => 'id' ),
78 'order' => array( 'required' => false, 'default' => 'desc' ),
79 )
80 ) );
81 register_rest_route( $this->namespace, '/folder_content', array(
82 'methods' => 'POST',
83 'permission_callback' => array( $this->core, 'can_access_features' ),
84 'callback' => array( $this, 'rest_folder_content' ),
85 ) );
86 register_rest_route( $this->namespace, '/gallery_content', array(
87 'methods' => 'GET',
88 'permission_callback' => array( $this->core, 'can_access_features' ),
89 'callback' => array( $this, 'rest_gallery_content' ),
90 'args' => array(
91 'collectionId' => array( 'required' => false, 'default' => null ),
92 'limit' => array( 'required' => false, 'default' => 20 ),
93 'skip' => array( 'required' => false, 'default' => 0 ),
94 'orderBy' => array( 'required' => false, 'default' => 'id' ),
95 'order' => array( 'required' => false, 'default' => 'desc' ),
96 )
97 ) );
98 register_rest_route( $this->namespace, '/delete_hierarchy', array(
99 'methods' => 'POST',
100 'permission_callback' => array( $this->core, 'can_access_settings' ),
101 'callback' => array( $this, 'rest_delete_hierarchy' ),
102 ) );
103 register_rest_route( $this->namespace, '/keywords_hierarchy', array(
104 'methods' => 'GET',
105 'permission_callback' => array( $this->core, 'can_access_settings' ),
106 'callback' => array( $this, 'rest_keywords_hierarchy' ),
107 ) );
108 register_rest_route( $this->namespace, '/delete_keywords_hierarchy', array(
109 'methods' => 'POST',
110 'permission_callback' => array( $this->core, 'can_access_settings' ),
111 'callback' => array( $this, 'rest_delete_keywords_hierarchy' ),
112 ) );
113
114 register_rest_route( $this->namespace, '/sync_info', array(
115 'methods' => 'POST',
116 'permission_callback' => array( $this->core, 'can_access_features' ),
117 'callback' => array( $this, 'rest_sync_info' )
118 ) );
119 register_rest_route( $this->namespace, '/link', array(
120 'methods' => 'POST',
121 'permission_callback' => array( $this->core, 'can_access_features' ),
122 'callback' => array( $this, 'rest_link' )
123 ) );
124 register_rest_route( $this->namespace, '/unlink', array(
125 'methods' => 'POST',
126 'permission_callback' => array( $this->core, 'can_access_features' ),
127 'callback' => array( $this, 'rest_unlink' )
128 ) );
129 register_rest_route( $this->namespace, '/extensions_query', array(
130 'methods' => 'POST',
131 'permission_callback' => array( $this->core, 'can_access_features' ),
132 'callback' => array( $this, 'rest_extensions_query' )
133 ) );
134 register_rest_route( $this->namespace, '/extensions_init', array(
135 'methods' => 'POST',
136 'permission_callback' => array( $this->core, 'can_access_features' ),
137 'callback' => array( $this, 'rest_extensions_init' )
138 ) );
139 register_rest_route( $this->namespace, '/extensions_reset', array(
140 'methods' => 'POST',
141 'permission_callback' => array( $this->core, 'can_access_features' ),
142 'callback' => array( $this, 'rest_extensions_reset' )
143 ) );
144 register_rest_route( $this->namespace, '/clean', array(
145 'methods' => 'POST',
146 'permission_callback' => array( $this->core, 'can_access_features' ),
147 'callback' => array( $this, 'rest_clean' )
148 ) );
149 register_rest_route( $this->namespace, '/repair', array(
150 'methods' => 'POST',
151 'permission_callback' => array( $this->core, 'can_access_features' ),
152 'callback' => array( $this, 'rest_repair' )
153 ) );
154 register_rest_route( $this->namespace, '/create_folder', array(
155 'methods' => 'POST',
156 'permission_callback' => array( $this->core, 'can_access_features' ),
157 'callback' => array( $this, 'rest_create_folder' )
158 ) );
159 register_rest_route( $this->namespace, '/create_gallery', array(
160 'methods' => 'POST',
161 'permission_callback' => array( $this->core, 'can_access_features' ),
162 'callback' => array( $this, 'rest_create_gallery' )
163 ) );
164 register_rest_route( $this->namespace, '/update_folder', array(
165 'methods' => 'POST',
166 'permission_callback' => array( $this->core, 'can_access_features' ),
167 'callback' => array( $this, 'rest_update_folder' )
168 ) );
169 register_rest_route( $this->namespace, '/update_gallery', array(
170 'methods' => 'POST',
171 'permission_callback' => array( $this->core, 'can_access_features' ),
172 'callback' => array( $this, 'rest_update_gallery' )
173 ) );
174 register_rest_route( $this->namespace, '/delete_folder', array(
175 'methods' => 'POST',
176 'permission_callback' => array( $this->core, 'can_access_features' ),
177 'callback' => array( $this, 'rest_delete_collection' )
178 ) );
179 register_rest_route( $this->namespace, '/delete_gallery', array(
180 'methods' => 'POST',
181 'permission_callback' => array( $this->core, 'can_access_features' ),
182 'callback' => array( $this, 'rest_delete_collection' )
183 ) );
184 register_rest_route( $this->namespace, '/move_collection', array(
185 'methods' => 'POST',
186 'permission_callback' => array( $this->core, 'can_access_features' ),
187 'callback' => array( $this, 'rest_move_collection' )
188 ) );
189 register_rest_route( $this->namespace, '/move_media', array(
190 'methods' => 'POST',
191 'permission_callback' => array( $this->core, 'can_access_features' ),
192 'callback' => array( $this, 'rest_move_media' )
193 ) );
194 register_rest_route( $this->namespace, '/copy_media', array(
195 'methods' => 'POST',
196 'permission_callback' => array( $this->core, 'can_access_features' ),
197 'callback' => array( $this, 'rest_copy_media' )
198 ) );
199 register_rest_route( $this->namespace, '/remove_media', array(
200 'methods' => 'POST',
201 'permission_callback' => array( $this->core, 'can_access_features' ),
202 'callback' => array( $this, 'rest_remove_media' )
203 ) );
204 register_rest_route( $this->namespace, '/update_media', array(
205 'methods' => 'POST',
206 'permission_callback' => array( $this->core, 'can_access_features' ),
207 'callback' => array( $this, 'rest_update_media' )
208 ) );
209 register_rest_route( $this->namespace, '/update_featured_image', array(
210 'methods' => 'POST',
211 'permission_callback' => array( $this->core, 'can_access_features' ),
212 'callback' => array( $this, 'rest_update_featured_image' )
213 ) );
214 register_rest_route( $this->namespace, '/reorder_media', array(
215 'methods' => 'POST',
216 'permission_callback' => array( $this->core, 'can_access_features' ),
217 'callback' => array( $this, 'rest_reorder_media' )
218 ) );
219 }
220 catch (Exception $e) {
221 var_dump($e);
222 }
223 }
224
225 function rest_all_settings() {
226 return new WP_REST_Response( [
227 'success' => true,
228 'data' => $this->admin->get_all_options()
229 ], 200 );
230 }
231
232 function rest_generate_auth_token() {
233 if ( !get_option( 'wplr_public_api', false ) ) {
234 return new WP_REST_Response( [
235 'success' => false,
236 'message' => 'The Public API is not enabled.'
237 ], 400 );
238 }
239 $token = $this->admin->generate_public_api_token();
240 $qr = $this->admin->get_public_api_qr( $token );
241 return new WP_REST_Response( [
242 'success' => true,
243 'data' => [
244 'wplr_auth_token' => $token,
245 'wplr_qr' => $qr
246 ]
247 ], 200 );
248 }
249
250 function rest_regenerate_user_token() {
251 $user_id = get_current_user_id();
252 if ( !$user_id ) {
253 return new WP_REST_Response( [
254 'success' => false,
255 'message' => 'No user is currently logged in.'
256 ], 400 );
257 }
258 try {
259 $token = $this->core->generate_auth_token( $user_id );
260 return new WP_REST_Response( [
261 'success' => true,
262 'data' => [
263 'wplr_user_token' => $token
264 ]
265 ], 200 );
266 }
267 catch ( Exception $e ) {
268 return new WP_REST_Response( [
269 'success' => false,
270 'message' => $e->getMessage()
271 ], 500 );
272 }
273 }
274
275 function rest_wp_hierarchy() {
276 $hierarchy = $this->core->get_hierarchy(null, 0, 'wp');
277 $hierarchy = $this->format_hierarchy( $hierarchy );
278 return new WP_REST_Response( [
279 'success' => true,
280 'data' => $hierarchy
281 ], 200 );
282 }
283
284 function rest_lr_hierarchy() {
285 $hierarchy = $this->core->get_hierarchy(null, 0, 'lr');
286 $hierarchy = $this->format_hierarchy( $hierarchy );
287 return new WP_REST_Response( [
288 'success' => true,
289 'data' => $hierarchy
290 ], 200 );
291 }
292
293 function rest_all_media($request) {
294 $limit = sanitize_text_field( $request->get_param('limit') );
295 $skip = sanitize_text_field( $request->get_param('skip') );
296 $orderBy = sanitize_text_field( $request->get_param('orderBy') );
297 $order = sanitize_text_field( $request->get_param('order') );
298 global $wpdb;
299 $total = (int)$wpdb->get_var( "SELECT COUNT(ID) FROM $wpdb->posts p
300 WHERE post_type='attachment' AND post_status='inherit'"
301 );
302 $orderSql = 'ORDER BY p.ID DESC ';
303 if ($orderBy === 'type') {
304 $orderSql = 'ORDER BY p.ID ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
305 }
306 $results = $wpdb->get_results(
307 $wpdb->prepare(
308 "SELECT p.ID, p.post_title, p.post_content as description, p.post_excerpt as caption, pm1.meta_value as alt, pm2.meta_value as path
309 FROM $wpdb->posts p
310 LEFT JOIN $wpdb->postmeta pm1 ON pm1.post_id = p.ID AND pm1.meta_key = '_wp_attachment_image_alt'
311 LEFT JOIN $wpdb->postmeta pm2 ON pm2.post_id = p.ID AND pm2.meta_key = '_wp_attached_file'
312 WHERE p.post_type='attachment'
313 AND p.post_status='inherit'
314 $orderSql
315 LIMIT %d, %d", $skip, $limit
316 ), ARRAY_A
317 );
318 $data = [];
319 if (count($results) > 0) {
320 foreach ($results as $record) {
321 $data[] = [
322 'ID' => $record['ID'],
323 'title' => $record['post_title'],
324 'description' => $record['description'],
325 'caption' => $record['caption'],
326 'alt' => $record['alt'],
327 'path' => $record['path'],
328 'thumbnail_url' => $this->getThumbnailUrl($record['ID'], 'medium')
329 ];
330 }
331 }
332 return new WP_REST_Response( [
333 'success' => true,
334 'data' => $data,
335 'total' => $total,
336 ], 200 );
337 }
338
339 function rest_unassigned_entries($request) {
340 $limit = sanitize_text_field( $request->get_param('limit') );
341 $skip = sanitize_text_field( $request->get_param('skip') );
342 $orderBy = sanitize_text_field( $request->get_param('orderBy') );
343 $order = sanitize_text_field( $request->get_param('order') );
344 $total = $this->count_unassigned_entries();
345 $results = $this->core->list_unassigned(true, $limit, $skip, $orderBy, $order);
346 $data = [];
347 if (count($results) > 0) {
348 foreach ($results as $obj_record) {
349 $record = (array) $obj_record;
350 $data[] = [
351 'ID' => $record['ID'],
352 'title' => $record['post_title'],
353 'description' => $record['post_content'],
354 'caption' => $record['post_excerpt'],
355 'alt' => $this->getThumbnailAlt($record['ID']),
356 'path' => $this->getThumbnailPath($record['ID']),
357 'thumbnail_url' => $this->getThumbnailUrl($record['ID'], 'medium')
358 ];
359 }
360 }
361 return new WP_REST_Response( [
362 'success' => true,
363 'data' => $data,
364 'total' => $total,
365 ], 200 );
366 }
367
368 function count_unassigned_entries() {
369 global $wpdb;
370 $table_name = $wpdb->prefix . "lrsync_relations";
371 $whereIsOriginal = "";
372 if ( $this->core->wpml_media_is_installed() ) {
373 global $sitepress;
374 $tbl_wpml = $wpdb->prefix . "icl_translations";
375 $language = $sitepress->get_default_language();
376 $whereIsOriginal = "AND p.ID IN (SELECT element_id FROM $tbl_wpml WHERE element_type = 'post_attachment' AND language_code = '$language') ";
377 }
378 return (int)$wpdb->get_var( "SELECT COUNT(ID) FROM $wpdb->posts p
379 WHERE post_status = 'inherit'
380 AND post_mime_type <> ''
381 AND p.ID NOT IN (SELECT wp_id FROM $table_name) " .
382 $whereIsOriginal
383 );
384 }
385
386 function rest_folder_content($request) {
387 $params = $request->get_json_params();
388 $folder_id = isset( $params['folder_id'] ) ? (int)$params['folder_id'] : null;
389 $source = isset( $params['source'] ) ? $params['source'] : null;
390 $collection_ids = $folder_id
391 ? $this->core->get_collections_from_folder($folder_id)
392 : $this->get_root_folders_by_source($source);
393 $data = [];
394 foreach ($collection_ids as $collection_id) {
395 $data[] = $this->core->get_collection($collection_id);
396 }
397 return new WP_REST_Response( [
398 'success' => true,
399 'data' => $data
400 ], 200 );
401 }
402
403 function rest_gallery_content( $request ) {
404 $collectionId = sanitize_text_field( $request->get_param('collectionId') );
405 $limit = sanitize_text_field( $request->get_param('limit') );
406 $skip = sanitize_text_field( $request->get_param('skip') );
407 $orderBy = sanitize_text_field( $request->get_param('orderBy') );
408 $order = sanitize_text_field( $request->get_param('order') );
409
410 // Get gallery based on wp_posts
411
412 $mediaIds = $this->core->get_media_from_collection($collectionId);
413 if (count($mediaIds) === 0) {
414 return new WP_REST_Response( [
415 'success' => true,
416 'data' => [],
417 'total' => 0,
418 ], 200 );
419 }
420 $mediaIdsPlaceholders = implode(', ', array_fill(0, count( $mediaIds ), '%s'));
421
422 global $wpdb;
423 $total = (int)$wpdb->get_var( $wpdb->prepare(
424 "SELECT COUNT(ID) FROM $wpdb->posts p
425 WHERE post_type='attachment'
426 AND post_status='inherit'
427 AND ID IN (" . $mediaIdsPlaceholders . ")", $mediaIds
428 ));
429 $orderSql = 'ORDER BY p.ID DESC ';
430 if ($orderBy === 'type') {
431 $orderSql = 'ORDER BY p.ID ' . ( $order === 'asc' ? 'ASC' : 'DESC' );
432 }
433 $results = $wpdb->get_results(
434 $wpdb->prepare(
435 "SELECT p.ID, p.post_title, p.post_content as description, p.post_excerpt as caption, pm1.meta_value as alt, pm2.meta_value as path
436 FROM $wpdb->posts p
437 LEFT JOIN $wpdb->postmeta pm1 ON pm1.post_id = p.ID AND pm1.meta_key = '_wp_attachment_image_alt'
438 LEFT JOIN $wpdb->postmeta pm2 ON pm2.post_id = p.ID AND pm2.meta_key = '_wp_attached_file'
439 WHERE post_type='attachment'
440 AND post_status='inherit'
441 AND ID IN (" . $mediaIdsPlaceholders . ")
442 $orderSql
443 LIMIT %d, %d", array_merge( $mediaIds, array( $skip, $limit ) )
444 ), ARRAY_A
445 );
446
447 $data = [];
448 if ( count( $results ) === 0 ) {
449 return new WP_REST_Response( [
450 'success' => true,
451 'data' => $data,
452 'total' => $total,
453 ], 200 );
454 }
455
456 // Prefer the order by clause if specified.
457 if ($orderBy === 'type') {
458 foreach ( $results as $record ) {
459 $data[] = [
460 'ID' => $record['ID'],
461 'title' => $record['post_title'],
462 'description' => $record['description'],
463 'caption' => $record['caption'],
464 'alt' => $record['alt'],
465 'path' => $record['path'],
466 'thumbnail_url' => $this->getThumbnailUrl( $record['ID'], 'medium' )
467 ];
468 }
469 return new WP_REST_Response( [
470 'success' => true,
471 'data' => $data,
472 'total' => $total,
473 ], 200 );
474 }
475
476 // We need to keep the same order as the WPLR DB, hence this two loops.
477 foreach ( $mediaIds as $mediaId ) {
478 foreach ( $results as $record ) {
479 if ( $record['ID'] === $mediaId ) {
480 $data[] = [
481 'ID' => $record['ID'],
482 'title' => $record['post_title'],
483 'description' => $record['description'],
484 'caption' => $record['caption'],
485 'alt' => $record['alt'],
486 'path' => $record['path'],
487 'thumbnail_url' => $this->getThumbnailUrl( $record['ID'], 'medium' )
488 ];
489 break;
490 }
491 }
492 }
493 return new WP_REST_Response( [
494 'success' => true,
495 'data' => $data,
496 'total' => $total,
497 ], 200 );
498 }
499
500 function format_hierarchy( $hierarchy ) {
501 global $wpdb;
502 $tbl_r = $wpdb->prefix . 'lrsync_relations';
503 foreach ( $hierarchy as $key => $c ) {
504 $is_folder = $c['type'] === 'folder';
505 $is_collection = $c['type'] === 'collection';
506 $hierarchy[$key]['is_folder'] = $is_folder;
507 $hierarchy[$key]['is_collection'] = $is_collection;
508 $hierarchy[$key]['featured_image_id'] = $c['featured_id'] ?? null;
509 $hierarchy[$key]['featured_image'] = $c['featured_id'] ? $this->getThumbnailUrl($c['featured_id'], 'thumbnail') : null;
510 unset($hierarchy[$key]['featured_id']);
511 if ( $is_folder ) {
512 $hierarchy[$key]['children'] = $this->format_hierarchy( $c['children'] );
513 }
514 if ( $is_collection ) {
515 $children = [];
516 // In fact, we are only interested in the count here, so let's avoid a heavy request.
517 $children = array_fill(0, $hierarchy[$key]['count'], '');
518 $hierarchy[$key]['children'] = $children;
519 }
520 }
521 return $hierarchy;
522 }
523
524 function rest_delete_hierarchy($request) {
525 $params = $request->get_json_params();
526 $delete_collection = isset( $params['delete_collection'] ) ? $params['delete_collection'] : null;
527
528 if (!$delete_collection) {
529 return new WP_REST_Response([
530 'success' => false,
531 'message' => 'delete_collection is missing.',
532 ], 400 );
533 }
534 $data = $this->core->delete_collection( $delete_collection );
535 return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
536 }
537
538 function rest_keywords_hierarchy() {
539 $hierarchy = $this->core->get_keywords_hierarchy();
540 return new WP_REST_Response( [
541 'success' => true,
542 'data' => $hierarchy
543 ], 200 );
544 }
545
546 function rest_delete_keywords_hierarchy($request) {
547 $params = $request->get_json_params();
548 $delete_keyword = isset( $params['delete_keyword'] ) ? $params['delete_keyword'] : null;
549
550 if (!$delete_keyword) {
551 return new WP_REST_Response([
552 'success' => false,
553 'message' => 'delete_keyword is missing.',
554 ], 400 );
555 }
556 $data = $this->core->delete_keyword( $delete_keyword );
557 return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
558 }
559
560 function rest_entries( $request ) {
561 $show = sanitize_text_field( $request->get_param( 'show' ) );
562 if ( empty( $show ) ) {
563 return new WP_REST_Response( [ 'success' => false, 'message' => 'Missing show parameter.' ], 400 );
564 }
565 $entries = [];
566 if ( $show === 'duplicates' ) {
567 $entries = $this->core->list_duplicates();
568 foreach ( $entries as $entry ) {
569 $wpids = explode( ',', $entry->wpids );
570 $details = [];
571 foreach ($wpids as $wpid) {
572 $details[] = [
573 'thumbnail_url' => $this->getThumbnailUrl( $wpid, 'thumbnail' ),
574 'ID' => $wpid
575 ];
576 }
577 $entry->details = $details;
578 }
579 return new WP_REST_Response( [ 'success' => true, 'data' => $entries ], 200 );
580 }
581 elseif ( $show === 'ignored' ) {
582 $entries = $this->core->list_ignored();
583 }
584 else {
585 $entries = $this->core->list_unlinks( true );
586 }
587 foreach ( $entries as $entry ) {
588 $entry->thumbnail_url = $this->getThumbnailUrl( $entry->ID, 'thumbnail' );
589 }
590 return new WP_REST_Response( [ 'success' => true, 'data' => $entries ], 200 );
591 }
592
593 function rest_sync_info( $request ) {
594 $params = $request->get_json_params();
595 $wpIds = isset( $params['wpIds'] ) ? (array)$params['wpIds'] : null;
596 $wpId = isset( $params['wpId'] ) ? (int)$params['wpId'] : null;
597 $data = array();
598 if ( !empty( $wpIds ) ) {
599 foreach ( $wpIds as $wpId ) {
600 $entry = $this->core->get_sync_info( $wpId );
601 array_push( $data, $entry );
602 }
603 }
604 else if ( !empty( $wpId ) ) {
605 $data = $this->core->get_sync_info( $wpId );
606 }
607 return new WP_REST_Response( [ 'success' => true, 'data' => $data ], 200 );
608 }
609
610 function rest_update_option( $request ) {
611 $params = $request->get_json_params();
612 try {
613 $name = $params['name'];
614 $options = $this->admin->list_options();
615 if ( !array_key_exists( $name, $options ) ) {
616 return new WP_REST_Response([ 'success' => false, 'message' => 'This option does not exist.' ], 200 );
617 }
618 $value = is_bool( $params['value'] ) ? ( $params['value'] ? '1' : '' ) : $params['value'];
619 $success = update_option( $name, $value );
620 if ( $success ) {
621 $res = $this->validate_updated_option( $name );
622 $result = $res['result'];
623 $message = $res['message'];
624 return new WP_REST_Response([ 'success' => $result, 'message' => $message ], 200 );
625 }
626 return new WP_REST_Response([ 'success' => false, 'message' => "Could not update option." ], 200 );
627 }
628 catch (Exception $e) {
629 return new WP_REST_Response([
630 'success' => false,
631 'message' => $e->getMessage(),
632 ], 500 );
633 }
634 }
635
636 function validate_updated_option( $option_name ) {
637 $wplr_library_show_hierarchy = get_option( 'wplr_library_show_hierarchy', 'none' );
638 $wplr_public_api = get_option( 'wplr_public_api', false );
639 if ( $wplr_library_show_hierarchy === '' )
640 update_option( 'wplr_library_show_hierarchy', 'none' );
641 if ( $wplr_public_api === '' )
642 update_option( 'wplr_public_api', false );
643 if (!get_option( 'wplr_public_api', false ) && get_transient( 'wplr_auth_token' ) !== false) {
644 delete_transient( 'wplr_auth_token' );
645 }
646 return $this->createValidationResult();
647 }
648
649 function createValidationResult( $result = true, $message = null) {
650 $message = $message ? $message : __( 'OK', 'wplr-sync' );
651 return ['result' => $result, 'message' => $message];
652 }
653
654 function rest_unlink($request) {
655 $params = $request->get_json_params();
656 $lr_id = isset( $params['lrId'] ) ? (int)$params['lrId'] : null;
657 $wp_id = isset( $params['wpId'] ) ? (int)$params['wpId'] : null;
658 $afterDelete = isset( $params['afterDelete'] ) ? (int)$params['afterDelete'] : false;
659
660 list($result, $message, $code) = $this->validate_link_unlink($lr_id, $wp_id);
661
662 if (!$result) {
663 return new WP_REST_Response([
664 'success' => $result,
665 'message' => $message,
666 ], $code );
667 }
668
669 $result = $this->core->unlink_media( $lr_id, $wp_id );
670
671 if ($result && $afterDelete) {
672 wp_delete_attachment( $wp_id );
673 }
674
675 return new WP_REST_Response([
676 'success' => $result,
677 'data' => !$result ? null : [
678 'wp_id' => $wp_id,
679 'lr_id' => null
680 ],
681 'message' => $result ? 'Success.' : $this->core->get_error(),
682 ], 200 );
683 }
684
685 function rest_link($request) {
686 $params = $request->get_json_params();
687 $lr_id = isset( $params['lrId'] ) ? (int)$params['lrId'] : null;
688 $wp_id = isset( $params['wpId'] ) ? (int)$params['wpId'] : null;
689
690 list($result, $message, $code) = $this->validate_link_unlink($lr_id, $wp_id);
691
692 if (!$result) {
693 return new WP_REST_Response([
694 'success' => $result,
695 'message' => $message,
696 ], $code );
697 }
698
699 $sync = $this->core->link_media( $lr_id, $wp_id );
700 $result = (bool)$sync;
701 return new WP_REST_Response([
702 'success' => $result,
703 'data' => !$result ? null : [
704 'wp_id' => $wp_id,
705 'lr_id' => $sync->lr_id,
706 'lastsync' => $sync->lastsync
707 ],
708 'message' => $result ? 'Success.' : $this->core->get_error(),
709 ], 200 );
710 }
711
712 function rest_extensions_query($request) {
713 $params = $request->get_json_params();
714 $task = isset( $params['task'] ) ? (array)$params['task'] : null;
715 if (!$task)
716 return new WP_REST_Response([
717 'success' => false,
718 'data' => 'The parameter task was missing.'
719 ], 500 );
720 try {
721 if ( $task['action'] == 'add_collection' ) {
722 if ( $task['is_folder'] )
723 do_action( 'wplr_create_folder', (int)$task['wp_col_id'], (int)$task['wp_folder_id'], array( 'name' => $task['name'] ) );
724 else
725 do_action( 'wplr_create_collection', (int)$task['wp_col_id'], (int)$task['wp_folder_id'], array( 'name' => $task['name'] ) );
726 }
727 else if ( $task['action'] == 'remove_collection' ) {
728 if ( $task['is_folder'] )
729 do_action( 'wplr_remove_folder', (int)$task['wp_col_id'] );
730 else
731 do_action( 'wplr_remove_collection', (int)$task['wp_col_id'] );
732 }
733 else if ( $task['action'] == 'add_media' )
734 do_action( 'wplr_add_media_to_collection', (int)$task['wp_id'], (int)$task['wp_col_id'] );
735 else if ( $task['action'] == 'remove_media' )
736 do_action( 'wplr_remove_media_from_collection', (int)$task['wp_id'], (int)$task['wp_col_id'] );
737 else if ( $task['action'] == 'add_tag' ) {
738 $pTagParent = $this->core->get_meta( 'tag_parent', (int)$task['id'] );
739 do_action( 'wplr_add_tag', (int)$task['id'], $task['name'], $pTagParent );
740 }
741 else if ( $task['action'] == 'remove_tag' )
742 do_action( 'wplr_remove_tag', (int)$task['id'] );
743 else if ( $task['action'] == 'update_tag' )
744 do_action( 'wplr_update_tag', (int)$task['id'], $task['name'], (int)$task['parent'] );
745 else if ( $task['action'] == 'add_media_tag' )
746 do_action( 'wplr_add_media_tag', (int)$task['wp_id'], (int)$task['id'] );
747 else if ( $task['action'] == 'remove_media_tag' )
748 do_action( 'wplr_remove_media_tag', (int)$task['wp_id'], (int)$task['id'] );
749
750 return new WP_REST_Response([
751 'success' => true,
752 ], 200 );
753 }
754 catch ( Exception $e ) {
755 error_log( print_r( $e, true ) );
756 return new WP_REST_Response([
757 'success' => false,
758 'message' => 'An exception was caught and written in the PHP error logs.',
759 ], 500 );
760 }
761 }
762
763 function rest_extensions_init($request) {
764 global $wpdb;
765 $params = $request->get_json_params();
766 $isRemoval = isset( $params['is_removal'] ) && $params['is_removal'] == 1;
767 $tbl_m = $wpdb->prefix . 'lrsync';
768 $tbl_r = $wpdb->prefix . 'lrsync_relations';
769 $tbl_t = $wpdb->prefix . 'lrsync_meta';
770
771 $tasks = array();
772
773 // Tags
774 $tags = $wpdb->get_results( $wpdb->prepare( "SELECT id as id, value as name FROM $tbl_t WHERE name = %s", 'tag_name' ), ARRAY_A );
775 foreach ( $tags as $tag )
776 array_push( $tasks, array_merge( array( 'action' => $isRemoval ? 'remove_tag' : 'add_tag' ), $tag ) );
777
778 // Tag's Parents
779 if ( !$isRemoval ) {
780 $tags = $wpdb->get_results( $wpdb->prepare( "SELECT m1.id as id, m1.value as name, m2.value as parent
781 FROM $tbl_t m1
782 JOIN $tbl_t m2 ON m2.id = m1.id AND m2.name = %s
783 WHERE m1.name = %s", 'tag_parent', 'tag_name' ), ARRAY_A );
784
785 foreach ( $tags as $tag )
786 array_push( $tasks, array_merge( array( 'action' => 'update_tag' ), $tag ) );
787 }
788
789 // Collections
790 $collections = $this->core->read_collections_recursively( null, array(), $isRemoval );
791 $tasks = array_merge( $tasks, $collections );
792
793 // Photos
794 foreach ( $collections as $c ) {
795 if ( !$c['is_folder'] ) {
796 $photos = $wpdb->get_results( $wpdb->prepare( "SELECT wp_id, wp_col_id, sort FROM $tbl_r WHERE wp_col_id = %d ORDER BY sort", $c['wp_col_id'] ), ARRAY_A );
797 foreach ( $photos as $p )
798 array_push( $tasks, array_merge( array( 'action' => $isRemoval ? 'remove_media' : 'add_media' ), $p ) );
799 }
800 };
801
802 // Media Tags
803 $tags = $wpdb->get_results( $wpdb->prepare( "
804 SELECT id as wp_id, value as id
805 FROM $tbl_t
806 WHERE name = %s", 'media_tag' ), ARRAY_A );
807 foreach ( $tags as $tag )
808 array_push( $tasks, array_merge( array( 'action' => $isRemoval ? 'remove_media_tag' : 'add_media_tag' ), $tag ) );
809
810 return new WP_REST_Response([
811 'success' => true,
812 'data' => $isRemoval ? $tasks : array_reverse( $tasks )
813 ], 200 );
814 }
815
816 function rest_extensions_reset() {
817 try {
818 do_action( 'wplr_reset' );
819 return new WP_REST_Response([
820 'success' => true,
821 ], 200 );
822 }
823 catch ( Exception $e ) {
824 error_log( print_r( $e, true ) );
825 return new WP_REST_Response([
826 'success' => false,
827 'data' => 'An exception was caught and written in the PHP error logs.'
828 ], 500 );
829 }
830 }
831
832 function rest_clean() {
833 global $wpdb;
834 $tbl_m = $wpdb->prefix . 'lrsync';
835 $tbl_r = $wpdb->prefix . 'lrsync_relations';
836 $tbl_c = $wpdb->prefix . 'lrsync_collections';
837 $tbl_mt = $wpdb->prefix . 'lrsync_meta';
838 try {
839 do_action( 'wplr_clean' );
840 $wpdb->query( "DELETE FROM $tbl_m WHERE wp_id NOT IN (SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment')" );
841 $wpdb->query( "DELETE FROM $tbl_r WHERE wp_id NOT IN (SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment')" );
842 $wpdb->query( "DELETE FROM $tbl_r WHERE wp_col_id NOT IN (SELECT wp_col_id FROM $tbl_c)" );
843 $wpdb->query( "DELETE FROM $tbl_mt WHERE name = 'media_tag' AND id NOT IN (SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment')" );
844 meow_wplrsync_activate();
845 return new WP_REST_Response([
846 'success' => true,
847 ], 200 );
848 }
849 catch ( Exception $e ) {
850 error_log( print_r( $e, true ) );
851 return new WP_REST_Response([
852 'success' => false,
853 'data' => 'An exception was caught and written in the PHP error logs.'
854 ], 500 );
855 }
856 }
857
858 function rest_repair() {
859 $messages = $this->core->check_db();
860
861 if ( empty( $messages ) ) {
862 $messages[] = '🟢 No issues found.';
863 }
864
865 return new WP_REST_Response([
866 'success' => true,
867 'data' => $messages
868 ], 200 );
869 }
870
871 function rest_create_folder($request) {
872 $params = $request->get_json_params();
873 $name = isset( $params['name'] ) ? $params['name'] : '';
874 $parentFolderId = isset( $params['parent_folder_id'] ) ? $params['parent_folder_id'] : null;
875 $source = isset( $params['source'] ) ? $params['source'] : '';
876
877 if (!$name || !$source) {
878 return new WP_REST_Response([
879 'success' => false,
880 'message' => 'The create folder parameters are missing.',
881 ], 400 );
882 }
883 if (!$this->core->create_collection('folder', $name, $parentFolderId, $source)) {
884 return new WP_REST_Response([
885 'success' => false,
886 'message' => 'Failed to create a new folder.',
887 ], 400 );
888 }
889
890 return new WP_REST_Response([
891 'success' => true,
892 ], 200 );
893 }
894
895 function rest_create_gallery($request) {
896 $params = $request->get_json_params();
897 $name = isset( $params['name'] ) ? $params['name'] : '';
898 $parentFolderId = isset( $params['parent_folder_id'] ) ? $params['parent_folder_id'] : null;
899 $source = isset( $params['source'] ) ? $params['source'] : '';
900
901 if (!$name || !$source) {
902 return new WP_REST_Response([
903 'success' => false,
904 'message' => 'The create gallery parameters are missing.',
905 ], 400 );
906 }
907 if (!$this->core->create_collection('collection', $name, $parentFolderId, $source)) {
908 return new WP_REST_Response([
909 'success' => false,
910 'message' => 'Failed to create a new gallery.',
911 ], 400 );
912 }
913
914 return new WP_REST_Response([
915 'success' => true,
916 ], 200 );
917 }
918
919 function rest_update_folder($request) {
920 $params = $request->get_json_params();
921 $wp_col_id = isset( $params['id'] ) ? $params['id'] : '';
922 $name = isset( $params['name'] ) ? $params['name'] : '';
923 $slug = isset( $params['slug'] ) ? $params['slug'] : '';
924
925 if ( !$wp_col_id || !$name ) {
926 return new WP_REST_Response([
927 'success' => false,
928 'message' => 'The update folder parameters are missing.',
929 ], 400 );
930 }
931
932 try {
933 $this->core->update_collection( $wp_col_id, $name, $slug );
934 return new WP_REST_Response([
935 'success' => true,
936 ], 200 );
937 }
938 catch (Exception $e) {
939 return new WP_REST_Response([
940 'success' => false,
941 'message' => $e->getMessage(),
942 ], 500 );
943 }
944 }
945
946 function rest_update_gallery($request) {
947 $params = $request->get_json_params();
948 $wp_col_id = isset( $params['id'] ) ? $params['id'] : '';
949 $name = isset( $params['name'] ) ? $params['name'] : '';
950 $slug = isset( $params['slug'] ) ? $params['slug'] : '';
951
952 if (!$wp_col_id || !$name) {
953 return new WP_REST_Response([
954 'success' => false,
955 'message' => 'The update gallery parameters are missing.',
956 ], 400 );
957 }
958
959 try {
960 $this->core->update_collection( $wp_col_id, $name, $slug );
961 return new WP_REST_Response([
962 'success' => true,
963 ], 200 );
964 }
965 catch (Exception $e) {
966 return new WP_REST_Response([
967 'success' => false,
968 'message' => $e->getMessage(),
969 ], 500 );
970 }
971 }
972
973 function rest_delete_collection($request) {
974 $params = $request->get_json_params();
975 $wpColId = isset( $params['id'] ) ? (int)$params['id'] : '';
976
977 if (!$wpColId) {
978 return new WP_REST_Response([
979 'success' => false,
980 'message' => 'The folder id or the gallery id to delete is missing.',
981 ], 400 );
982 }
983 if (!$this->core->delete_collection($wpColId)) {
984 return new WP_REST_Response([
985 'success' => false,
986 'message' => 'Failed to delete the folder/gallery.',
987 ], 400 );
988 }
989
990 return new WP_REST_Response([
991 'success' => true,
992 ], 200 );
993 }
994
995 function rest_move_collection($request) {
996 $params = $request->get_json_params();
997 $wp_col_ids = isset( $params['ids'] ) ? $params['ids'] : '';
998 $parent_folder_id = (isset( $params['parent_id'] ) || is_null( $params['parent_id'] )) ? $params['parent_id'] : '';
999 if (!count($wp_col_ids) || $parent_folder_id === '') {
1000 return new WP_REST_Response([
1001 'success' => false,
1002 'message' => 'The id to move or parent id is missing.',
1003 ], 400 );
1004 }
1005 try {
1006 foreach ($wp_col_ids as $wp_col_id) {
1007 $this->core->move_collection($wp_col_id, $parent_folder_id);
1008 }
1009 return new WP_REST_Response([
1010 'success' => true,
1011 ], 200 );
1012 }
1013 catch (Exception $e) {
1014 return new WP_REST_Response([
1015 'success' => false,
1016 'message' => $e->getMessage(),
1017 ], 500 );
1018 }
1019 }
1020
1021 function rest_move_media($request) {
1022 $params = $request->get_json_params();
1023 $wp_ids = isset( $params['ids'] ) ? $params['ids'] : '';
1024 $new_wp_col_id = isset( $params['new_col_id'] ) ? $params['new_col_id'] : '';
1025 $previous_wp_col_id = isset( $params['current_col_id'] ) ? $params['current_col_id'] : '';
1026 if (!count($wp_ids) || !$new_wp_col_id) {
1027 return new WP_REST_Response([
1028 'success' => false,
1029 'message' => 'The id to move, new collection id, or current collection id is missing.',
1030 ], 400 );
1031 }
1032 try {
1033 foreach ($wp_ids as $wp_id) {
1034 if ($this->core->add_media_to_collection($wp_id, $new_wp_col_id) === false) {
1035 throw new Exception($this->core->get_error());
1036 }
1037 if ($previous_wp_col_id) {
1038 $this->core->remove_media_from_collection($wp_id, $previous_wp_col_id);
1039 }
1040 }
1041 return new WP_REST_Response([
1042 'success' => true,
1043 ], 200 );
1044 }
1045 catch (Exception $e) {
1046 return new WP_REST_Response([
1047 'success' => false,
1048 'message' => $e->getMessage(),
1049 ], 500 );
1050 }
1051 }
1052
1053 function rest_copy_media($request) {
1054 $params = $request->get_json_params();
1055 $wp_ids = isset( $params['ids'] ) ? $params['ids'] : '';
1056 $new_wp_col_id = isset( $params['new_col_id'] ) ? $params['new_col_id'] : '';
1057 if (!count($wp_ids) || $new_wp_col_id === '') {
1058 return new WP_REST_Response([
1059 'success' => false,
1060 'message' => 'The media id or a collection id is missing.',
1061 ], 400 );
1062 }
1063 try {
1064 foreach ($wp_ids as $wp_id) {
1065 if ($this->core->add_media_to_collection($wp_id, $new_wp_col_id) === false) {
1066 throw new Exception($this->core->get_error());
1067 }
1068 }
1069 return new WP_REST_Response([
1070 'success' => true,
1071 ], 200 );
1072 }
1073 catch (Exception $e) {
1074 return new WP_REST_Response([
1075 'success' => false,
1076 'message' => $e->getMessage(),
1077 ], 500 );
1078 }
1079 }
1080
1081 function rest_remove_media($request) {
1082 $params = $request->get_json_params();
1083 $wp_ids = isset( $params['ids'] ) ? $params['ids'] : '';
1084 $previous_wp_col_id = isset( $params['current_col_id'] ) ? $params['current_col_id'] : '';
1085 if (!count($wp_ids) || !$previous_wp_col_id) {
1086 return new WP_REST_Response([
1087 'success' => false,
1088 'message' => 'The id to move or current collection id is missing.',
1089 ], 400 );
1090 }
1091 try {
1092 foreach ($wp_ids as $wp_id) {
1093 $this->core->remove_media_from_collection($wp_id, $previous_wp_col_id);
1094 }
1095 return new WP_REST_Response([
1096 'success' => true,
1097 ], 200 );
1098 }
1099 catch (Exception $e) {
1100 return new WP_REST_Response([
1101 'success' => false,
1102 'message' => $e->getMessage(),
1103 ], 500 );
1104 }
1105 }
1106
1107 function rest_update_media($request) {
1108 $params = $request->get_json_params();
1109 $wp_id = isset( $params['id'] ) ? $params['id'] : '';
1110 $title = isset( $params['title'] ) ? $params['title'] : '';
1111 $description = isset( $params['description'] ) ? $params['description'] : '';
1112 $caption = isset( $params['caption'] ) ? $params['caption'] : '';
1113 $alt = isset( $params['alt'] ) ? $params['alt'] : '';
1114 if (!$wp_id) {
1115 return new WP_REST_Response([
1116 'success' => false,
1117 'message' => 'The id to move or current collection id is missing.',
1118 ], 400 );
1119 }
1120 try {
1121 $post = [
1122 'ID' => $wp_id,
1123 'post_title' => $title,
1124 'post_content' => $description,
1125 'post_excerpt' => $caption
1126 ];
1127 $result = wp_update_post( $post, true );
1128 if ( is_wp_error( $result ) ) {
1129 throw new Exception($result->get_error_message());
1130 }
1131 update_post_meta( $wp_id, '_wp_attachment_image_alt', $alt );
1132
1133 return new WP_REST_Response([
1134 'success' => true,
1135 ], 200 );
1136 }
1137 catch (Exception $e) {
1138 return new WP_REST_Response([
1139 'success' => false,
1140 'message' => $e->getMessage(),
1141 ], 500 );
1142 }
1143 }
1144
1145 public function rest_update_featured_image($request) {
1146 $params = $request->get_json_params();
1147 $collection_id = isset( $params['collection_id'] ) ? $params['collection_id'] : '';
1148 $featured_image_id = isset( $params['featured_image_id'] ) ? $params['featured_image_id'] : '';
1149 if (!$collection_id || !$featured_image_id ) {
1150 return new WP_REST_Response([
1151 'success' => false,
1152 'message' => 'The featured image id or current collection id is missing.',
1153 ], 400 );
1154 }
1155 try {
1156 $this->core->set_featured_image($collection_id, $featured_image_id);
1157
1158 return new WP_REST_Response([
1159 'success' => true,
1160 ], 200 );
1161 }
1162 catch (Exception $e) {
1163 return new WP_REST_Response([
1164 'success' => false,
1165 'message' => $e->getMessage(),
1166 ], 500 );
1167 }
1168 }
1169
1170 public function rest_reorder_media($request) {
1171 $params = $request->get_json_params();
1172 $collection_id = isset( $params['collection_id'] ) ? $params['collection_id'] : '';
1173 $media_ids = isset( $params['media_ids'] ) ? $params['media_ids'] : [];
1174 if (!$collection_id || !is_array($media_ids) || count($media_ids) === 0) {
1175 return new WP_REST_Response([
1176 'success' => false,
1177 'message' => 'The collection id or media ids are missing.',
1178 ], 400 );
1179 }
1180 try {
1181 global $wpdb;
1182 $tbl_r = $wpdb->prefix . 'lrsync_relations';
1183
1184 // Update the sort order for each media in the collection
1185 foreach ($media_ids as $index => $media_id) {
1186 $wpdb->update(
1187 $tbl_r,
1188 array( 'sort' => $index ),
1189 array( 'wp_col_id' => $collection_id, 'wp_id' => $media_id ),
1190 array( '%d' ),
1191 array( '%d', '%d' )
1192 );
1193 }
1194
1195 return new WP_REST_Response([
1196 'success' => true,
1197 ], 200 );
1198 }
1199 catch (Exception $e) {
1200 return new WP_REST_Response([
1201 'success' => false,
1202 'message' => $e->getMessage(),
1203 ], 500 );
1204 }
1205 }
1206
1207 /**
1208 * Private Methods
1209 */
1210 private function validate_link_unlink($lr_id, $wp_id)
1211 {
1212 if ( !current_user_can('upload_files') ) {
1213 return [ false, 'You do not have the roles to perform this action.', 403 ];
1214 }
1215 if ( $lr_id === '' || $lr_id === null || $wp_id === '' || $wp_id === null ) {
1216 return [ false, 'Some information is missing.', 422 ];
1217 }
1218 return [ true, null, null ];
1219 }
1220
1221 private function getThumbnailUrl($id, $size)
1222 {
1223 $attachment_src = wp_get_attachment_image_src( $id, $size );
1224 return empty( $attachment_src ) ? null : $attachment_src[0];
1225 }
1226
1227 private function getThumbnailAlt($id)
1228 {
1229 return get_post_meta( $id, '_wp_attachment_image_alt', true );
1230 }
1231
1232 private function getThumbnailPath($id)
1233 {
1234 return get_post_meta( $id, '_wp_attached_file', true );
1235 }
1236
1237 /**
1238 * Get the folders which have no wp_folder_id in the specific source.
1239 *
1240 * @param string $source
1241 * @return array
1242 */
1243 private function get_root_folders_by_source( $source ) {
1244 global $wpdb;
1245 $tbl_c = $wpdb->prefix . 'lrsync_collections';
1246 $collections = $wpdb->get_col( $wpdb->prepare( "SELECT wp_col_id FROM $tbl_c
1247 WHERE wp_folder_id IS NULL AND source = %s ORDER BY name, lr_col_id", $source ) );
1248 return $collections;
1249 }
1250 }
1251