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/REST/DocCategories.php +17 -9 4.5.24.9.2 View file →
@@ -1,6 +1,10 @@
1 1 <?php
2 -
2 +// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- core docs taxonomy REST endpoints; meta filtering required.
3 +// phpcs:disable WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- endpoint exposes user-driven exclusion.
4 +// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table identifiers (WP-provided) and dynamic %s placeholders are intentional.
5 +// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- the uncategorized-docs scan needs raw SQL because WP_Query has no NOT-IN-via-subquery primitive.
6 +// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- list is rebuilt per-request from live post/term state; cache would mask uncategorized status changes.
3 7 namespace WPDeveloper\BetterDocs\REST;
4 8
5 9 use stdClass;
6 10 use WPDeveloper\BetterDocs\Core\BaseAPI;
@@ -14,9 +18,9 @@
14 18
15 19 public function register() {
16 20 $this->get( 'doc-categories', array( $this, 'get_response' ), array(
17 21 'password' => array(
18 - 'description' => __( 'The password for password-protected docs.' ),
22 + 'description' => __( 'The password for password-protected docs.', 'betterdocs' ),
19 23 'type' => 'string'
20 24 )
21 25 ) );
22 26 $this->get( 'doc-categories-kb', array( $this, 'doc_categories_kb_response' ) );
@@ -190,9 +194,9 @@
190 194 $posts = betterdocs()->query->get_posts( $query_args, true );
191 195 $response[ $term->term_id ] = array();
192 196
193 197 if ( ! $posts->have_posts() ) {
194 - wp_reset_query();
198 + wp_reset_postdata();
195 199 }
196 200 while ( $posts->have_posts() ):
197 201 $posts->the_post();
198 202 $post_obj = get_post( get_the_ID() );
@@ -209,9 +213,9 @@
209 213 array_push( $response[ $term->term_id ], $data );
210 214 endwhile;
211 215
212 216 wp_reset_postdata();
213 - wp_reset_query();
217 + wp_reset_query(); // phpcs:ignore WordPress.WP.DiscouragedFunctions.wp_reset_query_wp_reset_query -- explicit global WP_Query reset after a custom loop; wp_reset_postdata() above only restores post data.
214 218
215 219 // WP_Query's `orderby=post__in` is stripped by some plugins/filters
216 220 // (notably WPML on REST requests), so apply the saved order in PHP
217 221 // here as the source of truth. Posts not in the saved order are
@@ -224,16 +228,20 @@
224 228
225 229 /**
226 230 * Uncategories Docs
227 231 */
228 - // Build secure query for uncategorized docs with proper post status filtering
232 + // Build secure query for uncategorized docs with proper post status filtering.
233 + // $wpdb->posts / $wpdb->term_relationships / $wpdb->term_taxonomy are WP-provided
234 + // table identifiers (safe to interpolate). Dynamic %s placeholder count is built
235 + // from a fixed-shape $post_status array.
229 236 $post_status_placeholders = implode( ',', array_fill( 0, count( $post_status ), '%s' ) );
230 - $_post__not_in_query = $wpdb->prepare(
237 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber -- WP table identifiers; placeholders dynamically generated to match $post_status size.
238 + $_post__not_in_query = $wpdb->prepare(
231 239 "SELECT ID as post_id from $wpdb->posts WHERE post_type = %s AND post_status IN ($post_status_placeholders) AND post_status != 'trash' AND post_status != 'auto-draft' AND ID NOT IN ( SELECT object_id as post_id FROM $wpdb->term_relationships WHERE term_taxonomy_id IN ( SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = %s ) )",
232 240 array_merge( array( 'docs' ), $post_status, array( 'doc_category' ) )
233 241 );
234 242
235 - $_post__not_in = $wpdb->get_col( $_post__not_in_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
243 + $_post__not_in = $wpdb->get_col( $_post__not_in_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- query is prepared above.
236 244
237 245 if ( ! empty( $_post__not_in ) ) {
238 246 $uncategorized_docs = array();
239 247 $uncategorized_query_args = array(
@@ -249,9 +257,9 @@
249 257
250 258 $_uncategorized_docs_query = new \WP_Query( $uncategorized_query_args );
251 259
252 260 if ( ! $_uncategorized_docs_query->have_posts() ) {
253 - wp_reset_query();
261 + wp_reset_postdata();
254 262 }
255 263 while ( $_uncategorized_docs_query->have_posts() ):
256 264 $_uncategorized_docs_query->the_post();
257 265 $post_obj = get_post( get_the_ID() );
@@ -268,9 +276,9 @@
268 276 array_push( $uncategorized_docs, $data );
269 277 endwhile;
270 278
271 279 wp_reset_postdata();
272 - wp_reset_query();
280 + wp_reset_postdata();
273 281
274 282 $response[ 'uncategorized' ] = $uncategorized_docs;
275 283 }
276 284