PluginProbe
Boxzilla – WordPress Popup Builder / trunk
Boxzilla – WordPress Popup Builder vtrunk
3.4.11 3.4.10 3.4.9 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 trunk 3.0 3.0.1 3.0.2 3.0.3 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 All 72 releases
boxzilla / src / admin / class-autocomplete.php

class-autocomplete.php in Boxzilla – WordPress Popup Builder trunk, at src/admin/class-autocomplete.php

152 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Boxzilla\Filter;
4
5 if (! defined('ABSPATH')) {
6 exit;
7 }
8
9 class Autocomplete
10 {
11 private const MAX_RESULTS = 20;
12
13 public function init(): void
14 {
15 add_action('wp_ajax_boxzilla_autocomplete', [ $this, 'ajax' ], 10, 0);
16 }
17
18 /**
19 * AJAX listener for autocomplete
20 */
21 public function ajax(): void
22 {
23 if (! current_user_can('edit_box')) {
24 wp_die('', '', [ 'response' => 403 ]);
25 }
26
27 $q = isset($_GET['q']) ? sanitize_text_field(wp_unslash($_GET['q'])) : '';
28 $allowed_types = [ 'page', 'post', 'category', 'post_type', 'post_tag' ];
29 $type = isset($_GET['type']) ? sanitize_key(wp_unslash($_GET['type'])) : '';
30 if (! in_array($type, $allowed_types, true)) {
31 $type = 'post';
32 }
33
34 // do nothing if supplied 'q' parameter is omitted or empty
35 // or less than 2 characters long
36 if (empty($q) || strlen($q) < 2) {
37 wp_die();
38 }
39
40 switch ($type) {
41 default:
42 case 'post':
43 case 'page':
44 echo esc_html($this->list_posts($q, $type));
45 break;
46
47 case 'category':
48 echo esc_html($this->list_categories($q));
49 break;
50
51 case 'post_type':
52 echo esc_html($this->list_post_types($q));
53 break;
54
55 case 'post_tag':
56 echo esc_html($this->list_tags($q));
57 break;
58 }
59
60 wp_die();
61 }
62
63 /**
64 * @param string $query
65 * @param string $post_type
66 *
67 * @return string
68 */
69 protected function list_posts($query, $post_type = 'post')
70 {
71 global $wpdb;
72 $like = $wpdb->esc_like($query) . '%';
73 $limit = self::MAX_RESULTS;
74
75 $post_slugs = $wpdb->get_col(
76 $wpdb->prepare(
77 "SELECT p.post_name FROM $wpdb->posts p WHERE p.post_type = %s AND p.post_status = 'publish' AND ( p.post_title LIKE %s OR p.post_name LIKE %s ) GROUP BY p.post_name ORDER BY p.post_name ASC LIMIT %d",
78 $post_type,
79 $like,
80 $like,
81 $limit
82 )
83 );
84 return join(PHP_EOL, $post_slugs);
85 }
86
87 /**
88 * @param string $query
89 *
90 * @return string
91 */
92 protected function list_categories($query)
93 {
94 $terms = get_terms([
95 'taxonomy' => 'category',
96 'name__like' => $query,
97 'number' => self::MAX_RESULTS,
98 'fields' => 'names',
99 'hide_empty' => false,
100 ]);
101
102 if (is_wp_error($terms)) {
103 return '';
104 }
105
106 return join(PHP_EOL, $terms);
107 }
108
109 /**
110 * @param string $query
111 *
112 * @return string
113 */
114 protected function list_tags($query)
115 {
116 $terms = get_terms([
117 'taxonomy' => 'post_tag',
118 'name__like' => $query,
119 'number' => self::MAX_RESULTS,
120 'fields' => 'names',
121 'hide_empty' => false,
122 ]);
123
124 if (is_wp_error($terms)) {
125 return '';
126 }
127
128 return join(PHP_EOL, $terms);
129 }
130
131
132 /**
133 * @param string $query
134 *
135 * @return string
136 */
137 protected function list_post_types($query)
138 {
139 $post_types = get_post_types([ 'public' => true ], 'names');
140 $matched_post_types = array_filter(
141 $post_types,
142 function ($name) use ($query) {
143 return strpos($name, $query) === 0;
144 }
145 );
146
147 $matched_post_types = array_slice($matched_post_types, 0, self::MAX_RESULTS);
148
149 return join(PHP_EOL, $matched_post_types);
150 }
151 }
152