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

920 lines 27.1 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 use WPDeveloper\BetterDocs\Utils\Helper;
9
10 class Glossaries extends Base {
11 /**
12 * REST API namespace
13 * @var string
14 */
15 private $namespace = 'betterdocs';
16 public $post_type = 'docs';
17 public $category = 'glossaries';
18
19 /**
20 *
21 * Initialize the class and start calling our hooks and filters
22 *
23 * @since 1.0.0
24 *
25 */
26 public function __construct() {
27 add_action( 'init', [ $this, 'register_post' ] );
28 // fires after a new betterdocs_glossaries is created
29 add_action( 'created_glossaries', [ $this, 'action_created_betterdocs_glossaries' ], 10, 2 );
30 add_action( 'rest_api_init', [ $this, 'register_api_endpoint' ] );
31 add_action( 'rest_api_init', [ $this, 'register_glossary_rest_fields' ] );
32 add_action( 'rest_glossaries_query', array( $this, 'glossaries_orderby_meta' ), 10, 2 );
33 add_action( 'rest_glossaries_query', array( $this, 'disable_language_filtering_for_admin_rest' ), 5, 2 );
34 // Ensure meta fields are properly exposed in REST API
35 add_filter( 'rest_prepare_glossaries', array( $this, 'add_meta_to_rest_response' ), 10, 3 );
36 // Enqueue Scripts
37 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );
38 // Ensure existing glossaries have proper status
39 add_action( 'admin_init', [ $this, 'ensure_glossaries_have_status' ] );
40 }
41
42 public function register_post() {
43 // Register term meta fields for glossaries taxonomy
44 // Force register without duplicate checks to ensure they're properly registered
45 register_term_meta(
46 $this->category,
47 'status',
48 [
49 'show_in_rest' => true,
50 'single' => true,
51 'type' => 'string', // Changed to string to match React expectation
52 'default' => '1',
53 'sanitize_callback' => 'sanitize_text_field'
54 ]
55 );
56
57 register_term_meta(
58 $this->category,
59 'order',
60 [
61 'show_in_rest' => true,
62 'single' => true,
63 'type' => 'string', // Changed to string for consistency
64 'default' => '0',
65 'sanitize_callback' => 'sanitize_text_field'
66 ]
67 );
68
69 register_term_meta(
70 $this->category,
71 'glossary_term_description',
72 [
73 'show_in_rest' => true,
74 'single' => true,
75 'type' => 'string',
76 'default' => '',
77 'sanitize_callback' => 'wp_kses_post'
78 ]
79 );
80 }
81
82 public function enqueue( $hook ) {
83 if ( $hook === 'betterdocs_page_betterdocs-glossaries' ) {
84 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/css/faq.css' );
85
86 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/js/glossaries.js' );
87
88 // removing emoji support
89 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
90 remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
91
92 betterdocs()->assets->localize(
93 'betterdocs-admin-glossaries',
94 'betterdocs',
95 [
96 'dir_url' => BETTERDOCS_ABSURL,
97 'rest_url' => esc_url_raw( rest_url() ),
98 'free_version' => betterdocs()->version,
99 'nonce' => wp_create_nonce( 'wp_rest' ),
100 'current_language' => Helper::get_current_language(),
101 'is_multilingual' => Helper::is_multilingual_active()
102 ]
103 );
104 }
105 }
106
107 public function output() {
108 betterdocs()->views->get( 'admin/glossaries' );
109 }
110
111 /**
112 * Ensure existing glossaries have proper status meta
113 * This fixes the issue where existing glossaries appear disabled
114 */
115 public function ensure_glossaries_have_status() {
116 // Run this every time in admin to ensure status is properly set
117 // Get all glossaries terms
118 $all_terms = get_terms( array(
119 'taxonomy' => 'glossaries',
120 'hide_empty' => false,
121 'suppress_filters' => true // Bypass language filtering
122 ) );
123
124 if ( ! empty( $all_terms ) && ! is_wp_error( $all_terms ) ) {
125 foreach ( $all_terms as $term ) {
126 $current_status = get_term_meta( $term->term_id, 'status', true );
127
128 // If status is empty or not set, set it to enabled ('1')
129 if ( empty( $current_status ) || $current_status === '' ) {
130 update_term_meta( $term->term_id, 'status', '1' );
131 }
132
133 // Also ensure order meta exists
134 $current_order = get_term_meta( $term->term_id, 'order', true );
135 if ( empty( $current_order ) || $current_order === '' ) {
136 update_term_meta( $term->term_id, 'order', '0' );
137 }
138 }
139 }
140 }
141
142
143 /**
144 * Default the taxonomy's terms' order if it's not set.
145 *
146 * @param string $tax_slug The taxonomy's slug.
147 */
148 public function action_created_betterdocs_glossaries( $term_id ) {
149 $order = $this->get_max_taxonomy_order( 'glossaries' );
150 // update_term_meta( $term_id, 'order', $order++ );
151 update_term_meta( $term_id, 'status', '1' ); // Set as string
152 update_term_meta( $term_id, 'order', '0' ); // Also set order
153 }
154
155 /**
156 * Default the taxonomy's terms' order if it's not set.
157 *
158 * @param string $tax_slug The taxonomy's slug.
159 */
160 public function default_term_order( $tax_slug ) {
161 $terms = get_terms(
162 [
163 'taxonomy' => $tax_slug,
164 'hide_empty' => false,
165 ]
166 );
167
168 $order = $this->get_max_taxonomy_order( $tax_slug );
169
170 foreach ( $terms as $term ) {
171 if ( ! get_term_meta( $term->term_id, 'order', true ) ) {
172 update_term_meta( $term->term_id, 'order', $order );
173 ++$order;
174 }
175 }
176 }
177
178 /**
179 * Get the maximum order for this taxonomy. This will be applied to terms that don't have a tax position.
180 */
181 private function get_max_taxonomy_order( $tax_slug ) {
182 global $wpdb;
183
184 $max_term_order = $wpdb->get_col(
185 $wpdb->prepare(
186 "SELECT MAX( CAST( tm.meta_value AS UNSIGNED ) )
187 FROM $wpdb->terms t
188 JOIN $wpdb->term_taxonomy tt ON t.term_id = tt.term_id AND tt.taxonomy = '%s'
189 JOIN $wpdb->termmeta tm ON tm.term_id = t.term_id WHERE tm.meta_key = 'order'",
190 $tax_slug
191 )
192 );
193
194 $max_term_order = is_array( $max_term_order ) ? current( $max_term_order ) : 0;
195
196 return (int) $max_term_order === 0 || empty( $max_term_order ) ? 1 : (int) $max_term_order + 1;
197 }
198
199 /**
200 * Re-Order the taxonomies based on the order value.
201 *
202 * @param array $pieces Array of SQL query clauses.
203 * @param array $taxonomies Array of taxonomy names.
204 * @param array $args Array of term query args.
205 */
206 public function set_tax_order( $pieces, $taxonomies, $args ) {
207 foreach ( $taxonomies as $taxonomy ) {
208 global $wpdb;
209
210 if ( $taxonomy === 'betterdocs_glossaries' ) {
211 $join_statement = " LEFT JOIN $wpdb->termmeta AS term_meta ON t.term_id = term_meta.term_id AND term_meta.meta_key = 'order'";
212
213 if ( ! $this->does_substring_exist( $pieces['join'], $join_statement ) ) {
214 $pieces['join'] .= $join_statement;
215 }
216
217 $pieces['orderby'] = 'ORDER BY CAST( term_meta.meta_value AS UNSIGNED )';
218 }
219 }
220
221 return $pieces;
222 }
223
224 /**
225 * Order the taxonomies on the front end.
226 */
227 public function front_end_order_terms() {
228 if ( ! is_admin() ) {
229 add_filter( 'terms_clauses', [ $this, 'set_tax_order' ], 10, 3 );
230 }
231 }
232
233 /**
234 * Check if a substring exists inside a string.
235 *
236 * @param string $string The main string (haystack) we're searching in.
237 * @param string $substring The substring we're searching for.
238 *
239 * @return bool True if substring exists, else false.
240 */
241 protected function does_substring_exist( $string, $substring ) {
242 return strstr( $string, $substring ) !== false;
243 }
244
245 public function register_api_endpoint() {
246 register_rest_route(
247 $this->namespace,
248 '/glossary/sample_data',
249 [
250 'methods' => [ 'POST' ],
251 'callback' => [ $this, 'create_glossary_sample' ],
252 'permission_callback' => function () {
253 return current_user_can( 'edit_others_posts' );
254 }
255 ]
256 );
257
258 register_rest_route(
259 $this->namespace,
260 '/glossary/posts/(?P<type>\S+)',
261 [
262 'methods' => [ 'GET' ],
263 'callback' => [ $this, 'fetch_faq_posts' ],
264 'permission_callback' => '__return_true'
265 ]
266 );
267
268 register_rest_route(
269 $this->namespace,
270 '/glossary/create_glossary',
271 [
272 'methods' => [ 'POST' ],
273 'callback' => [ $this, 'create_glossaries' ],
274 'permission_callback' => function () {
275 return current_user_can( 'edit_others_posts' );
276 }
277 ]
278 );
279
280 register_rest_route(
281 $this->namespace,
282 '/glossary/update_glossary',
283 [
284 'methods' => [ 'POST' ],
285 'callback' => [ $this, 'update_glossaries' ],
286 'permission_callback' => function () {
287 return current_user_can( 'edit_others_posts' );
288 }
289 ]
290 );
291
292 register_rest_route(
293 $this->namespace,
294 '/glossary/delete_glossary',
295 [
296 'methods' => [ 'POST' ],
297 'callback' => [ $this, 'delete_glossaries' ],
298 'permission_callback' => function () {
299 return current_user_can( 'edit_others_posts' );
300 }
301 ]
302 );
303
304 register_rest_route(
305 $this->namespace,
306 '/glossary/glossary_status',
307 [
308 'methods' => [ 'POST' ],
309 'callback' => [ $this, 'update_glossary_status' ],
310 'permission_callback' => function () {
311 return current_user_can( 'edit_others_posts' );
312 }
313 ]
314 );
315
316 register_rest_route(
317 $this->namespace,
318 '/glossary/glossaries_order',
319 [
320 'methods' => [ 'POST' ],
321 'callback' => [ $this, 'update_glossaries_order' ],
322 'permission_callback' => function () {
323 return current_user_can( 'edit_others_posts' );
324 }
325 ]
326 );
327
328 register_rest_route(
329 $this->namespace,
330 '/glossary/update_order_by_glossary',
331 [
332 'methods' => [ 'POST' ],
333 'callback' => [ $this, 'update_faq_order_by_glossary' ],
334 'permission_callback' => function () {
335 return current_user_can( 'edit_others_posts' );
336 }
337 ]
338 );
339
340 register_rest_route(
341 $this->namespace,
342 '/glossary/glossary_search',
343 [
344 'methods' => [ 'GET' ],
345 'callback' => [ $this, 'glossary_search' ],
346 'permission_callback' => '__return_true',
347 'args' => array(
348 'title' => array(
349 'type' => 'string',
350 'required' => true
351 ),
352 ),
353 ]
354 );
355
356 register_rest_route(
357 $this->namespace,
358 '/glossary/glossary_count',
359 [
360 'methods' => [ 'GET' ],
361 'callback' => [ $this, 'get_glossary_count' ],
362 'permission_callback' => function () {
363 return current_user_can( 'edit_others_posts' );
364 }
365 ]
366 );
367 register_rest_route(
368 $this->namespace,
369 '/glossary/get_glossaries',
370 [
371 'methods' => [ 'GET' ],
372 'callback' => [ $this, 'get_glossaries' ],
373 'permission_callback' => function () {
374 return current_user_can( 'edit_others_posts' );
375 }
376 ]
377 );
378 }
379
380 public function create_glossary_sample( $params ) {
381 $sample_data = json_decode( $params->get_param( 'sample_data' ), true );
382 foreach ( $sample_data as $key => $value ) {
383 $insert_term = wp_insert_term(
384 $key,
385 'glossaries'
386 );
387 if ( $insert_term ) {
388 foreach ( $value['posts'] as $key => $value ) {
389 $this->insert_betterdocs_faq( $value['post_title'], $value['post_content'], $insert_term['term_id'] );
390 }
391 }
392 }
393 return true;
394 }
395
396 public function create_glossaries( $params ) {
397 $title = $params->get_param( 'title' );
398 $description = $params->get_param( 'description' );
399 $slug = $params->get_param( 'slug' );
400 $language = $params->get_param( 'language' );
401
402 // Create the term
403 $new_term = wp_insert_term(
404 $title,
405 'glossaries',
406 [
407 'slug' => $slug,
408 ]
409 );
410
411 if ( is_wp_error( $new_term ) ) {
412 return ['status' => 'failed', 'data' => $new_term];
413 }
414
415 // Set the custom field description
416 $term_id = $new_term['term_id'];
417 update_term_meta( $term_id, 'glossary_term_description', $description ); //phpcs:ignore inline styles are need for the front-end
418
419 // Set language for multilingual plugins
420 if ( $language && Helper::is_multilingual_active() ) {
421 // WPML Support
422 if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) ) {
423 global $sitepress;
424 if ( $sitepress && method_exists( $sitepress, 'set_element_language_details' ) ) {
425 $sitepress->set_element_language_details( $term_id, 'tax_glossaries', null, $language );
426 }
427 }
428 // Polylang Support
429 elseif ( function_exists( 'pll_set_term_language' ) ) {
430 pll_set_term_language( $term_id, $language );
431 }
432 }
433
434 $new_term = $this->glossary_term_in_rest_api_schema($term_id, $description);
435 return ['status' => 'success', 'data' => $new_term];
436 }
437
438 /**
439 * Form Glossary Term In Rest Api Schema Format
440 *
441 * @param int $term_id
442 * @param string $meta_description
443 * @return array
444 */
445 public function glossary_term_in_rest_api_schema( $term_id, $meta_description = '' ) {
446 $term = get_term_by('id', $term_id, 'glossaries');
447 return [
448 'count' => $term->count,
449 'description' => $term->description,
450 'glossary_term_description' => $meta_description, //get the current description
451 'id' => $term->term_id,
452 'link' => get_permalink($term->term_id),
453 'meta' => [
454 'status' => get_term_meta( $term->term_id, 'status', true )
455 ],
456 'name' => $term->name,
457 'parent' => $term->parent,
458 'slug' => $term->slug,
459 'taxonomy' => $term->taxonomy
460 ];
461 }
462
463 public function update_glossaries( $request ) {
464 $term_id = $request->get_param( 'term_id' );
465 $title = $request->get_param( 'title' );
466 $description = $request->get_param( 'description' );
467 $description = ( $description !== 'undefined' ) ? $description : '';
468 $slug = $request->get_param( 'slug' );
469 $language = $request->get_param( 'language' );
470
471 // Verify that we're updating the correct language version of the term
472 if ( $language && Helper::is_multilingual_active() ) {
473 $term_language = null;
474
475 // WPML Support
476 if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) ) {
477 global $sitepress;
478 if ( $sitepress && method_exists( $sitepress, 'get_element_language_details' ) ) {
479 $lang_details = $sitepress->get_element_language_details( $term_id, 'tax_glossaries' );
480 $term_language = $lang_details ? $lang_details->language_code : null;
481 }
482 }
483 // Polylang Support
484 elseif ( function_exists( 'pll_get_term_language' ) ) {
485 $term_language = pll_get_term_language( $term_id );
486 }
487
488 // Only update if the term belongs to the current language
489 if ( $term_language && $term_language !== $language ) {
490 return ['status' => 'failed', 'data' => new \WP_Error( 'wrong_language', 'Cannot update term from different language' )];
491 }
492 }
493
494 // Check if there's old data in the default description field and transfer it to the custom field
495 $old_description = get_term_field( 'description', $term_id, 'glossaries' );
496 if ( ! empty( $old_description ) && empty( get_term_meta( $term_id, 'glossary_term_description', true ) ) ) {
497 update_term_meta( $term_id, 'glossary_term_description', wp_kses_post( $old_description ) );
498 wp_update_term( $term_id, $this->glossaries, [ 'description' => '' ] );
499 }
500
501 // Update the term
502 $update = wp_update_term(
503 $term_id,
504 'glossaries',
505 [
506 'name' => $title,
507 'slug' => $slug,
508 ]
509 );
510
511 if ( is_wp_error( $update ) ) {
512 return ['status' => 'failed', 'data' => $update];
513 } else {
514 // Update the custom field description
515 update_term_meta( $term_id, 'glossary_term_description', $description );
516 return ['status' => 'success', 'data' => $this->glossary_term_in_rest_api_schema($term_id, $description)];
517 }
518 }
519
520 public function save_glossary_term_meta( $term_id, $tt_id ) {
521 // Debug: Log what's happening
522 error_log( 'BetterDocs Glossaries: save_glossary_term_meta called for term_id: ' . $term_id );
523 error_log( 'BetterDocs Glossaries: $_POST data: ' . print_r( $_POST, true ) );
524
525 if ( isset( $_POST['glossary_term_description'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
526 $description = wp_kses_post( wp_unslash( $_POST['glossary_term_description'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
527 error_log( 'BetterDocs Glossaries: Saving description: ' . $description );
528 update_term_meta( $term_id, 'glossary_term_description', $description );
529 } else {
530 error_log( 'BetterDocs Glossaries: glossary_term_description not found in $_POST' );
531 }
532 }
533
534 public function register_glossary_rest_fields() {
535 register_rest_field(
536 'glossaries',
537 'glossary_term_description',
538 [
539 'get_callback' => function ( $term ) {
540 return get_term_meta( $term['id'], 'glossary_term_description', true );
541 },
542 'update_callback' => null,
543 'schema' => [
544 'description' => __( 'Glossary Term Description', 'betterdocs' ),
545 'type' => 'string',
546 'context' => [ 'view', 'edit' ],
547 ],
548 ]
549 );
550 }
551
552 public function delete_glossaries( $params ) {
553 $term_id = $params->get_param( 'term_id' );
554 $delete = wp_delete_term( $term_id, 'glossaries' );
555
556 if ( is_wp_error( $delete ) ) {
557 return $delete;
558 } else {
559 return true;
560 }
561 }
562
563
564 public function insert_betterdocs_glossaries( $title, $description, $slug = '' ) {
565 $insert_term = wp_insert_term(
566 $title,
567 'glossaries',
568 [
569 'slug' => $slug,
570 'description' => $description
571 ]
572 );
573
574 if ( is_wp_error( $insert_term ) ) {
575 return $insert_term;
576 } else {
577 return true;
578 }
579 }
580
581 public function update_glossaries_order( $params ) {
582 $glossaries_order = $params->get_param( 'glossaries_order' );
583 $glossaries_order = json_decode( $glossaries_order, true );
584
585 foreach ( $glossaries_order as $order_data ) {
586 if ( (int) $order_data['current_position'] != (int) $order_data['updated_position'] ) {
587 update_term_meta( $order_data['id'], 'order', ( (int) $order_data['updated_position'] ) );
588 }
589 }
590 return true;
591 }
592
593 public function insert_betterdocs_faq( $post_title, $post_content, $term_id ) {
594 $post = wp_insert_post(
595 [
596 'post_type' => 'betterdocs_faq',
597 'post_title' => wp_strip_all_tags( $post_title ),
598 'post_content' => $post_content,
599 'post_status' => 'publish'
600 ]
601 );
602
603 if ( $term_id ) {
604 $set_terms = wp_set_object_terms( $post, $term_id, 'glossaries' );
605 if ( is_wp_error( $set_terms ) ) {
606 return $set_terms;
607 } else {
608 return $this->update_faq_order_on_insert( $term_id, $post );
609 }
610 } else {
611 return $post;
612 }
613 }
614
615 public function update_faq_order_on_insert( $term_id, $post ) {
616 $term_meta = get_term_meta( $term_id, '_betterdocs_faq_order' );
617 if ( ! empty( $term_meta ) ) {
618 $term_meta_arr = explode( ',', $term_meta[0] );
619 if ( ! in_array( $post, $term_meta_arr ) ) {
620 array_unshift( $term_meta_arr, $post );
621 $docs_ordering_data = filter_var_array( wp_unslash( $term_meta_arr ), FILTER_SANITIZE_NUMBER_INT );
622 return update_term_meta( $term_id, '_betterdocs_faq_order', implode( ',', $docs_ordering_data ) );
623 }
624 } else {
625 return update_term_meta( $term_id, '_betterdocs_faq_order', $post );
626 }
627 }
628
629 /**
630 * Update _betterdocs_faq_order meta when new post created
631 */
632
633 public function update_faq_order_by_glossary( $params ) {
634 $term_id = $params->get_param( 'term_id' );
635 $posts = $params->get_param( 'posts' );
636 return update_term_meta( $term_id, '_betterdocs_faq_order', $posts );
637 }
638
639 public function create_betterdocs_faq( $params ) {
640 $post_title = $params->get_param( 'post_title' );
641 $post_content = $params->get_param( 'post_content' );
642 $term_id = $params->get_param( 'term_id' );
643 return $this->insert_betterdocs_faq( $post_title, $post_content, $term_id );
644 }
645
646 public function update_betterdocs_faq( $params ) {
647 $post_id = $params->get_param( 'post_id' );
648 $post_title = $params->get_param( 'post_title' );
649 $post_content = $params->get_param( 'post_content' );
650 $status = $params->get_param( 'status' );
651 $term_id = $params->get_param( 'term_id' );
652 if ( $status ) {
653 $data = [
654 'post_type' => 'betterdocs_faq',
655 'ID' => $post_id,
656 'status' => $status
657 ];
658 } else {
659 $data = [
660 'post_type' => 'betterdocs_faq',
661 'ID' => $post_id,
662 'post_title' => $post_title,
663 'post_content' => $post_content
664 ];
665
666 if ( $term_id ) {
667 $data['tax_input'] = [
668 'betterdocs_glossaries' => $term_id
669 ];
670
671 $term_meta = get_term_meta( $term_id, '_betterdocs_faq_order' );
672 $term_meta_arr = explode( ',', $term_meta[0] );
673 if ( ! in_array( $post_id, $term_meta_arr ) ) {
674 array_unshift( $term_meta_arr, $post_id );
675 $docs_ordering_data = filter_var_array( wp_unslash( $term_meta_arr ), FILTER_SANITIZE_NUMBER_INT );
676 update_term_meta( $term_id, '_betterdocs_faq_order', implode( ',', $docs_ordering_data ) );
677 }
678 }
679 }
680
681 return wp_update_post( $data );
682 }
683
684 public function delete_betterdocs_faq( $params ) {
685 $post_id = $params->get_param( 'post_id' );
686 return wp_delete_post( $post_id );
687 }
688
689 public function faq_post_loop( $args ) {
690 $posts = [];
691 $query = new WP_Query( $args );
692 if ( $query->have_posts() ) :
693 while ( $query->have_posts() ) :
694 $query->the_post();
695 $posts[ get_the_ID() ]['title'] = get_the_title();
696 $posts[ get_the_ID() ]['content'] = get_the_content();
697 endwhile;
698 endif;
699
700 return $posts;
701 }
702
703 public function update_glossary_status( $params ) {
704 $term_id = $params->get_param( 'term_id' );
705 $status = $params->get_param( 'status' );
706
707 // Ensure status is a string ('0' or '1')
708 $status = $status ? '1' : '0';
709
710 $result = update_term_meta( $term_id, 'status', $status );
711
712 // Return success response with updated status
713 return array(
714 'success' => $result !== false,
715 'term_id' => $term_id,
716 'status' => $status,
717 'message' => $result !== false ? 'Status updated successfully' : 'Failed to update status'
718 );
719 }
720
721 public function fetch_faq_posts( $params ) {
722 $faq = [];
723 $type = $params->get_param( 'type' );
724
725 if ( $type == 'category' ) {
726 $term_args = [
727 'taxonomy' => 'glossaries',
728 'hide_empty' => false,
729 ];
730
731 // Add language filtering if multilingual plugin is active and we should apply filtering
732 $current_language = Helper::get_current_language();
733 if ( $current_language && Helper::is_multilingual_active() && Helper::should_apply_language_filtering() ) {
734 // For WPML and Polylang, use 'lang' parameter
735 if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) || function_exists( 'pll_current_language' ) ) {
736 $term_args['lang'] = $current_language;
737 }
738 }
739
740 $taxonomy_objects = get_terms( $term_args );
741
742 if ( $taxonomy_objects && ! is_wp_error( $taxonomy_objects ) ) :
743 foreach ( $taxonomy_objects as $term ) :
744 $args = [
745 'post_type' => 'betterdocs_faq',
746 'post_status' => 'publish',
747 'post_per_page' => -1,
748 'tax_query' => [
749 [
750 'taxonomy' => 'glossaries',
751 'field' => 'term_id',
752 'terms' => $term->term_id
753 ]
754 ]
755 ];
756
757 $posts = $this->faq_post_loop( $args );
758
759 $faq[ $term->slug ] = [
760 (array) $term,
761 'posts' => $posts
762 ];
763 endforeach;
764 endif;
765 } else {
766 $args = [
767 'post_type' => 'betterdocs_faq',
768 'post_status' => 'publish',
769 'post_per_page' => -1
770 ];
771 $posts = $this->faq_post_loop( $args );
772 $faq['posts'] = $posts;
773 }
774
775 return $faq;
776 }
777
778
779 public function glossary_search( $request ) {
780
781 $title = $request['title'];
782 $lang = $request['lang'] ?? null;
783
784 // Perform the taxonomy search
785 $taxonomy_args = array(
786 'name__like' => $title,
787 'taxonomy' => 'glossaries',
788 'hide_empty' => false
789 );
790
791 // Add language filtering if multilingual plugin is active
792 $language_to_use = $lang ?: Helper::get_current_language();
793 if ( $language_to_use && Helper::is_multilingual_active() ) {
794 // For WPML and Polylang, use 'lang' parameter
795 if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) || function_exists( 'pll_current_language' ) ) {
796 $taxonomy_args['lang'] = $language_to_use;
797 }
798 }
799
800 $taxonomies = get_terms( $taxonomy_args );
801
802 if ( ! empty( $taxonomies ) ) {
803 $result = array();
804 foreach ( $taxonomies as $taxonomy ) {
805 $result[] = array(
806 'id' => $taxonomy->term_id,
807 'count' => $taxonomy->count,
808 'description' => $taxonomy->description,
809 'name' => $taxonomy->name,
810 'slug' => $taxonomy->slug
811 // Add more fields as needed
812 );
813 }
814 // Return the taxonomy data
815 return $result;
816 } else {
817 // Taxonomy not found
818 return new WP_Error( 'taxonomy_not_found', 'Taxonomy not found.', array( 'status' => 404 ) );
819 }
820 }
821
822 public function disable_language_filtering_for_admin_rest( $args, $request ) {
823 // Check if this is an admin REST request for glossaries management
824 if ( is_user_logged_in() && current_user_can( 'edit_others_posts' ) ) {
825 // Check if language parameter is explicitly provided in the request
826 $lang_param = $request->get_param( 'lang' );
827
828 if ( $lang_param ) {
829 // If language is specified, use it for filtering
830 $args['lang'] = $lang_param;
831 } else {
832 // If no language specified, remove language filtering to show all
833 unset( $args['lang'] );
834 // Add a temporary filter to bypass language restrictions
835 add_filter( 'get_terms', array( $this, 'ensure_all_glossaries_in_admin' ), 10, 3 );
836 }
837 }
838
839 return $args;
840 }
841
842 public function ensure_all_glossaries_in_admin( $terms, $taxonomies, $args ) {
843 // Only apply to glossaries taxonomy in admin context
844 if ( in_array( 'glossaries', (array) $taxonomies ) && is_user_logged_in() && current_user_can( 'edit_others_posts' ) ) {
845 // Remove this filter to prevent infinite loops
846 remove_filter( 'get_terms', array( $this, 'ensure_all_glossaries_in_admin' ), 10 );
847
848 // Get all glossaries terms without language filtering
849 $all_args = $args;
850 unset( $all_args['lang'] );
851 $all_args['suppress_filters'] = true; // Bypass all filters including language ones
852
853 $all_terms = get_terms( $all_args );
854
855 // Re-add the filter for future calls
856 add_filter( 'get_terms', array( $this, 'ensure_all_glossaries_in_admin' ), 10, 3 );
857
858 return is_wp_error( $all_terms ) ? $terms : $all_terms;
859 }
860
861 return $terms;
862 }
863
864 /**
865 * Add meta fields to REST API response
866 */
867 public function add_meta_to_rest_response( $response, $term, $request ) {
868 // Ensure meta fields are properly included
869 $meta = get_term_meta( $term->term_id );
870
871 // Format meta data as expected by React component
872 $response->data['meta'] = array();
873
874 if ( isset( $meta['status'] ) ) {
875 $response->data['meta']['status'] = $meta['status'];
876 } else {
877 $response->data['meta']['status'] = array( '1' ); // Default to enabled
878 }
879
880 if ( isset( $meta['order'] ) ) {
881 $response->data['meta']['order'] = $meta['order'];
882 } else {
883 $response->data['meta']['order'] = array( '0' ); // Default order
884 }
885
886 if ( isset( $meta['glossary_term_description'] ) ) {
887 $response->data['meta']['glossary_term_description'] = $meta['glossary_term_description'];
888 } else {
889 $response->data['meta']['glossary_term_description'] = array( '' );
890 }
891
892 return $response;
893 }
894
895 public function glossaries_orderby_meta( $args, $request ) {
896 if ( $args['taxonomy'] === 'glossaries' ) {
897 $args['orderby'] = 'meta_value_num';
898 $args['meta_key'] = 'status';
899 }
900 return $args;
901 }
902
903 public function get_glossary_count( $request ) {
904 $options = get_option( 'store_glossary_count' );
905 return rest_ensure_response( $options );
906 }
907 public function get_glossaries( $request ) {
908 $taxo = get_taxonomies(
909 array(
910 'name' => array(
911 'glossaries'
912 )
913 ),
914 'objects'
915 );
916
917 return rest_ensure_response( $taxo );
918 }
919 }
920