PluginProbe
Filter Everything — WordPress & WooCommerce Filters / trunk
Filter Everything — WordPress & WooCommerce Filters vtrunk
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 trunk, at src/Admin/AutoFilterSet.php

506 lines 20.4 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 $filterSets = $this->prepareFilterEntities();
317 $filterFields = parent::getFilterFieldService();
318
319 if ($filterSets !== false) {
320 foreach ($filterSets as $filterSet) {
321 $filterSetFields = $filterSet[self::FIELD_NAME_PREFIX];
322 $filterSetFields['post_name'] = $filterSet['filter_set']['post_name'];
323 $is_valid = $this->validateSetFields($filterSetFields);
324 if(!$is_valid){
325 $errors = $this->getErrors();
326 if(in_array(92, $errors)){
327 $limit = $this->getFreeLimitForPostType($filterSetFields['post_type'] ?? '');
328 flrt_refresh_temp_transient(
329 'wpc_auto_filters_error',
330 $filterFields->getErrorMessage(92, $limit)
331 );
332 }
333 continue;
334 }
335 $filterSet = (array)$filterSet['filter_set'];
336 if (!empty($filterSet['post_content'])) {
337 $filterSet['post_content'] = maybe_serialize($filterSet['post_content']);
338 }
339 add_filter('pre_wp_unique_post_slug', 'flrt_force_non_unique_slug', 10, 2);
340
341 $filterSet_post_id = wp_insert_post($filterSet);
342
343 remove_filter('pre_wp_unique_post_slug', 'flrt_force_non_unique_slug', 10);
344 }
345 return true;
346 }
347 return false;
348 }
349
350 public function saveSet($post_id, $post)
351 {
352 $filterSets = $this->prepareFilterEntities();
353
354 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
355 return $post_id;
356 }
357
358 if (wp_is_post_revision($post_id)) {
359 return $post_id;
360 }
361
362 if ($post->post_type !== FLRT_FILTERS_SET_POST_TYPE) {
363 return $post_id;
364 }
365
366 $nonce = filter_input(INPUT_GET, '_flrt_nonce');
367
368 if (!parent::verifyNonce($nonce)) {
369 return $post_id;
370 }
371
372 if (!current_user_can(flrt_plugin_user_caps())) {
373 return $post_id;
374 }
375
376 remove_action('save_post', array($this, 'saveSet'), 10, 2);
377
378 $filterFields = parent::getFilterFieldService();
379 $saveFiltersTrigger = true;
380 $allFiltersValid = true;
381
382 // Save filter fields
383 if (!empty($filterSets[$post->post_excerpt]['wpc_filter_fields'])) {
384 $postData['wpc_filter_fields'] = $filterSets[$post->post_excerpt]['wpc_filter_fields'];
385 // Validate filters
386 if (!$filterFields->validateFilters($postData['wpc_filter_fields'])) {
387 $saveFiltersTrigger = false;
388 }
389
390 if ($saveFiltersTrigger) {
391 $filtersToSave = [];
392
393 // loop
394 $filterConfiguredFields = $filterFields->getFieldsMapping();
395 foreach ($postData['wpc_filter_fields'] as $filterId => $filter) {
396
397 // Set up checkbox fields if they are empty
398 $filter = $filterFields->prepareFilterCheckboxFields($filter, $filterFields->getFieldsByType('checkbox', $filterConfiguredFields));
399
400 // set parent
401 if (!$filter['parent']) {
402 $filter['parent'] = $post_id;
403 }
404
405 $filter = $filterFields->sanitizeFilterFields($filter);
406 $filtersToSave[$filterId] = $filter;
407
408 if (!$filterFields->validateTheFilter($filter, $filterId)) {
409 unset($postData['wpc_filter_fields'][$filterId]);
410 unset($filtersToSave[$filterId]);
411 }
412 }
413 if (empty($filtersToSave)) {
414 $allFiltersValid = false;
415 }
416
417 // Loop to save
418 if ($allFiltersValid) {
419
420 $update_after_save = [];
421 $old_new_ids = [];
422
423 foreach ($filtersToSave as $filterId => $filter) {
424 // save filter
425 // saveFilter() runs the wpc_pre_save_filter hook, where
426 // PermalinksTab::maybeAddGlobalPrefix() forces the slug to the
427 // global prefix of this entity or registers a new one in
428 // wpc_filter_permalinks — nothing else must touch that registry
429 // here (a stale copy written back afterwards used to wipe the
430 // freshly registered prefixes and leave a junk '#' entry).
431 $saved_filter = $filterFields->saveFilter($filter);
432
433 if (isset($saved_filter['parent_filter']) && isset($saved_filter['ID'])) {
434 if (strpos($saved_filter['parent_filter'], 'filter_', 0) !== false) {
435 $update_after_save[$saved_filter['ID']][] = [
436 'key' => 'parent_filter',
437 'value' => $saved_filter['parent_filter']
438 ];
439 }
440 $old_new_ids[$filterId] = $saved_filter['ID'];
441 }
442 }
443
444 // Update data after saving Filters and getting IDs of new ones.
445 if (!empty($update_after_save)) {
446
447 foreach ($update_after_save as $filter_post_id => $fields_to_update) {
448 $filter_post_data = get_post($filter_post_id);
449 $filter_data = maybe_unserialize($filter_post_data->post_content);
450
451 if (!$filter_data) {
452 continue;
453 }
454
455 foreach ($fields_to_update as $field_attr) {
456 if ($field_attr['key'] === 'parent_filter') {
457 if (isset($filter_data['parent_filter'])) {
458 if (isset($old_new_ids[$field_attr['value']])) {
459 $filter_data[$field_attr['key']] = $old_new_ids[$field_attr['value']];
460 }
461 }
462 }
463 }
464
465 $to_update = array(
466 'ID' => $filter_post_id,
467 'post_content' => maybe_serialize($filter_data)
468 );
469
470 // Unhook wp_targeted_link_rel() filter from WP 5.1 corrupting serialized data.
471 remove_filter('content_save_pre', 'wp_targeted_link_rel');
472 add_filter('pre_wp_unique_post_slug', 'flrt_force_non_unique_slug', 10, 2);
473
474 // Slash data.
475 // WP expects all data to be slashed and will unslash it (fixes '\' character issues)
476 $to_update = wp_slash($to_update);
477
478 wp_update_post($to_update);
479
480 remove_filter('pre_wp_unique_post_slug', 'flrt_force_non_unique_slug', 10);
481 }
482 }
483 }
484 }
485 }
486
487 // Save Set fields
488 $set_fields_key = self::FIELD_NAME_PREFIX;
489
490 if (!empty($filterSets[$post->post_excerpt][$set_fields_key]) && $saveFiltersTrigger && $allFiltersValid) {
491 $setFields = $filterSets[$post->post_excerpt][$set_fields_key];
492 $setFields['ID'] = $post_id;
493 $setFields['title'] = isset($post->post_title) ? $post->post_title : '';
494
495 parent::saveSetFields($setFields);
496 }
497
498 if (!$saveFiltersTrigger || !$allFiltersValid) {
499 wp_delete_post($post_id, true);
500 }
501
502 add_action('save_post', array($this, 'saveSet'), 10, 2);
503
504 return $post;
505 }
506 }