PluginProbe ʕ •ᴥ•ʔ
Responsive Lightbox & Gallery / 2.4.4
Responsive Lightbox & Gallery v2.4.4
2.7.8 trunk 1.0.0 1.0.1 1.0.1.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4.0 1.4.0.1 1.4.1 1.4.11 1.4.12 1.4.13 1.4.14 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3.1 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7
responsive-lightbox / includes / class-folders.php
responsive-lightbox / includes Last commit date
providers 3 years ago class-fast-image.php 3 years ago class-folders-walker.php 7 years ago class-folders.php 3 years ago class-frontend.php 3 years ago class-galleries.php 3 years ago class-multilang.php 3 years ago class-remote-library-api.php 3 years ago class-remote-library.php 3 years ago class-settings.php 3 years ago class-tour.php 3 years ago class-welcome.php 3 years ago class-widgets.php 3 years ago functions.php 3 years ago
class-folders.php
1349 lines
1 <?php
2 // exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) )
4 exit;
5
6 /**
7 * Responsive Lightbox folders class.
8 *
9 * @class Responsive_Lightbox_Folders
10 */
11 class Responsive_Lightbox_Folders {
12
13 private $mode = '';
14 private $term_counters = [
15 'keys' => [],
16 'values' => []
17 ];
18 private $allowed_select_html = [
19 'select' => [
20 'name' => [],
21 'id' => [],
22 'class' => [],
23 'required' => [],
24 'tabindex' => [],
25 'aria-describedby' => []
26 ],
27 'option' => [
28 'value' => [],
29 'class' => [],
30 'selected' => []
31 ]
32 ];
33
34 /**
35 * Class constructor.
36 *
37 * @param bool $read_only Whether plugin is in read only mode
38 * @return void
39 */
40 public function __construct( $read_only = false ) {
41 // set instance
42 Responsive_Lightbox()->folders = $this;
43
44 // allow to load old taxonomies even in read only mode
45 add_action( 'wp_ajax_rl-folders-load-old-taxonomies', [ $this, 'load_old_taxonomies' ] );
46
47 if ( $read_only )
48 return;
49
50 // actions
51 add_action( 'init', [ $this, 'detect_library_mode' ], 11 );
52 add_action( 'restrict_manage_posts', [ $this, 'restrict_manage_posts' ] );
53 add_action( 'wp_enqueue_media', [ $this, 'add_library_scripts' ] );
54 add_action( 'admin_enqueue_scripts', [ $this, 'add_library_scripts' ] );
55 add_action( 'pre-upload-ui', [ $this, 'pre_upload_ui' ] );
56 add_action( 'post-upload-ui', [ $this, 'post_upload_ui' ] );
57 add_action( 'add_attachment', [ $this, 'add_attachment' ] );
58 add_action( 'wp_ajax_save-attachment-compat', [ $this, 'ajax_save_attachment_compat' ], 0 );
59 add_action( 'wp_ajax_rl-folders-delete-term', [ $this, 'delete_term' ] );
60 add_action( 'wp_ajax_rl-folders-rename-term', [ $this, 'rename_term' ] );
61 add_action( 'wp_ajax_rl-folders-add-term', [ $this, 'add_term' ] );
62 add_action( 'wp_ajax_rl-folders-move-term', [ $this, 'move_term' ] );
63 add_action( 'wp_ajax_rl-folders-move-attachments', [ $this, 'move_attachments' ] );
64
65 // filters
66 add_filter( 'admin_body_class', [ $this, 'admin_body_class' ] );
67 add_filter( 'parse_query', [ $this, 'parse_query' ] );
68 add_filter( 'ajax_query_attachments_args', [ $this, 'ajax_query_attachments_args' ] );
69 add_filter( 'attachment_fields_to_edit', [ $this, 'attachment_fields_to_edit' ], 10, 2 );
70 add_filter( 'rl_count_attachments', [ $this, 'count_attachments' ], 10 );
71 }
72
73 /**
74 * Load previously used media taxonomies via AJAX.
75 *
76 * @return void
77 */
78 public function load_old_taxonomies() {
79 // no data?
80 if ( ! isset( $_POST['taxonomies'], $_POST['nonce'] ) )
81 wp_send_json_error();
82
83 // invalid taxonomies format?
84 if ( ! is_array( $_POST['taxonomies'] ) )
85 wp_send_json_error();
86
87 // invalid nonce?
88 if ( ! ctype_alnum( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'rl-folders-ajax-taxonomies-nonce' ) )
89 wp_send_json_error();
90
91 // get all possible (current and previous) taxonomies
92 $fields = $this->get_taxonomies();
93
94 // any results?
95 if ( ! empty( $fields ) ) {
96 // remove main taxonomy
97 if ( ( $key = array_search( 'rl_media_folder', $fields, true ) ) !== false )
98 unset( $fields[$key] );
99
100 // remove media tags
101 if ( ( $key = array_search( 'rl_media_tag', $fields, true ) ) !== false )
102 unset( $fields[$key] );
103
104 // sanitize taxonomies
105 $taxonomies = array_map( 'santize_key', $_POST['taxonomies'] );
106
107 foreach ( $taxonomies as $taxonomy ) {
108 // remove available taxonomy
109 if ( ( $key = array_search( $taxonomy, $fields, true ) ) !== false )
110 unset( $fields[$key] );
111 }
112 }
113
114 // send taxonomies, reindex them to avoid casting to an object in js
115 wp_send_json_success( [ 'taxonomies' => array_values( $fields ) ] );
116
117 }
118
119 /**
120 * Detect library mode (list or grid).
121 *
122 * @global string $pagenow
123 *
124 * @return void
125 */
126 public function detect_library_mode() {
127 global $pagenow;
128
129 if ( $pagenow === 'upload.php' ) {
130 // available modes
131 $modes = [ 'grid', 'list' ];
132
133 // sanitize mode
134 if ( isset( $_GET['mode'] ) )
135 $mode = sanitize_key( $_GET['mode'] );
136 else
137 $mode = '';
138
139 // check mode
140 if ( ! ( $mode && ctype_lower( $mode ) && in_array( $mode, $modes, true ) ) ) {
141 // get user mode
142 $user_mode = (string) get_user_option( 'media_library_mode' );
143
144 // valid user mode?
145 if ( in_array( $user_mode, $modes, true ) )
146 $mode = $user_mode;
147 // default wp mode
148 else
149 $mode = 'grid';
150 }
151
152 // store mode
153 $this->mode = $mode;
154 }
155
156 if ( $pagenow === 'upload.php' || wp_doing_ajax() ) {
157 $this->rl_media_tag_terms = get_terms(
158 [
159 'taxonomy' => 'rl_media_tag',
160 'hide_empty' => false,
161 'orderby' => 'name',
162 'order' => 'asc',
163 'number' => 0,
164 'fields' => 'id=>name',
165 'hierarchical' => false
166 ]
167 );
168 }
169 }
170
171 /**
172 * Admin body classes.
173 *
174 * @global string $pagenow
175 *
176 * @param array $classes Admin body classes
177 * @return array
178 */
179 public function admin_body_class( $classes ) {
180 global $pagenow;
181
182 if ( $pagenow === 'upload.php' ) {
183 // append class
184 $classes .= ' rl-folders-upload-' . $this->mode . '-mode';
185 }
186
187 return $classes;
188 }
189
190 /**
191 * Get folders dropdown HTML.
192 *
193 * @param string $taxonomy Folders taxonomy
194 * @param string $selected Folders taxonomy ID
195 * @return string
196 */
197 private function get_folders( $taxonomy, $selected = 0 ) {
198 // get only 1 term to check if taxonomy is empty
199 $any_terms = get_terms(
200 [
201 'taxonomy' => $taxonomy,
202 'hide_empty' => false,
203 'fields' => 'ids',
204 'hierarchical' => false,
205 'number' => 1
206 ]
207 );
208
209 // prepare dropdown categories parameters
210 $args = [
211 'orderby' => 'name',
212 'order' => 'asc',
213 'show_option_all' => __( 'Root Folder', 'responsive-lightbox' ),
214 'show_count' => false,
215 'hide_empty' => false,
216 'hierarchical' => true,
217 'hide_if_empty' => false,
218 'echo' => false,
219 'selected' => (int) $selected,
220 'id' => 'rl_folders_upload_files',
221 'name' => 'rl_folders_upload_files_term_id',
222 'taxonomy' => $taxonomy
223 ];
224
225 // no terms?
226 if ( ! is_wp_error( $any_terms ) && empty( $any_terms ) ) {
227 $args['show_option_none'] = __( 'Root Folder', 'responsive-lightbox' );
228 $args['option_none_value'] = 0;
229 }
230
231 return wp_dropdown_categories( $args );
232 }
233
234 /**
235 * Add filter to add media folder id to the uploader
236 *
237 * @return void
238 */
239 public function pre_upload_ui() {
240 add_filter( 'upload_post_params', [ $this, 'upload_post_params' ] );
241 }
242
243 /**
244 * Add media folder id param to the uploader
245 *
246 * @param array $params Plupload parameters
247 * @return array
248 */
249 public function upload_post_params( $params ) {
250 $params['rl_folders_upload_files_term_id'] = 0;
251
252 return $params;
253 }
254
255 /**
256 * Display dropdown at media upload UI screen.
257 *
258 * @return void
259 */
260 public function post_upload_ui() {
261 // get taxonomy
262 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
263
264 // get only 1 term to check if taxonomy is empty
265 $any_terms = get_terms(
266 [
267 'taxonomy' => $taxonomy,
268 'hide_empty' => false,
269 'fields' => 'ids',
270 'hierarchical' => false,
271 'number' => 1
272 ]
273 );
274
275 // prepare dropdown categories parameters
276 $args = [
277 'orderby' => 'name',
278 'order' => 'asc',
279 'show_option_all' => __( 'Root Folder', 'responsive-lightbox' ),
280 'show_count' => false,
281 'hide_empty' => false,
282 'hierarchical' => true,
283 'hide_if_empty' => false,
284 'echo' => false,
285 'selected' => isset( $_GET[$taxonomy] ) ? (int) $_GET[$taxonomy] : 0,
286 'id' => 'rl_folders_upload_files',
287 'name' => 'rl_folders_upload_files_term_id',
288 'taxonomy' => $taxonomy
289 ];
290
291 // no terms?
292 if ( ! is_wp_error( $any_terms ) && empty( $any_terms ) ) {
293 $args['show_option_none'] = __( 'Root Folder', 'responsive-lightbox' );
294 $args['option_none_value'] = 0;
295 }
296
297 // display select
298 echo '<p><label>' . esc_html__( 'Upload files to', 'responsive-lightbox' ) . ': ' . wp_kses( wp_dropdown_categories( $args ), $this->allowed_select_html ) . '</label></p>';
299 }
300
301 /**
302 * Assign attachment to given term.
303 *
304 * @param int $post_id Current attachment ID
305 * @return void
306 */
307 public function add_attachment( $post_id ) {
308 if ( isset( $_POST['rl_folders_upload_files_term_id'] ) ) {
309 // cast term id
310 $term_id = (int) $_POST['rl_folders_upload_files_term_id'];
311
312 // get taxonomy
313 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
314
315 // valid term?
316 if ( is_array( term_exists( $term_id, $taxonomy ) ) )
317 wp_set_object_terms( $post_id, $term_id, $taxonomy, false );
318 }
319 }
320
321 /**
322 * Add filterable dropdown to media library.
323 *
324 * @global string $pagenow
325 *
326 * @return void
327 */
328 public function restrict_manage_posts() {
329 global $pagenow;
330
331 if ( $pagenow === 'upload.php' ) {
332 // get taxonomy
333 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
334
335 $html = wp_dropdown_categories(
336 [
337 'orderby' => 'name',
338 'order' => 'asc',
339 'id' => 'media-attachment-rl-folders-filters',
340 'show_option_all' => __( 'All Files', 'responsive-lightbox' ),
341 'show_count' => false,
342 'hide_empty' => false,
343 'hierarchical' => true,
344 'selected' => ( isset( $_GET[$taxonomy] ) ? (int) $_GET[$taxonomy] : 0 ),
345 'name' => $taxonomy,
346 'taxonomy' => $taxonomy,
347 'hide_if_empty' => true,
348 'echo' => false
349 ]
350 );
351
352 if ( $html === '' )
353 echo '<select name="' . esc_attr( $taxonomy ) . '" id="media-attachment-rl-folders-filters" class="postform"><option>' . esc_html__( 'All Files', 'responsive-lightbox' ) . '</option></select> ';
354 else
355 echo wp_kses( $html, $this->allowed_select_html );
356 }
357 }
358
359 /**
360 * Change query to adjust taxonomy if needed.
361 *
362 * @global string $pagenow
363 *
364 * @param object $query WP Query
365 * @return object
366 */
367 public function parse_query( $query ) {
368 global $pagenow;
369
370 // get taxonomy
371 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
372
373 if ( $pagenow === 'upload.php' && isset( $_GET[$taxonomy] ) ) {
374 // get tax query
375 $tax_query = $query->get( 'tax_query' );
376
377 if ( empty( $tax_query ) || ! is_array( $tax_query ) )
378 $tax_query = [];
379
380 // -1 === root, 0 === all files, >0 === term_id
381 $term_id = (int) $_GET[$taxonomy];
382
383 if ( $term_id !== 0 && ( $query->is_main_query() || empty( $query->query['rl_folders_root'] ) ) ) {
384 $tax = [
385 'taxonomy' => $taxonomy,
386 'field' => 'id'
387 ];
388
389 // root folder?
390 if ( $term_id === -1 ) {
391 $tax['terms'] = 0;
392 $tax['operator'] = 'NOT EXISTS';
393 $tax['include_children'] = false;
394 // specified term id
395 } else {
396 $tax['terms'] = $term_id;
397 $tax['include_children'] = false;
398 }
399
400 // add new tax query
401 $tax_query[] = [ 'relation' => 'AND', $tax ];
402
403 // set new tax query
404 $query->set( 'tax_query', $tax_query );
405 }
406 }
407
408 return $query;
409 }
410
411 /**
412 * Change AJAX query parameters to adjust taxonomy in the media library if needed.
413 *
414 * @param array $query Query arguments
415 * @return array
416 */
417 public function ajax_query_attachments_args( $query ) {
418 // get taxonomy
419 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
420
421 if ( isset( $_POST['query'][$taxonomy] ) ) {
422 $term_id = sanitize_key( $_POST['query'][$taxonomy] );
423
424 if ( $term_id === 'all' )
425 return $query;
426
427 $term_id = (int) $term_id;
428
429 if ( $term_id < 0 )
430 return $query;
431
432 if ( empty( $query['tax_query'] ) || ! is_array( $query['tax_query'] ) )
433 $query['tax_query'] = [];
434
435 $query['tax_query'][] = [
436 'relation' => 'AND',
437 [
438 'taxonomy' => $taxonomy,
439 'field' => 'id',
440 'terms' => $term_id,
441 'include_children' => ( ! ( isset( $_POST['query']['include_children'] ) && $_POST['query']['include_children'] === 'false' ) ),
442 'operator' => ( $term_id === 0 ? 'NOT EXISTS' : 'IN' )
443 ]
444 ];
445 }
446
447 return $query;
448 }
449
450 /**
451 * Filter the array of attachment fields that are displayed when editing an attachment.
452 *
453 * @param array $fields Attachment fields
454 * @param object $post Post object
455 * @return array
456 */
457 public function attachment_fields_to_edit( $fields, $post ) {
458 if ( wp_doing_ajax() ) {
459 // get taxonomy option
460 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
461
462 // get taxonomy object
463 $tax = (array) get_taxonomy( $taxonomy );
464
465 if ( ! empty( $tax ) ) {
466 if ( ! $tax['public'] || ! $tax['show_ui'] )
467 return $fields;
468
469 if ( empty( $tax['args'] ) )
470 $tax['args'] = [];
471
472 $ids = wp_get_post_terms( $post->ID, $taxonomy, [ 'fields' => 'ids' ] );
473
474 // get select HTML
475 $dropdown = wp_dropdown_categories(
476 [
477 'orderby' => 'name',
478 'order' => 'asc',
479 'show_option_none' => __( 'Root Folder', 'responsive-lightbox' ),
480 'show_option_all' => false,
481 'show_count' => false,
482 'hide_empty' => false,
483 'hierarchical' => true,
484 'selected' => ( ! empty( $ids ) ? reset( $ids ) : 0 ),
485 'name' => $taxonomy . '_term',
486 'taxonomy' => $taxonomy,
487 'hide_if_empty' => false,
488 'echo' => false
489 ]
490 );
491
492 $tax['input'] = 'html';
493 $tax['html'] = wp_kses( $dropdown, $this->allowed_select_html );
494
495 $fields[$taxonomy] = $tax;
496 }
497
498 if ( Responsive_Lightbox()->options['folders']['media_tags'] && taxonomy_exists( 'rl_media_tag' ) ) {
499 // get taxonomy object
500 $tax = (array) get_taxonomy( 'rl_media_tag' );
501
502 if ( ! empty( $tax ) ) {
503 if ( ! $tax['public'] || ! $tax['show_ui'] )
504 return $fields;
505
506 if ( empty( $tax['args'] ) )
507 $tax['args'] = [];
508
509 $tags_html = '';
510
511 // get terms
512 $tags = wp_get_post_terms( $post->ID, 'rl_media_tag', [ 'fields' => 'id=>name' ] );
513
514 // valid terms?
515 if ( ! is_wp_error( $tags ) && ! empty( $tags ) ) {
516 foreach ( $tags as $tag_name ) {
517 $tags_html .= '<option value="' . esc_attr( $tag_name ) . '" selected="selected">' . esc_html( $tag_name ) . '</li>';
518 }
519 } else
520 $tags = [];
521
522 // update input
523 $tax['input'] = 'html';
524
525 // $tags_html is already escaped here
526 $tax['html'] = '
527 <select class="rl-media-tag-select2" multiple="multiple" name="attachments[' . (int) $post->ID . '][rl_media_tag]">
528 ' . $tags_html . '
529 </select>';
530
531 // update taxonomy
532 $fields['rl_media_tag'] = $tax;
533 }
534 }
535 }
536
537 return $fields;
538 }
539
540 /**
541 * Assign new term IDs to given attachment ID via AJAX in modal attachment edit screen.
542 *
543 * @return void
544 */
545 function ajax_save_attachment_compat() {
546 // no attachment id?
547 if ( ! isset( $_REQUEST['id'] ) )
548 wp_send_json_error();
549
550 $id = (int) $_REQUEST['id'];
551
552 // invalid id?
553 if ( $id <= 0 )
554 wp_send_json_error();
555
556 // no valid data?
557 if ( empty( $_REQUEST['attachments'][$id] ) || ! is_array( $_REQUEST['attachments'][$id] ) )
558 wp_send_json_error();
559
560 // no sanitization like in wordpress core: wp_ajax_save_attachment_compat() function
561 $attachment_data = $_REQUEST['attachments'][$id];
562
563 // check nonce
564 check_ajax_referer( 'update-post_' . $id, 'nonce' );
565
566 if ( ! current_user_can( 'edit_post', $id ) )
567 wp_send_json_error();
568
569 // get post
570 $post = get_post( $id, ARRAY_A );
571
572 if ( empty( $post ) || $post['post_type'] !== 'attachment' )
573 wp_send_json_error();
574
575 // update attachment data if needed
576 $post = apply_filters( 'attachment_fields_to_save', $post, $attachment_data );
577
578 if ( isset( $post['errors'] ) )
579 wp_send_json_error();
580
581 // update attachment
582 wp_update_post( $post );
583
584 // get taxonomy
585 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
586
587 // first if needed?
588 if ( isset( $attachment_data[$taxonomy] ) )
589 wp_set_object_terms( $id, (int) reset( array_map( 'trim', $attachment_data[$taxonomy] ) ), $taxonomy, false );
590 elseif ( isset( $_REQUEST[$taxonomy . '_term'] ) )
591 wp_set_object_terms( $id, (int) $_REQUEST[$taxonomy . '_term'], $taxonomy, false );
592 else
593 wp_set_object_terms( $id, '', $taxonomy, false );
594
595 // check media tags
596 if ( isset( $attachment_data['rl_media_tag'] ) && is_string( $attachment_data['rl_media_tag'] ) ) {
597 $media_tags = explode( ',', $attachment_data['rl_media_tag'] );
598
599 if ( ! empty( $media_tags ) && is_array( $media_tags ) )
600 $media_tags = array_filter( array_map( 'sanitize_title', $media_tags ) );
601
602 // any media tags?
603 if ( ! empty( $media_tags ) )
604 wp_set_object_terms( $id, $media_tags, 'rl_media_tag', false );
605 else
606 wp_set_object_terms( $id, '', 'rl_media_tag', false );
607 }
608
609 // get attachment data
610 $attachment = wp_prepare_attachment_for_js( $id );
611
612 // invalid attachment?
613 if ( ! $attachment )
614 wp_send_json_error();
615
616 // finally send success
617 wp_send_json_success( $attachment );
618 }
619
620 /**
621 * AJAX action to delete term.
622 *
623 * @return void
624 */
625 public function delete_term() {
626 // no data?
627 if ( ! isset( $_POST['term_id'], $_POST['nonce'], $_POST['children'] ) )
628 wp_send_json_error();
629
630 // invalid nonce?
631 if ( ! ctype_alnum( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'rl-folders-ajax-library-nonce' ) )
632 wp_send_json_error();
633
634 // sanitize term id
635 $term_id = (int) $_POST['term_id'];
636
637 if ( $term_id <= 0 )
638 wp_send_json_error();
639
640 // get taxonomy
641 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
642
643 $remove_children = (int) $_POST['children'];
644
645 // delete children?
646 if ( $remove_children === 1 ) {
647 // get term children
648 $children = get_term_children( $term_id, $taxonomy );
649
650 // found any children?
651 if ( ! empty( $children ) && ! is_wp_error( $children ) ) {
652 // reverse array to delete terms with no children first
653 foreach ( array_reverse( $children ) as $child_id ) {
654 // delete child
655 wp_delete_term( $child_id, $taxonomy );
656 }
657 }
658 }
659
660 // delete parent
661 if ( is_wp_error( wp_delete_term( $term_id, $taxonomy ) ) )
662 wp_send_json_error();
663 else
664 wp_send_json_success( $this->get_folders( $taxonomy ) );
665 }
666
667 /**
668 * AJAX action to assign new parent of the term.
669 *
670 * @return void
671 */
672 public function move_term() {
673 // no data?
674 if ( ! isset( $_POST['parent_id'], $_POST['term_id'], $_POST['nonce'] ) )
675 wp_send_json_error();
676
677 // invalid nonce?
678 if ( ! ctype_alnum( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'rl-folders-ajax-library-nonce' ) )
679 wp_send_json_error();
680
681 // get taxonomy
682 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
683
684 // update term
685 $update = wp_update_term( (int) $_POST['term_id'], $taxonomy, [ 'parent' => (int) $_POST['parent_id'] ] );
686
687 // error?
688 if ( is_wp_error( $update ) )
689 wp_send_json_error();
690 else
691 wp_send_json_success( $this->get_folders( $taxonomy ) );
692 }
693
694 /**
695 * AJAX action to add new term.
696 *
697 * @return void
698 */
699 public function add_term() {
700 // no data?
701 if ( ! isset( $_POST['parent_id'], $_POST['name'], $_POST['nonce'] ) )
702 wp_send_json_error();
703
704 // invalid nonce?
705 if ( ! ctype_alnum( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'rl-folders-ajax-library-nonce' ) )
706 wp_send_json_error();
707
708 // get taxonomy
709 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
710
711 // prepare data
712 $original_slug = $slug = sanitize_title( $_POST['name'] );
713 $parent_id = (int) $_POST['parent_id'];
714
715 // get all term slugs
716 $terms = get_terms(
717 [
718 'taxonomy' => $taxonomy,
719 'hide_empty' => false,
720 'number' => 0,
721 'fields' => 'id=>slug',
722 'hierarchical' => true
723 ]
724 );
725
726 // any terms?
727 if ( ! is_wp_error( $terms ) && is_array( $terms ) && ! empty( $terms ) ) {
728 $i = 2;
729
730 // slug already exists? create unique one
731 while ( in_array( $slug, $terms, true ) ) {
732 $slug = $original_slug . '-' . $i ++;
733 }
734 }
735
736 // add new term, name is sanitized inside wp_insert_term with sanitize_term function
737 $term = wp_insert_term(
738 $_POST['name'],
739 $taxonomy,
740 [
741 'parent' => $parent_id,
742 'slug' => $slug
743 ]
744 );
745
746 // error?
747 if ( is_wp_error( $term ) )
748 wp_send_json_error();
749
750 $term = get_term( $term['term_id'], $taxonomy );
751
752 // error?
753 if ( is_wp_error( $term ) )
754 wp_send_json_error();
755 else {
756 wp_send_json_success(
757 [
758 'name' => $term->name,
759 'term_id' => $term->term_id,
760 'url' => admin_url( 'upload.php?mode=' . $this->mode . '&' . $taxonomy . '=' . $term->term_id ),
761 'select' => $this->get_folders( $taxonomy, $term->term_id )
762 ]
763 );
764 }
765 }
766
767 /**
768 * AJAX action to rename term.
769 *
770 * @return void
771 */
772 public function rename_term() {
773 // no data?
774 if ( ! isset( $_POST['term_id'], $_POST['name'], $_POST['nonce'] ) )
775 wp_send_json_error();
776
777 // invalid nonce?
778 if ( ! ctype_alnum( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'rl-folders-ajax-library-nonce' ) )
779 wp_send_json_error();
780
781 // sanitize term id
782 $term_id = (int) $_POST['term_id'];
783
784 if ( $term_id <= 0 )
785 wp_send_json_error();
786
787 // get taxonomy
788 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
789
790 // update term, name is sanitized inside wp_update_term with sanitize_term function
791 $update = wp_update_term( $term_id, $taxonomy, [ 'name' => $_POST['name'] ] );
792
793 // error?
794 if ( is_wp_error( $update ) )
795 wp_send_json_error();
796
797 $term = get_term( $term_id, $taxonomy );
798
799 // error?
800 if ( is_wp_error( $term ) )
801 wp_send_json_error();
802 else {
803 wp_send_json_success(
804 [
805 'name' => $term->name,
806 'select' => $this->get_folders( $taxonomy, $term_id )
807 ]
808 );
809 }
810 }
811
812 /**
813 * AJAX action to assign new term to attachments.
814 *
815 * @return void
816 */
817 public function move_attachments() {
818 // no data?
819 if ( ! isset( $_POST['attachment_ids'], $_POST['old_term_id'], $_POST['new_term_id'], $_POST['nonce'] ) )
820 wp_send_json_error();
821
822 // invalid nonce?
823 if ( ! ctype_alnum( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'rl-folders-ajax-library-nonce' ) )
824 wp_send_json_error();
825
826 // not empty attachment ids array?
827 if ( empty( $_POST['attachment_ids'] ) || ! is_array( $_POST['attachment_ids'] ) )
828 wp_send_json_error();
829
830 // prepare data
831 $ids = $all_terms = [];
832 $attachments = [
833 'success' => [],
834 'failure' => [],
835 'duplicated' => []
836 ];
837
838 // filter unwanted data
839 $ids = array_unique( array_filter( array_map( 'intval', $_POST['attachment_ids'] ) ) );
840
841 // no ids?
842 if ( empty( $ids ) )
843 wp_send_json_error();
844
845 // prepare term ids
846 $old_term_id = (int) $_POST['old_term_id'];
847 $new_term_id = (int) $_POST['new_term_id'];
848
849 // get taxonomy
850 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
851
852 // moving to root folder?
853 if ( $new_term_id === 0 ) {
854 foreach ( $ids as $id ) {
855 // get attachment term ids
856 $all_terms[$id] = wp_get_object_terms( $id, $taxonomy, [ 'fields' => 'ids' ] );
857
858 // remove all terms assigned to attachment
859 if ( ! is_wp_error( wp_set_object_terms( $id, null, $taxonomy, false ) ) )
860 $attachments['success'][] = $id;
861 else
862 $attachments['failure'][] = $id;
863 }
864 } else {
865 foreach ( $ids as $id ) {
866 // get attachment term ids
867 $terms = wp_get_object_terms( $id, $taxonomy, [ 'fields' => 'ids' ] );
868
869 // got terms?
870 if ( ! is_wp_error( $terms ) ) {
871 // save existing term (attachment already assigned to this term)
872 if ( in_array( $new_term_id, $terms, true ) )
873 $attachments['duplicated'][] = $id;
874
875 // update attachment's term
876 if ( ! is_wp_error( wp_set_object_terms( $id, $new_term_id, $taxonomy, false ) ) )
877 $attachments['success'][] = $id;
878 else
879 $attachments['failure'][] = $id;
880 }
881 }
882 }
883
884 if ( empty( $attachments['success'] ) )
885 wp_send_json_error();
886 else {
887 wp_send_json_success(
888 [
889 'attachments' => $attachments,
890 'terms' => $all_terms
891 ]
892 );
893 }
894 }
895
896 /**
897 * Change wp_list_categories HTML link.
898 *
899 * @param array $matches Matched elements
900 * @return string
901 */
902 public function replace_folders_href( $matches ) {
903 // get taxonomy
904 $taxonomy = Responsive_Lightbox()->options['folders']['media_taxonomy'];
905
906 // set 'all files' folder
907 $term_id = -1;
908 $url_term_id = 0;
909
910 // any matches?
911 if ( ! empty( $matches[1] ) ) {
912 $params = parse_url( html_entity_decode( urldecode( $matches[1] ) ) );
913
914 if ( isset( $params['query'] ) ) {
915 // parse query string
916 parse_str( $params['query'], $atts );
917
918 if ( isset( $atts['term'] ) ) {
919 // get term
920 $term = get_term_by( 'slug', $atts['term'], $taxonomy );
921
922 // valid term?
923 if ( $term !== false ) {
924 $this->term_counters['keys'][] = $term->term_id;
925
926 // set term id
927 $url_term_id = $term_id = $term->term_id;
928 }
929 }
930 }
931 }
932
933 // escape url early
934 return 'href="' . esc_url( apply_filters( 'rl_folders_media_folder_url', add_query_arg( [ 'mode' => $this->mode, $taxonomy => $url_term_id ] ), $matches, $this->mode, $url_term_id ) ) . '" data-term_id="' . $term_id . '"';
935 }
936
937 /**
938 * Change wp_list_categories HTML link by adding attachment counter.
939 *
940 * @param array $matches Matched elements
941 * @return string
942 */
943 public function replace_folders_count( $matches ) {
944 if ( isset( $matches[1] ) ) {
945 $count = (int) str_replace( [ ' ', '&nbsp;' ], '', $matches[1] );
946 $this->term_counters['values'][] = $count;
947
948 return ' (' . $count . ')</a>';
949 }
950
951 return '</a>';
952 }
953
954 /**
955 * Change wp_list_categories HTML output by adding jsTree attributes if needed.
956 *
957 * @param array $matches Matched elements
958 * @return string
959 */
960 public function open_folders( $matches ) {
961 if ( isset( $matches[0] ) ) {
962 // open parent term
963 if ( isset( $matches[0] ) && strpos( $matches[0], 'current-cat-ancestor' ) !== false )
964 return $matches[0] . ' data-jstree=\'{ "opened": true }\'';
965
966 // select current term
967 if ( strpos( $matches[0], 'current-cat' ) !== false )
968 return $matches[0] . ' data-jstree=\'{ "selected": true }\'';
969 }
970 }
971
972 /**
973 * Enqueue all needed scripts and styles for media library and modal screens.
974 *
975 * @global string $pagenow
976 * @global object $wp_list_table
977 * @global array $_wp_admin_css_colors
978 *
979 * @param string $page Current page similar to $pagenow depends on from which filter function was called
980 * @return void
981 */
982 public function add_library_scripts( $page ) {
983 // count how many times function was executed, allow this only once
984 static $run = 0;
985
986 // allow only wp media scripts (empty $page), upload.php or media-new.php
987 if ( ! ( ( $page === '' || $page === 'upload.php' || $page === 'media-new.php' ) && $run < 1 ) )
988 return;
989
990 global $pagenow;
991
992 $run++;
993
994 // change page for wp_enqueue_media
995 if ( $page === '' ) {
996 if ( $pagenow === 'upload.php' )
997 $page = 'upload.php';
998 else
999 $page = 'media';
1000 }
1001
1002 // get main instance
1003 $rl = Responsive_Lightbox();
1004
1005 // include select2 styles
1006 wp_enqueue_style( 'responsive-lightbox-admin-select2', RESPONSIVE_LIGHTBOX_URL . '/assets/select2/select2' . ( ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '.min' : '' ) . '.css', [], $rl->defaults['version'] );
1007
1008 // filterable media folders taxonomy
1009 $taxonomy = get_taxonomy( $rl->options['folders']['media_taxonomy'] );
1010
1011 // no taxonomy? it should be available here, updated in init_folders method
1012 if ( $taxonomy === false )
1013 return;
1014
1015 // main script dependencies
1016 $dependencies = [ 'jquery', 'underscore', 'jquery-ui-draggable', 'jquery-ui-droppable', 'media-models', 'tags-suggest' ];
1017
1018 // create folder counters
1019 $counters = [];
1020
1021 if ( $page !== 'media' ) {
1022 // prepare variables
1023 $no_items = '';
1024 $childless = false;
1025
1026 // include styles
1027 wp_enqueue_style( 'responsive-lightbox-folders-admin-css', RESPONSIVE_LIGHTBOX_URL . '/css/admin-folders.css' );
1028 wp_enqueue_style( 'responsive-lightbox-folders-perfect-scrollbar', RESPONSIVE_LIGHTBOX_URL . '/assets/perfect-scrollbar/perfect-scrollbar' . ( ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '.min' : '' ) . '.css' );
1029 wp_enqueue_style( 'responsive-lightbox-folders-jstree', RESPONSIVE_LIGHTBOX_URL . '/assets/jstree/themes/default/style' . ( ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '.min' : '' ) . '.css' );
1030
1031 // get color scheme global
1032 global $_wp_admin_css_colors;
1033
1034 // set default color;
1035 $color = '0,160,210';
1036
1037 if ( ! empty( $_wp_admin_css_colors ) ) {
1038 // get current admin color scheme name
1039 $current_color_scheme = get_user_option( 'admin_color' );
1040
1041 if ( empty( $current_color_scheme ) )
1042 $current_color_scheme = 'fresh';
1043
1044 // color exists? some schemes don't have 4 colors
1045 if ( isset( $_wp_admin_css_colors[$current_color_scheme] ) && property_exists( $_wp_admin_css_colors[$current_color_scheme], 'colors' ) && isset( $_wp_admin_css_colors[$current_color_scheme]->colors[3] ) ) {
1046 // convert color
1047 $rgb = $rl->hex2rgb( $_wp_admin_css_colors[$current_color_scheme]->colors[3] );
1048
1049 // valid color?
1050 if ( $rgb !== false )
1051 $color = implode( ',', $rgb );
1052 }
1053 }
1054
1055 // $color is already validated, no escaping
1056 wp_add_inline_style(
1057 'responsive-lightbox-folders-jstree',
1058 '#rl-folders-tree-container .jstree .rl-folders-state-active.rl-folders-state-hover {
1059 background: #fff !important;
1060 }
1061 #rl-folders-tree-container .jstree-container-ul .jstree-wholerow-clicked,
1062 #rl-folders-tree-container .jstree-container-ul:not(.jstree-wholerow-ul) .jstree-clicked {
1063 background: rgba(' . $color . ', 0.15);
1064 }
1065 #rl-folders-tree-container .jstree-container-ul .jstree-wholerow-hovered,
1066 #rl-folders-tree-container .jstree-container-ul:not(.jstree-wholerow-ul) .jstree-hovered {
1067 background: rgba(' . $color . ', 0.05);
1068 }'
1069 );
1070
1071 // list categories parameters
1072 $categories = [
1073 'orderby' => 'name',
1074 'order' => 'asc',
1075 'show_count' => true,
1076 'show_option_all' => '',
1077 'show_option_none' => '',
1078 'use_desc_for_title' => false,
1079 'title_li' => '',
1080 'hide_empty' => false,
1081 'hierarchical' => true,
1082 'taxonomy' => $taxonomy->name,
1083 'hide_title_if_empty' => true,
1084 'echo' => false
1085 ];
1086
1087 // get current term id
1088 $term_id = isset( $_GET[$taxonomy->name] ) ? (int) $_GET[$taxonomy->name] : 0;
1089
1090 // list mode?
1091 if ( $this->mode === 'list' ) {
1092 // get global wp list table instance
1093 global $wp_list_table;
1094
1095 // empty instance?
1096 if ( is_null( $wp_list_table ) )
1097 $wp_list_table = _get_list_table( 'WP_Media_List_Table' );
1098
1099 // start buffering
1100 ob_start();
1101
1102 // display "no media" table row
1103 echo '<tr class="no-items"><td class="colspanchange" colspan="' . (int) $wp_list_table->get_column_count() . '">';
1104
1105 $wp_list_table->no_items();
1106
1107 echo '</td></tr>';
1108
1109 // save "no media" table row
1110 $no_items = ob_get_contents();
1111
1112 // clear the buffer
1113 ob_end_clean();
1114
1115 // valid term?
1116 if ( $term_id > 0 ) {
1117 $children = get_term_children( $term_id, $taxonomy->name );
1118
1119 // found any children?
1120 $childless = ! ( ! empty( $children ) && ! is_wp_error( $children ) );
1121 }
1122 }
1123
1124 // set current term id
1125 if ( $term_id > 0 )
1126 $categories['current_category'] = $term_id;
1127
1128 // hide filter for grid
1129 if ( $this->mode !== 'list' ) {
1130 wp_add_inline_style(
1131 'responsive-lightbox-folders-admin-css',
1132 '#media-attachment-rl-folders-filters { display: none; }
1133 .media-modal-content .media-frame select.attachment-filters {
1134 max-width: 100%;
1135 min-width: auto;
1136 }'
1137 );
1138 }
1139
1140 // get taxonomy html output
1141 $html = wp_list_categories( $categories );
1142
1143 if ( $html !== '' ) {
1144 // fix for urls
1145 $html = preg_replace_callback( '/href=(?:\'|")(.*?)(?:\'|")/', [ $this, 'replace_folders_href' ], $html );
1146
1147 // fix for counters
1148 $html = preg_replace_callback( '/<\/a> \(((?:\d+|&nbsp;)+)\)/', [ $this, 'replace_folders_count' ], $html );
1149
1150 // open all needed folders at start
1151 if ( $term_id > 0 )
1152 $html = preg_replace_callback( '/class="cat-item cat-item-(\d+)(?:[a-z\s0-9-]+)?"/', [ $this, 'open_folders' ], $html );
1153
1154 // check whether counters are valid
1155 if ( ! ( empty( $this->term_counters['keys'] ) || empty( $this->term_counters['values'] ) || count( $this->term_counters['keys'] ) !== count( $this->term_counters['values'] ) ) ) {
1156 //@TODO counters are supposed to be used in JS but not implemented yet
1157 // update folder counters
1158 $counters = array_combine( $this->term_counters['keys'], $this->term_counters['values'] );
1159 }
1160 }
1161
1162 // root folder query
1163 $root_query = new WP_Query(
1164 apply_filters(
1165 'rl_root_folder_query_args',
1166 [
1167 'rl_folders_root' => true,
1168 'posts_per_page' => -1,
1169 'post_type' => 'attachment',
1170 'post_status' => 'inherit,private',
1171 'fields' => 'ids',
1172 'no_found_rows' => false,
1173 'tax_query' => [
1174 [
1175 'relation' => 'AND',
1176 [
1177 'taxonomy' => $taxonomy->name,
1178 'field' => 'id',
1179 'terms' => 0,
1180 'include_children' => false,
1181 'operator' => 'NOT EXISTS'
1182 ]
1183 ]
1184 ]
1185 ]
1186 )
1187 );
1188
1189 // set number of all attachments
1190 $counters[-1] = (int) apply_filters( 'rl_count_attachments', 0 );
1191
1192 // set number of root attachments (not categorized)
1193 $counters[0] = (int) $root_query->post_count;
1194
1195 // $html is escaped at the end
1196 $html = '
1197 <ul>
1198 <li class="cat-item cat-item-all"' . ( $term_id === 0 ? ' data-jstree=\'{ "selected": true }\'' : '' ) . '>
1199 <a href="' . esc_url( apply_filters( 'rl_folders_media_folder_url', add_query_arg( [ 'mode' => $this->mode, $taxonomy->name => 0 ] ), null, $this->mode, 0 ) ) . '" data-term_id="all">' . esc_html__( 'All Files', 'responsive-lightbox' ) . ' (' . (int) $counters[-1] . ')</a>
1200 </li>
1201 <li class="cat-item cat-item-0" data-jstree=\'{ "opened": true' . ( $term_id === -1 ? ', "selected": true ' : '' ) . ' }\'>
1202 <a href="' . esc_url( apply_filters( 'rl_folders_media_folder_url', add_query_arg( [ 'mode' => $this->mode, $taxonomy->name => -1 ] ), null, $this->mode, -1 ) ) . '" data-term_id="0">' . esc_html__( 'Root Folder', 'responsive-lightbox' ) . ' (' . (int) $counters[0] . ')</a>
1203 <ul>' . $html . '</ul>
1204 </li>
1205 </ul>';
1206
1207 // register scripts
1208 wp_register_script( 'responsive-lightbox-folders-jstree', RESPONSIVE_LIGHTBOX_URL . '/assets/jstree/jstree' . ( ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '.min' : '' ) . '.js', [], $rl->defaults['version'], false );
1209 wp_register_script( 'responsive-lightbox-folders-perfect-scrollbar', RESPONSIVE_LIGHTBOX_URL . '/assets/perfect-scrollbar/perfect-scrollbar' . ( ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '.min' : '' ) . '.js', [], $rl->defaults['version'], false );
1210
1211 $dependencies[] = 'responsive-lightbox-folders-jstree';
1212 $dependencies[] = 'responsive-lightbox-folders-perfect-scrollbar';
1213 }
1214
1215 wp_enqueue_script( 'responsive-lightbox-admin-select2', RESPONSIVE_LIGHTBOX_URL . '/assets/select2/select2.full' . ( ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '.min' : '' ) . '.js', [ 'jquery' ], $rl->defaults['version'], false );
1216
1217 wp_enqueue_script( 'responsive-lightbox-folders-admin', RESPONSIVE_LIGHTBOX_URL . '/js/admin-folders.js', $dependencies, $rl->defaults['version'], false );
1218
1219 if ( $page === 'media' ) {
1220 wp_localize_script(
1221 'responsive-lightbox-folders-admin',
1222 'rlFoldersArgs',
1223 [
1224 'taxonomy' => $taxonomy->name,
1225 'page' => $page,
1226 'root' => esc_html__( 'Root Folder', 'responsive-lightbox' ),
1227 'terms' => wp_dropdown_categories(
1228 [
1229 'orderby' => 'name',
1230 'order' => 'asc',
1231 'show_option_all' => esc_html__( 'All Files', 'responsive-lightbox' ),
1232 'show_count' => false,
1233 'hide_empty' => false,
1234 'hierarchical' => true,
1235 'selected' => ( isset( $_GET[$taxonomy->name] ) ? (int) $_GET[$taxonomy->name] : 0 ),
1236 'name' => $taxonomy->name,
1237 'taxonomy' => $taxonomy->name,
1238 'hide_if_empty' => true,
1239 'echo' => false
1240 ]
1241 )
1242 ]
1243 );
1244 } else {
1245 wp_localize_script(
1246 'responsive-lightbox-folders-admin',
1247 'rlFoldersArgs',
1248 [
1249 'remove_children' => (int) $rl->options['folders']['folders_removal'],
1250 'wholerow' => (int) $rl->options['folders']['jstree_wholerow'],
1251 'theme' => 'default',
1252 'counters' => $counters,
1253 'no_media_items' => $no_items,
1254 'taxonomy' => $taxonomy->name,
1255 'page' => $page,
1256 'root' => esc_html__( 'Root Folder', 'responsive-lightbox' ),
1257 'all_terms' => esc_html__( 'All Files', 'responsive-lightbox' ),
1258 'new_folder' => esc_html__( 'New Folder', 'responsive-lightbox' ),
1259 'delete_term' => esc_html__( 'Are you sure you want to delete this folder?', 'responsive-lightbox' ),
1260 'delete_terms' => esc_html__( 'Are you sure you want to delete this folder with all subfolders?', 'responsive-lightbox' ),
1261 'nonce' => wp_create_nonce( 'rl-folders-ajax-library-nonce' ),
1262 'terms' => wp_dropdown_categories(
1263 [
1264 'orderby' => 'name',
1265 'order' => 'asc',
1266 'show_option_all' => esc_html__( 'All Files', 'responsive-lightbox' ),
1267 'show_count' => false,
1268 'hide_empty' => false,
1269 'hierarchical' => true,
1270 'selected' => ( isset( $_GET[$taxonomy->name] ) ? (int) $_GET[$taxonomy->name] : 0 ),
1271 'name' => $taxonomy->name,
1272 'taxonomy' => $taxonomy->name,
1273 'hide_if_empty' => true,
1274 'echo' => false
1275 ]
1276 ),
1277 'template' => '
1278 <div id="rl-folders-tree-container">
1279 <div class="media-toolbar wp-filter">
1280 <div class="view-switch rl-folders-action-links">
1281 <a href="#" title="' . esc_attr( $taxonomy->labels->add_new_item ) . '" class="dashicons dashicons-plus rl-folders-add-new-folder' . ( $this->mode === 'list' && ( $term_id === -1 || $term_id > 0 ) ? '' : ' disabled-link' ) . '"></a>
1282 <a href="#" title="' . esc_attr( sprintf( __( 'Save new %s', 'responsive-lightbox' ), $taxonomy->labels->singular_name ) ) . '" class="dashicons dashicons-yes rl-folders-save-new-folder" style="display: none;"></a>
1283 <a href="#" title="' . esc_attr( sprintf( __( 'Cancel adding new %s', 'responsive-lightbox' ), $taxonomy->labels->singular_name ) ) . '" class="dashicons dashicons-no rl-folders-cancel-new-folder" style="display: none;"></a>
1284 <a href="#" title="' . esc_attr( $taxonomy->labels->edit_item ) . '" class="dashicons dashicons-edit rl-folders-rename-folder' . ( $this->mode === 'list' && $term_id > 0 ? '' : ' disabled-link' ) . '"></a>
1285 <a href="#" title="' . esc_attr( sprintf( __( 'Save %s', 'responsive-lightbox' ), $taxonomy->labels->singular_name ) ) . '" class="dashicons dashicons-yes rl-folders-save-folder" style="display: none;"></a>
1286 <a href="#" title="' . esc_attr( sprintf( __( 'Cancel renaming %s', 'responsive-lightbox' ), $taxonomy->labels->singular_name ) ) . '" class="dashicons dashicons-no rl-folders-cancel-folder" style="display: none;"></a>
1287 <a href="#" title="' . esc_attr( sprintf( __( 'Delete %s', 'responsive-lightbox' ), $taxonomy->labels->singular_name ) ) . '" class="dashicons dashicons-trash rl-folders-delete-folder' . ( $this->mode === 'list' && $term_id > 0 ? '' : ' disabled-link' ) . '"></a>
1288 <a href="#" title="' . esc_attr( sprintf( __( 'Expand %s', 'responsive-lightbox' ), $taxonomy->labels->singular_name ) ) . '" class="dashicons dashicons-arrow-down-alt2 rl-folders-expand-folder' . ( $this->mode === 'list' && ! $childless && ( $term_id === -1 || $term_id > 0 ) ? '' : ' disabled-link' ) . '"></a>
1289 <a href="#" title="' . esc_attr( sprintf( __( 'Collapse %s', 'responsive-lightbox' ), $taxonomy->labels->singular_name ) ) . '" class="dashicons dashicons-arrow-up-alt2 rl-folders-collapse-folder' . ( $this->mode === 'list' && ! $childless && ( $term_id === -1 || $term_id > 0 ) ? '' : ' disabled-link' ) . '"></a>
1290 </div>
1291 </div>
1292 <div id="rl-folders-tree">' . esc_html( $html ) . '</div>
1293 </div>'
1294 ]
1295 );
1296 }
1297
1298 add_action( 'admin_print_styles', [ $this, 'admin_print_media_styles' ] );
1299 }
1300
1301 /**
1302 * CSS fix for media folders checklist.
1303 *
1304 * @return void
1305 */
1306 public function admin_print_media_styles() {
1307 echo '<style>.rl_media_folder li .selectit input[type="checkbox"] { margin: 0 3px; }</style>';
1308 }
1309
1310 /**
1311 * Count attachments.
1312 *
1313 * @return int
1314 */
1315 public function count_attachments() {
1316 $count = wp_count_posts( 'attachment' );
1317
1318 return (int) $count->inherit;
1319 }
1320
1321 /**
1322 * Get all previously used media taxonomies.
1323 *
1324 * @global object $wpdb
1325 *
1326 * @return array
1327 */
1328 public function get_taxonomies() {
1329 global $wpdb;
1330
1331 // query
1332 $fields = $wpdb->get_col( "
1333 SELECT DISTINCT tt.taxonomy
1334 FROM " . $wpdb->prefix . "term_taxonomy tt
1335 LEFT JOIN " . $wpdb->prefix . "term_relationships tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
1336 LEFT JOIN " . $wpdb->prefix . "posts p ON p.ID = tr.object_id
1337 WHERE p.post_type = 'attachment'
1338 ORDER BY tt.taxonomy ASC"
1339 );
1340
1341 if ( ! empty( $fields ) ) {
1342 // remove polylang taxonomy
1343 if ( ( $key = array_search( 'language', $fields, true ) ) !== false )
1344 unset( $fields[$key] );
1345 }
1346
1347 return $fields;
1348 }
1349 }