PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.5.5
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.5.5
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 3.5.2 All 199 releases
betterdocs / includes / Core / FAQBuilder.php

FAQBuilder.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.5.5, at includes/Core/FAQBuilder.php

746 lines 21.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WPDeveloper\BetterDocs\Core;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 // FAQ-by-category lookups require tax_query / meta_key filters by design.
9 // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
10 // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
11 // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_tax_query
12
13 use WP_Error;
14 use WP_Query;
15 use WPDeveloper\BetterDocs\Utils\Base;
16 use WPDeveloper\BetterDocs\Utils\Helper;
17
18 class FAQBuilder extends Base {
19 /**
20 * REST API namespace
21 * @var string
22 */
23 private $namespace = 'betterdocs';
24 public $post_type = 'betterdocs_faq';
25 public $category = 'betterdocs_faq_category';
26
27 /**
28 *
29 * Initialize the class and start calling our hooks and filters
30 *
31 * @since 1.0.0
32 *
33 */
34 public function __construct() {
35 // assign default admin capabilities for docs, doc terms, doc tags, knowledge base
36 add_action( 'init', [ $this, 'register_post' ] );
37 // fires after a new betterdocs_faq_category is created
38 add_action( 'created_betterdocs_faq_category', [ $this, 'action_created_betterdocs_faq_category' ], 10, 2 );
39 add_action( 'rest_api_init', [ $this, 'register_api_endpoint' ] );
40 add_action( 'rest_betterdocs_faq_category_query', [ $this, 'faq_category_orderby_meta' ], 10, 2 );
41 }
42
43 public function output() {
44 betterdocs()->views->get( 'admin/faq-builder' );
45 }
46
47 /**
48 *
49 * Register post type and taxonomies
50 *
51 * @since 1.0.0
52 *
53 */
54 public function register_post() {
55 /**
56 * Register category taxonomy
57 */
58 $category_labels = [
59 'name' => __( 'FAQ Categories', 'betterdocs' ),
60 'singular_name' => __( 'FAQ Category', 'betterdocs' ),
61 'all_items' => __( 'FAQ Categories', 'betterdocs' ),
62 'parent_item' => __( 'Parent FAQ Category', 'betterdocs' ),
63 'parent_item_colon' => __( 'Parent FAQ Category:', 'betterdocs' ),
64 'edit_item' => __( 'Edit Category', 'betterdocs' ),
65 'update_item' => __( 'Update Category', 'betterdocs' ),
66 'add_new_item' => __( 'Add New FAQ Category', 'betterdocs' ),
67 'new_item_name' => __( 'New FAQ Category Name', 'betterdocs' ),
68 'menu_name' => __( 'Categories', 'betterdocs' )
69 ];
70
71 $category_args = [
72 'hierarchical' => true,
73 'public' => false,
74 'labels' => $category_labels,
75 'show_ui' => true,
76 'show_admin_column' => true,
77 'query_var' => true,
78 'show_in_rest' => true,
79 'has_archive' => false,
80 'rewrite' => false,
81 'capabilities' => [
82 'manage_terms' => 'manage_doc_terms',
83 'edit_terms' => 'edit_doc_terms',
84 'delete_terms' => 'delete_doc_terms',
85 'assign_terms' => 'edit_docs'
86 ]
87 ];
88
89 register_taxonomy( $this->category, [ $this->post_type ], $category_args );
90 register_term_meta( $this->category, 'order', [ 'show_in_rest' => true ] );
91 register_term_meta( $this->category, 'status', [ 'show_in_rest' => true ] );
92 register_term_meta( $this->category, '_betterdocs_faq_order', [ 'show_in_rest' => true ] );
93 register_term_meta( $this->category, 'faq_group_icon', [ 'show_in_rest' => true ]);
94
95 /**
96 * Register post type
97 */
98 $labels = [
99 'name' => __( 'BetterDocs FAQ', 'betterdocs' ),
100 'singular_name' => __( 'BetterDocs FAQ', 'betterdocs' ),
101 'menu_name' => __( 'FAQ', 'betterdocs' ),
102 'name_admin_bar' => __( 'FAQ', 'betterdocs' ),
103 'add_new' => __( 'Add New', 'betterdocs' ),
104 'add_new_item' => __( 'Add New FAQ', 'betterdocs' ),
105 'new_item' => __( 'New FAQ', 'betterdocs' ),
106 'edit_item' => __( 'Edit FAQ', 'betterdocs' ),
107 'view_item' => __( 'View FAQ', 'betterdocs' ),
108 'all_items' => __( 'All FAQ', 'betterdocs' ),
109 'search_items' => __( 'Search FAQ', 'betterdocs' ),
110 'parent_item_colorn' => null,
111 'not_found' => __( 'No FAQ found', 'betterdocs' ),
112 'not_found_in_trash' => __( 'No FAQ found in trash', 'betterdocs' )
113 ];
114
115 $args = [
116 'labels' => $labels,
117 'description' => __( 'Add new faq from here', 'betterdocs' ),
118 'public' => false,
119 'public_queryable' => true,
120 'exclude_from_search' => false,
121 'show_ui' => true,
122 'show_in_menu' => false,
123 'query_var' => true,
124 'capability_type' => [ 'doc', 'docs' ],
125 'hierarchical' => true,
126 'map_meta_cap' => true,
127 'has_archive' => false,
128 'rewrite' => false,
129 'show_in_rest' => true,
130 'menu_icon' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg' ),
131 'supports' => [ 'title', 'editor', 'thumbnail', 'excerpt', 'author', 'revisions', 'custom-fields', 'comments' ]
132 ];
133
134 register_post_type( $this->post_type, $args );
135 register_post_meta( $this->post_type, 'faq_open_by_default', [ 'show_in_rest' => true, 'single' => true ] );
136 }
137
138 /**
139 * Default the taxonomy's terms' order if it's not set.
140 *
141 * @param string $tax_slug The taxonomy's slug.
142 */
143 public function action_created_betterdocs_faq_category( $term_id ) {
144 $order = $this->get_max_taxonomy_order( 'betterdocs_faq_category' );
145 update_term_meta( $term_id, 'order', $order++ );
146 update_term_meta( $term_id, 'status', 1 );
147 }
148
149 /**
150 * Default the taxonomy's terms' order if it's not set.
151 *
152 * @param string $tax_slug The taxonomy's slug.
153 */
154 public function default_term_order( $tax_slug ) {
155 $terms = get_terms(
156 [
157 'taxonomy' => $tax_slug,
158 'hide_empty' => false,
159 ]
160 );
161 $order = $this->get_max_taxonomy_order( $tax_slug );
162
163 foreach ( $terms as $term ) {
164 if ( ! get_term_meta( $term->term_id, 'order', true ) ) {
165 update_term_meta( $term->term_id, 'order', $order );
166 ++$order;
167 }
168 }
169 }
170
171 /**
172 * Get the maximum order for this taxonomy. This will be applied to terms that don't have a tax position.
173 */
174 private function get_max_taxonomy_order( $tax_slug ) {
175 global $wpdb;
176 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- live max-order needed when assigning new terms; cache would be stale.
177 $max_term_order = $wpdb->get_col(
178 $wpdb->prepare(
179 "SELECT MAX( CAST( tm.meta_value AS UNSIGNED ) )
180 FROM $wpdb->terms t
181 JOIN $wpdb->term_taxonomy tt ON t.term_id = tt.term_id AND tt.taxonomy = %s
182 JOIN $wpdb->termmeta tm ON tm.term_id = t.term_id WHERE tm.meta_key = 'order'",
183 $tax_slug
184 )
185 );
186
187 $max_term_order = is_array( $max_term_order ) ? current( $max_term_order ) : 0;
188
189 return (int) $max_term_order === 0 || empty( $max_term_order ) ? 1 : (int) $max_term_order + 1;
190 }
191
192 /**
193 * Re-Order the taxonomies based on the order value.
194 *
195 * @param array $pieces Array of SQL query clauses.
196 * @param array $taxonomies Array of taxonomy names.
197 * @param array $args Array of term query args.
198 */
199 public function set_tax_order( $pieces, $taxonomies, $args ) {
200 foreach ( $taxonomies as $taxonomy ) {
201 global $wpdb;
202
203 if ( $taxonomy === 'betterdocs_faq_category' ) {
204 $join_statement = " LEFT JOIN $wpdb->termmeta AS term_meta ON t.term_id = term_meta.term_id AND term_meta.meta_key = 'order'";
205
206 if ( ! $this->does_substring_exist( $pieces['join'], $join_statement ) ) {
207 $pieces['join'] .= $join_statement;
208 }
209
210 $pieces['orderby'] = 'ORDER BY CAST( term_meta.meta_value AS UNSIGNED )';
211 }
212 }
213
214 return $pieces;
215 }
216
217 /**
218 * Order the taxonomies on the front end.
219 */
220 public function front_end_order_terms() {
221 if ( ! is_admin() ) {
222 add_filter( 'terms_clauses', [ $this, 'set_tax_order' ], 10, 3 );
223 }
224 }
225
226 /**
227 * Check if a substring exists inside a string.
228 *
229 * @param string $string The main string (haystack) we're searching in.
230 * @param string $substring The substring we're searching for.
231 *
232 * @return bool True if substring exists, else false.
233 */
234 protected function does_substring_exist( $string, $substring ) {
235 return strstr( $string, $substring ) !== false;
236 }
237
238 public function register_api_endpoint() {
239 register_rest_route(
240 $this->namespace,
241 '/faq/sample_data',
242 [
243 'methods' => [ 'POST' ],
244 'callback' => [ $this, 'create_faq_sample' ],
245 'permission_callback' => function () {
246 return current_user_can( 'edit_others_posts' );
247 }
248 ]
249 );
250
251 register_rest_route(
252 $this->namespace,
253 '/faq/posts/(?P<type>\S+)',
254 [
255 'methods' => [ 'GET' ],
256 'callback' => [ $this, 'fetch_faq_posts' ],
257 'permission_callback' => function () {
258 return current_user_can( 'edit_others_posts' );
259 }
260 ]
261 );
262
263 register_rest_route(
264 $this->namespace,
265 '/faq/create_category',
266 [
267 'methods' => [ 'POST' ],
268 'callback' => [ $this, 'create_faq_category' ],
269 'permission_callback' => function () {
270 return current_user_can( 'edit_others_posts' );
271 }
272 ]
273 );
274
275 register_rest_route(
276 $this->namespace,
277 '/faq/update_category',
278 [
279 'methods' => [ 'POST' ],
280 'callback' => [ $this, 'update_faq_category' ],
281 'permission_callback' => function () {
282 return current_user_can( 'edit_others_posts' );
283 }
284 ]
285 );
286
287 register_rest_route(
288 $this->namespace,
289 '/faq/delete_category',
290 [
291 'methods' => [ 'POST' ],
292 'callback' => [ $this, 'delete_faq_category' ],
293 'permission_callback' => function () {
294 return current_user_can( 'edit_others_posts' );
295 }
296 ]
297 );
298
299 register_rest_route(
300 $this->namespace,
301 '/faq/create_post',
302 [
303 'methods' => [ 'POST' ],
304 'callback' => [ $this, 'create_betterdocs_faq' ],
305 'permission_callback' => function () {
306 return current_user_can( 'edit_others_posts' );
307 }
308 ]
309 );
310
311 register_rest_route(
312 $this->namespace,
313 '/faq/update_post',
314 [
315 'methods' => [ 'POST' ],
316 'callback' => [ $this, 'update_betterdocs_faq' ],
317 'permission_callback' => function () {
318 return current_user_can( 'edit_others_posts' );
319 }
320 ]
321 );
322
323 register_rest_route(
324 $this->namespace,
325 '/faq/delete_post',
326 [
327 'methods' => [ 'POST' ],
328 'callback' => [ $this, 'delete_betterdocs_faq' ],
329 'permission_callback' => function () {
330 return current_user_can( 'edit_others_posts' );
331 }
332 ]
333 );
334
335 register_rest_route(
336 $this->namespace,
337 '/faq/category_status',
338 [
339 'methods' => [ 'POST' ],
340 'callback' => [ $this, 'update_category_status' ],
341 'permission_callback' => function () {
342 return current_user_can( 'edit_others_posts' );
343 }
344 ]
345 );
346
347 register_rest_route(
348 $this->namespace,
349 '/faq/category_order',
350 [
351 'methods' => [ 'POST' ],
352 'callback' => [ $this, 'update_faq_category_order' ],
353 'permission_callback' => function () {
354 return current_user_can( 'edit_others_posts' );
355 }
356 ]
357 );
358
359 register_rest_route(
360 $this->namespace,
361 '/faq/update_order_by_category',
362 [
363 'methods' => [ 'POST' ],
364 'callback' => [ $this, 'update_faq_order_by_category' ],
365 'permission_callback' => function () {
366 return current_user_can( 'edit_others_posts' );
367 }
368 ]
369 );
370
371 register_rest_route(
372 $this->namespace,
373 '/faq/uncategorised',
374 [
375 'methods' => [ 'GET' ],
376 'callback' => [ $this, 'get_uncategorised_faq' ],
377 'permission_callback' => function () {
378 return current_user_can( 'edit_others_posts' );
379 }
380 ]
381 );
382
383 register_rest_route(
384 $this->namespace,
385 '/faq/category_search',
386 [
387 'methods' => [ 'GET' ],
388 'callback' => [ $this, 'category_search' ],
389 'permission_callback' => function () {
390 return current_user_can( 'edit_others_posts' );
391 },
392 'args' => [
393 'title' => [
394 'type' => 'string',
395 'required' => true,
396 'sanitize_callback' => 'sanitize_text_field'
397 ]
398 ]
399 ]
400 );
401 }
402
403 public function create_faq_sample( $params ) {
404 $sample_data = json_decode( $params->get_param( 'sample_data' ), true );
405 foreach ( $sample_data as $key => $value ) {
406 $insert_term = wp_insert_term(
407 $key,
408 'betterdocs_faq_category'
409 );
410 if ( $insert_term ) {
411 foreach ( $value['posts'] as $key => $value ) {
412 $this->insert_betterdocs_faq( $value['post_title'], $value['post_content'], $insert_term['term_id'] );
413 }
414 }
415 }
416 return true;
417 }
418
419 public function create_faq_category( $params ) {
420 $title = $params->get_param( 'title' );
421 $description = $params->get_param( 'description' );
422 $description = ( $description !== 'undefined' ) ? $description : '';
423 $slug = $params->get_param( 'slug' );
424 $group_icon_url = $params->get_param('group_icon_url');
425 return $this->insert_betterdocs_faq_category( $title, $description, $group_icon_url, $slug );
426 }
427
428 public function update_faq_category( $params ) {
429 $term_id = $params->get_param( 'term_id' );
430 $title = $params->get_param( 'title' );
431 $description = $params->get_param( 'description' );
432 $group_icon_url = $params->get_param('group_icon_url');
433 $description = ( $description !== 'undefined' ) ? $description : '';
434 $slug = $params->get_param( 'slug' );
435 $update = wp_update_term(
436 $term_id,
437 'betterdocs_faq_category',
438 [
439 'name' => $title,
440 'slug' => $slug,
441 'description' => $description
442 ]
443 );
444
445 if ( is_wp_error( $update ) ) {
446 return $update;
447 } else {
448 $term_id = isset( $update['term_id'] ) ? $update['term_id'] : 0;
449 if( $term_id != 0 ) {
450 $previous_icon_url = get_term_meta($term_id, 'faq_group_icon', true);
451 update_term_meta($term_id, 'faq_group_icon', $group_icon_url, $previous_icon_url);
452 }
453 return true;
454 }
455 }
456
457 public function delete_faq_category( $params ) {
458 $term_id = $params->get_param( 'term_id' );
459 $delete_all_docs = $params->get_param('with_all_post');
460
461 if ( $delete_all_docs ) {
462 Helper::delete_specific_faq_posts_by_faq_category( $term_id );
463 }
464
465 $delete = wp_delete_term( $term_id, 'betterdocs_faq_category' );
466
467 if ( is_wp_error( $delete ) ) {
468 return $delete;
469 } else {
470 return true;
471 }
472 }
473
474 public function insert_betterdocs_faq_category( $title, $description, $icon_url, $slug = '' ) {
475 $insert_term = wp_insert_term(
476 $title,
477 'betterdocs_faq_category',
478 [
479 'slug' => $slug,
480 'description' => $description
481 ]
482 );
483
484 if ( is_wp_error( $insert_term ) ) {
485 return $insert_term;
486 } else {
487 $term_id = isset( $insert_term['term_id'] ) ? $insert_term['term_id'] : 0;
488 if( $term_id != 0 ) {
489 update_term_meta($term_id, 'faq_group_icon', $icon_url);
490 }
491 return true;
492 }
493 }
494
495 public function update_faq_category_order( $params ) {
496 $faq_category_order = $params->get_param( 'faq_category_order' );
497 $faq_category_order = json_decode( $faq_category_order, true );
498
499 foreach ( $faq_category_order as $order_data ) {
500 if ( (int) $order_data['current_position'] != (int) $order_data['updated_position'] ) {
501 update_term_meta( $order_data['id'], 'order', ( (int) $order_data['updated_position'] ) );
502 }
503 }
504 return true;
505 }
506
507 public function insert_betterdocs_faq( $post_title, $post_content, $term_id ) {
508 $post = wp_insert_post(
509 [
510 'post_type' => 'betterdocs_faq',
511 'post_title' => wp_strip_all_tags( $post_title ),
512 'post_content' => $post_content,
513 'post_status' => 'publish'
514 ]
515 );
516
517 if ( $term_id ) {
518 $set_terms = wp_set_object_terms( $post, $term_id, 'betterdocs_faq_category' );
519 if ( is_wp_error( $set_terms ) ) {
520 return $set_terms;
521 } else {
522 return $this->update_faq_order_on_insert( $term_id, $post );
523 }
524 } else {
525 return $post;
526 }
527 }
528
529 public function update_faq_order_on_insert( $term_id, $post ) {
530 $term_meta = get_term_meta( $term_id, '_betterdocs_faq_order' );
531 if ( ! empty( $term_meta ) ) {
532 $term_meta_arr = explode( ',', $term_meta[0] );
533 if ( ! in_array( $post, $term_meta_arr ) ) {
534 array_unshift( $term_meta_arr, $post );
535 $docs_ordering_data = filter_var_array( wp_unslash( $term_meta_arr ), FILTER_SANITIZE_NUMBER_INT );
536 return update_term_meta( $term_id, '_betterdocs_faq_order', implode( ',', $docs_ordering_data ) );
537 }
538 } else {
539 return update_term_meta( $term_id, '_betterdocs_faq_order', $post );
540 }
541 }
542
543 /**
544 * Update _betterdocs_faq_order meta when new post created
545 */
546
547 public function update_faq_order_by_category( $params ) {
548 $term_id = $params->get_param( 'term_id' );
549 $posts = $params->get_param( 'posts' );
550 return update_term_meta( $term_id, '_betterdocs_faq_order', $posts );
551 }
552
553 public function create_betterdocs_faq( $params ) {
554 $post_title = $params->get_param( 'post_title' );
555 $post_content = $params->get_param( 'post_content' );
556 $term_id = $params->get_param( 'term_id' );
557 return $this->insert_betterdocs_faq( $post_title, $post_content, $term_id );
558 }
559
560 public function update_betterdocs_faq( $params ) {
561 $post_id = $params->get_param( 'post_id' );
562 $post_title = $params->get_param( 'post_title' );
563 $post_content = $params->get_param( 'post_content' );
564 $status = $params->get_param( 'status' );
565 $term_id = $params->get_param( 'term_id' );
566 if ( $status ) {
567 $data = [
568 'post_type' => 'betterdocs_faq',
569 'ID' => $post_id,
570 'status' => $status
571 ];
572 } else {
573 $data = [
574 'post_type' => 'betterdocs_faq',
575 'ID' => $post_id,
576 'post_title' => $post_title,
577 'post_content' => $post_content
578 ];
579
580 if ( $term_id ) {
581 $data['tax_input'] = [
582 'betterdocs_faq_category' => $term_id
583 ];
584
585 $term_meta = get_term_meta( $term_id, '_betterdocs_faq_order' );
586 $term_meta_arr = explode( ',', $term_meta[0] );
587 if ( ! in_array( $post_id, $term_meta_arr ) ) {
588 array_unshift( $term_meta_arr, $post_id );
589 $docs_ordering_data = filter_var_array( wp_unslash( $term_meta_arr ), FILTER_SANITIZE_NUMBER_INT );
590 update_term_meta( $term_id, '_betterdocs_faq_order', implode( ',', $docs_ordering_data ) );
591 }
592 }
593 }
594
595 return wp_update_post( $data );
596 }
597
598 public function delete_betterdocs_faq( $params ) {
599 $post_id = $params->get_param( 'post_id' );
600 return wp_delete_post( $post_id );
601 }
602
603 public function faq_post_loop( $args ) {
604 $posts = [];
605 $query = new WP_Query( $args );
606 if ( $query->have_posts() ) :
607 while ( $query->have_posts() ) :
608 $query->the_post();
609 $posts[ get_the_ID() ]['title'] = get_the_title();
610 $posts[ get_the_ID() ]['content'] = get_the_content();
611 endwhile;
612 endif;
613
614 return $posts;
615 }
616
617 public function update_category_status( $params ) {
618 $term_id = $params->get_param( 'term_id' );
619 $status = $params->get_param( 'status' );
620 return update_term_meta( $term_id, 'status', $status );
621 }
622
623 public function fetch_faq_posts( $params ) {
624 $faq = [];
625 $type = $params->get_param( 'type' );
626
627 if ( $type == 'category' ) {
628 $taxonomy_objects = get_terms(
629 [
630 'taxonomy' => 'betterdocs_faq_category',
631 'hide_empty' => false
632 ]
633 );
634
635 if ( $taxonomy_objects && ! is_wp_error( $taxonomy_objects ) ) :
636 foreach ( $taxonomy_objects as $term ) :
637 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- core FAQ-by-category query; tax filtering is required functionality.
638 $args = [
639 'post_type' => 'betterdocs_faq',
640 'post_status' => 'publish',
641 'post_per_page' => -1,
642 'tax_query' => [
643 [
644 'taxonomy' => 'betterdocs_faq_category',
645 'field' => 'term_id',
646 'terms' => $term->term_id
647 ]
648 ]
649 ];
650
651 $posts = $this->faq_post_loop( $args );
652
653 $faq[ $term->slug ] = [
654 (array) $term,
655 'posts' => $posts
656 ];
657 endforeach;
658 endif;
659 } else {
660 $args = [
661 'post_type' => 'betterdocs_faq',
662 'post_status' => 'publish',
663 'post_per_page' => -1
664 ];
665 $posts = $this->faq_post_loop( $args );
666 $faq['posts'] = $posts;
667 }
668
669 return $faq;
670 }
671
672 public function get_uncategorised_faq() {
673 $available_terms = array_map(
674 function ( $term ) {
675 return $term->term_id;
676 },
677 get_terms(
678 [
679 'taxonomy' => 'betterdocs_faq_category',
680 'hide_empty' => false
681 ]
682 )
683 );
684
685 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- intentional NOT-IN scan to find FAQs without any category assignment.
686 return get_posts(
687 [
688 'post_type' => 'betterdocs_faq',
689 'post_status' => current_user_can( 'edit_others_posts' ) ? [ 'publish', 'draft' ] : 'publish',
690 'posts_per_page' => -1,
691 'tax_query' => [
692 'relation' => 'AND',
693 [
694 'taxonomy' => 'betterdocs_faq_category',
695 'field' => 'term_id',
696 'terms' => $available_terms,
697 'operator' => 'NOT IN'
698 ]
699 ]
700 ]
701 );
702 }
703
704 public function category_search( $request ) {
705
706 $title = $request['title'];
707
708 // Perform the taxonomy search
709 $taxonomy_args = [
710 'name__like' => $title,
711 'taxonomy' => 'betterdocs_faq_category',
712 'hide_empty' => false
713 ];
714
715 $taxonomies = get_terms( $taxonomy_args );
716
717 if ( ! empty( $taxonomies ) ) {
718 $result = [];
719 foreach ( $taxonomies as $taxonomy ) {
720 $result[] = [
721 'id' => $taxonomy->term_id,
722 'count' => $taxonomy->count,
723 'description' => $taxonomy->description,
724 'name' => $taxonomy->name,
725 'slug' => $taxonomy->slug
726 // Add more fields as needed
727 ];
728 }
729 // Return the taxonomy data
730 return $result;
731 } else {
732 // Taxonomy not found
733 return new WP_Error( 'taxonomy_not_found', 'Taxonomy not found.', [ 'status' => 404 ] );
734 }
735 }
736
737 public function faq_category_orderby_meta( $args, $request ) {
738 if ( $args['taxonomy'] === 'betterdocs_faq_category' ) {
739 $args['orderby'] = 'meta_value_num';
740 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- ordering by user-assigned 'order' meta is required UX.
741 $args['meta_key'] = 'order';
742 }
743 return $args;
744 }
745 }
746