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

913 lines 26.7 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 if ( isset( $_POST['glossary_term_description'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
522 $description = wp_kses_post( wp_unslash( $_POST['glossary_term_description'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
523 update_term_meta( $term_id, 'glossary_term_description', $description );
524 }
525 }
526
527 public function register_glossary_rest_fields() {
528 register_rest_field(
529 'glossaries',
530 'glossary_term_description',
531 [
532 'get_callback' => function ( $term ) {
533 return get_term_meta( $term['id'], 'glossary_term_description', true );
534 },
535 'update_callback' => null,
536 'schema' => [
537 'description' => __( 'Glossary Term Description', 'betterdocs' ),
538 'type' => 'string',
539 'context' => [ 'view', 'edit' ],
540 ],
541 ]
542 );
543 }
544
545 public function delete_glossaries( $params ) {
546 $term_id = $params->get_param( 'term_id' );
547 $delete = wp_delete_term( $term_id, 'glossaries' );
548
549 if ( is_wp_error( $delete ) ) {
550 return $delete;
551 } else {
552 return true;
553 }
554 }
555
556
557 public function insert_betterdocs_glossaries( $title, $description, $slug = '' ) {
558 $insert_term = wp_insert_term(
559 $title,
560 'glossaries',
561 [
562 'slug' => $slug,
563 'description' => $description
564 ]
565 );
566
567 if ( is_wp_error( $insert_term ) ) {
568 return $insert_term;
569 } else {
570 return true;
571 }
572 }
573
574 public function update_glossaries_order( $params ) {
575 $glossaries_order = $params->get_param( 'glossaries_order' );
576 $glossaries_order = json_decode( $glossaries_order, true );
577
578 foreach ( $glossaries_order as $order_data ) {
579 if ( (int) $order_data['current_position'] != (int) $order_data['updated_position'] ) {
580 update_term_meta( $order_data['id'], 'order', ( (int) $order_data['updated_position'] ) );
581 }
582 }
583 return true;
584 }
585
586 public function insert_betterdocs_faq( $post_title, $post_content, $term_id ) {
587 $post = wp_insert_post(
588 [
589 'post_type' => 'betterdocs_faq',
590 'post_title' => wp_strip_all_tags( $post_title ),
591 'post_content' => $post_content,
592 'post_status' => 'publish'
593 ]
594 );
595
596 if ( $term_id ) {
597 $set_terms = wp_set_object_terms( $post, $term_id, 'glossaries' );
598 if ( is_wp_error( $set_terms ) ) {
599 return $set_terms;
600 } else {
601 return $this->update_faq_order_on_insert( $term_id, $post );
602 }
603 } else {
604 return $post;
605 }
606 }
607
608 public function update_faq_order_on_insert( $term_id, $post ) {
609 $term_meta = get_term_meta( $term_id, '_betterdocs_faq_order' );
610 if ( ! empty( $term_meta ) ) {
611 $term_meta_arr = explode( ',', $term_meta[0] );
612 if ( ! in_array( $post, $term_meta_arr ) ) {
613 array_unshift( $term_meta_arr, $post );
614 $docs_ordering_data = filter_var_array( wp_unslash( $term_meta_arr ), FILTER_SANITIZE_NUMBER_INT );
615 return update_term_meta( $term_id, '_betterdocs_faq_order', implode( ',', $docs_ordering_data ) );
616 }
617 } else {
618 return update_term_meta( $term_id, '_betterdocs_faq_order', $post );
619 }
620 }
621
622 /**
623 * Update _betterdocs_faq_order meta when new post created
624 */
625
626 public function update_faq_order_by_glossary( $params ) {
627 $term_id = $params->get_param( 'term_id' );
628 $posts = $params->get_param( 'posts' );
629 return update_term_meta( $term_id, '_betterdocs_faq_order', $posts );
630 }
631
632 public function create_betterdocs_faq( $params ) {
633 $post_title = $params->get_param( 'post_title' );
634 $post_content = $params->get_param( 'post_content' );
635 $term_id = $params->get_param( 'term_id' );
636 return $this->insert_betterdocs_faq( $post_title, $post_content, $term_id );
637 }
638
639 public function update_betterdocs_faq( $params ) {
640 $post_id = $params->get_param( 'post_id' );
641 $post_title = $params->get_param( 'post_title' );
642 $post_content = $params->get_param( 'post_content' );
643 $status = $params->get_param( 'status' );
644 $term_id = $params->get_param( 'term_id' );
645 if ( $status ) {
646 $data = [
647 'post_type' => 'betterdocs_faq',
648 'ID' => $post_id,
649 'status' => $status
650 ];
651 } else {
652 $data = [
653 'post_type' => 'betterdocs_faq',
654 'ID' => $post_id,
655 'post_title' => $post_title,
656 'post_content' => $post_content
657 ];
658
659 if ( $term_id ) {
660 $data['tax_input'] = [
661 'betterdocs_glossaries' => $term_id
662 ];
663
664 $term_meta = get_term_meta( $term_id, '_betterdocs_faq_order' );
665 $term_meta_arr = explode( ',', $term_meta[0] );
666 if ( ! in_array( $post_id, $term_meta_arr ) ) {
667 array_unshift( $term_meta_arr, $post_id );
668 $docs_ordering_data = filter_var_array( wp_unslash( $term_meta_arr ), FILTER_SANITIZE_NUMBER_INT );
669 update_term_meta( $term_id, '_betterdocs_faq_order', implode( ',', $docs_ordering_data ) );
670 }
671 }
672 }
673
674 return wp_update_post( $data );
675 }
676
677 public function delete_betterdocs_faq( $params ) {
678 $post_id = $params->get_param( 'post_id' );
679 return wp_delete_post( $post_id );
680 }
681
682 public function faq_post_loop( $args ) {
683 $posts = [];
684 $query = new WP_Query( $args );
685 if ( $query->have_posts() ) :
686 while ( $query->have_posts() ) :
687 $query->the_post();
688 $posts[ get_the_ID() ]['title'] = get_the_title();
689 $posts[ get_the_ID() ]['content'] = get_the_content();
690 endwhile;
691 endif;
692
693 return $posts;
694 }
695
696 public function update_glossary_status( $params ) {
697 $term_id = $params->get_param( 'term_id' );
698 $status = $params->get_param( 'status' );
699
700 // Ensure status is a string ('0' or '1')
701 $status = $status ? '1' : '0';
702
703 $result = update_term_meta( $term_id, 'status', $status );
704
705 // Return success response with updated status
706 return array(
707 'success' => $result !== false,
708 'term_id' => $term_id,
709 'status' => $status,
710 'message' => $result !== false ? 'Status updated successfully' : 'Failed to update status'
711 );
712 }
713
714 public function fetch_faq_posts( $params ) {
715 $faq = [];
716 $type = $params->get_param( 'type' );
717
718 if ( $type == 'category' ) {
719 $term_args = [
720 'taxonomy' => 'glossaries',
721 'hide_empty' => false,
722 ];
723
724 // Add language filtering if multilingual plugin is active and we should apply filtering
725 $current_language = Helper::get_current_language();
726 if ( $current_language && Helper::is_multilingual_active() && Helper::should_apply_language_filtering() ) {
727 // For WPML and Polylang, use 'lang' parameter
728 if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) || function_exists( 'pll_current_language' ) ) {
729 $term_args['lang'] = $current_language;
730 }
731 }
732
733 $taxonomy_objects = get_terms( $term_args );
734
735 if ( $taxonomy_objects && ! is_wp_error( $taxonomy_objects ) ) :
736 foreach ( $taxonomy_objects as $term ) :
737 $args = [
738 'post_type' => 'betterdocs_faq',
739 'post_status' => 'publish',
740 'post_per_page' => -1,
741 'tax_query' => [
742 [
743 'taxonomy' => 'glossaries',
744 'field' => 'term_id',
745 'terms' => $term->term_id
746 ]
747 ]
748 ];
749
750 $posts = $this->faq_post_loop( $args );
751
752 $faq[ $term->slug ] = [
753 (array) $term,
754 'posts' => $posts
755 ];
756 endforeach;
757 endif;
758 } else {
759 $args = [
760 'post_type' => 'betterdocs_faq',
761 'post_status' => 'publish',
762 'post_per_page' => -1
763 ];
764 $posts = $this->faq_post_loop( $args );
765 $faq['posts'] = $posts;
766 }
767
768 return $faq;
769 }
770
771
772 public function glossary_search( $request ) {
773
774 $title = $request['title'];
775 $lang = $request['lang'] ?? null;
776
777 // Perform the taxonomy search
778 $taxonomy_args = array(
779 'name__like' => $title,
780 'taxonomy' => 'glossaries',
781 'hide_empty' => false
782 );
783
784 // Add language filtering if multilingual plugin is active
785 $language_to_use = $lang ?: Helper::get_current_language();
786 if ( $language_to_use && Helper::is_multilingual_active() ) {
787 // For WPML and Polylang, use 'lang' parameter
788 if ( is_plugin_active( 'sitepress-multilingual-cms/sitepress.php' ) || function_exists( 'pll_current_language' ) ) {
789 $taxonomy_args['lang'] = $language_to_use;
790 }
791 }
792
793 $taxonomies = get_terms( $taxonomy_args );
794
795 if ( ! empty( $taxonomies ) ) {
796 $result = array();
797 foreach ( $taxonomies as $taxonomy ) {
798 $result[] = array(
799 'id' => $taxonomy->term_id,
800 'count' => $taxonomy->count,
801 'description' => $taxonomy->description,
802 'name' => $taxonomy->name,
803 'slug' => $taxonomy->slug
804 // Add more fields as needed
805 );
806 }
807 // Return the taxonomy data
808 return $result;
809 } else {
810 // Taxonomy not found
811 return new WP_Error( 'taxonomy_not_found', 'Taxonomy not found.', array( 'status' => 404 ) );
812 }
813 }
814
815 public function disable_language_filtering_for_admin_rest( $args, $request ) {
816 // Check if this is an admin REST request for glossaries management
817 if ( is_user_logged_in() && current_user_can( 'edit_others_posts' ) ) {
818 // Check if language parameter is explicitly provided in the request
819 $lang_param = $request->get_param( 'lang' );
820
821 if ( $lang_param ) {
822 // If language is specified, use it for filtering
823 $args['lang'] = $lang_param;
824 } else {
825 // If no language specified, remove language filtering to show all
826 unset( $args['lang'] );
827 // Add a temporary filter to bypass language restrictions
828 add_filter( 'get_terms', array( $this, 'ensure_all_glossaries_in_admin' ), 10, 3 );
829 }
830 }
831
832 return $args;
833 }
834
835 public function ensure_all_glossaries_in_admin( $terms, $taxonomies, $args ) {
836 // Only apply to glossaries taxonomy in admin context
837 if ( in_array( 'glossaries', (array) $taxonomies ) && is_user_logged_in() && current_user_can( 'edit_others_posts' ) ) {
838 // Remove this filter to prevent infinite loops
839 remove_filter( 'get_terms', array( $this, 'ensure_all_glossaries_in_admin' ), 10 );
840
841 // Get all glossaries terms without language filtering
842 $all_args = $args;
843 unset( $all_args['lang'] );
844 $all_args['suppress_filters'] = true; // Bypass all filters including language ones
845
846 $all_terms = get_terms( $all_args );
847
848 // Re-add the filter for future calls
849 add_filter( 'get_terms', array( $this, 'ensure_all_glossaries_in_admin' ), 10, 3 );
850
851 return is_wp_error( $all_terms ) ? $terms : $all_terms;
852 }
853
854 return $terms;
855 }
856
857 /**
858 * Add meta fields to REST API response
859 */
860 public function add_meta_to_rest_response( $response, $term, $request ) {
861 // Ensure meta fields are properly included
862 $meta = get_term_meta( $term->term_id );
863
864 // Format meta data as expected by React component
865 $response->data['meta'] = array();
866
867 if ( isset( $meta['status'] ) ) {
868 $response->data['meta']['status'] = $meta['status'];
869 } else {
870 $response->data['meta']['status'] = array( '1' ); // Default to enabled
871 }
872
873 if ( isset( $meta['order'] ) ) {
874 $response->data['meta']['order'] = $meta['order'];
875 } else {
876 $response->data['meta']['order'] = array( '0' ); // Default order
877 }
878
879 if ( isset( $meta['glossary_term_description'] ) ) {
880 $response->data['meta']['glossary_term_description'] = $meta['glossary_term_description'];
881 } else {
882 $response->data['meta']['glossary_term_description'] = array( '' );
883 }
884
885 return $response;
886 }
887
888 public function glossaries_orderby_meta( $args, $request ) {
889 if ( $args['taxonomy'] === 'glossaries' ) {
890 $args['orderby'] = 'meta_value_num';
891 $args['meta_key'] = 'status';
892 }
893 return $args;
894 }
895
896 public function get_glossary_count( $request ) {
897 $options = get_option( 'store_glossary_count' );
898 return rest_ensure_response( $options );
899 }
900 public function get_glossaries( $request ) {
901 $taxo = get_taxonomies(
902 array(
903 'name' => array(
904 'glossaries'
905 )
906 ),
907 'objects'
908 );
909
910 return rest_ensure_response( $taxo );
911 }
912 }
913