PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.8.1
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.8.1
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.1, at includes/Core/Glossaries.php

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