PluginProbe
WP Ultimate Post Grid / 4.0.1
WP Ultimate Post Grid v4.0.1
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-filter-isotope.php

class-wpupg-filter-isotope.php in WP Ultimate Post Grid 4.0.1, at includes/public/class-wpupg-filter-isotope.php

512 lines 19.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle output for the Isotope Filter.
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 * Handle output for the Isotope Filter.
14 *
15 * @since 3.0.0
16 * @package WP_Ultimate_Post_Grid
17 * @subpackage WP_Ultimate_Post_Grid/includes/public
18 * @author Brecht Vandersmissen <[email protected]>
19 */
20 class WPUPG_Filter_Isotope {
21
22 /**
23 * Register actions and filters.
24 *
25 * @since 3.0.0
26 */
27 public static function init() {
28 add_filter( 'wpupg_filter_defaults', array( __CLASS__, 'defaults' ), 9 );
29 add_filter( 'wpupg_filter_sanitize_options', array( __CLASS__, 'sanitize' ), 9, 2 );
30 add_filter( 'wpupg_javascript_args_filter', array( __CLASS__, 'javascript_args' ), 9, 3 );
31 add_filter( 'wpupg_output_filter', array( __CLASS__, 'output' ), 9, 4 );
32 }
33
34 /**
35 * Default options for this filter.
36 *
37 * @since 3.0.0
38 * @param mixed $defaults Current defaults to filter.
39 */
40 public static function defaults( $defaults ) {
41 $defaults['isotope'] = array(
42 'source' => 'taxonomies',
43 'custom_field' => '',
44 'custom_field_numeric' => false,
45 'custom_field_fuzzy' => false,
46 'custom_field_options' => array(),
47 'taxonomies' => array(),
48 'match_parents' => false,
49 'inverse' => false,
50 'show_empty' => false,
51 'count' => false,
52 'multiselect' => false,
53 'multiselect_type' => 'match_all',
54 'limit' => false,
55 'limit_exclude' => false,
56 'limit_terms' => array(),
57 'all_button_text' => __( 'All', 'wp-ultimate-post-grid' ),
58 'term_order' => 'alphabetical',
59 'custom_term_order' => array(),
60 'style' => array(
61 'font_size' => '14',
62 'background_color' => '#2E5077',
63 'background_active_color' => '#1C3148',
64 'background_hover_color' => '#1C3148',
65 'text_color' => '#FFFFFF',
66 'text_active_color' => '#FFFFFF',
67 'text_hover_color' => '#FFFFFF',
68 'border_color' => '#1C3148',
69 'border_active_color' => '#1C3148',
70 'border_hover_color' => '#1C3148',
71 'border_width' => '1',
72 'border_radius' => '0',
73 'margin_vertical' => '5',
74 'margin_horizontal' => '5',
75 'padding_vertical' => '5',
76 'padding_horizontal' => '10',
77 'alignment' => 'left',
78 ),
79 );
80
81 return $defaults;
82 }
83
84 /**
85 * Sanitize filter options when saving.
86 *
87 * @since 3.0.0
88 * @param mixed $sanitized_options Current sanitized options.
89 * @param mixed $filter Filter to sanitize.
90 */
91 public static function sanitize( $sanitized_options, $filter ) {
92 if ( 'isotope' === $filter['type'] ) {
93 $options = $filter['options'];
94
95 // Boolean fields.
96 if ( isset( $options['count'] ) ) { $sanitized_options['count'] = $options['count'] ? true : false; }
97 if ( isset( $options['inverse'] ) ) { $sanitized_options['inverse'] = $options['inverse'] ? true : false; }
98 if ( isset( $options['limit'] ) ) { $sanitized_options['limit'] = $options['limit'] ? true : false; }
99 if ( isset( $options['limit_exclude'] ) ) { $sanitized_options['limit_exclude'] = $options['limit_exclude'] ? true : false; }
100 if ( isset( $options['match_parents'] ) ) { $sanitized_options['match_parents'] = $options['match_parents'] ? true : false; }
101 if ( isset( $options['multiselect'] ) ) { $sanitized_options['multiselect'] = $options['multiselect'] ? true : false; }
102 if ( isset( $options['show_empty'] ) ) { $sanitized_options['show_empty'] = $options['show_empty'] ? true : false; }
103
104 // Custom Field.
105 if ( isset( $options['custom_field'] ) ) { $sanitized_options['custom_field'] = sanitize_key( $options['custom_field'] ); }
106 if ( isset( $options['custom_field_numeric'] ) ) { $sanitized_options['custom_field_numeric'] = $options['custom_field_numeric'] ? true : false; }
107 if ( isset( $options['custom_field_fuzzy'] ) ) { $sanitized_options['custom_field_fuzzy'] = $options['custom_field_fuzzy'] ? true : false; }
108 if ( isset( $options['custom_field_options'] ) ) {
109 $sanitized_options['custom_field_options'] = array_map( function( $custom_field_option ) {
110 return array(
111 'value' => sanitize_text_field( $custom_field_option['value'] ),
112 'label' => sanitize_text_field( $custom_field_option['label'] ),
113 );
114 }, $options['custom_field_options'] );
115 }
116
117 // Text fields.
118 if ( isset( $options['all_button_text'] ) ) { $sanitized_options['all_button_text'] = sanitize_text_field( $options['all_button_text'] ); }
119
120 // Limited options fields.
121 $field_options = array( 'taxonomies', 'custom_field' );
122 if ( isset( $options['source'] ) && in_array( $options['source'], $field_options, true ) ) {
123 $sanitized_options['source'] = $options['source'];
124 }
125
126 $field_options = array( 'match_all', 'match_one' );
127 if ( isset( $options['multiselect_type'] ) && in_array( $options['multiselect_type'], $field_options, true ) ) {
128 $sanitized_options['multiselect_type'] = $options['multiselect_type'];
129 }
130
131 $field_options = array( 'alphabetical', 'reverse_alphabetical', 'alphabetical_taxonomies', 'reverse_alphabetical_taxonomies', 'alphabetical_taxonomies_grouped', 'reverse_alphabetical_taxonomies_grouped', 'count_asc', 'count_desc', 'custom' );
132 if ( isset( $options['term_order'] ) && in_array( $options['term_order'], $field_options, true ) ) {
133 $sanitized_options['term_order'] = $options['term_order'];
134 }
135
136 // Taxonomies.
137 if ( isset( $options['taxonomies'] ) ) {
138 $sanitized_options['taxonomies'] = array_map( function( $taxonomy ) {
139 return sanitize_key( $taxonomy );
140 }, $options['taxonomies'] );
141 }
142
143 // Terms.
144 if ( isset( $options['limit_terms'] ) ) {
145 $sanitized_options['limit_terms'] = array();
146
147 foreach ( $options['limit_terms'] as $taxonomy => $terms ) {
148 $taxonomy = sanitize_key( $taxonomy );
149 $sanitized_options['limit_terms'][ $taxonomy ] = array_map( 'intval', $terms );
150 }
151 }
152
153 if ( isset( $options['custom_term_order'] ) ) {
154 $sanitized_options['custom_term_order'] = array();
155
156 foreach ( $options['custom_term_order'] as $taxonomy => $terms ) {
157 $taxonomy = sanitize_key( $taxonomy );
158 $sanitized_options['custom_term_order'][ $taxonomy ] = array_map( 'intval', $terms );
159 }
160 }
161
162 // Style.
163 if ( isset( $options['style'] ) ) {
164 $sanitized_style = array();
165 $style = $options['style'];
166
167 // Text fields.
168 if ( isset( $style['background_active_color'] ) ) { $sanitized_style['background_active_color'] = sanitize_text_field( $style['background_active_color'] ); }
169 if ( isset( $style['background_color'] ) ) { $sanitized_style['background_color'] = sanitize_text_field( $style['background_color'] ); }
170 if ( isset( $style['background_hover_color'] ) ) { $sanitized_style['background_hover_color'] = sanitize_text_field( $style['background_hover_color'] ); }
171 if ( isset( $style['border_active_color'] ) ) { $sanitized_style['border_active_color'] = sanitize_text_field( $style['border_active_color'] ); }
172 if ( isset( $style['border_color'] ) ) { $sanitized_style['border_color'] = sanitize_text_field( $style['border_color'] ); }
173 if ( isset( $style['border_hover_color'] ) ) { $sanitized_style['border_hover_color'] = sanitize_text_field( $style['border_hover_color'] ); }
174 if ( isset( $style['text_active_color'] ) ) { $sanitized_style['text_active_color'] = sanitize_text_field( $style['text_active_color'] ); }
175 if ( isset( $style['text_color'] ) ) { $sanitized_style['text_color'] = sanitize_text_field( $style['text_color'] ); }
176 if ( isset( $style['text_hover_color'] ) ) { $sanitized_style['text_hover_color'] = sanitize_text_field( $style['text_hover_color'] ); }
177
178 // Number fields.
179 if ( isset( $style['border_width'] ) ) { $sanitized_style['border_width'] = intval( $style['border_width'] ); }
180 if ( isset( $style['border_radius'] ) ) { $sanitized_style['border_radius'] = intval( $style['border_radius'] ); }
181 if ( isset( $style['font_size'] ) ) { $sanitized_style['font_size'] = intval( $style['font_size'] ); }
182 if ( isset( $style['margin_horizontal'] ) ) { $sanitized_style['margin_horizontal'] = intval( $style['margin_horizontal'] ); }
183 if ( isset( $style['margin_vertical'] ) ) { $sanitized_style['margin_vertical'] = intval( $style['margin_vertical'] ); }
184 if ( isset( $style['padding_horizontal'] ) ) { $sanitized_style['padding_horizontal'] = intval( $style['padding_horizontal'] ); }
185 if ( isset( $style['padding_vertical'] ) ) { $sanitized_style['padding_vertical'] = intval( $style['padding_vertical'] ); }
186
187 // Limited options fields.
188 $field_options = array( 'left', 'center', 'right' );
189 if ( isset( $style['alignment'] ) && in_array( $style['alignment'], $field_options, true ) ) {
190 $sanitized_style['alignment'] = $style['alignment'];
191 }
192
193 $sanitized_options['style'] = $sanitized_style;
194 }
195
196 // Combine with defaults.
197 $filter_defaults = WPUPG_Filter::get_defaults( 'isotope' );
198 $sanitized_options = array_replace_recursive( $filter_defaults, $sanitized_options );
199 }
200
201 return $sanitized_options;
202 }
203
204 /**
205 * JavaScript arguments for this type of filter.
206 *
207 * @since 3.0.0
208 * @param mixed $args Current JavaScript arguments.
209 * @param mixed $grid Grid to output.
210 * @param mixed $filter Filter to output.
211 */
212 public static function javascript_args( $args, $grid, $filter ) {
213 if ( 'isotope' === $filter['type'] ) {
214 $args['source'] = $filter['options']['source'];
215 $args['custom_field'] = $filter['options']['custom_field'];
216 $args['custom_field_numeric'] = $filter['options']['custom_field_numeric'];
217 $args['custom_field_fuzzy'] = $filter['options']['custom_field_fuzzy'];
218 $args['inverse'] = $filter['options']['inverse'];
219 $args['match_parents'] = $filter['options']['match_parents'];
220 $args['multiselect'] = $filter['options']['multiselect'];
221 $args['multiselect_type'] = $filter['options']['multiselect_type'];
222 }
223
224 return $args;
225 }
226
227 /**
228 * Output a specific filter for a specific grid.
229 *
230 * @since 3.0.0
231 * @param mixed $output Current filter output.
232 * @param mixed $grid Grid to output.
233 * @param mixed $filter Filter to output.
234 * @param mixed $args Optional arguments.
235 */
236 public static function output( $output, $grid, $filter, $args ) {
237 if ( 'isotope' === $filter['type']
238 && (
239 ( 'taxonomies' === $filter['options']['source'] && 0 < count( $filter['options']['taxonomies'] ) )
240 || ( 'custom_field' === $filter['options']['source'] && 0 < count( $filter['options']['custom_field_options'] ) )
241 )
242 ) {
243 $output = '';
244 $output .= self::style( $grid, $filter, $args );
245 $output .= self::html( $grid, $filter, $args );
246 }
247
248 return $output;
249 }
250
251 /**
252 * Output HTML for a filter.
253 *
254 * @since 3.0.0
255 * @param mixed $grid Grid to output.
256 * @param mixed $filter Filter to output.
257 * @param mixed $args Optional arguments.
258 */
259 public static function html( $grid, $filter, $args ) {
260 $output = '';
261 $options = $filter['options'];
262
263 // Output all button if set.
264 if ( $options['all_button_text'] ) {
265 $output .= '<div class="wpupg-filter-item wpupg-filter-isotope-term wpupg-filter-isotope-all wpupg-filter-tag- active" role="button" tabindex="0">' . $options['all_button_text'] . '</div>';
266 }
267
268 // Get the output for each button.
269 if ( 'custom_field' === $options['source'] ) {
270 $button_output = self::button_output_custom_field( $grid, $options );
271 } else {
272 $button_output = self::button_output_taxonomies( $grid, $options );
273 }
274
275 // Allow order and output to get altered.
276 $button_output = apply_filters( 'wpupg_filter_isotope_buttons', $button_output, $filter, $grid, $args );
277
278 // Output buttons.
279 $current_group = false;
280 foreach ( $button_output as $sort_key => $button_output ) {
281 if ( 'taxonomies' === $options['source'] && in_array( $options['term_order'], array( 'alphabetical_taxonomies_grouped', 'reverse_alphabetical_taxonomies_grouped' ) ) ) {
282 $sort_key_parts = explode( ';', $sort_key );
283
284 if ( $current_group !== $sort_key_parts[0] ) {
285 if ( false !== $current_group ) {
286 $output .= '</div>';
287 }
288 $current_group = $sort_key_parts[0];
289 $output .= '<div class="wpupg-filter-tax-container wpupg-filter-tax-' . $sort_key_parts[0] . '">';
290 }
291
292 }
293
294 $output .= $button_output;
295 }
296
297 // Make sure to add closing div if buttons were grouped.
298 if ( false !== $current_group ) {
299 $output .= '</div>';
300 }
301
302 return $output;
303 }
304
305 /**
306 * Get taxonomy buttons.
307 *
308 * @since 3.3.0
309 * @param mixed $grid Grid to output.
310 * @param mixed $options Filter options.
311 */
312 private static function button_output_taxonomies( $grid, $options ) {
313 $button_output = array();
314 foreach ( $options['taxonomies'] as $taxonomy_order => $taxonomy ) {
315 $taxonomy_terms = $grid->get_terms_for_taxonomy( $taxonomy );
316
317 // Show empty terms.
318 if ( $options['show_empty'] ) {
319 $all_terms = get_terms( array(
320 'taxonomy' => $taxonomy,
321 'hide_empty' => false,
322 ) );
323
324 if ( $all_terms && ! is_wp_error( $all_terms ) ) {
325 foreach( $all_terms as $term ) {
326 $slug = urldecode( $term->slug );
327 $name = apply_filters( 'wpupg_term_name', $term->name, $term->term_id, $taxonomy );
328
329 if ( ! array_key_exists( $slug, $taxonomy_terms ) ) {
330 $taxonomy_terms[ $slug ] = array(
331 'id' => $term->term_id,
332 'name' => $name,
333 'posts' => array(),
334 'child_posts' => array(),
335 );
336 }
337 }
338 }
339 }
340
341 // Optionally limit the terms to output.
342 if ( $options['limit'] ) {
343 $limit_term_ids = isset( $options['limit_terms'][ $taxonomy ] ) ? $options['limit_terms'][ $taxonomy ] : array();
344 $exclude_term_ids = $options['limit_exclude'];
345
346 if ( 0 < count( $limit_term_ids ) ) {
347 $taxonomy_terms = array_filter( $taxonomy_terms, function( $term ) use ( $limit_term_ids, $exclude_term_ids ) {
348 $in_array = in_array( $term['id'], $limit_term_ids );
349 return $exclude_term_ids ? ! $in_array : $in_array;
350 });
351 }
352 }
353
354 // Get button output for all terms;
355 foreach ( $taxonomy_terms as $slug => $term ) {
356 $filter_terms = array( $slug );
357
358 // Optionally add count label.
359 $count_number = 0;
360 $count_label = '';
361 if ( $options['count'] || in_array( $options['term_order'], array( 'count_desc', 'count_asc' ) ) ) {
362 if ( $options['match_parents'] ) {
363 $count_number = count( $term['posts'] ) + count( $term['child_posts'] );
364 } else {
365 $count_number = count( $term['posts'] );
366 }
367
368 if ( $options['count'] ) {
369 $count_label = ' (<span class="wpupg-term-count">' . $count_number . '</span>)';
370 }
371 }
372
373 // Need to skip terms that don't have a direct match when not showing empty.
374 if ( ! $options['show_empty'] ) {
375 if ( $options['match_parents'] ) {
376 if ( 0 === count( $term['posts'] ) + count( $term['child_posts'] ) ) {
377 continue;
378 }
379 } else {
380 if ( 0 === count( $term['posts'] ) ) {
381 continue;
382 }
383 }
384 }
385
386 // Construct sort key.
387 $sort_key = strtolower( $term['name'] ) . ';' . str_pad( $term['id'], 10, '0', STR_PAD_LEFT );
388
389 // Sort by count.
390 if ( in_array( $options['term_order'], array( 'count_desc', 'count_asc' ) ) ) {
391 $sort_key = str_pad( $count_number, 10, '0', STR_PAD_LEFT ) . ';' . $sort_key;
392 } elseif ( ! in_array( $options['term_order'], array( 'alphabetical', 'reverse_alphabetical' ) ) ) {
393 if ( 'custom' === $options['term_order'] ) {
394 $index = isset( $options['custom_term_order'][ $taxonomy ] ) ? array_search( $term['id'], $options['custom_term_order'][ $taxonomy ] ) : false;
395
396 if ( false !== $index ) {
397 $sort_key = str_pad( $index, 10, '0', STR_PAD_LEFT );
398 } else {
399 // Last, ordered by ID.
400 $sort_key = str_pad( $term['id'], 10, '1', STR_PAD_LEFT );
401 }
402 }
403
404 // Grouped by taxonomy.
405 $sort_key = str_pad( $taxonomy_order, 10, '0', STR_PAD_LEFT ) . ';' . $sort_key;
406 }
407
408 $button_output[ $sort_key ] = '<div class="wpupg-filter-item wpupg-filter-isotope-term wpupg-filter-isotope-term-' . $taxonomy .' wpupg-filter-tag-' . $slug .'" data-taxonomy="' . $taxonomy . '" data-terms="' . implode( ';', $filter_terms ) . '" role="button" tabindex="0">' . $term['name'] . $count_label . '</div>';
409 }
410 }
411
412 // Sort buttons (reverse) alphabetically.
413 if ( in_array( $options['term_order'], array( 'alphabetical', 'alphabetical_taxonomies', 'alphabetical_taxonomies_grouped', 'count_asc', 'custom' ) ) ) {
414 ksort( $button_output );
415 } else {
416 krsort( $button_output );
417 }
418
419 return $button_output;
420 }
421
422 /**
423 * Get custom field buttons.
424 *
425 * @since 3.3.0
426 * @param mixed $grid Grid to output.
427 * @param mixed $options Filter options.
428 */
429 private static function button_output_custom_field( $grid, $options ) {
430 $button_output = array();
431 $custom_field = $options['custom_field'];
432
433 foreach ( $options['custom_field_options'] as $index => $custom_field_option ) {
434 $value = $custom_field_option['value'];
435 $label = $custom_field_option['label'];
436
437 if ( $value && $label ) {
438 $button_output[] = '<div class="wpupg-filter-item wpupg-filter-isotope-term wpupg-filter-isotope-custom-field wpupg-filter-isotope-custom-field-' . $custom_field . '" data-value="' . esc_attr( $value ) . '" role="button" tabindex="0">' . $label . '</div>';
439 }
440 }
441
442 return $button_output;
443 }
444
445 /**
446 * Output styling for a filter.
447 *
448 * @since 3.0.0
449 * @param mixed $grid Grid to output.
450 * @param mixed $filter Filter to output.
451 * @param mixed $args Optional arguments.
452 */
453 public static function style( $grid, $filter, $args ) {
454 $style = $filter['options']['style'];
455
456 $output = '<style>';
457
458 // Filter styling.
459 $filter_selector = '#wpupg-grid-' . $grid->slug_or_id() . '-filter-' . $filter['id'];
460 $output .= $filter_selector . ' {';
461 $output .= 'text-align: ' . $style['alignment'] . ';';
462 $output .= 'margin: 0 -' . $style['margin_horizontal'] . 'px;';
463 $output .= '}';
464
465 // Default Item styling.
466 $item_selector = $filter_selector . ' .wpupg-filter-item';
467
468 $output .= $item_selector . ' {';
469
470 if ( $style['border_width'] ) {
471 $output .= 'border: ' . $style['border_width'] . 'px solid ' . $style['border_color'] . ';';
472 }
473 if ( $style['border_radius'] ) {
474 $output .= 'border-radius: ' . $style['border_radius'] . 'px;';
475 }
476 $output .= 'background-color: ' . $style['background_color'] . ';';
477 $output .= 'color: ' . $style['text_color'] . ';';
478
479 $output .= 'font-size: ' . $style['font_size'] . 'px;';
480 $output .= 'margin: ' . $style['margin_vertical'] . 'px ' . $style['margin_horizontal'] . 'px;';
481 $output .= 'padding: ' . $style['padding_vertical'] . 'px ' . $style['padding_horizontal'] . 'px;';
482 $output .= '}';
483
484 // Active Item styling.
485 $output .= $item_selector . '.active {';
486 $output .= 'border-color: ' . $style['border_active_color'] . ';';
487 $output .= 'background-color: ' . $style['background_active_color'] . ';';
488 $output .= 'color: ' . $style['text_active_color'] . ';';
489 $output .= '}';
490
491 // Focus Item styling.
492 $hover_styles = '';
493 $hover_styles .= 'outline: none;';
494 $hover_styles .= 'border-color: ' . $style['border_hover_color'] . ';';
495 $hover_styles .= 'background-color: ' . $style['background_hover_color'] . ';';
496 $hover_styles .= 'color: ' . $style['text_hover_color'] . ';';
497
498 $output .= $item_selector . ':focus {' . $hover_styles . '}';
499
500 // Hover Item, only with mouse pointer.
501 $output .= '@media (hover: hover) and (pointer: fine) {';
502 $output .= $item_selector . ':hover {' . $hover_styles . '}';
503 $output .= '}';
504
505 $output .= '</style>';
506
507 return $output;
508 }
509 }
510
511 WPUPG_Filter_Isotope::init();
512