PluginProbe
Filter Everything — WordPress & WooCommerce Filters / 1.9.5
Filter Everything — WordPress & WooCommerce Filters v1.9.5
1.9.6 1.9.5 1.9.4 1.9.3 1.9.2.2 1.9.2.1 trunk 1.2.1 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.4.1 1.4.4 1.4.5 1.4.8 1.4.9 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 1.6.3 All 51 releases
filter-everything / src / Admin / AutoFilterSet.php

AutoFilterSet.php in Filter Everything — WordPress & WooCommerce Filters 1.9.5, at src/Admin/AutoFilterSet.php

512 lines 20.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FilterEverything\Filter;
4
5 if (!defined('ABSPATH')) {
6 exit;
7 }
8
9 class AutoFilterSet extends FilterSet
10 {
11 public $post_types;
12
13 public $publicTaxonomies = [];
14
15 public $postTaxonomies = [];
16
17 public $limit = 5;
18
19 public $redirect_url = '';
20
21 public $fse;
22
23
24 public function __construct($redirect_url = '')
25 {
26 add_action('save_post', array($this, 'saveSet'), 10, 2);
27 $this->redirect_url = $redirect_url;
28 $this->fse = Container::instance()->getFilterSetService();
29 $this->post_types = $this->fse->getPostTypes();
30
31 if (empty($this->post_types)) {
32 flrt_refresh_temp_transient('wpc_auto_filters_error', esc_html__('Error: No post types found. Please add your first post and try again, or create a Filter Set manually.', 'filter-everything'));
33 wp_redirect(esc_url_raw($redirect_url));
34 exit();
35 }
36
37 if (!empty($this->post_types['page'])) {
38 unset($this->post_types['page']);
39 }
40
41 $this->publicTaxonomies = get_taxonomies(['public' => true], 'objects');
42
43 if (flrt_is_woocommerce()) {
44 $attributeTaxonomies = wc_get_attribute_taxonomies();
45
46 if (!empty($attributeTaxonomies)) {
47 foreach ($attributeTaxonomies as $attr) {
48 $taxonomy = wc_attribute_taxonomy_name($attr->attribute_name);
49 $taxonomy_obj = get_taxonomy($taxonomy);
50 if ($taxonomy_obj) {
51 $this->publicTaxonomies[$taxonomy] = $taxonomy_obj;
52 }
53 }
54 }
55 }
56
57 foreach ($this->post_types as $post_type => $post_name) {
58 $this->postTaxonomies[$post_type] = $this->getPostTaxonomies($post_type);
59 }
60
61 $result = $this->addAutoFilters();
62 if (!$result) {
63 flrt_refresh_temp_transient('wpc_auto_filters_error', esc_html__("Error: Automatic filters were not created. Please try again, or set them up manually.", 'filter-everything'));
64 wp_redirect(esc_url_raw($redirect_url));
65 exit();
66 }
67
68 wp_redirect(esc_url_raw($redirect_url));
69 exit();
70 }
71
72 private function filterSetDefaultSettings($post)
73 {
74 return array(
75 'post_author' => wp_get_current_user()->ID,
76 'post_type' => FLRT_FILTERS_SET_POST_TYPE,
77 'post_status' => 'inherit',
78 'post_title' => $post['post_title'],
79 'post_excerpt' => $post['post_excerpt'],
80 'post_name' => '1'
81 );
82 }
83
84 private function filterSetFields($post)
85 {
86 return array(
87 'post_type' => (!empty($post['post_type'])) ? $post['post_type'] : 'post',
88 'search_field_menu_order' => $post['search_field_menu_order'],
89 'apply_button_menu_order' => $post['apply_button_menu_order'],
90 'wp_page_type' => 'common___common',
91 'wp_filter_query' => '-1',
92 'hide_empty' => 'no',
93 'show_count' => 'yes',
94 'search_field_label' => ' ' . esc_html__('Search', 'filter-everything'),
95 'search_field_placeholder' => '',
96 'apply_button_text' => ' ' . esc_html__('Apply', 'filter-everything'),
97 'reset_button_text' => ' ' . esc_html__('Reset', 'filter-everything'),
98 'horizontal_view_priority' => 'filter_set',
99 );
100 }
101
102 private function filterFieldDefaultSettings($post)
103 {
104
105 return array(
106 'ID' => 'wpc_new_id',
107 'entity' => $post['entity'],
108 'e_name' => (!empty($post['e_name'])) ? $post['e_name'] : '',
109 'view' => (!empty($post['view'])) ? $post['view'] : 'checkboxes',
110 'date_type' => 'date',
111 'show_term_names' => 'yes',
112 'dropdown_label' => '',
113 'date_format' => 'F j, Y',
114 'logic' => (!empty($post['logic'])) ? $post['logic'] : 'or',
115 'label' => (!empty($post['label'])) ? $post['label'] : '',
116 'orderby' => 'default',
117 'in_path' => (!empty($post['in_path'])) ? $post['in_path'] : 'yes',
118 'range_slider' => 'yes',
119 'step' => '1',
120 'parent_filter' => '-1',
121 'parent' => '',
122 'min_num_label' => '',
123 'max_num_label' => '',
124 'tooltip' => '',
125 'show_chips' => 'yes',
126 'more_less' => 'yes',
127 'slug' => $post['post_name'],
128 );
129 }
130
131 private function getPostTaxonomies($post_type)
132 {
133 global $wpdb;
134 $sql = "SELECT tt.taxonomy, MIN(tr.term_taxonomy_id) AS term_taxonomy_id
135 FROM {$wpdb->posts} p
136 INNER JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
137 INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
138 WHERE p.post_type = '%s'
139 GROUP BY tt.taxonomy
140 ORDER BY term_taxonomy_id ASC;";
141
142 $excludeTaxonomies = flrt_excluded_taxonomies();
143 $query = $wpdb->prepare($sql, $post_type);
144 $taxonomies = $wpdb->get_results($query, ARRAY_A);
145 if (!empty($taxonomies)) {
146 foreach ($taxonomies as $key => $taxonomy) {
147 if (empty($this->publicTaxonomies[$taxonomy['taxonomy']])) {
148 unset($taxonomies[$key]);
149 }
150 if (in_array($taxonomy['taxonomy'], $excludeTaxonomies)) {
151 unset($taxonomies[$key]);
152 }
153 }
154 return $taxonomies;
155 }
156 return false;
157 }
158
159 public function standardPostFilters()
160 {
161 $entities = array(
162 'post' => array(
163 'taxonomy' => ['category', 'post_tag']
164 )
165 );
166
167
168 if (flrt_is_woocommerce()) {
169 $entities['product'] = array(
170 'taxonomy' => ['product_cat', 'product_tag'],
171 'post_meta_num' => ['_price'],
172 );
173 }
174
175 foreach ($entities as $post_type => $entity) {
176 foreach ($entity['taxonomy'] as $taxonomy) {
177 if (empty($this->checkTaxonomyTerms($taxonomy))) {
178 $key = array_search($taxonomy, $entities[$post_type]['taxonomy']);
179 if ($key !== false) {
180 unset($entities[$post_type]['taxonomy']);
181 }
182 }
183 }
184 }
185
186
187 foreach ($this->postTaxonomies as $post_type => $taxonomies) {
188 $i = 1;
189 foreach ($taxonomies as $taxonomy) {
190 if ($this->limit < $i) continue;
191 if (!empty($entities[$post_type]) &&
192 !empty($entities[$post_type]['taxonomy'])
193 && in_array($taxonomy['taxonomy'], $entities[$post_type]['taxonomy'])) {
194 $i++;
195 continue;
196 }
197 if (empty($this->checkTaxonomyTerms($taxonomy))) {
198 continue;
199 }
200 $entities[$post_type]['taxonomy'][] = $taxonomy['taxonomy'];
201 $i++;
202 }
203 }
204 return $entities;
205 }
206
207 private function checkTaxonomyTerms($taxonomy)
208 {
209 return get_terms([
210 'taxonomy' => $taxonomy,
211 'hide_empty' => false,
212 ]);
213 }
214
215 private function prepareFilterEntities()
216 {
217 $filterSets = [];
218 $entities = $this->standardPostFilters();
219 $empty_all_entities = true;
220 foreach ($entities as $entity) {
221 if (!empty($entity)) {
222 $empty_all_entities = false;
223 }
224 }
225 if ($empty_all_entities) {
226 flrt_refresh_temp_transient('wpc_auto_filters_error', esc_html__("Error: No taxonomies found. Please create your first taxonomy and then try again.", 'filter-everything'));
227 wp_redirect(esc_url_raw($this->redirect_url));
228 exit();
229 }
230
231 if (!empty($entities)) {
232 foreach ($entities as $post_type => $data) {
233 $post = [];
234 $title_base = (string)$post_type;
235 $title_base = ltrim($title_base);
236 if ($title_base !== '') {
237 $firstChar = mb_substr($title_base, 0, 1, 'UTF-8');
238 $rest = mb_substr($title_base, 1, null, 'UTF-8');
239 $title_base = mb_strtoupper($firstChar, 'UTF-8') . $rest;
240 }
241 $post_title = $title_base . " " . esc_html__('filters', 'filter-everything');
242 $post['post_title'] = flrt_generate_unique_copy_title($post_title, FLRT_FILTERS_SET_POST_TYPE, esc_html__('(auto-generated)', 'filter-everything'), false);
243 $post['post_excerpt'] = $post_type;
244
245 $filterSets[$post_type]['filter_set'] = $this->filterSetDefaultSettings($post);
246 $post = [];
247 $post['post_type'] = $post_type;
248 $post['search_field_menu_order'] = count($data['taxonomy']) + 1;
249 $post['apply_button_menu_order'] = count($data['taxonomy']) + 2;
250 $filterSets[$post_type][self::FIELD_NAME_PREFIX] = $this->filterSetFields($post);
251
252 $standard_slugs = [
253 'category' => 'pcat',
254 'post_tag' => 'ptag',
255 'product_cat' => 'category',
256 'product_tag' => 'tag'
257 ];
258
259 foreach ($data as $entity => $taxonomies) {
260 foreach ($taxonomies as $taxonomy) {
261 // $post_filter_field['post_title'] = '';
262 $post_filter_field = [];
263 if ($entity === 'taxonomy') {
264 $post_filter_field['in_path'] = 'yes';
265 $post_filter_field['entity'] = $entity . "_" . $taxonomy;
266 $post_filter_field['label'] = $this->publicTaxonomies[$taxonomy]->label;
267 $post_filter_field['post_name'] = $taxonomy;
268 }
269
270
271 if (flrt_is_woocommerce() && $post_type === 'product') {
272 if (isset($post_filter_field['post_name']) && isset($standard_slugs[$post_filter_field['post_name']])) {
273 $post_filter_field['post_name'] = $standard_slugs[$post_filter_field['post_name']];
274 } elseif (strpos($post_filter_field['post_name'], 'pa_') === 0) {
275 $post_filter_field['post_name'] = substr($post_filter_field['post_name'], 3);
276 }
277 }
278
279 if ($post_type === 'post' && isset($post_filter_field['post_name']) && isset($standard_slugs[$post_filter_field['post_name']])) {
280 $post_filter_field['post_name'] = $standard_slugs[$post_filter_field['post_name']];
281 }
282
283
284 if (defined('FLRT_FILTERS_PRO') && FLRT_FILTERS_PRO) {
285 $post_filter_field['post_name'] = ltrim($post_filter_field['post_name'], "_");
286 $post_filter_field['post_name'] = str_replace("_", "-", $post_filter_field['post_name']);
287 } else {
288 $post_filter_field['post_name'] = '_' . $post_filter_field['post_name'];
289 }
290
291 if ($entity === 'post_meta_num') {
292 $post_filter_field['label'] = esc_html__('Price', 'filter-everything');
293 $post_filter_field['view'] = 'range';
294 $post_filter_field['logic'] = 'and';
295 $post_filter_field['post_name'] = 'price';
296 $post_filter_field['entity'] = $entity;
297 $post_filter_field['e_name'] = $taxonomy;
298 }
299
300 $filter_field = $this->filterFieldDefaultSettings($post_filter_field);
301 if ($entity === 'post_meta_num') {
302 unset($filter_field['in_path']);
303 }
304 $filterSets[$post_type]['wpc_filter_fields'][] = $filter_field;
305 }
306 }
307 }
308
309 return apply_filters('wpc_default_filters_config', $filterSets);
310 }
311 return false;
312 }
313
314 private function addAutoFilters()
315 {
316 $filterLinks = get_option('wpc_filter_permalinks', []);
317 $filterSets = $this->prepareFilterEntities();
318 $filterFields = parent::getFilterFieldService();
319
320 if ($filterSets !== false) {
321 foreach ($filterSets as $filterSet) {
322 $filterSetFields = $filterSet[self::FIELD_NAME_PREFIX];
323 $filterSetFields['post_name'] = $filterSet['filter_set']['post_name'];
324 $is_valid = $this->validateSetFields($filterSetFields);
325 if(!$is_valid){
326 $errors = $this->getErrors();
327 if(in_array(92, $errors)){
328 $limit = $this->getFreeLimitForPostType($filterSetFields['post_type'] ?? '');
329 flrt_refresh_temp_transient(
330 'wpc_auto_filters_error',
331 $filterFields->getErrorMessage(92, $limit)
332 );
333 }
334 continue;
335 }
336 $filterSet = (array)$filterSet['filter_set'];
337 if (!empty($filterSet['post_content'])) {
338 $filterSet['post_content'] = maybe_serialize($filterSet['post_content']);
339 }
340 add_filter('pre_wp_unique_post_slug', 'flrt_force_non_unique_slug', 10, 2);
341
342 $filterSet_post_id = wp_insert_post($filterSet);
343
344 remove_filter('pre_wp_unique_post_slug', 'flrt_force_non_unique_slug', 10);
345 }
346 return true;
347 }
348 return false;
349 }
350
351 public function saveSet($post_id, $post)
352 {
353 $filterSets = $this->prepareFilterEntities();
354
355 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
356 return $post_id;
357 }
358
359 if (wp_is_post_revision($post_id)) {
360 return $post_id;
361 }
362
363 if ($post->post_type !== FLRT_FILTERS_SET_POST_TYPE) {
364 return $post_id;
365 }
366
367 $nonce = filter_input(INPUT_GET, '_flrt_nonce');
368
369 if (!parent::verifyNonce($nonce)) {
370 return $post_id;
371 }
372
373 if (!current_user_can(flrt_plugin_user_caps())) {
374 return $post_id;
375 }
376
377 remove_action('save_post', array($this, 'saveSet'), 10, 2);
378
379 $filterFields = parent::getFilterFieldService();
380 $saveFiltersTrigger = true;
381 $allFiltersValid = true;
382 $filterLinks = get_option('wpc_filter_permalinks', []);
383
384 // Save filter fields
385 if (!empty($filterSets[$post->post_excerpt]['wpc_filter_fields'])) {
386 $postData['wpc_filter_fields'] = $filterSets[$post->post_excerpt]['wpc_filter_fields'];
387 // Validate filters
388 if (!$filterFields->validateFilters($postData['wpc_filter_fields'])) {
389 $saveFiltersTrigger = false;
390 }
391
392 if ($saveFiltersTrigger) {
393 $filtersToSave = [];
394
395 // loop
396 $filterConfiguredFields = $filterFields->getFieldsMapping();
397 foreach ($postData['wpc_filter_fields'] as $filterId => $filter) {
398
399 // Set up checkbox fields if they are empty
400 $filter = $filterFields->prepareFilterCheckboxFields($filter, $filterFields->getFieldsByType('checkbox', $filterConfiguredFields));
401
402 // set parent
403 if (!$filter['parent']) {
404 $filter['parent'] = $post_id;
405 }
406
407 $filter = $filterFields->sanitizeFilterFields($filter);
408 $filtersToSave[$filterId] = $filter;
409
410 if (!$filterFields->validateTheFilter($filter, $filterId)) {
411 unset($postData['wpc_filter_fields'][$filterId]);
412 unset($filtersToSave[$filterId]);
413 }
414 }
415 if (empty($filtersToSave)) {
416 $allFiltersValid = false;
417 }
418
419 // Loop to save
420 if ($allFiltersValid) {
421
422 $update_after_save = [];
423 $old_new_ids = [];
424
425 foreach ($filtersToSave as $filterId => $filter) {
426 // save filter
427 $saved_filter = $filterFields->saveFilter($filter);
428 $link_filter = $saved_filter;
429 $link_filter['post_content'] = maybe_serialize($link_filter['post_content']);
430 $entity = $link_filter['post_content']['entity'];
431 $taxonomy = $link_filter['post_content']['e_name'];
432 if (!empty($filterLinks[$entity . "#" . $taxonomy])) {
433 $filterField['post_name'] = $filterLinks[$entity . "#" . $taxonomy];
434 } else {
435 $filterLinks[$entity . "#" . $taxonomy] = $filterField['post_name'];
436 }
437
438 if (isset($saved_filter['parent_filter']) && isset($saved_filter['ID'])) {
439 if (strpos($saved_filter['parent_filter'], 'filter_', 0) !== false) {
440 $update_after_save[$saved_filter['ID']][] = [
441 'key' => 'parent_filter',
442 'value' => $saved_filter['parent_filter']
443 ];
444 }
445 $old_new_ids[$filterId] = $saved_filter['ID'];
446 }
447 }
448
449 update_option('wpc_filter_permalinks', $filterLinks);
450 // Update data after saving Filters and getting IDs of new ones.
451 if (!empty($update_after_save)) {
452
453 foreach ($update_after_save as $filter_post_id => $fields_to_update) {
454 $filter_post_data = get_post($filter_post_id);
455 $filter_data = maybe_unserialize($filter_post_data->post_content);
456
457 if (!$filter_data) {
458 continue;
459 }
460
461 foreach ($fields_to_update as $field_attr) {
462 if ($field_attr['key'] === 'parent_filter') {
463 if (isset($filter_data['parent_filter'])) {
464 if (isset($old_new_ids[$field_attr['value']])) {
465 $filter_data[$field_attr['key']] = $old_new_ids[$field_attr['value']];
466 }
467 }
468 }
469 }
470
471 $to_update = array(
472 'ID' => $filter_post_id,
473 'post_content' => maybe_serialize($filter_data)
474 );
475
476 // Unhook wp_targeted_link_rel() filter from WP 5.1 corrupting serialized data.
477 remove_filter('content_save_pre', 'wp_targeted_link_rel');
478 add_filter('pre_wp_unique_post_slug', 'flrt_force_non_unique_slug', 10, 2);
479
480 // Slash data.
481 // WP expects all data to be slashed and will unslash it (fixes '\' character issues)
482 $to_update = wp_slash($to_update);
483
484 wp_update_post($to_update);
485
486 remove_filter('pre_wp_unique_post_slug', 'flrt_force_non_unique_slug', 10);
487 }
488 }
489 }
490 }
491 }
492
493 // Save Set fields
494 $set_fields_key = self::FIELD_NAME_PREFIX;
495
496 if (!empty($filterSets[$post->post_excerpt][$set_fields_key]) && $saveFiltersTrigger && $allFiltersValid) {
497 $setFields = $filterSets[$post->post_excerpt][$set_fields_key];
498 $setFields['ID'] = $post_id;
499 $setFields['title'] = isset($post->post_title) ? $post->post_title : '';
500
501 parent::saveSetFields($setFields);
502 }
503
504 if (!$saveFiltersTrigger || !$allFiltersValid) {
505 wp_delete_post($post_id, true);
506 }
507
508 add_action('save_post', array($this, 'saveSet'), 10, 2);
509
510 return $post;
511 }
512 }