PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.2
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.2
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 +26 -11 4.5.34.9.2 View file →
@@ -1,8 +1,12 @@
1 1 <?php
2 +namespace WPDeveloper\BetterDocs\Shortcodes;
2 3
3 -namespace WPDeveloper\BetterDocs\Shortcodes;
4 +if ( ! defined( 'ABSPATH' ) ) {
5 + exit;
6 +}
4 7
8 +
5 9 use WPDeveloper\BetterDocs\Core\Query;
6 10 use WPDeveloper\BetterDocs\Utils\Helper;
7 11 use WPDeveloper\BetterDocs\Core\Settings;
8 12 use WPDeveloper\BetterDocs\Core\Shortcode;
@@ -72,12 +76,17 @@
72 76 $current_lang = $lang_codes['current_language'];
73 77
74 78 // Only search in translation table if current language is different from default
75 79 if ( $default_lang !== $current_lang ) {
80 + $default_lang = preg_replace( '/[^a-z0-9_]/', '', $default_lang );
81 + $current_lang = preg_replace( '/[^a-z0-9_]/', '', $current_lang );
76 82 // TranslatePress table naming: wp_trp_dictionary_{default_lang}_{current_lang}
77 83 $trp_table = $wpdb->prefix . 'trp_dictionary_' . $default_lang . '_' . $current_lang;
78 -
84 +
79 85 if ( $this->table_exists( $trp_table ) ) {
86 + // $trp_table is composed from $wpdb->prefix + sanitized lang slugs (preg_replace allowlist above);
87 + // $like is esc_like()-wrapped with intentional % wildcards; CONCAT() wildcards are query literals, not user input.
88 + // phpcs:disable WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
80 89 $search .= $wpdb->prepare(
81 90 " OR EXISTS (
82 91 SELECT 1 FROM {$trp_table} trp
83 92 WHERE (trp.original LIKE %s OR trp.translated LIKE %s)
@@ -90,8 +99,9 @@
90 99 )",
91 100 $like,
92 101 $like
93 102 );
103 + // phpcs:enable WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
94 104 }
95 105 }
96 106 }
97 107 $search .= " ) ";
@@ -139,8 +149,9 @@
139 149 * Check if a database table exists
140 150 */
141 151 private function table_exists( $table_name ) {
142 152 global $wpdb;
153 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- schema check, caching would mask plugin-activation state.
143 154 $result = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
144 155 return $result === $table_name;
145 156 }
146 157
@@ -145,11 +156,13 @@
145 156 }
146 157
147 158 public function get_search_results() {
148 159 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
160 + // phpcs:disable WordPress.Security.NonceVerification.Missing -- public live-search endpoint, no state change.
161 + $search_input = isset( $_POST['search_input'] ) ? sanitize_text_field( wp_unslash( $_POST['search_input'] ) ) : '';
162 + $search_cat = isset( $_POST['search_cat'] ) ? wp_strip_all_tags( wp_unslash( $_POST['search_cat'] ) ) : '';
163 + $lang = isset( $_POST['lang'] ) ? wp_strip_all_tags( wp_unslash( $_POST['lang'] ) ) : '';
164 + // phpcs:enable WordPress.Security.NonceVerification.Missing
152 165 // Removed preg_replace that was stripping non-Latin characters - sanitize_text_field() already handles security
153 166
154 167 $tax_query = [];
155 168 if ( $search_cat ) {
@@ -171,16 +184,18 @@
171 184 if( current_user_can( 'read_private_docs' ) ) {
172 185 array_push($post_status, 'private');
173 186 }
174 187
188 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- search query supports user-selected category filter.
175 189 $args = [
176 190 'term_id' => isset( $term->term_id ) ? $term->term_id : 0,
177 191 'post_type' => 'docs',
178 192 'post_status' => $post_status,
179 193 'posts_per_page' => -1,
180 - 'suppress_filters' => false,
194 + 'suppress_filters' => false, // Changed to false to allow posts_search filter
181 195 's' => $search_input,
182 196 'orderby' => 'relevance',
197 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- category-scoped search is a core BetterDocs feature; the taxonomy filter is intrinsic to the query.
183 198 'tax_query' => $tax_query
184 199 ];
185 200
186 201 // Handle WPML multilingual search
@@ -189,9 +204,9 @@
189 204 // search across all languages to find translated posts
190 205 if ( preg_match('/[^\x00-\x7F]/', $search_input) ) {
191 206 // Non-ASCII search: bypass WPML language filtering but allow posts_search filter
192 207 // This allows searching across all languages
193 - $args['suppress_filters'] = true;
208 + $args['suppress_filters'] = true; // phpcs:ignore WordPressVIPMinimum.Hooks.PreGetPosts.PreGetPosts,WordPressVIPMinimum.Performance.WPQueryParams.SuppressFilters_suppress_filters -- non-ASCII search must reach all WPML translations.
194 209 } else {
195 210 // ASCII-only search (English), use WPML filters to restrict to current language
196 211 $args['suppress_filters'] = false;
197 212 $args['lang'] = ICL_LANGUAGE_CODE;
@@ -266,9 +281,9 @@
266 281 'doc_categories_ids' => '',
267 282 'enable_docs_search' => true,
268 283 'enable_faq_search' => true,
269 284 'enable_ai_powered_search' => false,
270 - 'kb_based_search' => '' // KB slug to filter search results
285 + 'kb_based_search' => '' // KB slug to filter search results
271 286 ]
272 287 );
273 288 }
274 289
@@ -298,9 +313,9 @@
298 313 'doc_categories_ids' => isset( $atts['doc_categories_ids'] ) ? $atts['doc_categories_ids'] : '',
299 314 'enable_faq_search' => isset( $atts['enable_faq_search'] ) ? $atts['enable_faq_search'] : $defaults_attrs['enable_faq_search'],
300 315 'enable_docs_search' => isset( $atts['enable_docs_search'] ) ? $atts['enable_docs_search'] : $defaults_attrs['enable_docs_search'],
301 316 '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']
317 + 'kb_based_search' => isset( $atts['kb_based_search'] ) ? $atts['kb_based_search'] : $defaults_attrs['kb_based_search']
303 318 ];
304 319 $attributes = apply_filters( 'betterdocs_search_modal_shortcode_attributes', $attributes );
305 320 echo '<div class="betterdocs-search-modal-layout-1" id="betterdocs-search-modal"';
306 321 foreach ( $attributes as $key => $value ) {
@@ -320,9 +335,9 @@
320 335 'doc_categories_ids' => isset( $atts['doc_categories_ids'] ) ? $atts['doc_categories_ids'] : '',
321 336 'enable_faq_search' => isset( $atts['enable_faq_search'] ) ? $atts['enable_faq_search'] : $defaults_attrs['enable_faq_search'],
322 337 'enable_docs_search' => isset( $atts['enable_docs_search'] ) ? $atts['enable_docs_search'] : $defaults_attrs['enable_docs_search'],
323 338 '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']
339 + 'kb_based_search' => isset( $atts['kb_based_search'] ) ? $atts['kb_based_search'] : $defaults_attrs['kb_based_search']
325 340 ];
326 341 $attributes = apply_filters( 'betterdocs_search_modal_shortcode_attributes', $attributes );
327 342
328 343 echo '<div class="betterdocs-search-modal-archive" id="betterdocs-search-modal"';
@@ -342,9 +357,9 @@
342 357 'doc_categories_ids' => isset( $atts['doc_categories_ids'] ) ? $atts['doc_categories_ids'] : '',
343 358 'enable_faq_search' => isset( $atts['enable_faq_search'] ) ? $atts['enable_faq_search'] : $defaults_attrs['enable_faq_search'],
344 359 'enable_docs_search' => isset( $atts['enable_docs_search'] ) ? $atts['enable_docs_search'] : $defaults_attrs['enable_docs_search'],
345 360 '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']
361 + 'kb_based_search' => isset( $atts['kb_based_search'] ) ? $atts['kb_based_search'] : $defaults_attrs['kb_based_search']
347 362 ];
348 363 $attributes = apply_filters( 'betterdocs_search_modal_shortcode_attributes', $attributes );
349 364
350 365 echo '<div class="betterdocs-search-modal-sidebar" id="betterdocs-search-modal"';