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 / core.php

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

2,463 lines 79.2 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_Core {
4 private $error;
5 public $admin = null;
6 public $is_rest = false;
7 public $is_cli = false;
8 public $site_url = null;
9
10 public $cached_collections = null;
11
12 public function __construct() {
13 $this->site_url = get_site_url();
14 $this->is_rest = MeowKit_WPLR_Helpers::is_rest();
15 $this->is_cli = defined( 'WP_CLI' ) && WP_CLI;
16 add_action( 'delete_attachment', array( $this, 'delete_attachment' ) );
17 add_filter( 'manage_media_columns', array( $this, 'manage_media_columns' ) );
18 add_filter( 'shortcode_atts_gallery', array( $this, 'gallery_images_shortcode' ), 10, 3 );
19 add_filter( 'shortcode_atts_collection', array( $this, 'collection_images_shortcode' ), 10, 3 );
20 //add_filter( 'foogallery_shortcode_atts', array( $this, 'foogallery_shortcode' ), 10, 1 );
21 add_action( 'manage_media_custom_column', array( $this, 'manage_media_custom_column' ), 10, 2 );
22 add_action( 'admin_head', array( $this, 'admin_head' ), 10, 2 );
23 add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ) );
24 add_action( 'init', array( $this, 'init' ) );
25 add_action( 'profile_update', array( $this, 'profile_update' ) );
26 }
27
28 public function get_version() {
29 return WPLR_SYNC_VERSION;
30 }
31
32 public function get_error() {
33 if ( $this->error )
34 return $this->error;
35 else
36 return __( 'Unknown error.', 'wplr-sync' );
37 }
38
39 /*****************************************************************************
40 WP GALLERY: FOLDERS, COLLECTIONS AND KEYWORDS
41 *****************************************************************************/
42
43 // function foogallery_shortcode( $atts ) {
44 // $ids = $this->gallery_images( array(), $atts );
45 // if ( !empty( $ids ) && count( $ids ) > 0 ) {
46 // $atts['ids'] = $ids;
47 // }
48 // return $atts;
49 // }
50
51 function collection_images_shortcode( $result, $defaults, $atts ) {
52 $thumnails = $this->collection_images( array(), $atts );
53
54 $result['wplr-thumbnails'] = $thumnails;
55 return $result;
56 }
57
58 /**
59 * We receive an id from $atts['wplr-folder']
60 * from which we get all the collections, we ignore sub-folders
61 * for each collection we return the first image, the collection id and name
62 */
63 function collection_images( $ids, $atts ){
64 $ids = empty( $ids ) ? array() : $ids;
65 $inner_folders = array();
66
67 if ( !array_key_exists( 'wplr-folder', $atts ) ) { return $ids; }
68
69 $folder = $atts['wplr-folder'];
70 $collections = array();
71
72
73
74 if ( !empty( $folder ) ) {
75 $folder_collections = $this->get_collections_from_folder( $folder );
76 foreach ( $folder_collections as $collection ) {
77 $collections[] = $this->create_collection_array( $collection );
78 }
79
80 if ( array_key_exists( 'wplr-recursive', $atts ) && $atts['wplr-recursive'] == 'true' ) {
81 $inner_folders = $this->get_folders_from_folder( $folder );
82 foreach ( $inner_folders as $inner_folder ) {
83 $inner_folder_collections = $this->get_collections_from_folder( $inner_folder );
84 foreach ( $inner_folder_collections as $collection ) {
85 $collections[] = $this->create_collection_array( $collection );
86 }
87 }
88 }
89 }
90
91 return $collections;
92 }
93
94 private function create_collection_array( $collection ) {
95 $std_collection = $this->get_collection( $collection );
96 return array(
97 'id' => $std_collection->wp_col_id,
98 'collection' => $std_collection,
99 'thumbnail' => $std_collection->featured_id,
100 );
101 }
102
103 function gallery_images_shortcode( $result, $defaults, $atts ) {
104 $ids = $this->gallery_images( array(), $atts );
105 if ( !empty( $ids ) && count( $ids ) > 0 ) {
106 $result['include'] = $ids;
107 $result['id'] = null;
108 $result['order'] = '';
109 $result['orderby'] = 'post__in';
110 foreach ( $atts as $key => $value ) {
111 $result[$key] = $value;
112 }
113 }
114 return $result;
115 }
116
117 function gallery_images( $ids, $attrs ) {
118 $ids = empty( $ids ) ? array() : $ids;
119 $addedIds = array();
120
121 if ( !empty( $attrs['wplr-folder'] ) ) {
122 $newIds = $this->get_collections_from_folder( $attrs['wplr-folder'] );
123 $attrs['wplr-collection'] = implode( ',', $newIds );
124 }
125 if ( !empty( $attrs['wplr-collection'] ) ) {
126 $collections = explode( ',', $attrs['wplr-collection'] );
127 foreach ( $collections as $collection ) {
128 $newIds = $this->get_media_from_collection( $collection );
129 $addedIds = array_merge( $addedIds, $newIds );
130 }
131 }
132 if ( !empty( $attrs['wplr-collections'] ) ) {
133 $collections = explode( ',', $attrs['wplr-collections'] );
134 foreach ( $collections as $collection ) {
135 $newIds = $this->get_media_from_collection( $collection );
136 $addedIds = array_merge( $addedIds, $newIds );
137 }
138 }
139 if ( !empty( $attrs['wplr-keyword'] ) ) {
140 $keywords = explode( ',', $attrs['wplr-keyword'] );
141 foreach ( $keywords as $keyword ) {
142 $newIds = $this->get_media_from_tag( $keyword );
143 $addedIds = array_merge( $addedIds, $newIds );
144 }
145 }
146 // Keywords outer join
147 if ( !empty( $attrs['wplr-keywords'] ) ) {
148 $keywords = explode( ',', $attrs['wplr-keywords'] );
149 foreach ( $keywords as $keyword ) {
150 $newIds = $this->get_media_from_tag( $keyword );
151 $addedIds = array_merge( $addedIds, $newIds );
152 }
153 }
154 // Keywords inner join
155 if ( !empty( $attrs['wplr-keywords-and'] ) ) {
156 $keywords = explode( ',', $attrs['wplr-keywords-and'] );
157 foreach ( $keywords as $keyword ) {
158 $newIds = $this->get_media_from_tag( $keyword );
159 $addedIds = array_merge( $addedIds, $newIds );
160 }
161 $unique = array_unique( $addedIds );
162 $diffkeys = array_diff_key( $addedIds, $unique );
163 $addedIds = array_unique( $diffkeys );
164 }
165 return empty( $addedIds ) ? $ids : $addedIds;
166 }
167
168 /*****************************************************************************
169 INIT
170 *****************************************************************************/
171
172 function init() {
173 if ( get_option( 'wplr_enable_keywords', false ) || get_option( 'wplr_sync_keywords', false ) ) {
174 new Meow_WPLR_Sync_Keywords();
175 }
176 if ( get_option( 'wr2x_big_image_size_threshold', false ) ) {
177 add_filter( 'big_image_size_threshold', array( $this, 'big_image_size_threshold' ) );
178 }
179
180 // $res = $this->get_collection(5);
181 // print_r($res);
182 // exit;
183 }
184
185 function big_image_size_threshold() {
186 return false;
187 }
188
189 function plugins_loaded() {
190 // Part of the core, settings and stuff
191 $this->admin = new Meow_WPLR_Sync_Admin();
192 if ( is_admin() ) {
193 global $wplr_admin;
194 $wplr_admin = $this->admin;
195 new Meow_WPLR_Sync_UI( $this );
196 }
197
198 // APIs
199 new Meow_WPLR_Sync_API();
200 if ( get_option( "wplr_public_api", true ) ) {
201 new Meow_WPLR_Sync_Public_API();
202 }
203
204 // Rest
205 if ( $this->is_rest ) {
206 new Meow_WPLR_Sync_Rest( $this, $this->admin );
207 }
208
209 $loaded = load_plugin_textdomain( 'wplr-sync', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
210 $plugins = get_option( 'wplr_plugins' );
211 if ( is_array( $plugins ) ) {
212 $dir = trailingslashit( plugin_dir_path( __FILE__ ) ) . trailingslashit( 'extensions' );
213 $valid = array();
214 $isdead = false;
215 foreach ( $plugins as $plugin ) {
216 if ( file_exists( trailingslashit( $dir ) . $plugin ) ) {
217 include( trailingslashit( $dir ) . $plugin );
218 array_push( $valid, $plugin );
219 }
220 else {
221 $plugin = preg_replace( '/([0-9]_)(\w+)/i', '$2', $plugin );
222 if ( file_exists( trailingslashit( $dir ) . $plugin ) ) {
223 include( trailingslashit( $dir ) . $plugin );
224 array_push( $valid, $plugin );
225 }
226 $isdead = true;
227 }
228 }
229 if ( $isdead ) {
230 update_option( 'wplr_plugins', $valid );
231 }
232 }
233 }
234
235 /*
236 CORE
237 */
238
239 function log( $data, $force = false ) {
240 if ( !$force && !get_option( 'wplr_debuglogs', false ) )
241 return;
242 try {
243 if ( is_writable( dirname( __FILE__ ) ) ) {
244 $fh = fopen( trailingslashit( dirname( __FILE__ ) ) . 'wplr-sync.log', 'a' );
245 if ( ! $fh ) {
246 throw new Exception( 'Cannot open log file.' );
247 }
248 $date = date( "Y-m-d H:i:s" );
249 fwrite( $fh, "$date: {$data}\n" );
250 fclose( $fh );
251 }
252 else {
253 error_log( 'Cannot create or write the Photo Engine Logs.' );
254 }
255 }
256 catch ( Exception $e ) {
257 error_log( 'Cannot create or write the Photo Engine Logs: ' . $e->getMessage() );
258 }
259 }
260
261 function profile_update( $user_id ) {
262 $token = get_user_meta( $user_id, 'wplr_auth_token', true );
263 if ( empty( $token ) ) {
264 $token = $this->generate_auth_token( $user_id );
265 }
266 }
267
268 /**
269 * Generates a new auth token for the specified user and stores it in DB
270 * @param WP_User $user
271 * @return string The new token
272 */
273 function generate_auth_token( $userId ) {
274 static $MIN_LENGTH = 24;
275 static $MAX_LENGTH = 32;
276
277 // Seed
278 list( $usec, $sec ) = explode( ' ', microtime() );
279 $seed = $sec + $usec * 1000000;
280 srand( $seed );
281
282 // Compose
283 $r = '';
284 $chars = str_split( '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' );
285 $nChars = count( $chars );
286 $length = rand( $MIN_LENGTH, $MAX_LENGTH );
287 for ( $i = 0; $i < $length; $i++ ) $r .= $chars[rand( 0, $nChars - 1 )];
288
289 // Save
290 if ( update_user_meta( $userId, 'wplr_auth_token', $r ) === false ) {
291 throw new Exception( "Save Failure" );
292 }
293
294 return $r;
295 }
296
297 function check_db() {
298 $this->log( '[WP/LR] Checking the database...' );
299
300 global $wpdb;
301 $tbl_s = $wpdb->prefix . 'lrsync';
302 $tbl_m = $wpdb->prefix . 'lrsync_meta';
303 $tbl_c = $wpdb->prefix . 'lrsync_collections';
304 $tbl_r = $wpdb->prefix . 'lrsync_relations';
305
306 $messages = array();
307
308 // To make sure there are primary keys (Added in version 6.0+)
309 $messages[] = 'Checking '. $tbl_s . ' table...';
310 if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1)
311 FROM information_schema.table_constraints
312 WHERE table_schema = '%s'
313 AND table_name = '%s'
314 AND constraint_name = 'PRIMARY';", $wpdb->dbname, $tbl_s ) ) ) {
315 meow_wplrsync_activate();
316
317 $messages[] = '🟠 Primary key added to ' . $tbl_s;
318 } else {
319 $messages[] = '🟢 Primary key exists in ' . $tbl_s;
320 }
321
322
323 // Check if the table $tbl_m exists (Added in version 6.0+)
324 $messages[] = 'Checking '. $tbl_m . ' table...';
325 if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM information_schema.tables WHERE table_schema = '%s' AND table_name = '%s';", $wpdb->dbname, $tbl_m ) ) ) {
326 meow_wplrsync_activate();
327
328 $messages[] = '🟠 Table ' . $tbl_m . ' created.';
329 } else {
330 $messages[] = '🟢 Table ' . $tbl_m . ' exists.';
331 }
332
333 // Check if the table $tbl_r exists
334 $messages[] = 'Checking '. $tbl_r . ' table...';
335 if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM information_schema.tables WHERE table_schema = '%s' AND table_name = '%s';", $wpdb->dbname, $tbl_r ) ) ) {
336 meow_wplrsync_activate();
337
338 $messages[] = '🟠 Table ' . $tbl_r . ' created.';
339 } else {
340 $messages[] = '🟢 Table ' . $tbl_r . ' exists.';
341 }
342
343 // Check if the table $tbl_c exists (Added in version 6.0+)
344 $messages[] = 'Checking '. $tbl_c . ' table...';
345 if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM information_schema.tables WHERE table_schema = '%s' AND table_name = '%s';", $wpdb->dbname, $tbl_c ) ) ) {
346 meow_wplrsync_activate();
347
348 $messages[] = '🟠 Table ' . $tbl_c . ' created.';
349 } else {
350 $messages[] = '🟢 Table ' . $tbl_c . ' exists.';
351 }
352
353 // Check if the new column 'source' exists in collections table (Added in version 6.0+)
354 $messages[] = 'Checking column source in ' . $tbl_c . ' table...';
355 if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM information_schema.columns WHERE table_schema = '%s' AND table_name = '%s' AND column_name = '%s';", $wpdb->dbname, $tbl_c, 'source' ) ) ) {
356 meow_wplrsync_activate();
357
358 $messages[] = '🟠 Column source added to ' . $tbl_c;
359 } else {
360 $messages[] = '🟢 Column source exists in ' . $tbl_c;
361 }
362
363 // Check if the new column 'featured_id' exists in collections table (Added in version 6.0+)
364 $messages[] = 'Checking column featured_id in ' . $tbl_c . ' table...';
365 if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM information_schema.columns WHERE table_schema = '%s' AND table_name = '%s' AND column_name = '%s';", $wpdb->dbname, $tbl_c, 'featured_id' ) ) ) {
366 meow_wplrsync_activate();
367
368 $messages[] = '🟠 Column featured_id added to ' . $tbl_c;
369 } else {
370 $messages[] = '🟢 Column featured_id exists in ' . $tbl_c;
371 }
372
373 // Check if the new column 'slug' exists in collections table (Added in version 6.0+)
374 // Create the slugs if they aren't there.
375 $messages[] = 'Checking column slug in ' . $tbl_c . ' table...';
376 if ( !$wpdb->get_var( $wpdb->prepare( "SELECT COUNT(1) FROM information_schema.columns WHERE table_schema = '%s' AND table_name = '%s' AND column_name = '%s';", $wpdb->dbname, $tbl_c, 'slug' ) ) ) {
377 meow_wplrsync_activate();
378
379 $messages[] = '🟠 Column slug added to ' . $tbl_c;
380
381 $galleries = $wpdb->get_results( "SELECT wp_col_id id, name FROM $tbl_c", OBJECT);
382 foreach ( $galleries as $gallery ) {
383 $slug = sanitize_title( $gallery->name );
384 //error_log("{$gallery->id} => $slug");
385 $wpdb->update( $tbl_c, array( 'slug' => $slug ), array( 'wp_col_id' => $gallery->id ), array( '%s' ), array( '%d' ) );
386
387 $messages[] = "Slug $slug added to gallery {$gallery->id}";
388 }
389 } else {
390 $messages[] = '🟢 Column slug exists in ' . $tbl_c;
391 }
392
393 return $messages;
394 }
395
396 function reset_db() {
397 do_action( 'wplr_reset' );
398 meow_wplrsync_uninstall();
399 meow_wplrsync_activate();
400 }
401
402 function wpml_original_id( $wpid ) {
403 if ( $this->wpml_media_is_installed() ) {
404 global $sitepress;
405 $language = $sitepress->get_default_language( $wpid );
406 return icl_object_id( $wpid, 'attachment', true, $language );
407 }
408 return $wpid;
409 }
410
411 function wpml_media_is_installed() {
412 return defined( 'WPML_MEDIA_VERSION' );
413 //return function_exists( 'icl_object_id' ) && !class_exists( 'Polylang' );
414 }
415
416 function wpml_original_array( $wpids ) {
417 if ( $this->wpml_media_is_installed() ) {
418 for ($c = 0; $c < count( $wpids ); $c++ ) {
419 $wpids[$c] = $this->wpml_original_id( $wpids[$c] );
420 }
421 $wpids = array_unique( $wpids );
422 }
423 return $wpids;
424 }
425
426 function get_tags_from_media( $mediaId ) {
427 global $wpdb;
428 $tbl_meta = $wpdb->prefix . "lrsync_meta";
429 $results = $wpdb->get_col( $wpdb->prepare( "
430 SELECT value
431 FROM $tbl_meta
432 WHERE id = %d AND name = 'media_tag'
433 ", $mediaId ) );
434 return $results;
435 }
436
437 function get_media_from_tag( $id ) {
438 global $wpdb;
439 $tbl_meta = $wpdb->prefix . "lrsync_meta";
440 $results = $wpdb->get_col( $wpdb->prepare( "
441 SELECT id
442 FROM $tbl_meta
443 WHERE value = %d AND name = 'media_tag'
444 ", $id ) );
445 return $results;
446 }
447
448 function get_media_from_collection( $id, $limit = 100000, $offset = 0 ) {
449 global $wpdb;
450 $tbl_relations = $wpdb->prefix . "lrsync_relations";
451 $results = $wpdb->get_col( $wpdb->prepare( "
452 SELECT wp_id
453 FROM $tbl_relations, $wpdb->posts p
454 WHERE wp_id = p.ID
455 AND wp_col_id = %d
456 ORDER BY sort, post_date ASC
457 LIMIT %d OFFSET %d
458 ", $id, $limit, $offset ) );
459 return $results;
460 }
461
462 function get_collection_from_slug( $slug ) {
463 global $wpdb;
464 $tbl_col = $wpdb->prefix . "lrsync_collections";
465 $info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tbl_col WHERE slug = %s", $slug ), OBJECT );
466 return $info;
467 }
468
469 function get_folder_from_slug( $slug ) {
470 return $this->get_collection_from_slug( $slug );
471 }
472
473 function get_collection( $id, $col_id = null ) {
474 global $wpdb;
475 $tbl_col = $wpdb->prefix . "lrsync_collections";
476
477 if ( !is_null( $col_id ) ) {
478 $info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tbl_col c
479 WHERE wp_col_id = %d
480 AND lr_col_id = %d", $id, $col_id ),
481 OBJECT
482 );
483 }
484 else {
485 $info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $tbl_col
486 WHERE wp_col_id = %d", $id ),
487 OBJECT
488 );
489 }
490 return $info;
491 }
492
493 function get_folder( $id ) {
494 return $this->get_collection( $id );
495 }
496
497 function get_collections_from_media( $mediaId ) {
498 global $wpdb;
499 $tbl_relations = $wpdb->prefix . "lrsync_relations";
500 $results = $wpdb->get_col( $wpdb->prepare( "
501 SELECT wp_col_id
502 FROM $tbl_relations
503 WHERE wp_id = %d AND wp_col_id >= 0
504 ", $mediaId ) );
505 return $results;
506 }
507
508 function get_collections_from_folder( $folderId = NULL) {
509 global $wpdb;
510 $tbl_c = $wpdb->prefix . 'lrsync_collections';
511 if ( !$folderId ) {
512 $collections = $wpdb->get_col( "SELECT wp_col_id FROM $tbl_c
513 WHERE wp_folder_id IS NULL AND is_folder = 0 ORDER BY name, lr_col_id" );
514 }
515 else {
516 $collections = $wpdb->get_col( $wpdb->prepare( "SELECT wp_col_id FROM $tbl_c
517 WHERE wp_folder_id = %d AND is_folder = 0 ORDER BY name, lr_col_id", $folderId ) );
518 }
519 return $collections;
520 }
521
522 function get_folders_from_folder( $folderId = NULL) {
523 global $wpdb;
524 $tbl_c = $wpdb->prefix . 'lrsync_collections';
525 if ( !$folderId ) {
526 $collections = $wpdb->get_col( "SELECT wp_col_id FROM $tbl_c
527 WHERE wp_folder_id IS NULL AND is_folder = 1 ORDER BY name, lr_col_id" );
528 }
529 else {
530 $collections = $wpdb->get_col( $wpdb->prepare( "SELECT wp_col_id FROM $tbl_c
531 WHERE wp_folder_id = %d AND is_folder = 1 ORDER BY name, lr_col_id", $folderId ) );
532 }
533 return $collections;
534 }
535
536 /**
537 * Returns MIME-type for a file
538 * @param string $file File path
539 * @return string
540 */
541 function get_mime_type( $file ) {
542 static $types;
543
544 if ( function_exists( 'mime_content_type' ) ) {
545 if ( $r = mime_content_type( $file ) ) {
546 return $r; // Detect from content
547 }
548 }
549
550 // Determine from extension
551 if ( !$types ) {
552 $types = array (
553 'avi' => 'video/x-msvideo',
554 'bmp' => 'image/bmp',
555 'gif' => 'image/gif',
556 'ico' => 'image/x-icon',
557 'jpe' => 'image/jpeg',
558 'jpeg' => 'image/jpeg',
559 'jpg' => 'image/jpeg',
560 'avif' => 'image/avif',
561 'mov' => 'video/quicktime',
562 'movie' => 'video/x-sgi-movie',
563 'mp2' => 'audio/mpeg',
564 'mp3' => 'audio/mpeg',
565 'mpe' => 'video/mpeg',
566 'mpeg' => 'video/mpeg',
567 'mpg' => 'video/mpeg',
568 'png' => 'image/png',
569 'pnm' => 'image/x-portable-anymap',
570 'ppm' => 'image/x-portable-pixmap',
571 'qt' => 'video/quicktime',
572 'ras' => 'image/x-cmu-raster',
573 'rgb' => 'image/x-rgb',
574 'svg' => 'image/svg+xml',
575 'svgz' => 'image/svg+xml',
576 'tif' => 'image/tiff',
577 'tiff' => 'image/tiff',
578 'wbmp' => 'image/vnd.wap.wbmp',
579 'xbm' => 'image/x-xbitmap',
580 'xpm' => 'image/x-xpixmap',
581 'xwd' => 'image/x-xwindowdump'
582 );
583 }
584 $ext = pathinfo( $file, PATHINFO_EXTENSION );
585 if ( !isset( $types[$ext] ) ) {
586 error_log('Photo Engine could not find the mime type for the file (so it was set to jpg).');
587 return 'image/jpeg';
588 }
589 return $types[$ext];
590 }
591
592 function read_collections_recursively( $parent = null, $results = array(), $isRemoval = false, $level = 0 ) {
593
594 if ( $parent === null && !empty( $this->cached_collections ) ) {
595 return $this->cached_collections;
596 }
597
598 global $wpdb;
599 $tbl_c = $wpdb->prefix . 'lrsync_collections';
600 if ( is_null( $parent ) )
601 $collections = $wpdb->get_results( "SELECT wp_col_id, name, wp_folder_id, is_folder, source
602 FROM $tbl_c WHERE wp_folder_id IS NULL ORDER BY is_folder DESC, name, lr_col_id", ARRAY_A );
603 else
604 $collections = $wpdb->get_results( $wpdb->prepare( "SELECT wp_col_id, name, wp_folder_id, is_folder, source
605 FROM $tbl_c WHERE wp_folder_id = %d ORDER BY is_folder DESC, name, lr_col_id", $parent ), ARRAY_A );
606 foreach ( $collections as $c ) {
607 array_push( $results, array_merge(
608 array(
609 'level' => $level,
610 'action' => $isRemoval ? 'remove_collection' : 'add_collection',
611 ), $c ) );
612 if ( $c['is_folder'] )
613 $results = $this->read_collections_recursively( $c['wp_col_id'], $results, $isRemoval, $level + 1 );
614 }
615 if ( $parent === null ) {
616 $this->cached_collections = $results;
617 }
618 return $results;
619 }
620
621 function get_meta_from_value( $name, $value, $isArray = false ) {
622 global $wpdb;
623 $tbl_meta = $wpdb->prefix . "lrsync_meta";
624 $results = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $tbl_meta WHERE name = %s AND value = %s", $name, $value ) );
625 if ( count( $results ) > 1 )
626 return $results;
627 else if ( count( $results ) == 1 )
628 return $isArray ? array( $results[0] ) : $results[0];
629 return $isArray ? array() : null;
630 }
631
632 function get_meta( $name, $id, $isArray = false ) {
633 global $wpdb;
634 $tbl_meta = $wpdb->prefix . "lrsync_meta";
635 $results = $wpdb->get_col( $wpdb->prepare( "SELECT value FROM $tbl_meta WHERE name = %s AND id = %d", $name, $id ) );
636 if ( count( $results ) > 1 )
637 return $results;
638 else if ( count( $results ) == 1 )
639 return $isArray ? array( $results[0] ) : $results[0];
640 return $isArray ? array() : null;
641 }
642
643 function set_meta( $name, $id, $value, $unique = false ) {
644 global $wpdb;
645 $tbl_meta = $wpdb->prefix . "lrsync_meta";
646 if ( $unique ) {
647 $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $tbl_meta WHERE name = %s AND id = %d", $name, $id ) );
648 if ( $count > 0 ) {
649 $wpdb->update( $tbl_meta, array( 'value' => $value ), array( 'name' => $name, 'id' => $id ), array( '%s' ), array( '%s', '%d' ) );
650 return true;
651 }
652 }
653 $wpdb->insert( $tbl_meta, array( 'name' => $name, 'id' => $id, 'value' => $value ) );
654 }
655
656 // If no value given, all meta for this id will be deleted
657 function delete_meta( $name, $id, $value = null ) {
658 global $wpdb;
659 $tbl_meta = $wpdb->prefix . "lrsync_meta";
660 if ( is_null( $value ) )
661 $wpdb->query( $wpdb->prepare( "DELETE FROM $tbl_meta WHERE name = %s AND id = %d", $name, $id ) );
662 else
663 $wpdb->query( $wpdb->prepare( "DELETE FROM $tbl_meta WHERE name = %s AND id = %d AND value = %s", $name, $id, $value ) );
664 }
665
666 // Return SyncInfo for this WP ID
667 function get_sync_info( $wpid ) {
668 $wpid = $this->wpml_original_id( $wpid );
669 global $wpdb;
670 $table_name = $wpdb->prefix . "lrsync";
671 $info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE wp_id = %d", $wpid ), OBJECT );
672 return $info;
673 }
674
675 function get_sync_info_from_lr_id( $lr_id ) {
676 global $wpdb;
677 $table_name = $wpdb->prefix . "lrsync";
678 $info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE lr_id = %d", $lr_id ), OBJECT );
679 return $info;
680 }
681
682 // Check if there's a format mismatch between file extension and actual content
683 function check_format_mismatch( $wp_id ) {
684 // Check if this media is managed by WP/LR Sync
685 $sync_info = $this->get_sync_info( $wp_id );
686 if ( !$sync_info ) {
687 return false;
688 }
689
690 // Get the file path and extension
691 $file_path = get_attached_file( $wp_id );
692 if ( !$file_path || !file_exists( $file_path ) ) {
693 return false;
694 }
695
696 $file_extension = strtolower( pathinfo( $file_path, PATHINFO_EXTENSION ) );
697
698 // Get the actual MIME type from file content
699 $finfo = finfo_open( FILEINFO_MIME_TYPE );
700 $actual_mime = finfo_file( $finfo, $file_path );
701 finfo_close( $finfo );
702
703 // Map MIME types to expected extensions
704 $mime_to_ext = array(
705 'image/jpeg' => array( 'jpg', 'jpeg' ),
706 'image/png' => array( 'png' ),
707 'image/avif' => array( 'avif' ),
708 'image/tiff' => array( 'tiff', 'tif' ),
709 'image/webp' => array( 'webp' ),
710 'image/heic' => array( 'heic' ),
711 'image/heif' => array( 'heif' )
712 );
713
714 // Check if there's a mismatch
715 $has_mismatch = false;
716 $expected_format = '';
717 $actual_format = '';
718
719 if ( isset( $mime_to_ext[$actual_mime] ) ) {
720 $expected_extensions = $mime_to_ext[$actual_mime];
721 if ( !in_array( $file_extension, $expected_extensions ) ) {
722 $has_mismatch = true;
723 $actual_format = $expected_extensions[0];
724 $expected_format = $file_extension;
725 }
726 }
727
728 return array(
729 'has_mismatch' => $has_mismatch,
730 'file_extension' => $file_extension,
731 'actual_format' => $actual_format,
732 'actual_mime' => $actual_mime,
733 'message' => $has_mismatch ?
734 "This file has a .$file_extension extension but contains $actual_format data. This can happen when you change export formats in Lightroom. The file will display correctly, but the mismatched extension may cause confusion." : ''
735 );
736 }
737
738 function get_hierarchy( $parent = null, $level = 0, $source = null ) {
739 global $wpdb;
740 $tbl_r = $wpdb->prefix . 'lrsync_relations';
741 $tbl_c = $wpdb->prefix . 'lrsync_collections';
742
743 $where_source = $source !== null ? $wpdb->prepare( "AND source = %s", $source ) : '';
744
745 $current = array();
746
747 if ( is_null( $parent ) ) {
748 $collections = $wpdb->get_results( "SELECT *
749 FROM $tbl_c
750 WHERE wp_folder_id IS NULL $where_source
751 ORDER BY is_folder DESC, name, lr_col_id", OBJECT
752 );
753 }
754 else {
755 $collections = $wpdb->get_results( $wpdb->prepare( "SELECT *
756 FROM $tbl_c
757 WHERE wp_folder_id = %d $where_source
758 ORDER BY is_folder DESC, name, lr_col_id", $parent ), OBJECT
759 );
760 }
761
762 foreach ( $collections as $c ) {
763 $photos_count = 0;
764 if ( !$c->is_folder ) {
765 $photos_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*)
766 FROM $tbl_r
767 WHERE wp_col_id = %d", $c->wp_col_id )
768 );
769 }
770 $current[] = array(
771 'id' => $c->wp_col_id,
772 'source' => $c->source,
773 'level' => $level,
774 'type' => $c->is_folder ? 'folder' : 'collection',
775 'name' => $c->name,
776 'slug' => $c->slug,
777 'count' => $photos_count,
778 'featured_id' => $c->featured_id,
779 'children' => $c->is_folder ? $this->get_hierarchy( $c->wp_col_id, $level + 1 ) : null
780 );
781 }
782 return $current;
783 }
784
785 function get_keywords_hierarchy( $parent = null, $level = 0 ) {
786 global $wpdb;
787 $tbl_m = $wpdb->prefix . 'lrsync_meta';
788
789 $current = array();
790
791 if ( is_null( $parent ) )
792 $collections = $wpdb->get_results( "SELECT meta_id,
793 MAX(IF(`name` = 'tag_name', id, NULL)) id,
794 MAX(IF(`name` = 'tag_name', value, NULL)) name,
795 MAX(IF(`name` = 'tag_parent', value, NULL)) parent
796 FROM $tbl_m
797 WHERE name = 'tag_name' OR name = 'tag_parent'
798 GROUP BY id
799 HAVING parent IS NULL
800 ORDER BY id", OBJECT );
801 else {
802 $collections = $wpdb->get_results( $wpdb->prepare( "SELECT meta_id,
803 MAX(IF(`name` = 'tag_name', id, NULL)) id,
804 MAX(IF(`name` = 'tag_name', value, NULL)) name,
805 MAX(IF(`name` = 'tag_parent', value, NULL)) parent
806 FROM $tbl_m
807 WHERE name = 'tag_name' OR name = 'tag_parent'
808 GROUP BY id
809 HAVING parent = %d
810 ORDER BY id", $parent ), OBJECT );
811 }
812 foreach ( $collections as $c ) {
813 $photos_count = null;
814 $count = $wpdb->get_var( "SELECT COUNT(*) FROM $tbl_m WHERE name = 'media_tag' AND value = {$c->id}" );
815 $current[] = array(
816 'id' => $c->id,
817 'level' => $level,
818 'name' => $c->name,
819 'count' => $count,
820 'children' => !empty( $c->id ) ? $this->get_keywords_hierarchy( $c->id, $level + 1 ) : array()
821 );
822 }
823 return $current;
824 }
825
826 function get_gallery( $id ) {
827 global $wpdb;
828 $tbl_r = $wpdb->prefix . 'lrsync_relations';
829 $photos = $wpdb->get_results( $wpdb->prepare( "
830 SELECT wp_id id
831 FROM $tbl_r r
832 WHERE wp_col_id = %d
833 ORDER BY sort", $id ), ARRAY_A );
834 foreach ( $photos as &$photo ) {
835 $id = $photo['id'];
836 $photo['title'] = get_the_title( $id );
837 $photo['full_size'] = stripslashes( wp_get_attachment_url( $id ) );
838 $photo['thumbnail'] = stripslashes( wp_get_attachment_thumb_url( $id, 'post-thumbnail' ) );
839 }
840 return $photos;
841 }
842
843 function delete_media( $lr_id, $wp_col_id = null ) {
844 global $wpdb;
845 $lrinfo = $this->get_sync_info_from_lr_id( $lr_id );
846
847 if ( empty( $lrinfo ) ) {
848 error_log( "Photo Engine: seems like this media doesn't exist or has been already removed ($lr_id)." );
849 return true;
850 }
851
852 // Remove media from collection
853 $this->remove_media_from_collection( $lrinfo->wp_id, $wp_col_id );
854
855 // Delete media if it is not part of any collection
856 $tbl_r = $wpdb->prefix . 'lrsync_relations';
857 $left = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $tbl_r WHERE wp_id = %d", $lrinfo->wp_id ) );
858 if ( $left < 1 ) {
859 // Delete the media, it is not used anywhere
860 $table_name = $wpdb->prefix . "lrsync";
861 $sync_files = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE lr_id = %d", $lr_id), OBJECT );
862 $delete_count = 0;
863 foreach ( $sync_files as $sync ) {
864 if ( wp_delete_attachment( $sync->wp_id, true ) ) {
865 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE lr_id = %d", $lr_id ) );
866 $delete_count++;
867
868 //TODO: DELETE KEYWORDS
869 // Are the tags used by this Media now useless?
870 $keywords = $this->get_meta( 'media_tag', $sync->wp_id, true );
871 foreach ( $keywords as $keyword ) {
872 $results = $this->get_meta_from_value( 'media_tag', $keyword, true );
873 if ( count( $results ) < 1 ) {
874 $this->delete_keyword( $keyword );
875 }
876 }
877
878 }
879 }
880 if ( count( $sync_files ) < 1 ) {
881 // There were no files to remove
882 return true;
883 }
884 else if ( $delete_count > 0 ) {
885 // Files were removed
886 do_action( 'wplr_remove_media', (int)$lrinfo->wp_id );
887 return true;
888 }
889 else {
890 // Nothing was removed, strangely
891 $this->error = __( "The attachment could not be removed.", 'wplr-sync' );
892 return false;
893 }
894 }
895 else {
896 // Don't delete the media, it is used somewhere else
897 return true;
898 }
899 }
900
901 function delete_attachment( $wp_id ) {
902 $wp_id = $this->wpml_original_id( $wp_id );
903 $this->sync_media_tags( $wp_id );
904 global $wpdb;
905 $table_name = $wpdb->prefix . "lrsync";
906 $sql = $wpdb->prepare( "DELETE FROM $table_name WHERE wp_id = %d", $wp_id );
907 $wpdb->query( $sql );
908 $table_name = $wpdb->prefix . "lrsync_relations";
909 $sql = $wpdb->prepare( "DELETE FROM $table_name WHERE wp_id = %d", $wp_id );
910 $wpdb->query( $sql );
911 }
912
913 function unlink_media( $lr_id, $wp_id ) {
914 $wp_id = $this->wpml_original_id( $wp_id );
915 global $wpdb;
916 $table_name = $wpdb->prefix . "lrsync";
917
918 // Remove media
919 if ( $wp_id ) {
920 $sync = $this->get_sync_info( $wp_id );
921 if ( $sync ) {
922 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE wp_id = %d", $sync->wp_id ) );
923 return true;
924 }
925 }
926 else {
927 $wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE lr_id = %d", $lr_id ) );
928 return true;
929 }
930
931 $this->error = __( "There is no link for this media.", 'wplr-sync' );
932 return false;
933 }
934
935 function link_media( $lr_id, $wp_id ) {
936 $wp_id = $this->wpml_original_id( $wp_id );
937 global $wpdb;
938 $table_name = $wpdb->prefix . "lrsync";
939 if ( empty( $wp_id ) ) {
940 $this->error = __( "The arguments lr_id and wp_id are required.", 'wplr-sync' );
941 return false;
942 }
943 if ( !wp_attachment_is_image( $wp_id ) ) {
944 $this->error = __( "Attachment " . ($wp_id ? $wp_id : "[null]") . " does not exist or is not an image.", 'wplr-sync' );
945 return false;
946 }
947 $sync = $this->get_sync_info( $wp_id );
948 if ( !$sync ) {
949 $wpdb->insert( $table_name,
950 array(
951 'wp_id' => $wp_id,
952 'lr_id' => $lr_id,
953 'lr_file' => null,
954 'lastsync' => null
955 )
956 );
957 }
958 else {
959 $wpdb->query( $wpdb->prepare( "UPDATE $table_name
960 SET lr_id = %d
961 WHERE wp_id = %d", $lr_id, $wp_id )
962 );
963 }
964 $sync = $this->get_sync_info( $wp_id );
965 $info = Meow_WPLR_Sync_LRInfo::fromRow( $sync );
966 return $info;
967 }
968
969 function list_sync_media() {
970 global $wpdb;
971 $table_name = $wpdb->prefix . "lrsync";
972 $sync_files = $wpdb->get_results( "SELECT * FROM $table_name WHERE lr_id >= 0 AND wp_id >= 0", OBJECT );
973 $list = array();
974 foreach ( $sync_files as $sync_file ) {
975 $info = Meow_WPLR_Sync_LRInfo::fromRow( $sync_file );
976 array_push( $list, $info );
977 }
978 return $list;
979 }
980
981 function update_metadata( $wp_id, $lrinfo, $isTranslation = false ) {
982 // Update Title, Description and Caption
983
984 $meta = null;
985 if ( $isTranslation ) {
986 $meta = get_post( $wp_id, ARRAY_A );
987 }
988
989 // Update Title, Caption and Desc (if needed)
990 if ( $lrinfo->sync_title || $lrinfo->sync_caption || $lrinfo->sync_desc ) {
991 $post = array( 'ID' => $wp_id );
992 if ( $lrinfo->sync_title && ( !$meta || empty( $meta['post_title'] ) ) )
993 $post['post_title'] = $lrinfo->lr_title;
994 if ( $lrinfo->sync_desc && ( !$meta || empty( $meta['post_content'] ) ) )
995 $post['post_content'] = $lrinfo->lr_desc;
996 if ( $lrinfo->sync_caption && ( !$meta || empty( $meta['post_excerpt'] ) ) )
997 $post['post_excerpt'] = $lrinfo->lr_caption;
998 wp_update_post( $post );
999 }
1000
1001 // Update Alt Text if needed
1002 if ( $lrinfo->sync_alt_text ) {
1003 if ( $isTranslation )
1004 $meta_alt = get_post_meta( $wp_id, '_wp_attachment_image_alt', true );
1005 if ( !$isTranslation || empty( $meta_alt ) )
1006 update_post_meta( $wp_id, '_wp_attachment_image_alt', $lrinfo->lr_alt_text );
1007 }
1008 }
1009
1010 function create_keyword( $lrTagId, $name, $lrTagParentId = null ) {
1011 $this->set_meta( 'tag_name', $lrTagId, $name, true );
1012 $this->set_meta( 'tag_parent', $lrTagId, $lrTagParentId, true );
1013 do_action( 'wplr_add_tag', (int)$lrTagId, $name, $lrTagParentId );
1014 }
1015
1016 function update_keyword( $lrTagId, $name ) {
1017 $this->set_meta( 'tag_name', $lrTagId, $name, true );
1018 do_action( 'wplr_update_tag', (int)$lrTagId, $name );
1019 }
1020
1021 function move_keyword( $lrTagId, $lrTagParentId ) {
1022 $previous = $this->get_meta( 'tag_parent', $lrTagId );
1023 $this->set_meta( 'tag_parent', $lrTagId, $lrTagParentId, true );
1024 do_action( 'wplr_move_tag', (int)$lrTagId, $lrTagParentId, $previous );
1025 }
1026
1027 function delete_keyword( $lrTagId ) {
1028 $this->delete_meta( 'tag_name', $lrTagId );
1029 $this->delete_meta( 'tag_parent', $lrTagId );
1030 do_action( 'wplr_remove_tag', (int)$lrTagId );
1031 $kids = $this->get_meta_from_value( 'tag_parent', $lrTagId, true );
1032 foreach ( $kids as $kid ) {
1033 $kidName = $this->get_meta( 'tag_name', $kid );
1034 $this->delete_meta( 'tag_parent', $kid );
1035 do_action( 'wplr_update_tag', (int)$kid, $kidName, null );
1036 }
1037 $media = $this->get_meta_from_value( 'media_tag', $lrTagId, true );
1038 foreach ( $media as $m ) {
1039 $this->delete_meta( 'media_tag', $m );
1040 do_action( 'wplr_remove_media_tag', (int)$m, $lrTagId );
1041 }
1042 }
1043
1044
1045 function flatten_tags( $importTags, $allTags = array() ) {
1046 foreach ( $importTags as $tag ) {
1047 $currentTag = $tag;
1048 $allTags[(int)$tag['id']] = array(
1049 'id' => $tag['id'],
1050 'name' => trim( $tag['name'] ), // trim( $tag['name'], '\\"\' '),
1051 'parent' => null
1052 );
1053 while ( isset( $currentTag['parent'] ) && is_array( $currentTag['parent'] ) ) {
1054 $allTags[(int)$currentTag['id']]['parent'] = $currentTag['parent']['id'];
1055 $currentTag = $currentTag['parent'];
1056 $allTags[(int)$currentTag['id']] = array(
1057 'id' => $currentTag['id'],
1058 'name' => trim( $currentTag['name'] ), // trim( $currentTag['name'], '\\"\' '),
1059 'parent' => null
1060 );
1061 }
1062 }
1063 return $allTags;
1064 }
1065
1066 function sync_media_tags( $wp_id, $tags = '' ) {
1067 // If tags is not an array (so maybe an old string of tags, or empty tag, let's set it to empty)
1068 if ( !is_array( $tags ) )
1069 $tags = array();
1070 $newTags = array();
1071 $flatten = $this->flatten_tags( $tags );
1072 $deathcount = 1666;
1073
1074 // Read the tags given by LR, add them in the meta if they are new.
1075 while ( count( $flatten ) > 0 && $deathcount > 0 ) {
1076 $tag = array_shift( $flatten );
1077
1078 $deathcount--;
1079 $pTagName = $this->get_meta( 'tag_name', $tag['id'] );
1080 $pTagParent = $this->get_meta( 'tag_parent', $tag['id'] );
1081
1082 // Tag does not exist
1083 if ( empty( $pTagName ) ) {
1084
1085 // Has no parent, we can create it
1086 if ( $tag['parent'] == null ) {
1087 $this->create_keyword( $tag['id'], $tag['name'] );
1088 array_push( $newTags, $tag['id'] );
1089 continue;
1090 }
1091 // Has a parent, which is already registered
1092 $parentName = $this->get_meta( 'tag_name', $tag['parent'] );
1093 if ( !empty( $parentName ) ) {
1094 $this->create_keyword( $tag['id'], $tag['name'], $tag['parent'] );
1095 array_push( $newTags, $tag['id'] );
1096 continue;
1097 }
1098 }
1099
1100 // Tag exists
1101 if ( !empty( $pTagName ) ) {
1102
1103 // But has different name, so we update it
1104 if ( $pTagName != $tag['name'] )
1105 $this->update_keyword( $tag['id'], $tag['name'] );
1106
1107 // But has different parent
1108 if ( $pTagParent != (int)$tag['parent'] )
1109 $this->move_keyword( $tag['id'], (int)$tag['parent'] );
1110
1111 array_push( $newTags, $tag['id'] );
1112 continue;
1113 }
1114
1115 // Couldn't handle the tag, we put it back in
1116 array_push( $flatten, $tag );
1117 }
1118
1119 // Take care of the tags for the media
1120 if ( !is_array( $newTags ) )
1121 $newTags = array();
1122 $oldTags = $this->get_meta( 'media_tag', $wp_id, true );
1123 if ( !is_array( $oldTags ) )
1124 $oldTags = array();
1125 $toAdds = array_diff( $newTags, $oldTags );
1126 foreach ( $toAdds as $toAdd ) {
1127 $this->set_meta( 'media_tag', $wp_id, $toAdd );
1128 do_action( 'wplr_add_media_tag', (int)$wp_id, trim( $toAdd ) );
1129 }
1130 $toDeletes = array_diff( $oldTags, $newTags );
1131 if ( count( $toDeletes ) > 0 ) {
1132 foreach ( $toDeletes as $toDelete ) {
1133 $this->delete_meta( 'media_tag', $wp_id, $toDelete );
1134 do_action( 'wplr_remove_media_tag', (int)$wp_id, trim( $toDelete ) );
1135
1136 // Is the tag now useless?
1137 $results = $this->get_meta_from_value( 'media_tag', $toDelete, true );
1138 if ( count( $results ) < 1 ) {
1139 $this->delete_keyword( $toDelete );
1140 }
1141 }
1142 }
1143 return true;
1144 }
1145
1146 function get_exif_datetime( $path, $format = 'Y-m-d H:i:s' ) {
1147 if( empty( $path ) || !file_exists( $path ) ) {
1148 $this->log( "The file $path does not exist." );
1149 return null;
1150 }
1151
1152 if ( !function_exists( 'exif_read_data' ) ) {
1153 $this->log( "The EXIF library for PHP is not enabled." );
1154 return null;
1155 }
1156 $exif_data = null;
1157 try {
1158 $exif_data = @exif_read_data( $path );
1159 }
1160 catch ( Exception $e ) {
1161 $exif_data = null;
1162 error_log( $e->getMessage() );
1163 }
1164 if ( !empty( $exif_data ) && !empty( $exif_data[ 'DateTimeOriginal' ] ) ) {
1165 $takentime = strtotime( $exif_data[ 'DateTimeOriginal' ] );
1166 $takentime = date( $format, $takentime );
1167 return $takentime;
1168 }
1169 $this->log( "Couldn't read the EXIF DateTimeOriginal for $path." );
1170 return null;
1171 }
1172
1173 //If user prefers to use the time of the image instead of "now" in Media Library
1174 function update_media_date( $wp_id ) {
1175 if ( get_option( 'wplr_use_taken_date', false ) ) {
1176 $path = get_attached_file( $wp_id );
1177 $takentime = $this->get_exif_datetime( $path );
1178 if ( $takentime ) {
1179 $media = array(
1180 'ID' => $wp_id,
1181 'post_date' => $takentime,
1182 'post_date_gmt' => $takentime,
1183 );
1184 wp_update_post( $media );
1185 }
1186 }
1187 }
1188
1189 // This allows third-party plugins or scripts to check the existence of the files in a
1190 // different way, for instance, on a remote server.
1191 function check_file_exists( $file ) {
1192 $exists = apply_filters( 'wplr_file_exists', null, $file );
1193 if ( $exists === null )
1194 $exists = file_exists( $file );
1195 return $exists;
1196 }
1197
1198 function sync_media_update( $lrinfo, $tmp_path, $sync ) {
1199 global $wpdb;
1200 $table_name = $wpdb->prefix . "lrsync";
1201 $wp_id = $sync->wp_id;
1202 $meta = wp_get_attachment_metadata( $wp_id );
1203 $current_file = get_attached_file( $wp_id );
1204 $isSameFile = false;
1205
1206 // Check if the new file is the same as the one already uploaded
1207 if ( $this->check_file_exists( $current_file ) && get_option( 'wplr_check_same_file', false ) ) {
1208 clearstatcache();
1209 $old_size = get_transient( 'wplr-media-size-' . $wp_id );
1210 $new_size = filesize( $tmp_path );
1211 $isSameFile = strval( $old_size ) === strval( $new_size );
1212 //error_log("IS SAME FILE ? ${old_size} === ${new_size} -> " . ($isSameFile ? 'true' : 'false'));
1213 }
1214
1215 // If the file is different (or not existent), let's replace it
1216 if ( !$isSameFile ) {
1217
1218 // Support for WP Retina 2x
1219 if ( function_exists( 'wr2x_generate_images' ) )
1220 wr2x_delete_attachment( $wp_id );
1221
1222 // The file doesn't exist anymore for some reason
1223 if ( !$this->check_file_exists( $current_file ) ) {
1224 error_log( "Photo Engine: get_attached_file() returned empty. Assuming broken DB, delete link and continue." );
1225 $this->delete_attachment( $wp_id );
1226 }
1227
1228 $pathinfo = pathinfo( $current_file );
1229 if ( !isset( $pathinfo['dirname'] ) ) {
1230 error_log( "Photo Engine: pathinfo() failed in sync_media_update with " . $current_file );
1231 $this->error = __( "Could not handle the file on the server-side.", 'wplr-sync' );
1232 return false;
1233 }
1234 $basepath = $pathinfo['dirname'];
1235
1236 // Let's clean everything first
1237 if ( wp_attachment_is_image( $wp_id ) ) {
1238 $sizes = $this->get_image_sizes();
1239 foreach ($sizes as $name => $attr) {
1240 if (isset($meta['sizes'][$name]) && isset($meta['sizes'][$name]['file']) && file_exists( trailingslashit( $basepath ) . $meta['sizes'][$name]['file'] )) {
1241 $normal_file = trailingslashit( $basepath ) . $meta['sizes'][$name]['file'];
1242 $pathinfo = pathinfo( $normal_file );
1243
1244 // Support for WP Retina 2x
1245 if ( function_exists( 'wr2x_generate_images' ) )
1246 $retina_file = trailingslashit( $pathinfo['dirname'] ) . $pathinfo['filename'] . wr2x_retina_extension() . $pathinfo['extension'];
1247
1248 // Test if the file exists and if it is actually a file (and not a dir)
1249 // Some old WordPress Media Library are sometimes broken and link to directories
1250 if ( file_exists( $normal_file ) && is_file( $normal_file ) )
1251 unlink( $normal_file );
1252
1253 // Support for WP Retina 2x
1254 if ( function_exists( 'wr2x_generate_images' ) && ( file_exists( $retina_file ) && is_file( $retina_file ) ) )
1255 unlink( $retina_file );
1256 }
1257 }
1258 }
1259 if ( file_exists( $current_file ) )
1260 unlink( $current_file );
1261
1262 // Insert the new file and delete the temporary one
1263 copy( $tmp_path, $current_file );
1264 chmod( $current_file, 0644 );
1265 }
1266
1267 // Update the Upload/TakenTime Date
1268 $this->update_media_date( $wp_id );
1269
1270 // Update metadata
1271 $this->update_metadata( $wp_id, $lrinfo );
1272
1273 // If there are translations, maybe they need to be updated too!
1274 // Udate 2017/08/28: No, it's better to only keep the main media translated.
1275 // if ( $this->wpml_media_is_installed() ) {
1276 // global $sitepress;
1277 // $trid = $sitepress->get_element_trid( $wp_id, 'post_attachment' );
1278 // $translations = $sitepress->get_element_translations( $trid, 'post_attachment' );
1279 // foreach( $translations as $k => $v ) {
1280 // if ( $v->element_id != $wp_id )
1281 // $this->update_metadata( $v->element_id, $lrinfo, true );
1282 // }
1283 // }
1284
1285 if ( !$isSameFile ) {
1286
1287 // Generate the images
1288 require_once( ABSPATH . 'wp-admin/includes/image.php' );
1289 $metadata = null;
1290
1291 try {
1292 $metadata = wp_generate_attachment_metadata( $wp_id, $current_file );
1293 }
1294 catch ( Exception $e ) {
1295 $this->error = __( "Could not generate attachment metadata for " . $current_file . " ( ID: " . $wp_id . " ). Error: " . $e->getMessage(), 'wplr-sync' );
1296 return false;
1297 }
1298
1299 wp_update_attachment_metadata( $wp_id, $metadata );
1300
1301 // Support for WP Retina 2x
1302 if ( function_exists( 'wr2x_generate_images' ) )
1303 wr2x_generate_images( wp_get_attachment_metadata( $wp_id ) );
1304
1305 if ( get_option( 'wplr_check_same_file', false ) ) {
1306 set_transient( 'wplr-media-size-' . $wp_id, filesize( $current_file ) );
1307 }
1308 }
1309
1310 $wpdb->query( $wpdb->prepare( "UPDATE $table_name
1311 SET lr_file = %s, lastsync = NOW()
1312 WHERE lr_id = %d", $lrinfo->lr_file, $lrinfo->lr_id )
1313 );
1314
1315 // * If we update the media by deleting the tags, we want to sync even if empty, to remove them
1316 //if ( !empty( $lrinfo->tags ) )
1317 $this->sync_media_tags( $wp_id, $lrinfo->tags );
1318
1319 $tbl_r = $wpdb->prefix . "lrsync_relations";
1320 $gallery_ids = $wpdb->get_col( $wpdb->prepare( "SELECT wp_col_id FROM $tbl_r WHERE wp_id = %d", $wp_id ) );
1321
1322 // Increase the version number
1323 $this->increase_media_version( (int)$wp_id );
1324
1325 do_action( 'wplr_update_media', (int)$wp_id, $gallery_ids );
1326 return true;
1327 }
1328
1329 function increase_media_version( $mediaId ) {
1330 $version = get_post_meta( $mediaId, '_media_version', true );
1331 $version = $version ? intval( $version ) + 1 : 2;
1332 update_post_meta( $mediaId, '_media_version', $version );
1333 return $version;
1334 }
1335
1336 function wplr_sanitize_filename( $filename ) {
1337 if ( get_option( 'wplr_filename_accents', false ) )
1338 return $filename;
1339 $path = pathinfo( $filename );
1340 $new = preg_replace( '/.' . $path['extension'] . '$/', '', $filename );
1341 return sanitize_title( $new ) . '.' . $path['extension'];
1342 }
1343
1344 function sync_media_add( $lrinfo, $tmp_path, $userId = null ) {
1345 global $wpdb;
1346 $tbl_wplr = $wpdb->prefix . "lrsync";
1347 $upload_dir = wp_upload_dir();
1348
1349 if ( get_option( 'wplr_use_taken_date', false ) ) {
1350 if ( get_option( 'wplr_upload_folder', 'taken_date' ) === 'taken_date' ) {
1351 $date = $this->get_exif_datetime( $tmp_path, 'Y/m' );
1352 if ( $date ) {
1353 $upload_dir = wp_upload_dir( $date );
1354 }
1355 }
1356 }
1357 $newfile = wp_unique_filename( $upload_dir["path"], $this->wplr_sanitize_filename( $lrinfo->lr_file ) );
1358 $newpath = trailingslashit( $upload_dir["path"] ) . $newfile;
1359 chmod( $tmp_path, 0644 );
1360 if ( !@move_uploaded_file( $tmp_path, $newpath ) ) {
1361 $this->error = __( "Could not copy the file.", 'wplr-sync' );
1362 return false;
1363 }
1364 if ( empty( $userId ) )
1365 $userId = get_current_user_id();
1366 $wp_upload_dir = wp_upload_dir();
1367 if ( !$wp_id = wp_insert_attachment( array(
1368 'guid' => $wp_upload_dir['url'] . '/' . basename( $newpath ),
1369 'post_title' => $lrinfo->lr_title,
1370 'post_author' => $userId,
1371 'post_content' => $lrinfo->lr_desc,
1372 'post_excerpt' => $lrinfo->lr_caption,
1373 'post_mime_type' => $this->get_mime_type( $newpath ),
1374 'post_status' => "inherit",
1375 ), $newpath ) ) {
1376 $this->error = __( "Could not insert attachment for " . $newpath, 'wplr-sync' );
1377 return false;
1378 }
1379
1380 // Create Alt Text
1381 update_post_meta( $wp_id, '_wp_attachment_image_alt', $lrinfo->lr_alt_text );
1382
1383 require_once( ABSPATH . 'wp-admin/includes/image.php' );
1384 $attach_data = wp_generate_attachment_metadata( $wp_id, $newpath );
1385 wp_update_attachment_metadata( $wp_id, $attach_data );
1386
1387 // Support for WP Retina 2x
1388 if ( function_exists( 'wr2x_generate_images' ) ) {
1389 wr2x_generate_images( $attach_data );
1390 }
1391
1392 $wpdb->insert( $tbl_wplr,
1393 array(
1394 'wp_id' => $wp_id,
1395 'lr_id' => ( $lrinfo->lr_id == "" || $lrinfo->lr_id == null ) ? -1 : $lrinfo->lr_id,
1396 'lr_file' => $lrinfo->lr_file,
1397 'lastsync' => current_time( 'mysql' )
1398 )
1399 );
1400
1401 // Update the Upload/TakenTime Date
1402 $this->update_media_date( $wp_id );
1403
1404 if ( get_option( 'wplr_check_same_file', false ) ) {
1405 set_transient( 'wplr-media-size-' . $wp_id, filesize( $newpath ) );
1406 }
1407
1408 do_action( 'wplr_add_media', (int)$wp_id );
1409
1410 if ( !empty( $lrinfo->tags ) )
1411 $this->sync_media_tags( $wp_id, $lrinfo->tags );
1412
1413 return true;
1414 }
1415
1416 function sync_media( $lrinfo, $tmp_path, $wp_col_id = null, $user_id = null ) {
1417 require_once( ABSPATH . 'wp-admin/includes/media.php' );
1418 do_action( 'wplr_presync_media', $lrinfo, $tmp_path );
1419
1420 global $wpdb;
1421 $table_name = $wpdb->prefix . "lrsync";
1422 $sync_files = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE lr_id = %d", $lrinfo->lr_id ), OBJECT );
1423
1424 if ( $tmp_path == null || empty( $tmp_path ) ) {
1425 $this->error = __( "The file was not uploaded.", 'wplr-sync' );
1426 return false;
1427 }
1428
1429 // Never synced, create the attachment
1430 if ( !$sync_files ) {
1431 if ( !$this->sync_media_add( $lrinfo, $tmp_path, $user_id ) )
1432 return false;
1433 }
1434
1435 // Synced info found in DB, go through them
1436 else {
1437 $updates = 0;
1438 foreach ( $sync_files as $sync ) {
1439 if ( $this->sync_media_update( $lrinfo, $tmp_path, $sync ) )
1440 $updates++;
1441 }
1442 // In case DB is broken and no updates was made, we need to create the attachment
1443 if ( $updates == 0 ) {
1444 if ( !$this->sync_media_add( $lrinfo, $tmp_path, $user_id ) )
1445 return false;
1446 }
1447 }
1448 if ( file_exists( $tmp_path ) )
1449 unlink( $tmp_path );
1450
1451 // Returns only one result even if there are many.
1452 $sync = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE lr_id = %d", $lrinfo->lr_id ), OBJECT );
1453 $info = Meow_WPLR_Sync_LRInfo::fromRow( $sync );
1454 if ( empty( $info ) ) {
1455 $this->error = __( "The information about the media could not be retrieved.", 'wplr-sync' );
1456 return false;
1457 }
1458
1459 // Handle the collection if any
1460 if ( !is_null( $wp_col_id ) ) {
1461 $this->add_media_to_collection( $sync->wp_id, $wp_col_id );
1462 }
1463
1464 do_action( 'wplr_sync_media', $sync );
1465
1466 // Apply the order again, if needed.
1467 $this->apply_collection_order_by( $wp_col_id );
1468
1469 return $info;
1470 }
1471
1472 function get_image_sizes() {
1473 $sizes = array();
1474 global $_wp_additional_image_sizes;
1475 foreach (get_intermediate_image_sizes() as $s) {
1476 $crop = false;
1477 if (isset($_wp_additional_image_sizes[$s])) {
1478 $width = intval($_wp_additional_image_sizes[$s]['width']);
1479 $height = intval($_wp_additional_image_sizes[$s]['height']);
1480 $crop = $_wp_additional_image_sizes[$s]['crop'];
1481 } else {
1482 $width = get_option($s.'_size_w');
1483 $height = get_option($s.'_size_h');
1484 $crop = get_option($s.'_crop');
1485 }
1486 $sizes[$s] = array( 'width' => $width, 'height' => $height, 'crop' => $crop );
1487 }
1488 return $sizes;
1489 }
1490
1491 function pHashImage( $path ) {
1492 $pHash = apply_filters( 'wplr_calculate_pHash', null, $path );
1493 if ( !empty( $pHash ) )
1494 return $pHash;
1495 try {
1496 require_once( WPLR_SYNC_PATH . '/vendor/phasher.class.php' );
1497 $I = PHasher::Instance();
1498 return $I->HashAsString( $I->HashImage( $path, 0, 0, 16 ), true );
1499 }
1500 catch ( Throwable $e ) {
1501 error_log( 'PHasher error: ' . $e->getMessage() );
1502 return null;
1503 }
1504 }
1505
1506 // Returns link info for a file at this path
1507 function linkinfo_upload( $path, $meta = null, $thumbnailPath = null ) {
1508 $exif = null;
1509 if ( $meta == null) {
1510 require_once( ABSPATH . 'wp-admin/includes/image.php' );
1511 $meta = wp_read_image_metadata( $path );
1512 $exif = ( isset( $meta, $meta["created_timestamp"] ) && (int)$meta["created_timestamp"] > 0 ) ? date( "Y/m/d H:i:s", $meta["created_timestamp"] ) : null;
1513 }
1514 else if ( isset( $meta, $meta["image_meta"], $meta["image_meta"]["created_timestamp"] ) && (int)$meta["image_meta"]["created_timestamp"] > 0 ) {
1515 $exif = date( "Y/m/d H:i:s", $meta["image_meta"]["created_timestamp"] );
1516 }
1517 return array(
1518 'wp_phash' => $this->pHashImage( empty( $thumbnailPath ) ? $path : $thumbnailPath ),
1519 'wp_exif' => $exif
1520 );
1521 }
1522
1523 // Returns link info to help LR to find the original image
1524 function linkinfo_media( $wp_id ) {
1525 $wp_id = $this->wpml_original_id( $wp_id );
1526 if ( !wp_attachment_is_image( $wp_id ) ) {
1527 $this->error = __( "Attachment " . ($wp_id ? $wp_id : "[null]") . " does not exist or is not an image.", 'wplr-sync' );
1528 return false;
1529 }
1530 $attached_file = get_attached_file( $wp_id );
1531 $metadata = wp_get_attachment_metadata( $wp_id );
1532 $attached_file_thumb = isset( $metadata['sizes']['large']['file'] ) ?
1533 str_replace( wp_basename( $attached_file ), $metadata['sizes']['large']['file'], $attached_file ) : null;
1534 if ( !file_exists( $attached_file_thumb ) ) {
1535 $attached_file_thumb = null;
1536 }
1537 $linkinfo = $this->linkinfo_upload( $attached_file, $metadata, $attached_file_thumb );
1538 return array(
1539 'wp_id' => $wp_id,
1540 'wp_url' => wp_get_attachment_url( $wp_id ),
1541 'wp_phash' => $linkinfo["wp_phash"],
1542 'wp_exif' => $linkinfo["wp_exif"]
1543 );
1544 }
1545
1546 // Returns an array of wp_id linked to this lr_id
1547 function list_wpids( $lr_id ) {
1548 global $wpdb;
1549 $table_name = $wpdb->prefix . "lrsync";
1550 $wp_ids = $wpdb->get_results( $wpdb->prepare( "SELECT p.wp_id FROM $table_name p WHERE p.lr_id = %d", $lr_id ) );
1551 return $wp_ids;
1552 }
1553
1554 function list_ignored() {
1555 global $wpdb;
1556 $table_name = $wpdb->prefix . "lrsync";
1557 $posts = $wpdb->get_results(
1558 "SELECT wp_id ID
1559 FROM $table_name
1560 WHERE lr_id = 0
1561 ORDER BY wp_id DESC", OBJECT );
1562 return $posts;
1563 }
1564
1565 function list_duplicates() {
1566 global $wpdb;
1567 $table_name = $wpdb->prefix . "lrsync";
1568 $images = $wpdb->get_results(
1569 "SELECT lr.lr_id, lr.lr_file, GROUP_CONCAT(lr.wp_id SEPARATOR ',') as wpids
1570 FROM $wpdb->posts p, $table_name lr
1571 WHERE p.ID = lr.wp_id AND lr.lr_id != 0
1572 GROUP BY lr.lr_id
1573 HAVING COUNT(p.ID) > 1
1574 ORDER BY lr.lr_id DESC", OBJECT );
1575 return $images;
1576 }
1577
1578 function list_unassigned( $allfields = false, $limit = null, $skip = null, $orderBy = null, $order = null) {
1579 global $wpdb;
1580 $table_name = $wpdb->prefix . "lrsync_relations";
1581 $potentials = array();
1582
1583 $whereIsOriginal = "";
1584 if ( $this->wpml_media_is_installed() ) {
1585 global $sitepress;
1586 $tbl_wpml = $wpdb->prefix . "icl_translations";
1587 $language = $sitepress->get_default_language();
1588 $whereIsOriginal = "AND p.ID IN (SELECT element_id FROM $tbl_wpml WHERE element_type = 'post_attachment' AND language_code = '$language') ";
1589 }
1590
1591 $limitClause = "";
1592 if ($limit !== null && $skip !== null) {
1593 $limitClause = $wpdb->prepare("LIMIT %d, %d", $skip, $limit);
1594 }
1595
1596 $orderByClause = "ORDER BY p.ID DESC ";
1597 if ($orderBy !== null & $order !== null) {
1598 if ($orderBy === 'type') {
1599 $orderByClause = 'ORDER BY p.ID ' . ( $order === 'asc' ? 'ASC' : 'DESC' ) . ' ';
1600 }
1601 }
1602
1603 if ( $allfields ) {
1604 $posts = $wpdb->get_results( "SELECT * FROM $wpdb->posts p
1605 WHERE post_status = 'inherit'
1606 AND post_mime_type <> ''
1607 AND p.ID NOT IN (SELECT wp_id FROM $table_name) " .
1608 $whereIsOriginal .
1609 $orderByClause .
1610 $limitClause );
1611 }
1612 else {
1613 $posts = $wpdb->get_col( "SELECT p.ID FROM $wpdb->posts p
1614 WHERE post_status = 'inherit'
1615 AND post_mime_type <> ''
1616 AND p.ID NOT IN (SELECT wp_id FROM $table_name) " .
1617 $whereIsOriginal .
1618 $orderByClause .
1619 $limitClause );
1620 }
1621
1622 foreach ( $posts as $post ) {
1623 if ( $allfields ) {
1624 if ( !wp_attachment_is_image( $post->ID ) )
1625 continue;
1626 array_push( $potentials, $post );
1627 }
1628 else {
1629 if ( !wp_attachment_is_image( $post ) )
1630 continue;
1631 array_push( $potentials, $post );
1632 }
1633 }
1634 return $potentials;
1635 }
1636
1637 function list_unlinks( $allfields = false ) {
1638 global $wpdb;
1639 $table_name = $wpdb->prefix . "lrsync";
1640 $potentials = array();
1641
1642 $whereIsOriginal = "";
1643 if ( $this->wpml_media_is_installed() ) {
1644 global $sitepress;
1645 $tbl_wpml = $wpdb->prefix . "icl_translations";
1646 $language = $sitepress->get_default_language();
1647 $whereIsOriginal = "AND p.ID IN (SELECT element_id FROM $tbl_wpml WHERE element_type = 'post_attachment' AND language_code = '$language') ";
1648 }
1649
1650 if ( $allfields ) {
1651 $posts = $wpdb->get_results( "SELECT * FROM $wpdb->posts p
1652 WHERE post_status = 'inherit'
1653 AND post_mime_type <> ''
1654 AND p.ID NOT IN (SELECT wp_id FROM $table_name) " .
1655 $whereIsOriginal .
1656 "ORDER BY p.ID DESC" );
1657 }
1658 else {
1659 $posts = $wpdb->get_col( "SELECT p.ID FROM $wpdb->posts p
1660 WHERE post_status = 'inherit'
1661 AND post_mime_type <> ''
1662 AND p.ID NOT IN (SELECT wp_id FROM $table_name) " .
1663 $whereIsOriginal .
1664 "ORDER BY p.ID DESC" );
1665 }
1666
1667 foreach ( $posts as $post ) {
1668 if ( $allfields ) {
1669 if ( !wp_attachment_is_image( $post->ID ) )
1670 continue;
1671 array_push( $potentials, $post );
1672 }
1673 else {
1674 if ( !wp_attachment_is_image( $post ) )
1675 continue;
1676 array_push( $potentials, $post );
1677 }
1678 }
1679 return $potentials;
1680 }
1681
1682 /*****************************************************************************
1683 COLLECTIONS
1684 *****************************************************************************/
1685
1686 // Does collection contains Media ID
1687 function collection_contains( $wp_col_id, $wp_id ) {
1688 global $wpdb;
1689 $tbl_r = $wpdb->prefix . 'lrsync_relations';
1690 $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*)
1691 FROM $tbl_r
1692 WHERE wp_id = %d
1693 AND wp_col_id = %d",
1694 $wp_id, $wp_col_id )
1695 );
1696 return $count >= 1;
1697 }
1698
1699 // Set the Featured Image for the given Collection or Folder ID.
1700 function set_featured_image( $collectionId, $featuredImageId ) {
1701 global $wpdb;
1702 $tbl_col = $wpdb->prefix . 'lrsync_collections';
1703 $wpdb->query( $wpdb->prepare( "UPDATE $tbl_col
1704 SET featured_id = %d WHERE wp_col_id = %d", $featuredImageId, $collectionId )
1705 );
1706 }
1707
1708 function apply_featured_image_to_parents_folders( $col, $featured_id, $depth = 0 ) {
1709 if ( !empty( $col->wp_folder_id ) ) {
1710 $folder = $this->get_folder( $col->wp_folder_id );
1711 if ( empty( $folder->featured_id ) ) {
1712 $this->set_featured_image( $folder->wp_col_id, $featured_id );
1713 }
1714 if ( $depth < 10 ) {
1715 $this->apply_featured_image_to_parents_folders( $folder, $featured_id, $depth++ );
1716 }
1717 }
1718 }
1719
1720 function add_media_to_collection( $wp_id, $wp_col_id, $sort = 0 ) {
1721 global $wpdb;
1722 $tbl_r = $wpdb->prefix . 'lrsync_relations';
1723 $tbl_col = $wpdb->prefix . 'lrsync_collections';
1724 if ( !$this->collection_contains( $wp_col_id, $wp_id ) ) {
1725
1726 $inserted = $wpdb->insert( $tbl_r,
1727 array( 'wp_col_id' => $wp_col_id, 'wp_id' => $wp_id, 'sort' => $sort ),
1728 array( '%d', '%d', '%s' )
1729 );
1730
1731 if ( $inserted ) {
1732 // Manage the Featured Image ID automatically (if it is empty)
1733 $collection = $this->get_collection( $wp_col_id );
1734 $featured_id = empty( $collection->featured_id ) ? $wp_id : $collection->featured_id;
1735 $this->apply_featured_image_to_parents_folders( $collection, $featured_id );
1736
1737 // Update the Featured Image
1738 $this->set_featured_image( $wp_col_id, $featured_id );
1739
1740 // Update the Last Sync
1741 $wpdb->query( $wpdb->prepare( "UPDATE $tbl_col SET lastsync = %s
1742 WHERE wp_col_id = %d", current_time( 'mysql' ), $wp_col_id )
1743 );
1744
1745 if ( $wp_col_id > -1 )
1746 do_action( "wplr_add_media_to_collection", (int)$wp_id, (int)$wp_col_id );
1747 }
1748 else {
1749 $this->error = __( "Could not add media to collection.", 'wplr-sync' );
1750 return false;
1751 }
1752 }
1753 }
1754
1755 function remove_media_from_collection( $wp_id, $wp_col_id ) {
1756 global $wpdb;
1757 $tbl_r = $wpdb->prefix . 'lrsync_relations';
1758 $tbl_col = $wpdb->prefix . 'lrsync_collections';
1759 if ( !is_null( $wp_col_id ) ) {
1760 $wpdb->query( $wpdb->prepare( "DELETE FROM $tbl_r WHERE wp_id = %d AND wp_col_id = %d", $wp_id, $wp_col_id ) );
1761 if ( $wp_col_id >= 0 ) {
1762 $wpdb->query( $wpdb->prepare( "UPDATE $tbl_col
1763 SET lastsync = %s
1764 WHERE wp_col_id = %d", current_time( 'mysql' ), $wp_col_id )
1765 );
1766 do_action( 'wplr_remove_media_from_collection', (int)$wp_id, (int)$wp_col_id );
1767 }
1768 return true;
1769 }
1770 return false;
1771 }
1772
1773 function create_collection( $type = 'collection', $name = '', $parent_folder = null, $source = 'wp', $lr_col_id = null ) {
1774 global $wpdb;
1775 $tbl_col = $wpdb->prefix . 'lrsync_collections';
1776 $slug = $this->make_slug_unique( -1, sanitize_title( $name ) );
1777
1778 // Create the collection or folder
1779 $success = $wpdb->insert( $tbl_col,
1780 array(
1781 'source' => $source,
1782 'lr_col_id' => $lr_col_id,
1783 'is_folder' => $type == 'folder' ? 1 : 0,
1784 'name' => htmlspecialchars( $name, ENT_QUOTES, 'UTF-8' ),
1785 'slug' => $slug,
1786 'lastsync' => current_time( 'mysql' )
1787 ),
1788 array( '%s', '%d', '%d', '%s', '%s' )
1789 );
1790
1791 // Set the parent for this collection or folder (if there is any)
1792 if ( $success ) {
1793 $wp_col_id = $wpdb->insert_id;
1794 if ( !is_null( $parent_folder ) ) {
1795 $wpdb->query( $wpdb->prepare( "UPDATE $tbl_col
1796 SET wp_folder_id = %s
1797 WHERE wp_col_id = %d", $parent_folder, $wp_col_id )
1798 );
1799 }
1800 do_action( "wplr_create_$type", (int)$wp_col_id, (int)$parent_folder, array( 'name' => $name ) );
1801 return $this->get_collection( $wp_col_id );
1802 }
1803 else {
1804 $this->error = __( "Could not create the folder or collection.", 'wplr-sync' );
1805 return false;
1806 }
1807 }
1808
1809 function make_slug_unique( $col_id, $slug, $counter = null ) {
1810 global $wpdb;
1811 $slug = is_null( $counter ) ? $slug : ($slug . '-' . $counter);
1812 $tbl_col = $wpdb->prefix . 'lrsync_collections';
1813 $exists = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $tbl_col
1814 WHERE wp_col_id <> %d
1815 AND slug = %s", $col_id, $slug ) );
1816 if ( $exists ) {
1817 $counter = is_null( $counter ) ? 1 : $counter + 1;
1818 $slug = $this->make_slug_unique( $col_id, $slug, $counter );
1819 }
1820 return $slug;
1821 }
1822
1823 function update_collection( $wp_col_id, $name = '', $slug = '' ) {
1824 global $wpdb;
1825 $tbl_col = $wpdb->prefix . 'lrsync_collections';
1826 $current = $this->get_collection( $wp_col_id );
1827 $type = $current->is_folder ? 'folder' : 'collection';
1828 $slug = $this->make_slug_unique( $wp_col_id, empty( $slug ) ? sanitize_title( $name ) : $slug );
1829
1830 // If name is different, we update it
1831 if ( $name != $current->name ) {
1832 $wpdb->query( $wpdb->prepare( "UPDATE $tbl_col
1833 SET name = %s, slug = %s, lastsync = %s
1834 WHERE wp_col_id = %d", $name, $slug, current_time( 'mysql' ), $current->wp_col_id )
1835 );
1836 do_action( "wplr_update_$type" . ( $current->is_folder ? 'folder' : 'gallery' ),
1837 (int)$current->wp_col_id, array( 'name' => $name ) );
1838 }
1839 }
1840
1841 function move_collection( $wp_col_id, $parent_folder = null ) {
1842 global $wpdb;
1843 $tbl_col = $wpdb->prefix . 'lrsync_collections';
1844 $current = $this->get_collection( $wp_col_id );
1845 $type = $current->is_folder ? 'folder' : 'collection';
1846
1847 // If parent folder is different, we update it
1848 if ( $parent_folder != $current->wp_folder_id ) {
1849 if ( is_null( $parent_folder ) )
1850 $wpdb->query( $wpdb->prepare( "UPDATE $tbl_col SET wp_folder_id = NULL WHERE wp_col_id = %d", $current->wp_col_id ) );
1851 else
1852 $wpdb->query( $wpdb->prepare( "UPDATE $tbl_col SET wp_folder_id = %d WHERE wp_col_id = %d", $parent_folder, $current->wp_col_id ) );
1853 do_action( "wplr_move_$type", (int)$current->wp_col_id, (int)$parent_folder, (int)$current->wp_folder_id );
1854 }
1855 }
1856
1857 function collection_checks( $collection ) {
1858 if ( empty( $collection ) ) {
1859 $this->log("Empty collection found, skipping." );
1860 $this->error = __( "Collection is empty.", 'wplr-sync' );
1861 return false;
1862 }
1863
1864 if ( empty( $collection->name ) ) {
1865 $this->log("Collection name is empty, skipping." );
1866 $this->error = __( "Collection name is empty.", 'wplr-sync' );
1867 return false;
1868 }
1869
1870 if ( $collection->type != 'folder' && $collection->type != 'collection' ) {
1871 $this->log("Collection type is invalid, skipping." );
1872 $this->error = __( "Collection type is invalid.", 'wplr-sync' );
1873 return false;
1874 }
1875
1876 return true;
1877 }
1878
1879 function sync_collection( $collections, $source = 'lr' ) {
1880 global $wpdb;
1881 $folder = null;
1882 foreach ( $collections as &$collection ) {
1883 // Basic checks
1884 if ( !$this->collection_checks( $collection ) ) continue;
1885
1886
1887 $type = $collection->type == 'folder' ? 'folder' : 'collection';
1888
1889 $parent_folder = null;
1890 if ( !empty( $folder ) && !empty( $folder->wp_col_id ) ) {
1891 $parent_folder = (int)$folder->wp_col_id;
1892 }
1893
1894 // Get the collection if it already exists
1895 $row = empty( $collection->wp_col_id ) ? null : $this->get_collection( $collection->wp_col_id, $collection->lr_col_id );
1896
1897 if ( empty( $row ) ) {
1898 // Collection needs to be created in DB.
1899 $collection = $this->create_collection( $type, $collection->name, $parent_folder, $source, $collection->lr_col_id );
1900 }
1901 else {
1902 // Collection exists in DB, check for changes.
1903 $collection->wp_col_id = $row->wp_col_id;
1904 // It's a bit stupid to call those two functions, we should clean then and call them
1905 // only when really needed.
1906 $this->update_collection( $collection->wp_col_id, $collection->name );
1907 $this->move_collection( $collection->wp_col_id, $parent_folder );
1908 }
1909 $folder = $collection;
1910 }
1911 return $collections;
1912 }
1913
1914 private $maxdepth = 100;
1915 private $currentdepth = 0;
1916
1917 function delete_collection_recursively( $tbl_col, $tbl_r, $tbl_lr, $wp_col_id ) {
1918 global $wpdb;
1919 if ( $this->currentdepth++ > $this->maxdepth ) {
1920 error_log( "Photo Engine: delete_collection_recursively() reached maxdepth." );
1921 return false;
1922 }
1923 $children = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT(wp_col_id) FROM $tbl_col WHERE wp_folder_id = %d", $wp_col_id ) );
1924 foreach ( $children as $kid ) {
1925 $res = $this->delete_collection_recursively( $tbl_col, $tbl_r, $tbl_lr, $kid );
1926 if ( !$res )
1927 return false;
1928 }
1929
1930 // For Lightroom!
1931 // Lists all the LR IDs linked to that collection.
1932 // So that doesn't count the images which were dropped in this collection without a LR ID.
1933 $lr_ids = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT(lr_id) FROM $tbl_r r
1934 INNER JOIN $tbl_lr l ON r.wp_id = l.wp_id WHERE r.wp_col_id = %d", $wp_col_id ) );
1935 if ( !empty( $lr_ids ) ) {
1936 foreach ( $lr_ids as $lr_id ) {
1937 if ( !$this->delete_media( $lr_id, $wp_col_id ) ) {
1938 return false;
1939 }
1940 }
1941 }
1942
1943 // For PhotoEngine!
1944 // List all the WP IDs left for this collection.
1945 $wp_ids = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT(wp_id) FROM $tbl_r r
1946 WHERE r.wp_col_id = %d", $wp_col_id ) );
1947 if ( !empty( $wp_ids ) ) {
1948 foreach ( $wp_ids as $wp_id ) {
1949 if ( !$this->remove_media_from_collection( $wp_id, $wp_col_id ) ) {
1950 return false;
1951 }
1952 }
1953 }
1954
1955 $collection = $wpdb->get_row( $wpdb->prepare( "SELECT wp_col_id, is_folder FROM $tbl_col
1956 WHERE wp_col_id = %d", $wp_col_id ), OBJECT, 0 );
1957 if ( !empty( $collection ) ) {
1958 $type = $collection->is_folder ? 'folder' : 'collection';
1959 do_action( "wplr_remove_{$type}", (int)$wp_col_id );
1960 $wpdb->query( $wpdb->prepare( "DELETE FROM $tbl_col WHERE wp_col_id = %d", $wp_col_id ) );
1961 }
1962 return true;
1963 }
1964
1965 function delete_collection( $wp_col_id ) {
1966 global $wpdb;
1967 $folder = null;
1968 $tbl_col = $wpdb->prefix . 'lrsync_collections';
1969 $tbl_r = $wpdb->prefix . 'lrsync_relations';
1970 $tbl_lr = $wpdb->prefix . 'lrsync';
1971 $currentdepth = 0;
1972 $result = $this->delete_collection_recursively( $tbl_col, $tbl_r, $tbl_lr, $wp_col_id );
1973 return $result;
1974 }
1975
1976 // Set the meta 'collection_order' for the collection
1977 // Values can be: 'date-asc', 'date-desc' or 'name'.
1978 // This value be used by other plugins to apply the order.
1979 function order_collection_by( $wp_col_id, $order = null ) {
1980 if ( empty( $wp_col_id ) )
1981 return true;
1982 if ( empty( $order ) )
1983 $this->delete_meta( 'collection_order', $wp_col_id );
1984 else {
1985 $this->set_meta( 'collection_order', $wp_col_id, $order, true );
1986 $this->apply_collection_order_by( $wp_col_id );
1987 }
1988 return true;
1989 }
1990
1991 // In the case the meta 'collection_order' is set, Photo Engine can
1992 // re-organize the order of the images by calling this function.
1993 function apply_collection_order_by( $wp_col_id ) {
1994 global $wpdb;
1995 $orderBy = $this->get_meta( 'collection_order', $wp_col_id );
1996 $sqlOrderBy = '';
1997 if ( $orderBy === 'name-asc' )
1998 $sqlOrderBy = ' ORDER BY p.post_title ASC';
1999 else if ( $orderBy === 'date-asc' )
2000 $sqlOrderBy = ' ORDER BY p.post_date ASC';
2001 else if ( $orderBy === 'date-desc' )
2002 $sqlOrderBy = ' ORDER BY p.post_date DESC';
2003
2004 if ( !empty( $sqlOrderBy ) ) {
2005 $tbl_r = $wpdb->prefix . 'lrsync';
2006 $wpIds = $this->get_media_from_collection( $wp_col_id );
2007 if ( !empty( $wpIds ) ) {
2008 $wpIdsPlaceHolders = array_fill( 0, count( $wpIds ), '%d' );
2009 $wpIdsPlaceHolders = implode( ', ', $wpIdsPlaceHolders );
2010 $query = $wpdb->prepare( "SELECT lr.lr_id
2011 FROM $wpdb->posts p
2012 INNER JOIN $tbl_r lr
2013 ON lr.wp_id = p.ID
2014 WHERE p.ID IN ($wpIdsPlaceHolders)" . $sqlOrderBy, $wpIds );
2015 $lrIds = $wpdb->get_col( $query );
2016 if ( !empty( $lrIds ) ) {
2017 $this->order_collection( $wp_col_id, $lrIds );
2018 }
2019 }
2020 }
2021 }
2022
2023 function order_collection( $wp_col_id, $lr_ids ) {
2024 if ( empty( $wp_col_id ) )
2025 return true;
2026 global $wpdb;
2027 $tbl_r = $wpdb->prefix . 'lrsync_relations';
2028 $count = 0;
2029 $mediaIds = array();
2030 foreach ( $lr_ids as $lr_id ) {
2031 $info = $this->get_sync_info_from_lr_id( $lr_id );
2032 if ( !empty( $info ) ) {
2033 $wpdb->query( $wpdb->prepare( "UPDATE $tbl_r SET sort = %d WHERE wp_col_id = %d AND wp_id = %d",
2034 $count, $wp_col_id, $info->wp_id ) );
2035 array_push( $mediaIds, $info->wp_id );
2036 }
2037 else {
2038 error_log( "Could not find information for LR ID $lr_id while ordering the collection." );
2039 }
2040 $count++;
2041 }
2042 do_action( "wplr_order_collection", $mediaIds, (int)$wp_col_id );
2043 return true;
2044 }
2045
2046 /*****************************************************************************
2047 USEFUL FUNCTIONS
2048 *****************************************************************************/
2049
2050 function get_upload_root()
2051 {
2052 $uploads = wp_upload_dir();
2053 return $uploads['basedir'];
2054 }
2055
2056 // Converts PHP INI size type (e.g. 24M) to int
2057 function parse_ini_size( $size ) {
2058 $unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
2059 $size = preg_replace('/[^0-9\.]/', '', $size);
2060 if ( $unit )
2061 return round( $size * pow( 1024, stripos( 'bkmgtpezy', $unit[0] ) ) );
2062 else
2063 round( $size );
2064 }
2065
2066 // This function should not work even with HVVM
2067 function b64_to_file( $str ) {
2068
2069 // From version 1.3.4 (use uploads folder for tmp):
2070 if ( !file_exists( trailingslashit( $this->get_upload_root() ) . "wplr-tmp" ) )
2071 mkdir( trailingslashit( $this->get_upload_root() ) . "wplr-tmp" );
2072 $file = tempnam( trailingslashit( $this->get_upload_root() ) . "wplr-tmp", "wplr_" );
2073
2074 // Before version 1.3.4:
2075 //$file = tempnam( sys_get_temp_dir(), "wplr" );
2076
2077 $ifp = fopen( $file, "wb" );
2078 fwrite( $ifp, base64_decode( $str ) );
2079 fclose( $ifp );
2080 chmod( $file, 0664 );
2081 return $file;
2082 }
2083
2084 /*****************************************************************************
2085 POST TYPE / COLLECTION RELATED COLUMN
2086 *****************************************************************************/
2087
2088 function html_for_collection( $collection_id ) {
2089 $sync = $this->get_collection( $collection_id );
2090 $html = "";
2091 if ( !$sync ) {
2092 $html .= "<div>" . __( "Unknown", 'wplr-sync' ) . "</div>";
2093 }
2094 else {
2095 $name = $sync->name;
2096 $html .= "<div style='color: #006EFF;'>" . __( "Enabled", 'wplr-sync' ) . "</div>";
2097 if ( !strtotime( $sync->lastsync ) || $sync->lastsync == "0000-00-00 00:00:00" )
2098 $html .= "<div style='color: #0BF;'><small>" . __( "Never synced.", 'wplr-sync' ) . "</small></div>";
2099 else {
2100 if ( date('Ymd') == date('Ymd', strtotime( $sync->lastsync ) ) ) {
2101 $html .= "<div><small>" .
2102 sprintf( __( "Synced at %s with <i>$name</i>.", 'wplr-sync' ), date("g:ia", strtotime( $sync->lastsync ) ) ) .
2103 "</small></div>";
2104 }
2105 else {
2106 $html .= "<div><small>" .
2107 sprintf( __( "Synced at %s with <i>$name</i>.", 'wplr-sync' ), date("Y/m/d", strtotime( $sync->lastsync ) ) ) .
2108 "</small></div>";
2109 }
2110 }
2111 //$html .= "<div><small>LR COL ID: " . $sync->lr_col_id . "</small></div>";
2112 }
2113 return $html;
2114 }
2115
2116 /*****************************************************************************
2117 MEDIA LIBRARY COLUMN
2118 *****************************************************************************/
2119
2120 function html_for_media( $wpid, $sync = null ) {
2121 $wpid = $this->wpml_original_id($wpid);
2122 $html = "";
2123 if ( !$sync ) {
2124 $html .= "<div>" . __( "Unknown", 'wplr-sync' ) . "</div>";
2125 $html .= "<div>
2126 <small>LR ID:
2127 <input type='text' class='wplr-sync-lrid-input wplrsync-link-" . $wpid . "'></input>
2128 <span class='wplr-button' onclick='wplrsync_link($wpid)'>" . __( "Link", 'wplr-sync' ) . "</span>
2129 </small></div>";
2130 }
2131 else {
2132 if ( $sync->lr_id > 0 ) {
2133 $html .= "<div style='color: #006EFF;'>" . __( "Enabled", 'wplr-sync' ) . "</div>";
2134
2135 if ( !strtotime( $sync->lastsync ) || $sync->lastsync == "0000-00-00 00:00:00" )
2136 $html .= "<div style='color: #0BF;'><small>" . __( "Never synced.", 'wplr-sync' ) . "</small></div>";
2137 else {
2138 if ( date('Ymd') == date('Ymd', strtotime( $sync->lastsync ) ) ) {
2139 $html .= "<div><small>" .
2140 sprintf( __( "Synced at %s", 'wplr-sync' ), date("g:ia", strtotime( $sync->lastsync ) ) ) .
2141 "</small></div>";
2142 }
2143 else {
2144 $html .= "<div><small>" .
2145 sprintf( __( "Synced at %s", 'wplr-sync' ), date("Y/m/d", strtotime( $sync->lastsync ) ) ) .
2146 "</small></div>";
2147 }
2148 }
2149 $html .= "<div><small>LR ID: " . $sync->lr_id . "</small></div>";
2150 }
2151 else if ( $sync->lr_id == 0 ) {
2152 $html .= "<div style='color: gray;'>" . __( "Ignored", 'wplr-sync' ) . "</div>";
2153 }
2154 $html .= "<small><span class='wplr-link-undo' onclick='wplrsync_unlink($sync->lr_id, $wpid)'>" .
2155 __( "(undo)", 'wplr-sync' ) .
2156 "</span></small>";
2157 }
2158 return $html;
2159 }
2160
2161 function wplrsync_unlink() {
2162 $this->admin->wp_ajax_auth_check( 'wp_ajax_wplrsync_unlink' );
2163 $this->wplrsync_ajax_link_unlink(true);
2164 }
2165
2166 function wplrsync_link() {
2167 $this->admin->wp_ajax_auth_check( 'wp_ajax_wplrsync_link' );
2168 $this->wplrsync_ajax_link_unlink();
2169 }
2170
2171 function wplrsync_ajax_link_unlink( $is_unlink = false ) {
2172 if ( !current_user_can('upload_files') ) {
2173 echo json_encode( array( 'success' => false, 'message' => "You do not have the roles to perform this action." ) );
2174 die;
2175 }
2176 if ( !isset( $_POST['lr_id'] ) || $_POST['lr_id'] == "" || !isset( $_POST['wp_id'] ) || empty( $_POST['wp_id'] ) ) {
2177 echo json_encode( array( 'success' => false, 'message' => "Some information is missing." ) );
2178 die;
2179 }
2180
2181 $lr_id = intval( $_POST['lr_id'] );
2182 $wp_id = $this->wpml_original_id( intval( $_POST['wp_id'] ) );
2183
2184 $sync = null;
2185 if ( $is_unlink ) {
2186
2187 if ( $this->unlink_media( $lr_id, $wp_id ) ) {
2188 echo json_encode( array(
2189 'success' => true,
2190 'html' => $this->html_for_media( $wp_id, null )
2191 ) );
2192 }
2193 else {
2194 echo json_encode( array(
2195 'success' => false,
2196 'message' => $this->error || "Unknown error."
2197 ) );
2198 }
2199 }
2200 else {
2201 $sync = $this->link_media( $lr_id, $wp_id );
2202 if ( $sync ) {
2203 echo json_encode( array(
2204 'success' => true,
2205 'html' => $this->html_for_media( $wp_id, $sync )
2206 ) );
2207 }
2208 else {
2209 echo json_encode( array(
2210 'success' => false,
2211 'message' => $this->error || "Unknown error."
2212 ) );
2213 }
2214 }
2215 die();
2216 }
2217
2218 function admin_head() {
2219 echo '
2220 <style type="text/css">
2221
2222 .wplr-button {
2223 background: #3E79BB;
2224 color: white;
2225 display: inline;
2226 padding: 2px 8px;
2227 text-transform: uppercase;
2228 margin-left: 1px;
2229 flex: 1;
2230 text-align: center;
2231 }
2232
2233 .wplr-button:hover {
2234 cursor: pointer;
2235 background: #5D93CF;
2236 }
2237
2238 .wplr-link-undo {
2239 color: #5E5E5E;
2240 }
2241
2242 .wplr-link-undo:hover {
2243 cursor: pointer;
2244 color: #2ea2cc;
2245 }
2246
2247 .wplr-sync-info {
2248 line-height: 14px;
2249 }
2250
2251 .wplr-sync-lrid-input {
2252 width: 56px;
2253 font-size: 10px;
2254 font-weight: bold;
2255 color: black !important;
2256 }
2257
2258 </style>
2259
2260 <script>
2261
2262 function wplrsync_handle_response( wp_id, response ) {
2263 reply = jQuery.parseJSON(response);
2264 if ( reply.success ) {
2265 // Remove box (if in WP/LR Dashboard)
2266 jQuery("#wplr-image-box-" + wp_id).remove();
2267 // Update row (if in Media Library)
2268 jQuery(".wplrsync-media-" + wp_id).html(reply.html);
2269 }
2270 else {
2271 alert(reply.message);
2272 }
2273 }
2274
2275 function wplrsync_unlink( lr_id, wp_id ) {
2276 var data = { action: "wplrsync_unlink", lr_id: lr_id, wp_id: wp_id };
2277 jQuery.post(ajaxurl, data, function (response) {
2278 wplrsync_handle_response( wp_id, response );
2279 });
2280 }
2281
2282 function wplrsync_link( wp_id, ignore ) {
2283 if (!ignore) {
2284 lr_id = jQuery(".wplrsync-link-" + wp_id).val();
2285 }
2286 else {
2287 lr_id = 0;
2288 }
2289 var data = { action: "wplrsync_link", lr_id: lr_id, wp_id: wp_id };
2290 jQuery.post(ajaxurl, data, function (response) {
2291 wplrsync_handle_response( wp_id, response );
2292 });
2293 }
2294 </script>
2295 ';
2296 }
2297
2298 function manage_media_columns( $cols ) {
2299 $cols["WPLRSync"] = "LR Sync";
2300 return $cols;
2301 }
2302
2303 function manage_media_custom_column( $column_name, $wpid ) {
2304 if ( $column_name != 'WPLRSync' )
2305 return;
2306 $meta = wp_get_attachment_metadata( $wpid );
2307 if ( !($meta && isset( $meta['width'] ) && isset( $meta['height'] )) ) {
2308 return;
2309 }
2310 $info = $this->get_sync_info( $wpid );
2311 $lr_id = empty( $info ) ? null : $info->lr_id;
2312 $lastsync = empty( $info ) ? null : $info->lastsync;
2313 echo '<div class="wplr-sync-field" data-wp-id="' . $wpid . '" data-lr-id="' .
2314 $lr_id . '" data-lastsync="' . $lastsync . '" data-is-server-side="true"></div>';
2315 }
2316
2317 /*****************************************************************************
2318 HELPERS FOR TAXONOMIES MANAGEMENT
2319 USED BY KEYWORDS (CORE) AND POST TYPES (EXTENSION)
2320 *****************************************************************************/
2321
2322 function create_taxonomy( $keywordId, $inKeywordId, $keyword, $taxonomy, $metaKey ) {
2323 global $wplr;
2324
2325 $is_term_exists = false;
2326
2327 $term = get_term_by( 'name', $keyword['name'], $taxonomy );
2328 if ( !empty( $term ) ) {
2329 $wplr->set_meta( $metaKey, $keywordId, $term->term_id, true );
2330 $is_term_exists = true;
2331 }
2332
2333 // Create term
2334 if ( !$is_term_exists ) {
2335 $parentTermId = null;
2336 if ( !empty( $inKeywordId ) && is_taxonomy_hierarchical( $taxonomy ) )
2337 $parentTermId = $wplr->get_meta( $metaKey, $inKeywordId );
2338 $result = wp_insert_term( $keyword['name'], $taxonomy, $parentTermId ? array( 'parent' => $parentTermId ) : null );
2339 if ( is_wp_error( $result ) ) {
2340 error_log( "Issue while creating the keyword " . $keyword['name'] . "." );
2341 error_log( $result->get_error_message() );
2342 return;
2343 }
2344 $wplr->set_meta( $metaKey, $keywordId, $result['term_id'], true );
2345 }
2346 }
2347
2348 function update_taxonomy( $folderId, $folder, $taxonomy, $metaKey ) {
2349 global $wplr;
2350 $termId = $wplr->get_meta( $metaKey, $folderId );
2351 wp_update_term( $termId, $taxonomy, array( 'name' => $folder['name'] ) );
2352 }
2353
2354 // Move the folder (category) under another one.
2355 // If the folder is empty, then it is the root.
2356 function move_taxonomy( $folderId, $inFolderId, $taxonomy, $metaKey ) {
2357 global $wplr;
2358 $termId = $wplr->get_meta( $metaKey, $folderId );
2359 $parentTermId = null;
2360 if ( !empty( $inFolderId ) )
2361 $parentTermId = $wplr->get_meta( $metaKey, $inFolderId );
2362 wp_update_term( $termId, $taxonomy, array( 'parent' => $parentTermId ) );
2363 }
2364
2365 function remove_taxonomy( $folderId, $taxonomy, $postType, $metaKey ) {
2366 global $wplr;
2367 $id = $wplr->get_meta( $metaKey, $folderId );
2368 $objs = get_objects_in_term( $id, $taxonomy );
2369 $args = array(
2370 'post_type' => $postType,
2371 'tax_query' => array(
2372 array( 'taxonomy' => $taxonomy, 'field' => 'id', 'terms' => (int)$id )
2373 )
2374 );
2375 $query = new WP_Query( $args );
2376 if ( $query->found_posts < 1 ) {
2377 $r = wp_delete_term( $id, $taxonomy );
2378 if ( is_wp_error( $r ) ) {
2379 error_log( "Issue while deleting the folder " . $folderId . "." );
2380 error_log( $r->get_error_message() );
2381 return;
2382 }
2383 $wplr->delete_meta( $metaKey, $folderId );
2384 }
2385 }
2386
2387 // If postMetaKey is null, then we consider the postId is the ID
2388 // of the post type already (good for Media in Keywords)
2389 function add_taxonomy_to_posttype( $folderId, $collectionId, $taxonomy, $postMetaKey, $termMetaKey ) {
2390 global $wplr;
2391 $term = $this->get_term_from_folder( $folderId, $taxonomy, $termMetaKey );
2392 if ( !empty( $term ) ) {
2393 $postId = empty( $postMetaKey ) ? $collectionId : $wplr->get_meta( $postMetaKey, $collectionId );
2394 if ( empty( $postId ) ) {
2395 error_log( "Cannot find the post for $collectionId (postMetaKey: $postMetaKey)." );
2396 return;
2397 }
2398 $terms = wp_get_post_terms( $postId, $taxonomy, array( 'fields' => 'ids' ) );
2399 $terms[] = $term->term_id;
2400 $r = wp_set_post_terms( $postId, $terms, $taxonomy );
2401 if ( is_wp_error( $r ) )
2402 error_log( $r->get_error_message() );
2403 }
2404 else {
2405 error_log( "Could not add taxonomy $folderId to posttype $collectionId (taxonomy: $taxonomy, pm: $postMetaKey, tm: $termMetaKey)." );
2406 }
2407 }
2408
2409 // If postMetaKey is null, then we consider the postId is the ID
2410 // of the post type already (good for Media in Keywords)
2411 function remove_taxonomy_from_posttype( $folderId, $collectionId, $taxonomy, $postMetaKey, $termMetaKey ) {
2412 global $wplr;
2413 if ( empty( $folderId ) )
2414 return;
2415 $postId = empty( $postMetaKey ) ? $collectionId : $wplr->get_meta( $postMetaKey, $collectionId );
2416 if ( empty( $postId ) ) {
2417 error_log( "Cannot find the post for $collectionId (postMetaKey: $postMetaKey)." );
2418 return;
2419 }
2420 $folderId = empty( $folderId ) ? null : $wplr->get_meta( $termMetaKey, $folderId );
2421 if ( empty( $folderId ) ) {
2422 //error_log( "Cannot find the related term for folder $folderId." );
2423 return;
2424 }
2425 $r = wp_remove_object_terms( (int)$postId, (int)$folderId, $taxonomy );
2426 if ( is_wp_error( $r ) )
2427 error_log( $r->get_error_message() );
2428 }
2429
2430 function get_term_from_folder( $folderId, $taxonomy, $termMetaKey ) {
2431 global $wplr;
2432 if ( empty( $folderId ) )
2433 return;
2434 $parentTermId = $wplr->get_meta( $termMetaKey, $folderId );
2435 if ( empty( $parentTermId ) ) {
2436 error_log( "Cannot find the term for $folderId." );
2437 return;
2438 }
2439 $term = get_term_by( 'term_id', $parentTermId, $taxonomy );
2440 if ( empty( $term ) ) {
2441 error_log( "Cannot find information for the term $parentTermId (folder: $folderId, termMetaKey: $termMetaKey, taxonomy: $taxonomy)." );
2442 return;
2443 }
2444 return $term;
2445 }
2446
2447 /**
2448 *
2449 * Roles & Access Rights
2450 *
2451 */
2452 public function can_access_settings() {
2453 return apply_filters( 'wplr_allow_setup', current_user_can( 'manage_options' ) );
2454 }
2455
2456 public function can_access_features() {
2457 return apply_filters( 'wplr_allow_usage', current_user_can( 'upload_files' ) );
2458 }
2459
2460 }
2461
2462 ?>
2463