PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.8.10
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.8.10
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 / Glossaries.php

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

675 lines 17.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDeveloper\BetterDocs\Core;
4
5 use WP_Query;
6 use WP_Error;
7 use WPDeveloper\BetterDocs\Utils\Base;
8
9 class Glossaries extends Base {
10 /**
11 * REST API namespace
12 * @var string
13 */
14 private $namespace = 'betterdocs';
15 public $post_type = 'docs';
16 public $category = 'glossaries';
17
18 /**
19 *
20 * Initialize the class and start calling our hooks and filters
21 *
22 * @since 1.0.0
23 *
24 */
25 public function __construct() {
26 add_action( 'init', [ $this, 'register_post' ] );
27 // fires after a new betterdocs_glossaries is created
28 add_action( 'created_glossaries', [ $this, 'action_created_betterdocs_glossaries' ], 10, 2 );
29 add_action( 'rest_api_init', [ $this, 'register_api_endpoint' ] );
30 add_action( 'rest_api_init', [ $this, 'register_glossary_rest_fields' ] );
31 add_action( 'rest_glossaries_query', array( $this, 'glossaries_orderby_meta' ), 10, 2 );
32 // Enqueue Scripts
33 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );
34 }
35
36 public function register_post() {
37 register_term_meta(
38 $this->category,
39 'status',
40 [
41 'show_in_rest' => true,
42 'single' => true
43 ]
44 );
45 }
46
47 public function enqueue( $hook ) {
48 if ( $hook === 'betterdocs_page_betterdocs-glossaries' ) {
49 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/css/faq.css' );
50
51 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/js/glossaries.js' );
52
53 // removing emoji support
54 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
55 remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
56
57 betterdocs()->assets->localize(
58 'betterdocs-admin-glossaries',
59 'betterdocs',
60 [
61 'dir_url' => BETTERDOCS_ABSURL,
62 'rest_url' => esc_url_raw( rest_url() ),
63 'free_version' => betterdocs()->version,
64 'nonce' => wp_create_nonce( 'wp_rest' )
65 ]
66 );
67 }
68 }
69
70 public function output() {
71 betterdocs()->views->get( 'admin/glossaries' );
72 }
73
74
75 /**
76 * Default the taxonomy's terms' order if it's not set.
77 *
78 * @param string $tax_slug The taxonomy's slug.
79 */
80 public function action_created_betterdocs_glossaries( $term_id ) {
81 $order = $this->get_max_taxonomy_order( 'glossaries' );
82 // update_term_meta( $term_id, 'order', $order++ );
83 update_term_meta( $term_id, 'status', 1 );
84 }
85
86 /**
87 * Default the taxonomy's terms' order if it's not set.
88 *
89 * @param string $tax_slug The taxonomy's slug.
90 */
91 public function default_term_order( $tax_slug ) {
92 $terms = get_terms(
93 [
94 'taxonomy' => $tax_slug,
95 'hide_empty' => false,
96 ]
97 );
98
99 $order = $this->get_max_taxonomy_order( $tax_slug );
100
101 foreach ( $terms as $term ) {
102 if ( ! get_term_meta( $term->term_id, 'order', true ) ) {
103 update_term_meta( $term->term_id, 'order', $order );
104 ++$order;
105 }
106 }
107 }
108
109 /**
110 * Get the maximum order for this taxonomy. This will be applied to terms that don't have a tax position.
111 */
112 private function get_max_taxonomy_order( $tax_slug ) {
113 global $wpdb;
114
115 $max_term_order = $wpdb->get_col(
116 $wpdb->prepare(
117 "SELECT MAX( CAST( tm.meta_value AS UNSIGNED ) )
118 FROM $wpdb->terms t
119 JOIN $wpdb->term_taxonomy tt ON t.term_id = tt.term_id AND tt.taxonomy = '%s'
120 JOIN $wpdb->termmeta tm ON tm.term_id = t.term_id WHERE tm.meta_key = 'order'",
121 $tax_slug
122 )
123 );
124
125 $max_term_order = is_array( $max_term_order ) ? current( $max_term_order ) : 0;
126
127 return (int) $max_term_order === 0 || empty( $max_term_order ) ? 1 : (int) $max_term_order + 1;
128 }
129
130 /**
131 * Re-Order the taxonomies based on the order value.
132 *
133 * @param array $pieces Array of SQL query clauses.
134 * @param array $taxonomies Array of taxonomy names.
135 * @param array $args Array of term query args.
136 */
137 public function set_tax_order( $pieces, $taxonomies, $args ) {
138 foreach ( $taxonomies as $taxonomy ) {
139 global $wpdb;
140
141 if ( $taxonomy === 'betterdocs_glossaries' ) {
142 $join_statement = " LEFT JOIN $wpdb->termmeta AS term_meta ON t.term_id = term_meta.term_id AND term_meta.meta_key = 'order'";
143
144 if ( ! $this->does_substring_exist( $pieces['join'], $join_statement ) ) {
145 $pieces['join'] .= $join_statement;
146 }
147
148 $pieces['orderby'] = 'ORDER BY CAST( term_meta.meta_value AS UNSIGNED )';
149 }
150 }
151
152 return $pieces;
153 }
154
155 /**
156 * Order the taxonomies on the front end.
157 */
158 public function front_end_order_terms() {
159 if ( ! is_admin() ) {
160 add_filter( 'terms_clauses', [ $this, 'set_tax_order' ], 10, 3 );
161 }
162 }
163
164 /**
165 * Check if a substring exists inside a string.
166 *
167 * @param string $string The main string (haystack) we're searching in.
168 * @param string $substring The substring we're searching for.
169 *
170 * @return bool True if substring exists, else false.
171 */
172 protected function does_substring_exist( $string, $substring ) {
173 return strstr( $string, $substring ) !== false;
174 }
175
176 public function register_api_endpoint() {
177 register_rest_route(
178 $this->namespace,
179 '/glossary/sample_data',
180 [
181 'methods' => [ 'POST' ],
182 'callback' => [ $this, 'create_glossary_sample' ],
183 'permission_callback' => function () {
184 return current_user_can( 'edit_others_posts' );
185 }
186 ]
187 );
188
189 register_rest_route(
190 $this->namespace,
191 '/glossary/posts/(?P<type>\S+)',
192 [
193 'methods' => [ 'GET' ],
194 'callback' => [ $this, 'fetch_faq_posts' ],
195 'permission_callback' => '__return_true'
196 ]
197 );
198
199 register_rest_route(
200 $this->namespace,
201 '/glossary/create_glossary',
202 [
203 'methods' => [ 'POST' ],
204 'callback' => [ $this, 'create_glossaries' ],
205 'permission_callback' => function () {
206 return current_user_can( 'edit_others_posts' );
207 }
208 ]
209 );
210
211 register_rest_route(
212 $this->namespace,
213 '/glossary/update_glossary',
214 [
215 'methods' => [ 'POST' ],
216 'callback' => [ $this, 'update_glossaries' ],
217 'permission_callback' => function () {
218 return current_user_can( 'edit_others_posts' );
219 }
220 ]
221 );
222
223 register_rest_route(
224 $this->namespace,
225 '/glossary/delete_glossary',
226 [
227 'methods' => [ 'POST' ],
228 'callback' => [ $this, 'delete_glossaries' ],
229 'permission_callback' => function () {
230 return current_user_can( 'edit_others_posts' );
231 }
232 ]
233 );
234
235 register_rest_route(
236 $this->namespace,
237 '/glossary/glossary_status',
238 [
239 'methods' => [ 'POST' ],
240 'callback' => [ $this, 'update_glossary_status' ],
241 'permission_callback' => function () {
242 return current_user_can( 'edit_others_posts' );
243 }
244 ]
245 );
246
247 register_rest_route(
248 $this->namespace,
249 '/glossary/glossaries_order',
250 [
251 'methods' => [ 'POST' ],
252 'callback' => [ $this, 'update_glossaries_order' ],
253 'permission_callback' => function () {
254 return current_user_can( 'edit_others_posts' );
255 }
256 ]
257 );
258
259 register_rest_route(
260 $this->namespace,
261 '/glossary/update_order_by_glossary',
262 [
263 'methods' => [ 'POST' ],
264 'callback' => [ $this, 'update_faq_order_by_glossary' ],
265 'permission_callback' => function () {
266 return current_user_can( 'edit_others_posts' );
267 }
268 ]
269 );
270
271 register_rest_route(
272 $this->namespace,
273 '/glossary/glossary_search',
274 [
275 'methods' => [ 'GET' ],
276 'callback' => [ $this, 'glossary_search' ],
277 'permission_callback' => '__return_true',
278 'args' => array(
279 'title' => array(
280 'type' => 'string',
281 'required' => true
282 ),
283 ),
284 ]
285 );
286
287 register_rest_route(
288 $this->namespace,
289 '/glossary/glossary_count',
290 [
291 'methods' => [ 'GET' ],
292 'callback' => [ $this, 'get_glossary_count' ],
293 'permission_callback' => function () {
294 return current_user_can( 'edit_others_posts' );
295 }
296 ]
297 );
298 register_rest_route(
299 $this->namespace,
300 '/glossary/get_glossaries',
301 [
302 'methods' => [ 'GET' ],
303 'callback' => [ $this, 'get_glossaries' ],
304 'permission_callback' => function () {
305 return current_user_can( 'edit_others_posts' );
306 }
307 ]
308 );
309 }
310
311 public function create_glossary_sample( $params ) {
312 $sample_data = json_decode( $params->get_param( 'sample_data' ), true );
313 foreach ( $sample_data as $key => $value ) {
314 $insert_term = wp_insert_term(
315 $key,
316 'glossaries'
317 );
318 if ( $insert_term ) {
319 foreach ( $value['posts'] as $key => $value ) {
320 $this->insert_betterdocs_faq( $value['post_title'], $value['post_content'], $insert_term['term_id'] );
321 }
322 }
323 }
324 return true;
325 }
326
327 public function create_glossaries( $params ) {
328 $title = $params->get_param( 'title' );
329 $description = $params->get_param( 'description' );
330 $slug = $params->get_param( 'slug' );
331
332 // Create the term
333 $new_term = wp_insert_term(
334 $title,
335 'glossaries',
336 [
337 'slug' => $slug,
338 ]
339 );
340
341 if ( is_wp_error( $new_term ) ) {
342 return $new_term;
343 }
344
345 // Set the custom field description
346 $term_id = $new_term['term_id'];
347 update_term_meta( $term_id, 'glossary_term_description', $description ); //phpcs:ignore inline styles are need for the front-end
348
349 return true;
350 }
351
352 public function update_glossaries( $request ) {
353 $params = $request->get_params();
354
355 $term_id = $request->get_param( 'term_id' );
356 $title = $request->get_param( 'title' );
357 $description = $request->get_param( 'description' );
358 $description = ( $description !== 'undefined' ) ? $description : '';
359 $slug = $request->get_param( 'slug' );
360
361 // Check if there's old data in the default description field and transfer it to the custom field
362 $old_description = get_term_field( 'description', $term_id, 'glossaries' );
363 if ( ! empty( $old_description ) && empty( get_term_meta( $term_id, 'glossary_term_description', true ) ) ) {
364 update_term_meta( $term_id, 'glossary_term_description', wp_kses_post( $old_description ) );
365 wp_update_term( $term_id, $this->glossaries, [ 'description' => '' ] );
366 }
367
368 // Update the term
369 $update = wp_update_term(
370 $term_id,
371 'glossaries',
372 [
373 'name' => $title,
374 'slug' => $slug,
375 ]
376 );
377
378 if ( is_wp_error( $update ) ) {
379 return $update;
380 } else {
381 // Update the custom field description
382 update_term_meta( $term_id, 'glossary_term_description', $description );
383 return true;
384 }
385 }
386
387 public function save_glossary_term_meta( $term_id, $tt_id ) {
388 if ( isset( $_POST['glossary_term_description'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
389 update_term_meta( $term_id, 'glossary_term_description', wp_kses_post( $_POST['glossary_term_description'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
390 }
391 }
392
393 public function register_glossary_rest_fields() {
394 register_rest_field(
395 'glossaries',
396 'glossary_term_description',
397 [
398 'get_callback' => function ( $term ) {
399 return get_term_meta( $term['id'], 'glossary_term_description', true );
400 },
401 'update_callback' => null,
402 'schema' => [
403 'description' => __( 'Glossary Term Description', 'betterdocs' ),
404 'type' => 'string',
405 'context' => [ 'view', 'edit' ],
406 ],
407 ]
408 );
409 }
410
411 public function delete_glossaries( $params ) {
412 $term_id = $params->get_param( 'term_id' );
413 $delete = wp_delete_term( $term_id, 'glossaries' );
414
415 if ( is_wp_error( $delete ) ) {
416 return $delete;
417 } else {
418 return true;
419 }
420 }
421
422
423 public function insert_betterdocs_glossaries( $title, $description, $slug = '' ) {
424 $insert_term = wp_insert_term(
425 $title,
426 'glossaries',
427 [
428 'slug' => $slug,
429 'description' => $description
430 ]
431 );
432
433 if ( is_wp_error( $insert_term ) ) {
434 return $insert_term;
435 } else {
436 return true;
437 }
438 }
439
440 public function update_glossaries_order( $params ) {
441 $glossaries_order = $params->get_param( 'glossaries_order' );
442 $glossaries_order = json_decode( $glossaries_order, true );
443
444 foreach ( $glossaries_order as $order_data ) {
445 if ( (int) $order_data['current_position'] != (int) $order_data['updated_position'] ) {
446 update_term_meta( $order_data['id'], 'order', ( (int) $order_data['updated_position'] ) );
447 }
448 }
449 return true;
450 }
451
452 public function insert_betterdocs_faq( $post_title, $post_content, $term_id ) {
453 $post = wp_insert_post(
454 [
455 'post_type' => 'betterdocs_faq',
456 'post_title' => wp_strip_all_tags( $post_title ),
457 'post_content' => $post_content,
458 'post_status' => 'publish'
459 ]
460 );
461
462 if ( $term_id ) {
463 $set_terms = wp_set_object_terms( $post, $term_id, 'glossaries' );
464 if ( is_wp_error( $set_terms ) ) {
465 return $set_terms;
466 } else {
467 return $this->update_faq_order_on_insert( $term_id, $post );
468 }
469 } else {
470 return $post;
471 }
472 }
473
474 public function update_faq_order_on_insert( $term_id, $post ) {
475 $term_meta = get_term_meta( $term_id, '_betterdocs_faq_order' );
476 if ( ! empty( $term_meta ) ) {
477 $term_meta_arr = explode( ',', $term_meta[0] );
478 if ( ! in_array( $post, $term_meta_arr ) ) {
479 array_unshift( $term_meta_arr, $post );
480 $docs_ordering_data = filter_var_array( wp_unslash( $term_meta_arr ), FILTER_SANITIZE_NUMBER_INT );
481 return update_term_meta( $term_id, '_betterdocs_faq_order', implode( ',', $docs_ordering_data ) );
482 }
483 } else {
484 return update_term_meta( $term_id, '_betterdocs_faq_order', $post );
485 }
486 }
487
488 /**
489 * Update _betterdocs_faq_order meta when new post created
490 */
491
492 public function update_faq_order_by_glossary( $params ) {
493 $term_id = $params->get_param( 'term_id' );
494 $posts = $params->get_param( 'posts' );
495 return update_term_meta( $term_id, '_betterdocs_faq_order', $posts );
496 }
497
498 public function create_betterdocs_faq( $params ) {
499 $post_title = $params->get_param( 'post_title' );
500 $post_content = $params->get_param( 'post_content' );
501 $term_id = $params->get_param( 'term_id' );
502 return $this->insert_betterdocs_faq( $post_title, $post_content, $term_id );
503 }
504
505 public function update_betterdocs_faq( $params ) {
506 $post_id = $params->get_param( 'post_id' );
507 $post_title = $params->get_param( 'post_title' );
508 $post_content = $params->get_param( 'post_content' );
509 $status = $params->get_param( 'status' );
510 $term_id = $params->get_param( 'term_id' );
511 if ( $status ) {
512 $data = [
513 'post_type' => 'betterdocs_faq',
514 'ID' => $post_id,
515 'status' => $status
516 ];
517 } else {
518 $data = [
519 'post_type' => 'betterdocs_faq',
520 'ID' => $post_id,
521 'post_title' => $post_title,
522 'post_content' => $post_content
523 ];
524
525 if ( $term_id ) {
526 $data['tax_input'] = [
527 'betterdocs_glossaries' => $term_id
528 ];
529
530 $term_meta = get_term_meta( $term_id, '_betterdocs_faq_order' );
531 $term_meta_arr = explode( ',', $term_meta[0] );
532 if ( ! in_array( $post_id, $term_meta_arr ) ) {
533 array_unshift( $term_meta_arr, $post_id );
534 $docs_ordering_data = filter_var_array( wp_unslash( $term_meta_arr ), FILTER_SANITIZE_NUMBER_INT );
535 update_term_meta( $term_id, '_betterdocs_faq_order', implode( ',', $docs_ordering_data ) );
536 }
537 }
538 }
539
540 return wp_update_post( $data );
541 }
542
543 public function delete_betterdocs_faq( $params ) {
544 $post_id = $params->get_param( 'post_id' );
545 return wp_delete_post( $post_id );
546 }
547
548 public function faq_post_loop( $args ) {
549 $posts = [];
550 $query = new WP_Query( $args );
551 if ( $query->have_posts() ) :
552 while ( $query->have_posts() ) :
553 $query->the_post();
554 $posts[ get_the_ID() ]['title'] = get_the_title();
555 $posts[ get_the_ID() ]['content'] = get_the_content();
556 endwhile;
557 endif;
558
559 return $posts;
560 }
561
562 public function update_glossary_status( $params ) {
563 $term_id = $params->get_param( 'term_id' );
564 $status = $params->get_param( 'status' );
565 return update_term_meta( $term_id, 'status', $status );
566 }
567
568 public function fetch_faq_posts( $params ) {
569 $faq = [];
570 $type = $params->get_param( 'type' );
571
572 if ( $type == 'category' ) {
573 $taxonomy_objects = get_terms(
574 [
575 'taxonomy' => 'glossaries',
576 'hide_empty' => false,
577 ]
578 );
579
580 if ( $taxonomy_objects && ! is_wp_error( $taxonomy_objects ) ) :
581 foreach ( $taxonomy_objects as $term ) :
582 $args = [
583 'post_type' => 'betterdocs_faq',
584 'post_status' => 'publish',
585 'post_per_page' => -1,
586 'tax_query' => [
587 [
588 'taxonomy' => 'glossaries',
589 'field' => 'term_id',
590 'terms' => $term->term_id
591 ]
592 ]
593 ];
594
595 $posts = $this->faq_post_loop( $args );
596
597 $faq[ $term->slug ] = [
598 (array) $term,
599 'posts' => $posts
600 ];
601 endforeach;
602 endif;
603 } else {
604 $args = [
605 'post_type' => 'betterdocs_faq',
606 'post_status' => 'publish',
607 'post_per_page' => -1
608 ];
609 $posts = $this->faq_post_loop( $args );
610 $faq['posts'] = $posts;
611 }
612
613 return $faq;
614 }
615
616
617 public function glossary_search( $request ) {
618
619 $title = $request['title'];
620
621 // Perform the taxonomy search
622 $taxonomy_args = array(
623 'name__like' => $title,
624 'taxonomy' => 'glossaries',
625 'hide_empty' => false
626 );
627
628 $taxonomies = get_terms( $taxonomy_args );
629
630 if ( ! empty( $taxonomies ) ) {
631 $result = array();
632 foreach ( $taxonomies as $taxonomy ) {
633 $result[] = array(
634 'id' => $taxonomy->term_id,
635 'count' => $taxonomy->count,
636 'description' => $taxonomy->description,
637 'name' => $taxonomy->name,
638 'slug' => $taxonomy->slug
639 // Add more fields as needed
640 );
641 }
642 // Return the taxonomy data
643 return $result;
644 } else {
645 // Taxonomy not found
646 return new WP_Error( 'taxonomy_not_found', 'Taxonomy not found.', array( 'status' => 404 ) );
647 }
648 }
649
650 public function glossaries_orderby_meta( $args, $request ) {
651 if ( $args['taxonomy'] === 'glossaries' ) {
652 $args['orderby'] = 'meta_value_num';
653 $args['meta_key'] = 'status';
654 }
655 return $args;
656 }
657
658 public function get_glossary_count( $request ) {
659 $options = get_option( 'store_glossary_count' );
660 return rest_ensure_response( $options );
661 }
662 public function get_glossaries( $request ) {
663 $taxo = get_taxonomies(
664 array(
665 'name' => array(
666 'glossaries'
667 )
668 ),
669 'objects'
670 );
671
672 return rest_ensuree_response( $taxo );
673 }
674 }
675