PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.8.9
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.8.9
4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 All 200 releases
← All changes | includes/Shortcodes/SearchModal.php +10 -263 4.4.13.8.9 View file →
@@ -23,224 +23,8 @@
23 23 public function get_script_depends() {
24 24 return [ 'betterdocs-search-modal' ];
25 25 }
26 26
27 - /**
28 - * Modify search query to properly handle non-English characters
29 - *
30 - * @param string $search The search SQL for WHERE clause
31 - * @param WP_Query $query The WP_Query instance
32 - * @return string Modified search SQL
33 - */
34 - public function improve_search_for_non_english( $search, $query ) {
35 - global $wpdb;
36 -
37 - // Only modify our BetterDocs search queries
38 - if ( ! isset( $query->query_vars['post_type'] ) || $query->query_vars['post_type'] !== 'docs' ) {
39 - return $search;
40 - }
41 -
42 - // Only modify if there's a search term
43 - if ( empty( $query->query_vars['s'] ) ) {
44 - return $search;
45 - }
46 -
47 - $search_term = $query->query_vars['s'];
48 -
49 - // If the search term contains non-ASCII characters, we need to ensure proper UTF-8 handling
50 - if ( preg_match('/[^\x00-\x7F]/', $search_term) ) {
51 - // Get the search term with proper escaping
52 - $like = '%' . $wpdb->esc_like( $search_term ) . '%';
53 -
54 - // Build a UTF-8 compatible search query
55 - // Search in post_title, post_content, and post_excerpt
56 - // Note: Removed COLLATE clause to avoid collation mismatch with TranslatePress tables
57 - $search = $wpdb->prepare(
58 - " AND (
59 - ({$wpdb->posts}.post_title LIKE %s)
60 - OR ({$wpdb->posts}.post_content LIKE %s)
61 - OR ({$wpdb->posts}.post_excerpt LIKE %s)",
62 - $like,
63 - $like,
64 - $like
65 - );
66 -
67 - // If TranslatePress is active, also search in the translation dictionary
68 - if ( class_exists( '\TRP_Translate_Press' ) ) {
69 - // Get language codes
70 - $lang_codes = $this->get_trp_language_code();
71 - $default_lang = $lang_codes['default_language'];
72 - $current_lang = $lang_codes['current_language'];
73 -
74 - // Only search in translation table if current language is different from default
75 - if ( $default_lang !== $current_lang ) {
76 - // TranslatePress table naming: wp_trp_dictionary_{default_lang}_{current_lang}
77 - $trp_table = $wpdb->prefix . 'trp_dictionary_' . $default_lang . '_' . $current_lang;
78 -
79 - if ( $this->table_exists( $trp_table ) ) {
80 - $search .= $wpdb->prepare(
81 - " OR EXISTS (
82 - SELECT 1 FROM {$trp_table} trp
83 - WHERE (trp.original LIKE %s OR trp.translated LIKE %s)
84 - AND trp.status != 2
85 - AND (
86 - {$wpdb->posts}.post_title COLLATE utf8mb4_unicode_ci = trp.original COLLATE utf8mb4_unicode_ci
87 - OR {$wpdb->posts}.post_content COLLATE utf8mb4_unicode_ci LIKE CONCAT('%%', trp.original COLLATE utf8mb4_unicode_ci, '%%')
88 - OR {$wpdb->posts}.post_excerpt COLLATE utf8mb4_unicode_ci = trp.original COLLATE utf8mb4_unicode_ci
89 - )
90 - )",
91 - $like,
92 - $like
93 - );
94 - }
95 - }
96 - }
97 - $search .= " ) ";
98 - }
99 -
100 - return $search;
101 - }
102 -
103 - /**
104 - * Get TranslatePress language codes (default and current) for table name construction
105 - *
106 - * @return array Array with 'default_language' and 'current_language' keys
107 - */
108 - private function get_trp_language_code() {
109 - $result = [
110 - 'default_language' => 'en_US',
111 - 'current_language' => 'en_US'
112 - ];
113 -
114 - if ( class_exists( '\TRP_Translate_Press' ) ) {
115 - $trp = \TRP_Translate_Press::get_trp_instance();
116 - if ( isset( $trp ) && method_exists( $trp, 'get_component' ) ) {
117 - $trp_settings = $trp->get_component( 'settings' );
118 -
119 - // Get default language from settings
120 - if ( $trp_settings ) {
121 - $settings = $trp_settings->get_settings();
122 - if ( isset( $settings['default-language'] ) ) {
123 - $result['default_language'] = strtolower( $settings['default-language'] );
124 - }
125 - }
126 -
127 - // Get current language from global variable
128 - global $TRP_LANGUAGE;
129 - if ( isset( $TRP_LANGUAGE ) && ! empty( $TRP_LANGUAGE ) ) {
130 - $result['current_language'] = strtolower( $TRP_LANGUAGE );
131 - }
132 - }
133 - }
134 -
135 - return $result;
136 - }
137 -
138 - /**
139 - * Check if a database table exists
140 - */
141 - private function table_exists( $table_name ) {
142 - global $wpdb;
143 - $result = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
144 - return $result === $table_name;
145 - }
146 -
147 - public function get_search_results() {
148 - global $wpdb;
149 - $search_input = isset( $_POST['search_input'] ) ? sanitize_text_field( $_POST['search_input'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
150 - $search_cat = isset( $_POST['search_cat'] ) ? wp_strip_all_tags( $_POST['search_cat'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
151 - $lang = isset( $_POST['lang'] ) ? wp_strip_all_tags( $_POST['lang'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing
152 - // Removed preg_replace that was stripping non-Latin characters - sanitize_text_field() already handles security
153 -
154 - $tax_query = [];
155 - if ( $search_cat ) {
156 - $tax_query = [
157 - [
158 - 'taxonomy' => 'doc_category',
159 - 'field' => 'slug',
160 - 'terms' => $search_cat,
161 - 'operator' => 'AND',
162 - 'include_children' => true
163 - ]
164 - ];
165 - }
166 -
167 - $term = get_term_by( 'slug', $search_cat );
168 -
169 - $post_status = ['publish'];
170 -
171 - if( current_user_can( 'read_private_docs' ) ) {
172 - array_push($post_status, 'private');
173 - }
174 -
175 - $args = [
176 - 'term_id' => isset( $term->term_id ) ? $term->term_id : 0,
177 - 'post_type' => 'docs',
178 - 'post_status' => $post_status,
179 - 'posts_per_page' => -1,
180 - 'suppress_filters' => false, // Changed to false to allow posts_search filter
181 - 's' => $search_input,
182 - 'orderby' => 'relevance',
183 - 'tax_query' => $tax_query
184 - ];
185 -
186 - // Handle WPML multilingual search
187 - if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) ) {
188 - // If search term contains non-ASCII characters (e.g., Chinese, Japanese, Bangla),
189 - // search across all languages to find translated posts
190 - if ( preg_match('/[^\x00-\x7F]/', $search_input) ) {
191 - // Non-ASCII search: bypass WPML language filtering but allow posts_search filter
192 - // This allows searching across all languages
193 - $args['suppress_filters'] = true;
194 - } else {
195 - // ASCII-only search (English), use WPML filters to restrict to current language
196 - $args['suppress_filters'] = false;
197 - $args['lang'] = ICL_LANGUAGE_CODE;
198 - }
199 - }
200 - // Handle TranslatePress - always allow posts_search filter for non-ASCII
201 - elseif ( class_exists( '\TRP_Translate_Press' ) && preg_match('/[^\x00-\x7F]/', $search_input) ) {
202 - // For TranslatePress, we need posts_search filter to run
203 - $args['suppress_filters'] = false;
204 - }
205 -
206 - // Add filter to improve search for non-English characters
207 - add_filter( 'posts_search', [ $this, 'improve_search_for_non_english' ], 10, 2 );
208 -
209 - $search_results = $this->query->get_posts( $args );
210 -
211 - // Remove filter after query to avoid affecting other queries
212 - remove_filter( 'posts_search', [ $this, 'improve_search_for_non_english' ], 10 );
213 -
214 - $response = [];
215 -
216 - ob_start();
217 - betterdocs()->views->get(
218 - 'shortcode-parts/search-results',
219 - [
220 - 'search_results' => $search_results,
221 - 'search_input' => $search_input
222 - ]
223 - );
224 -
225 - $_output = ob_get_clean();
226 -
227 - $_input_not_found = '';
228 - if ( ! $search_results->have_posts() ) {
229 - $_input_not_found = $search_input;
230 - }
231 -
232 - $response['post_lists'] = $_output;
233 -
234 - if ( $_output && strlen( $search_input ) >= 3 ) {
235 - betterdocs()->query->insert_search_keyword( $search_input, $_input_not_found );
236 - }
237 -
238 - wp_reset_postdata();
239 -
240 - wp_send_json_success( $response );
241 - }
242 -
243 27 public function get_name() {
244 28 return 'betterdocs_search_modal';
245 29 }
246 30
@@ -254,10 +38,10 @@
254 38 [
255 39 'placeholder' => __( 'Search Doc', 'betterdocs' ),
256 40 'heading' => '',
257 41 'subheading' => '',
258 - 'heading_tag' => 'h1',
259 - 'subheading_tag' => 'p',
42 + 'heading_tag' => 'h2',
43 + 'subheading_tag' => 'h3',
260 44 'number_of_docs' => '5',
261 45 'number_of_faqs' => '5',
262 46 'search_button_text' => __( 'Search', 'betterdocs' ),
263 47 'faq_categories_ids' => '',
@@ -262,13 +46,9 @@
262 46 'search_button_text' => __( 'Search', 'betterdocs' ),
263 47 'faq_categories_ids' => '',
264 48 'layout' => 'layout-1',
265 49 'doc_ids' => '',
266 - 'doc_categories_ids' => '',
267 - 'enable_docs_search' => true,
268 - 'enable_faq_search' => true,
269 - 'enable_ai_powered_search' => false,
270 - 'kb_based_search' => '' // KB slug to filter search results
50 + 'doc_categories_ids' => ''
271 51 ]
272 52 );
273 53 }
274 54
@@ -280,27 +60,21 @@
280 60 'nonce' => wp_create_nonce( 'wp_rest' )
281 61 ]
282 62 );
283 63
284 - $defaults_attrs = $this->default_attributes();
285 -
286 64 if ( isset( $atts['layout'] ) && $atts['layout'] == 'layout-1' ) {
287 65 $attributes = [
288 - 'placeholder' => isset( $atts['placeholder'] ) ? $atts['placeholder'] : $defaults_attrs['placeholder'],
289 - 'heading' => isset( $atts['heading'] ) ? $atts['heading'] : $defaults_attrs['heading'],
290 - 'subheading' => isset( $atts['subheading'] ) ? $atts['subheading'] : $defaults_attrs['subheading'],
291 - 'headingtag' => isset( $atts['heading_tag'] ) ? $atts['heading_tag'] : $defaults_attrs['heading_tag'],
292 - 'subheadingtag' => isset( $atts['subheading_tag'] ) ? $atts['subheading_tag'] : $defaults_attrs['subheading_tag'],
66 + 'placeholder' => $atts['placeholder'],
67 + 'heading' => $atts['heading'],
68 + 'subheading' => $atts['subheading'],
69 + 'headingtag' => $atts['heading_tag'],
70 + 'subheadingtag' => $atts['subheading_tag'],
293 71 'buttontext' => isset( $atts['search_button_text'] ) ? $atts['search_button_text'] : '',
294 72 'numberofdocs' => isset( $atts['number_of_docs'] ) ? $atts['number_of_docs'] : 5,
295 73 'numberoffaqs' => isset( $atts['number_of_faqs'] ) ? $atts['number_of_faqs'] : 5,
296 74 'faq_categories_ids' => isset( $atts['faq_categories_ids'] ) ? $atts['faq_categories_ids'] : '',
297 75 'doc_ids' => isset( $atts['doc_ids'] ) ? $atts['doc_ids'] : '',
298 - 'doc_categories_ids' => isset( $atts['doc_categories_ids'] ) ? $atts['doc_categories_ids'] : '',
299 - 'enable_faq_search' => isset( $atts['enable_faq_search'] ) ? $atts['enable_faq_search'] : $defaults_attrs['enable_faq_search'],
300 - 'enable_docs_search' => isset( $atts['enable_docs_search'] ) ? $atts['enable_docs_search'] : $defaults_attrs['enable_docs_search'],
301 - 'enable_ai_powered_search' => isset( $atts['enable_ai_powered_search'] ) ? $atts['enable_ai_powered_search'] : $defaults_attrs['enable_ai_powered_search'],
302 - 'kb_based_search' => isset( $atts['kb_based_search'] ) ? $atts['kb_based_search'] : $defaults_attrs['kb_based_search']
76 + 'doc_categories_ids' => isset( $atts['doc_categories_ids'] ) ? $atts['doc_categories_ids'] : ''
303 77 ];
304 78 $attributes = apply_filters( 'betterdocs_search_modal_shortcode_attributes', $attributes );
305 79 echo '<div class="betterdocs-search-modal-layout-1" id="betterdocs-search-modal"';
306 80 foreach ( $attributes as $key => $value ) {
@@ -308,31 +82,8 @@
308 82 echo ' data-' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
309 83 }
310 84 }
311 85 echo '></div>';
312 - } else if ( isset( $atts['layout'] ) && $atts['layout'] == 'docs-archive' ) {
313 - $attributes = [
314 - 'placeholder' => isset( $atts['placeholder'] ) ? $atts['placeholder'] : '',
315 - 'buttontext' => isset( $atts['search_button_text'] ) ? $atts['search_button_text'] : '',
316 - 'numberofdocs' => isset( $atts['number_of_docs'] ) ? $atts['number_of_docs'] : 5,
317 - 'numberoffaqs' => isset( $atts['number_of_faqs'] ) ? $atts['number_of_faqs'] : 5,
318 - 'faq_categories_ids' => isset( $atts['faq_categories_ids'] ) ? $atts['faq_categories_ids'] : '',
319 - 'doc_ids' => isset( $atts['doc_ids'] ) ? $atts['doc_ids'] : '',
320 - 'doc_categories_ids' => isset( $atts['doc_categories_ids'] ) ? $atts['doc_categories_ids'] : '',
321 - 'enable_faq_search' => isset( $atts['enable_faq_search'] ) ? $atts['enable_faq_search'] : $defaults_attrs['enable_faq_search'],
322 - 'enable_docs_search' => isset( $atts['enable_docs_search'] ) ? $atts['enable_docs_search'] : $defaults_attrs['enable_docs_search'],
323 - 'enable_ai_powered_search' => isset( $atts['enable_ai_powered_search'] ) ? $atts['enable_ai_powered_search'] : $defaults_attrs['enable_ai_powered_search'],
324 - 'kb_based_search' => isset( $atts['kb_based_search'] ) ? $atts['kb_based_search'] : $defaults_attrs['kb_based_search']
325 - ];
326 - $attributes = apply_filters( 'betterdocs_search_modal_shortcode_attributes', $attributes );
327 -
328 - echo '<div class="betterdocs-search-modal-archive" id="betterdocs-search-modal"';
329 - foreach ( $attributes as $key => $value ) {
330 - if ( ! empty( $value ) ) {
331 - echo ' data-' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
332 - }
333 - }
334 - echo '></div>';
335 86 } elseif ( isset( $atts['layout'] ) && $atts['layout'] == 'sidebar' ) {
336 87 $attributes = [
337 88 'placeholder' => $atts['placeholder'],
338 89 'numberofdocs' => isset( $atts['number_of_docs'] ) ? $atts['number_of_docs'] : 5,
@@ -338,13 +89,9 @@
338 89 'numberofdocs' => isset( $atts['number_of_docs'] ) ? $atts['number_of_docs'] : 5,
339 90 'numberoffaqs' => isset( $atts['number_of_faqs'] ) ? $atts['number_of_faqs'] : 5,
340 91 'faq_categories_ids' => isset( $atts['faq_categories_ids'] ) ? $atts['faq_categories_ids'] : '',
341 92 'doc_ids' => isset( $atts['doc_ids'] ) ? $atts['doc_ids'] : '',
342 - 'doc_categories_ids' => isset( $atts['doc_categories_ids'] ) ? $atts['doc_categories_ids'] : '',
343 - 'enable_faq_search' => isset( $atts['enable_faq_search'] ) ? $atts['enable_faq_search'] : $defaults_attrs['enable_faq_search'],
344 - 'enable_docs_search' => isset( $atts['enable_docs_search'] ) ? $atts['enable_docs_search'] : $defaults_attrs['enable_docs_search'],
345 - 'enable_ai_powered_search' => isset( $atts['enable_ai_powered_search'] ) ? $atts['enable_ai_powered_search'] : $defaults_attrs['enable_ai_powered_search'],
346 - 'kb_based_search' => isset( $atts['kb_based_search'] ) ? $atts['kb_based_search'] : $defaults_attrs['kb_based_search']
93 + 'doc_categories_ids' => isset( $atts['doc_categories_ids'] ) ? $atts['doc_categories_ids'] : ''
347 94 ];
348 95 $attributes = apply_filters( 'betterdocs_search_modal_shortcode_attributes', $attributes );
349 96
350 97 echo '<div class="betterdocs-search-modal-sidebar" id="betterdocs-search-modal"';