PluginProbe
WP Ultimate Post Grid / 3.8.0
WP Ultimate Post Grid v3.8.0
4.1.1 trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.8 1.9 2.0 2.1 2.2 2.3 2.4.0 2.5.0 2.6.0 2.7.0 2.8.0 2.8.2 3.0.0 3.3.0 3.4.0 3.5.0 3.6.0 3.7.0 All 32 releases
wp-ultimate-post-grid / includes / public / class-wpupg-grid.php

class-wpupg-grid.php in WP Ultimate Post Grid 3.8.0, at includes/public/class-wpupg-grid.php

1,084 lines 30.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Represents a grid.
4 *
5 * @link https://bootstrapped.ventures
6 * @since 3.0.0
7 *
8 * @package WP_Ultimate_Post_Grid
9 * @subpackage WP_Ultimate_Post_Grid/includes/public
10 */
11
12 /**
13 * Represents a grid.
14 *
15 * @since 3.0.0
16 * @package WP_Ultimate_Post_Grid
17 * @subpackage WP_Ultimate_Post_Grid/includes/public
18 * @author Brecht Vandersmissen <brecht@bootstrapped.ventures>
19 */
20 class WPUPG_Grid {
21
22 /**
23 * WP_Post object associated with this grid post type.
24 *
25 * @since 3.0.0
26 * @access private
27 * @var object $post WP_Post object of this grid post type.
28 */
29 private $post;
30
31 /**
32 * Cached IDs to display in this grid.
33 *
34 * @since 3.0.0
35 * @access private
36 * @var array $ids Grid item IDs.
37 */
38 private $ids = false;
39
40 /**
41 * Cached total IDs to display in this grid.
42 *
43 * @since 3.3.0
44 * @access private
45 * @var array $total_ids Total number of grid ids.
46 */
47 private $total_ids = false;
48
49 /**
50 * Cached terms to display in this grid.
51 *
52 * @since 3.0.0
53 * @access private
54 * @var array $ids Terms for this grid.
55 */
56 private $terms = false;
57
58 /**
59 * Metadata associated with this grid post type.
60 *
61 * @since 3.0.0
62 * @access private
63 * @var array $meta Grid metadata.
64 */
65 private $meta = false;
66
67 /**
68 * Get new grid object from associated post.
69 *
70 * @since 3.0.0
71 * @param mixed $post Meta or WP_Post object for this grid post type.
72 */
73 public function __construct( $post_or_meta ) {
74 $post = is_object( $post_or_meta ) && $post_or_meta instanceof WP_Post ? $post_or_meta : false;
75 $this->post = $post;
76
77 // Not a WP_Post object, so just manually set the meta values.
78 if ( ! $post ) {
79 $this->meta = $post_or_meta;
80 }
81 }
82
83 /**
84 * Get grid data.
85 *
86 * @since 3.0.0
87 */
88 public function get_data() {
89 $grid = array();
90
91 // Technical Fields.
92 $grid['id'] = $this->id();
93 $grid['version'] = $this->version();
94
95 // Grid General.
96 $grid['name'] = $this->name();
97 $grid['slug'] = $this->slug();
98
99 // Grid Data Source.
100 $grid['type'] = $this->type();
101 $grid['post_types'] = $this->post_types();
102 $grid['post_status'] = $this->post_status();
103 $grid['post_status_require_permission'] = $this->post_status_require_permission();
104 $grid['taxonomies'] = $this->taxonomies();
105 $grid['password_protected'] = $this->password_protected();
106 $grid['order_by'] = $this->order_by();
107 $grid['order'] = $this->order();
108 $grid['order_custom_key'] = $this->order_custom_key();
109 $grid['order_custom_key_numeric'] = $this->order_custom_key_numeric();
110 $grid['terms_order_by'] = $this->terms_order_by();
111 $grid['terms_order'] = $this->terms_order();
112
113 // Grid Limit Items.
114 $grid['limit_posts_offset'] = $this->limit_posts_offset();
115 $grid['limit_posts_number'] = $this->limit_posts_number();
116 $grid['images_only'] = $this->images_only();
117 $grid['terms_images_only'] = $this->terms_images_only();
118 $grid['terms_hide_empty'] = $this->terms_hide_empty();
119 $grid['limit_terms'] = $this->limit_terms();
120 $grid['limit_terms_terms'] = $this->limit_terms_terms();
121 $grid['limit_terms_type'] = $this->limit_terms_type();
122 $grid['limit_posts'] = $this->limit_posts();
123 $grid['limit_rules'] = $this->limit_rules();
124
125 // Grid Filters.
126 $grid['filters'] = $this->filters();
127 $grid['filters_enabled'] = $this->filters_enabled();
128 $grid['filters_style'] = $this->filters_style();
129 $grid['filters_relation'] = $this->filters_relation();
130 $grid['responsive_toggle_style'] = $this->responsive_toggle_style();
131 $grid['responsive_toggle_style_closed'] = $this->responsive_toggle_style_closed();
132 $grid['responsive_toggle_style_open'] = $this->responsive_toggle_style_open();
133
134 // Grid Layout.
135 $grid['layout_mode'] = $this->layout_mode();
136 $grid['centered'] = $this->centered();
137 $grid['layout_desktop_sizing'] = $this->layout_desktop_sizing();
138 $grid['layout_desktop_sizing_fixed'] = $this->layout_desktop_sizing_fixed();
139 $grid['layout_desktop_sizing_columns'] = $this->layout_desktop_sizing_columns();
140 $grid['layout_desktop_sizing_margin'] = $this->layout_desktop_sizing_margin();
141 $grid['layout_tablet_different'] = $this->layout_tablet_different();
142 $grid['layout_tablet_sizing'] = $this->layout_tablet_sizing();
143 $grid['layout_tablet_sizing_fixed'] = $this->layout_tablet_sizing_fixed();
144 $grid['layout_tablet_sizing_columns'] = $this->layout_tablet_sizing_columns();
145 $grid['layout_tablet_sizing_margin'] = $this->layout_tablet_sizing_margin();
146 $grid['layout_mobile_different'] = $this->layout_mobile_different();
147 $grid['layout_mobile_sizing'] = $this->layout_mobile_sizing();
148 $grid['layout_mobile_sizing_fixed'] = $this->layout_mobile_sizing_fixed();
149 $grid['layout_mobile_sizing_columns'] = $this->layout_mobile_sizing_columns();
150 $grid['layout_mobile_sizing_margin'] = $this->layout_mobile_sizing_margin();
151
152 // Grid Item.
153 $grid['template'] = $this->template();
154 $grid['use_image'] = $this->use_image();
155 $grid['link'] = $this->link();
156 $grid['link_type'] = $this->link_type();
157 $grid['link_target'] = $this->link_target();
158
159 // Grid Pagination.
160 $grid['pagination_type'] = $this->pagination_type();
161 $grid['pagination'] = $this->pagination();
162
163 // Grid Other.
164 $grid['metadata'] = $this->metadata();
165 $grid['metadata_name'] = $this->metadata_name();
166 $grid['metadata_description'] = $this->metadata_description();
167 $grid['deeplinking'] = $this->deeplinking();
168 $grid['empty_message'] = $this->empty_message();
169
170 return $grid;
171 }
172
173 /**
174 * Get grid data for the manage page.
175 *
176 * @since 3.0.0
177 */
178 public function get_data_manage() {
179 $grid = $this->get_data();
180
181 $grid['date'] = $this->date();
182
183 return $grid;
184 }
185
186 /**
187 * Get isotope args for this grid.
188 *
189 * @since 3.0.0
190 */
191 public function get_javascript_args() {
192 $args = array();
193
194 // Arguments for grid.
195 $args['item_ids'] = $this->ids( array( 'type' => 'initial' ) );
196 $args['order'] = array(
197 array(
198 'by' => $this->order_by(),
199 'type' => $this->order(),
200 ),
201 );
202 $args['link'] = $this->link() ? $this->link_target() : false;
203 $args['deeplinking'] = $this->deeplinking();
204
205 // Arguments for Isotope JS.
206 $args['isotope'] = array(
207 'itemSelector' => '.wpupg-item',
208 'layoutMode' => $this->layout_mode(),
209 'transitionDuration' => intval( WPUPG_Settings::get( 'grid_animation_speed' ) ),
210 'stagger' => intval( WPUPG_Settings::get( 'grid_animation_stagger' ) ),
211 'hiddenStyle' => self::get_css_array( WPUPG_Settings::get( 'grid_animation_hide' ) ),
212 'visibleStyle' => self::get_css_array( WPUPG_Settings::get( 'grid_animation_show' ) ),
213 );
214
215 // Force height layout mode.
216 if ( 'fitRowsHeight' === $this->layout_mode() ) {
217 $args['isotope']['layoutMode'] = 'fitRows';
218 $args['force_height'] = true;
219 }
220
221 // CSS
222 if ( $this->can_use_centered() && $this->centered() ) {
223 $args['isotope']['masonry'] = array(
224 'isFitWidth' => true,
225 );
226 }
227
228 // Arguments for filters.
229 $args['filters_relation'] = $this->filters_relation();
230 $args['filters'] = array();
231 if ( $this->filters_enabled() ) {
232 $filters = $this->filters();
233
234 foreach ( $filters as $index => $filter ) {
235 // Make sure filter ID is set.
236 if ( ! $filter['id'] ) {
237 $filter['id'] = $index + 1;
238 }
239
240 $filter_args = array(
241 'id' => $filter['id'],
242 'type' => $filter['type'],
243 );
244
245 $args['filters'][ $filter['id'] ] = apply_filters( 'wpupg_javascript_args_filter', $filter_args, $this, $filter );
246 }
247 }
248
249 // Arguments for pagination.
250 $args['pagination_type'] = $this->pagination_type();
251 $args['pagination'] = apply_filters( 'wpupg_javascript_args_pagination', false, $this );
252
253 return apply_filters( 'wpupg_javascript_args', $args, $this );
254 }
255
256 /**
257 * Get CSS array from string.
258 *
259 * @since 3.0.0
260 * @param mixed $string String to get the CSS from.
261 */
262 public function get_css_array( $string ) {
263 $css = array();
264
265 if ( $string ) {
266 $properties = explode( ';', $string );
267
268 foreach( $properties as $property ) {
269 $parts = explode( ':', $property );
270
271 if ( 2 === count( $parts ) ) {
272 $key = trim( $parts[0] );
273
274 if ( $key ) {
275 $css[ $key ] = trim( $parts[1] );
276 }
277 }
278 }
279 }
280
281 return $css;
282 }
283
284 /**
285 * Get metadata value.
286 *
287 * @since 3.0.0
288 * @param mixed $field Metadata field to retrieve.
289 * @param mixed $default Default to return if metadata is not set.
290 */
291 public function meta( $field, $default = '' ) {
292 if ( false === $this->post ) {
293 if ( isset( $this->meta[ $field ] ) ) {
294 return $this->meta[ $field ];
295 }
296 } else {
297 // Use prefix when stored in actual meta.
298 $field = 'wpupg_' . $field;
299
300 if ( ! $this->meta ) {
301 $this->meta = get_post_custom( $this->id() );
302 }
303
304 if ( isset( $this->meta[ $field ] ) && null !== $this->meta[ $field ][0] ) {
305 return $this->meta[ $field ][0];
306 }
307 }
308
309 return $default;
310 }
311
312 /**
313 * Try to unserialize as best as possible.
314 *
315 * @since 3.0.0
316 * @param mixed $maybe_serialized Potentially serialized data.
317 */
318 public function unserialize( $maybe_serialized ) {
319 $unserialized = @maybe_unserialize( $maybe_serialized );
320
321 if ( false === $unserialized ) {
322 $maybe_serialized = preg_replace('/\s+/', ' ', $maybe_serialized );
323 $unserialized = unserialize( preg_replace_callback( '!s:(\d+):"(.*?)";!', array( $this, 'regex_replace_serialize' ), $maybe_serialized ) );
324 }
325
326 return $unserialized;
327 }
328
329 /**
330 * Callback for regex to fix serialize issues.
331 *
332 * @since 3.0.0
333 * @param mixed $match Regex match.
334 */
335 public function regex_replace_serialize( $match ) {
336 return ( $match[1] == strlen( $match[2] ) ) ? $match[0] : 's:' . strlen( $match[2] ) . ':"' . $match[2] . '";';
337 }
338
339 /**
340 * Grid Technical Fields.
341 */
342 public function id() {
343 return $this->post ? $this->post->ID : $this->meta( 'id' );
344 }
345 public function slug_or_id() {
346 $slug = $this->slug();
347
348 if ( ! $slug ) {
349 $slug = $this->id();
350 }
351
352 return $slug;
353 }
354 public function date() {
355 return $this->post ? $this->post->post_date : $this->meta( 'date' );
356 }
357 public function version() {
358 return $this->meta( 'version', '0.0.0' );
359 }
360
361 /**
362 * Grid General Fields.
363 */
364 public function name() {
365 return $this->post ? $this->post->post_title : $this->meta( 'name' );
366 }
367 public function slug() {
368 return $this->post ? $this->post->post_name : $this->meta( 'slug' );
369 }
370 /**
371 * Grid Data Source Fields.
372 */
373 public function type() {
374 return $this->meta( 'type', 'posts' );
375 }
376 public function post_types() {
377 return $this->unserialize( $this->meta( 'post_types', array( 'post' ) ) );
378 }
379 public function post_status() {
380 $post_status = $this->unserialize( $this->meta( 'post_status', array( 'publish' ) ) );
381
382 if ( in_array( 'attachment', $this->post_types() ) ) {
383 $post_status[] = 'inherit';
384 }
385
386 return $post_status;
387 }
388 public function post_status_require_permission() {
389 return $this->meta( 'post_status_require_permission', true );
390 }
391 public function taxonomies() {
392 return $this->unserialize( $this->meta( 'taxonomies', array( 'category' ) ) );
393 }
394 public function password_protected() {
395 return $this->meta( 'password_protected', 'all' );
396 }
397 public function order_by() {
398 return $this->meta( 'order_by', 'date' );
399 }
400 public function order() {
401 return $this->meta( 'order', 'desc' );
402 }
403 public function order_custom_key() {
404 return $this->meta( 'order_custom_key', '' );
405 }
406 public function order_custom_key_numeric() {
407 return $this->meta( 'order_custom_key_numeric', false );
408 }
409 public function terms_order_by() {
410 return $this->meta( 'terms_order_by', 'name' );
411 }
412 public function terms_order() {
413 return $this->meta( 'terms_order', 'asc' );
414 }
415 /**
416 * Grid Limit Items Fields.
417 */
418 public function limit_posts_offset() {
419 return $this->meta( 'limit_posts_offset', 0 );
420 }
421 public function limit_posts_number() {
422 return $this->meta( 'limit_posts_number', 0 );
423 }
424 public function images_only() {
425 return $this->meta( 'images_only', false );
426 }
427 public function terms_images_only() {
428 return $this->meta( 'terms_images_only', false );
429 }
430 public function terms_hide_empty() {
431 return $this->meta( 'terms_hide_empty', false );
432 }
433 public function limit_terms() {
434 return $this->meta( 'limit_terms', false );
435 }
436 public function limit_terms_terms() {
437 return $this->unserialize( $this->meta( 'limit_terms_terms', array() ) );
438 }
439 public function limit_terms_type() {
440 return $this->meta( 'limit_terms_type', 'restrict' );
441 }
442 public function limit_posts() {
443 return $this->meta( 'limit_posts', false );
444 }
445 public function limit_rules() {
446 return $this->unserialize( $this->meta( 'limit_rules', array() ) );
447 }
448
449 /**
450 * Grid Filters Fields.
451 */
452 public function filter( $id ) {
453 if ( ! $this->filters_enabled() || ! $id ) {
454 return false;
455 }
456
457 $filters = $this->filters();
458
459 // If identifier was found, return filter.
460 $index = array_search( $id, array_column( $filters, 'id' ) );
461 if ( false !== $index ) {
462 return WPUPG_Filter::filter_with_defaults( $filters[ $index ] );
463 }
464
465 // Check if index + 1 was used as the ID if not found by identifier.
466 $index = intval( $id ) - 1;
467 if ( isset( $filters[ $index ] ) ) {
468 $filter = $filters[ $index ];
469 $filter['id'] = $id;
470 return WPUPG_Filter::filter_with_defaults( $filter );
471 }
472
473 return false;
474 }
475 public function filters() {
476 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
477 return WPUPG_Migrations::single_filter_to_multiple( $this );
478 }
479
480 $filters_with_defaults = array();
481 $filters = $this->unserialize( $this->meta( 'filters', array() ) );
482
483 foreach ( $filters as $index => $filter ) {
484 $filters_with_defaults[ $index ] = WPUPG_Filter::filter_with_defaults( $filter );
485 }
486
487 return $filters_with_defaults;
488 }
489 public function filters_enabled() {
490 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
491 return 0 < count( $this->filters() );
492 }
493
494 // No filters for a term grid.
495 if ( 'terms' === $this->type() ) {
496 return false;
497 }
498
499 return $this->meta( 'filters_enabled', false );
500 }
501 public function filters_style( $field = false ) {
502 $defaults = WPUPG_Filter::get_general_style_defaults();
503 $filters_style = $this->unserialize( $this->meta( 'filters_style', array() ) );
504 $filters_style_with_defaults = array_replace_recursive( $defaults, $filters_style );
505
506 if ( $field === false ) {
507 return $filters_style_with_defaults;
508 } else {
509 return isset( $filters_style_with_defaults[ $field ] ) ? $filters_style_with_defaults[ $field ] : false;
510 }
511 }
512 public function filters_relation() {
513 return $this->meta( 'filters_relation', 'AND' );
514 }
515 public function responsive_toggle_style() {
516 return $this->meta( 'responsive_toggle_style', 'custom' );
517 }
518 public function responsive_toggle_style_closed() {
519 return $this->meta( 'responsive_toggle_style_closed', '+' );
520 }
521 public function responsive_toggle_style_open() {
522 return $this->meta( 'responsive_toggle_style_open', '-' );
523 }
524
525 /**
526 * Grid Layout Fields.
527 */
528 public function layout_mode() {
529 return $this->meta( 'layout_mode', 'masonry' );
530 }
531 public function centered() {
532 return $this->meta( 'centered', false );
533 }
534 public function can_use_centered() {
535 $can_use_centered = false;
536
537 if ( 'masonry' === $this->layout_mode() ) {
538 if ( ! $this->layout_tablet_different() && ! $this->layout_mobile_different() ) {
539 $can_use_centered = true;
540 }
541 }
542
543 return $can_use_centered;
544 }
545 public function layout_desktop_sizing() {
546 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
547 return 'ignore';
548 }
549 return $this->meta( 'layout_desktop_sizing', 'fixed' );
550 }
551 public function layout_desktop_sizing_fixed() {
552 return $this->meta( 'layout_desktop_sizing_fixed', 300 );
553 }
554 public function layout_desktop_sizing_columns() {
555 return $this->meta( 'layout_desktop_sizing_columns', 3 );
556 }
557 public function layout_desktop_sizing_margin() {
558 return $this->meta( 'layout_desktop_sizing_margin', 10 );
559 }
560 public function layout_tablet_different() {
561 return $this->meta( 'layout_tablet_different', false );
562 }
563 public function layout_tablet_sizing() {
564 return $this->meta( 'layout_tablet_sizing', 'fixed' );
565 }
566 public function layout_tablet_sizing_fixed() {
567 return $this->meta( 'layout_tablet_sizing_fixed', 300 );
568 }
569 public function layout_tablet_sizing_columns() {
570 return $this->meta( 'layout_tablet_sizing_columns', 2 );
571 }
572 public function layout_tablet_sizing_margin() {
573 return $this->meta( 'layout_tablet_sizing_margin', 10 );
574 }
575 public function layout_mobile_different() {
576 return $this->meta( 'layout_mobile_different', false );
577 }
578 public function layout_mobile_sizing() {
579 return $this->meta( 'layout_mobile_sizing', 'columns' );
580 }
581 public function layout_mobile_sizing_fixed() {
582 return $this->meta( 'layout_mobile_sizing_fixed', 300 );
583 }
584 public function layout_mobile_sizing_columns() {
585 return $this->meta( 'layout_mobile_sizing_columns', 1 );
586 }
587 public function layout_mobile_sizing_margin() {
588 return $this->meta( 'layout_mobile_sizing_margin', 10 );
589 }
590 /**
591 * Grid Item Fields.
592 */
593 public function template() {
594 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
595 return WPUPG_Migrations::template_mapping( $this );
596 }
597 return $this->meta( 'template', 'simple' );
598 }
599 public function use_image() {
600 return $this->meta( 'use_image', 'default' );
601 }
602 public function link() {
603 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
604 return 'none' !== $this->meta( 'link_type' );
605 }
606 return $this->meta( 'link', true );
607 }
608 public function link_type() {
609 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
610 return $this->meta( 'link_target', 'post' );
611 }
612 return $this->meta( 'link_type', 'post' );
613 }
614 public function link_target() {
615 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
616 $target = $this->meta( 'link_type', '_self' );
617 return 'none' === $target ? '_self' : $target;
618 }
619 return $this->meta( 'link_target', '_self' );
620 }
621 /**
622 * Grid Pagination Fields.
623 */
624 public function pagination_type() {
625 $pagination_type = $this->meta( 'pagination_type', 'none' );
626
627 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
628 $pagination_type = str_replace( 'load_more_filter', 'load_more', $pagination_type );
629 }
630
631 return $pagination_type;
632 }
633 public function pagination( $type = false ) {
634 if ( version_compare( $this->version(), '3.0.0', '<' ) ) {
635 $pagination = WPUPG_Migrations::get_pagination_with_style( $this );
636 } else {
637 $pagination = $this->unserialize( $this->meta( 'pagination', array() ) );
638 }
639
640 $pagination_defaults = WPUPG_Pagination::get_defaults();
641 $pagination = array_replace_recursive( $pagination_defaults, $pagination );
642
643 if ( false === $type ) {
644 return $pagination;
645 } else {
646 if ( isset( $pagination[ $type ] ) ) {
647 return $pagination[ $type ];
648 } else {
649 return array();
650 }
651 }
652 }
653 /**
654 * Grid Other Fields.
655 */
656 public function metadata() {
657 return $this->meta( 'metadata', false );
658 }
659 public function metadata_name() {
660 return $this->meta( 'metadata_name', '' );
661 }
662 public function metadata_description() {
663 return $this->meta( 'metadata_description', '' );
664 }
665 public function deeplinking() {
666 return $this->meta( 'deeplinking', true );
667 }
668 public function empty_message() {
669 return $this->meta( 'empty_message', '' );
670 }
671
672 /**
673 * Get the IDs that are displayed in this grid for the current page.
674 *
675 * @since 3.0.0
676 * @param mixed $grid_args Optional arguments.
677 */
678 public function ids( $grid_args = array() ) {
679 $all_ids = $this->all_ids( $grid_args );
680 $ids = apply_filters( 'wpupg_grid_ids', $all_ids, $this, $grid_args );
681
682 // Prevent already loaded IDs from loading again.
683 $already_loaded_ids = isset( $grid_args['loaded_ids'] ) ? $grid_args['loaded_ids'] : array();
684 return array_filter( $ids, function( $id ) use ( $already_loaded_ids ) { return ! in_array( $id, $already_loaded_ids ); } );
685 }
686
687 /**
688 * Get the total number of IDs for this grid.
689 *
690 * @since 3.4.0
691 */
692 public function total_ids() {
693 $total_ids = $this->total_ids;
694 return false !== $total_ids ? intval( $total_ids ) : false;
695 }
696
697 /**
698 * Get the query post arguments for getting all IDs.
699 *
700 * @since 3.0.0
701 * @param mixed $grid_args Optional arguments.
702 */
703 public function all_ids_query_post_args( $grid_args = array() ) {
704 $post_types = $this->post_types();
705
706 $args = array(
707 'post_type' => $post_types,
708 'post_status' => $this->post_status(),
709 'order' => $this->order(),
710 'orderby' => $this->order_by(),
711 'posts_per_page' => -1,
712 // 'posts_per_page' => 2,
713 'fields' => 'ids',
714 );
715
716 // Read permission for private posts.
717 if ( in_array( 'private', $this->post_status() ) && $this->post_status_require_permission() ) {
718 $args['perm'] = 'readable';
719 }
720
721 // Password protected.
722 switch ( $this->password_protected() ) {
723 case 'exclude':
724 $args['has_password'] = false;
725 break;
726 case 'only':
727 $args['has_password'] = true;
728 break;
729 default:
730 $args['has_password'] = null;
731 }
732
733 // Images Only
734 if ( $this->images_only() ) {
735 if ( in_array( 'attachment', $post_types ) ) {
736 $args['post_mime_type'] = 'image/jpeg,image/gif,image/jpg,image/png';
737 } else {
738 $args['meta_query'] = array(
739 array(
740 'relation' => 'OR',
741 array(
742 'key' => '_thumbnail_id',
743 'value' => '0',
744 'compare' => '>'
745 ),
746 array(
747 'key' => 'wpupg_custom_image_id',
748 'value' => '0',
749 'compare' => '>'
750 ),
751 )
752 );
753 }
754 }
755
756 // Exclude specific ids.
757 if ( isset( $grid_args['loaded_ids'] ) ) {
758 $args['post__not_in'] = $grid_args['loaded_ids'];
759 }
760
761 // Apply filters.
762 $tax_query = array(
763 'relation' => 'AND',
764 );
765
766 $meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array();
767 $meta_query['relation'] = 'AND';
768
769 $filters = isset( $grid_args['filters'] ) ? $grid_args['filters'] : array();
770 foreach ( $filters as $filter ) {
771 switch ( $filter['type'] ) {
772 case 'search':
773 $args['s'] = $filter['text'];
774 break;
775 case 'terms':
776 foreach ( $filter['terms'] as $taxonomy => $terms ) {
777 if ( $terms ) {
778 $tax_query[] = array(
779 'taxonomy' => $taxonomy,
780 'field' => 'slug',
781 'terms' => $terms,
782 'operator' => $filter['terms_inverse'] ? 'NOT IN' : 'IN',
783 );
784 }
785 }
786
787 if ( 'AND' !== $filter['terms_relation'] ) {
788 $tax_query['relation'] = $filter['terms_relation'];
789 }
790 break;
791 case 'custom_field':
792 foreach ( $filter['values'] as $value ) {
793 if ( $value ) {
794 switch ( $value['type'] ) {
795 case 'string':
796 $meta_query[] = array(
797 'key' => $filter['custom_field'],
798 'value' => $value['value'],
799 'compare' => $filter['values_inverse'] ? '!=' : '=',
800 );
801 break;
802 case 'number':
803 $meta_query[] = array(
804 'key' => $filter['custom_field'],
805 'value' => $value['value'],
806 'type' => 'NUMERIC',
807 'compare' => $filter['values_inverse'] ? '!=' : '=',
808 );
809 break;
810 case 'range':
811 $meta_query[] = array(
812 'key' => $filter['custom_field'],
813 'value' => $value['value'],
814 'type' => 'NUMERIC',
815 'compare' => $filter['values_inverse'] ? 'NOT BETWEEN' : 'BETWEEN',
816 );
817 break;
818 }
819 }
820 }
821
822 if ( 'AND' !== $filter['values_relation'] ) {
823 $meta_query['relation'] = $filter['values_relation'];
824 }
825 break;
826 }
827 }
828
829 if ( 1 < count( $tax_query ) ) {
830 $args['tax_query'] = $tax_query;
831 }
832 if ( 1 < count( $meta_query ) ) {
833 $args['meta_query'] = $meta_query;
834 }
835
836 return apply_filters( 'wpupg_query_post_args', $args, $this, $grid_args );
837 }
838
839 /**
840 * Get all the IDs that are displayed in this grid.
841 *
842 * @since 3.0.0
843 * @param mixed $grid_args Optional arguments.
844 */
845 public function all_ids( $grid_args = array() ) {
846 if ( false === $this->ids ) {
847 $ids = array();
848 $total_ids = false;
849
850 if ( 'posts' === $this->type() ) {
851 $args = $this->all_ids_query_post_args( $grid_args );
852
853 // Query IDs.
854 $query = new WP_Query( $args );
855 $posts = $query->have_posts() ? $query->posts : array();
856 $ids = array_map( 'intval', $posts );
857 $total_ids = $query->found_posts;
858
859 // Offset posts
860 if ( $this->limit_posts_offset() ) {
861 $ids = array_slice( $ids, $this->limit_posts_offset() );
862 }
863
864 // Limit Total # Posts
865 if ( $this->limit_posts_number() ) {
866 $ids = array_slice( $ids, 0, $this->limit_posts_number() );
867 }
868 }
869
870 $this->ids = apply_filters( 'wpupg_grid_all_ids', $ids, $this, $grid_args );
871 $this->total_ids = $total_ids;
872 }
873
874 return $this->ids;
875 }
876
877 /**
878 * Get the terms to display in this grid.
879 *
880 * @since 3.0.0
881 * @param mixed $grid_args Optional arguments.
882 */
883 public function terms( $grid_args = array() ) {
884 if ( false === $this->terms ) {
885 $terms = array(
886 'per_item' => array(),
887 'per_taxonomy' => array(),
888 );
889 $taxonomies = $this->filters_taxonomies();
890
891 // Only need to get terms if there actually are taxonomies.
892 if ( count( $taxonomies ) ) {
893 $post_ids = $this->all_ids( $grid_args );
894
895 // Build sanitized query.
896 global $wpdb;
897
898 $where_taxonomies = implode( '","', array_map( 'sanitize_key', $taxonomies ) );
899 $where_post_ids = implode( ',', array_map( 'intval', $post_ids ) );
900
901 $query = 'SELECT tr.object_id, tt.taxonomy, tt.parent, t.term_id, t.slug, t.name FROM ' . $wpdb->prefix . 'term_relationships tr JOIN ' . $wpdb->prefix . 'term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id JOIN ' . $wpdb->prefix . 'terms t on tt.term_id = t.term_id WHERE tt.taxonomy IN ("' . $where_taxonomies . '")';
902
903 if ( $where_post_ids ) {
904 $query .= ' AND tr.object_id IN (' . $where_post_ids . ')';
905 }
906
907 $results = $wpdb->get_results( $query, ARRAY_A );
908
909 // Loop over all results.
910 $terms = $this->handle_terms( $terms, $results );
911 }
912
913 $this->terms = $terms;
914 }
915
916 return $this->terms;
917 }
918
919 /**
920 * Get terms from query reults.
921 *
922 * @since 3.5.0
923 */
924 public function handle_terms( $terms, $results, $depth = 0 ) {
925 $parents = array();
926
927 foreach ( $results as $result ) {
928 $item_id = intval( $result['object_id'] );
929 $taxonomy = $result['taxonomy'];
930 $term_id = intval( $result['term_id'] );
931 $parent = intval( $result['parent'] );
932 $slug = rawurldecode( $result['slug'] );
933 $name = apply_filters( 'wpupg_term_name', $result['name'], $term_id, $taxonomy );
934
935 // Make sure arrays exist.
936 if ( ! isset( $terms['per_taxonomy'][ $taxonomy ] ) ) { $terms['per_taxonomy'][ $taxonomy ] = array(); }
937 if ( ! isset( $terms['per_item'][ $item_id ] ) ) { $terms['per_item'][ $item_id ] = array(); }
938 if ( ! isset( $terms['per_item'][ $item_id ][ $taxonomy ] ) ) {
939 $terms['per_item'][ $item_id ][ $taxonomy ] = array(
940 'terms' => array(),
941 'parent_terms' => array(),
942 );
943 }
944 if ( !isset( $terms['per_taxonomy'][ $taxonomy ][ $slug ] ) ) {
945 $terms['per_taxonomy'][ $taxonomy ][ $slug ] = array(
946 'id' => $term_id,
947 'parent' => $parent,
948 'name' => $name,
949 'posts' => array(),
950 'child_posts' => array(),
951 );
952 }
953
954 // Add in correct category.
955 if ( 0 === $depth ) {
956 $terms['per_item'][ $item_id ][ $taxonomy ]['terms'][] = $slug;
957 $terms['per_taxonomy'][ $taxonomy ][ $slug ]['posts'][] = $item_id;
958 } else {
959 $terms['per_item'][ $item_id ][ $taxonomy ]['parent_terms'][] = $slug;
960 $terms['per_taxonomy'][ $taxonomy ][ $slug ]['child_posts'][] = $item_id;
961 }
962
963 // Check if there are further parents we need to get.
964 if ( $parent ) {
965 $parents[] = array(
966 'object_id' => $item_id,
967 'taxonomy' => $taxonomy,
968 'term_id' => $parent,
969 );
970 }
971 }
972
973 // Check if there are any parents we need to associate as well.
974 if ( count( $parents ) ) {
975 $parent_results = array();
976
977 $parent_ids = wp_list_pluck( $parents, 'term_id' );
978 $parent_terms = get_terms( array(
979 'include' => $parent_ids,
980 ) );
981
982 if ( $parent_terms && ! is_wp_error( $parent_terms ) ) {
983 // Set term_id as key.
984 $keyed_parent_terms = array();
985 foreach ( $parent_terms as $parent_term ) {
986 $keyed_parent_terms[ $parent_term->term_id ] = $parent_term;
987 }
988
989 foreach( $parents as $index => $parent ) {
990 if ( isset( $keyed_parent_terms[ $parent['term_id'] ] ) ) {
991 $parent_term = $keyed_parent_terms[ $parent['term_id'] ];
992
993 $parent_results[] = array(
994 'object_id' => $parent['object_id'],
995 'taxonomy' => $parent['taxonomy'],
996 'term_id' => $parent['term_id'],
997 'parent' => $parent_term->parent,
998 'slug' => $parent_term->slug,
999 'name' => $parent_term->name,
1000 );
1001 }
1002 }
1003 }
1004
1005 // Recursive loop.
1006 if ( count( $parent_results ) ) {
1007 $terms = $this->handle_terms( $terms, $parent_results, $depth + 1 );
1008 }
1009 }
1010
1011 return $terms;
1012 }
1013
1014 /**
1015 * Get the terms for a specific item.
1016 *
1017 * @since 3.0.0
1018 * @param int $item_id Item to get the terms for.
1019 */
1020 public function get_terms_for_item( $item_id ) {
1021 $terms = $this->terms();
1022
1023 return isset( $terms['per_item'][ $item_id ] ) ? $terms['per_item'][ $item_id ] : array();
1024 }
1025
1026 /**
1027 * Get the terms for a specific taxonomy.
1028 *
1029 * @since 3.0.0
1030 * @param string $taxonomy Taxonomy to get the terms for.
1031 */
1032 public function get_terms_for_taxonomy( $taxonomy ) {
1033 $terms = $this->terms();
1034
1035 return isset( $terms['per_taxonomy'][ $taxonomy ] ) ? $terms['per_taxonomy'][ $taxonomy ] : array();
1036 }
1037
1038 /**
1039 * Get the taxonomies filtered by in this grid.
1040 *
1041 * @since 3.0.0
1042 */
1043 public function filters_taxonomies() {
1044 $taxonomies = array();
1045
1046 if ( $this->filters_enabled() ) {
1047 $filters = $this->filters();
1048
1049 foreach ( $filters as $filter ) {
1050 if ( ! isset( $filter['options']['source'] ) || 'taxonomies' === $filter['options']['source'] ) {
1051 if ( isset( $filter['options']['taxonomies'] ) ) {
1052 $taxonomies = array_merge( $taxonomies, $filter['options']['taxonomies'] );
1053 }
1054 }
1055 }
1056 }
1057
1058 return array_unique( $taxonomies );
1059 }
1060
1061 /**
1062 * Get the custom fields filtered by in this grid.
1063 *
1064 * @since 3.3.0
1065 */
1066 public function filters_custom_fields() {
1067 $custom_fields = array();
1068
1069 if ( $this->filters_enabled() ) {
1070 $filters = $this->filters();
1071
1072 foreach ( $filters as $filter ) {
1073 if ( ! isset( $filter['options']['source'] ) || 'custom_field' === $filter['options']['source'] ) {
1074 if ( isset( $filter['options']['custom_field'] ) ) {
1075 $custom_fields[] = $filter['options']['custom_field'];
1076 }
1077 }
1078 }
1079 }
1080
1081 return array_unique( $custom_fields );
1082 }
1083 }
1084