PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.6.2
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.6.2
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 / Settings.php

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

3,033 lines 197.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WPDeveloper\BetterDocs\Core;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8
9 use WP_Error;
10 use WP_User;
11 use WPDeveloper\BetterDocs\Admin\Builder\GlobalFields;
12 use WPDeveloper\BetterDocs\Admin\Builder\Rules;
13 use WPDeveloper\BetterDocs\Utils\AIHelper;
14 use WPDeveloper\BetterDocs\Utils\Base;
15 use WPDeveloper\BetterDocs\Utils\Database;
16 use WPDeveloper\BetterDocs\Utils\Helper;
17
18 class Settings extends Base {
19 public $base_key = 'betterdocs_settings';
20
21 /**
22 * Database class
23 * @var Database
24 */
25 protected $database;
26
27 private $deprecated = array();
28
29 private $cannot_be_empty = array(
30 'breadcrumb_doc_title',
31 'docs_slug',
32 'category_slug',
33 'tag_slug',
34 'permalink_structure',
35 'docs_page'
36 );
37
38 public function __construct( Database $database ) {
39 $this->database = $database;
40 $this->deprecated = $this->deprecated_settings();
41
42 add_filter( 'betterdocs_settings_tabs', array( $this, 'import_export_settings' ) );
43 add_filter( 'betterdocs_settings_tabs', array( $this, 'maybe_remove_git_tab' ), 20 );
44
45 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_old' ), 99 );
46 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue' ), 99 );
47
48 // if ( isset( $_GET['page'] ) && $_GET['page'] === 'betterdocs-settings' && ! has_action( 'betterdocs_settings_header' ) ) {
49 // add_action( 'betterdocs_settings_header', [ $this, 'header' ] );
50 // }
51
52 add_action( 'wp_ajax_betterdocs_dark_mode', array( $this, 'dark_mode' ) );
53 add_filter( 'betterdocs_settings_tab_advance', array( $this, 'hide_roles_management' ), 11, 1 );
54 add_action( 'betterdocs::settings::saved', array( $this, 'fallback_slugs' ), 99, 3 );
55 }
56
57 public function fallback_slugs( $_saved, $_settings, $_old_settings = array() ) {
58 $_default = $this->get_default();
59 foreach ( $this->cannot_be_empty as $key ) {
60 if ( 'docs_page' === $key && ! $_settings[ 'builtin_doc_page' ] && empty( $_settings[ $key ] ) ) {
61 $this->save( 'builtin_doc_page', true );
62 continue;
63 }
64
65 if ( empty( $_settings[ $key ] ) ) {
66 $this->save( $key, $_default[ $key ] );
67 }
68 }
69 }
70
71 /**
72 * Get the settings URL for admin
73 * @return string
74 */
75 public function url() {
76 return esc_url( admin_url( 'admin.php?page=betterdocs-settings' ) );
77 }
78
79 /**
80 * This method is responsible for enqueueing scripts in settings panel
81 *
82 * @param string $hook
83 *
84 * @return void
85 * @since 2.5.0
86 */
87 public function enqueue( $hook ) {
88 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
89 return;
90 }
91
92 wp_enqueue_media();
93 wp_enqueue_script( 'betterdocs-admin' );
94
95 $settings = GlobalFields::normalize( $this->settings_args() );
96
97 // Mask sensitive API keys before they reach the browser. Non-admins still get them stripped entirely below.
98 $sensitive_api_keys = array( 'ai_autowrite_api_key', 'ai_chatbot_api_key' );
99 foreach ( $sensitive_api_keys as $api_key_field ) {
100 if ( ! empty( $settings[ 'values' ][ $api_key_field ] ) ) {
101 $settings[ 'values' ][ $api_key_field ] = Helper::mask_api_key( $settings[ 'values' ][ $api_key_field ] );
102 }
103 }
104
105 if ( ! current_user_can( 'edit_docs_settings' ) ) {
106 foreach ( $sensitive_api_keys as $api_key_field ) {
107 if ( isset( $settings[ 'values' ][ $api_key_field ] ) ) {
108 unset( $settings[ 'values' ][ $api_key_field ] );
109 }
110 }
111 }
112
113 // Inject raw git settings to bypass get() fallback (e.g., '' -> 'docs')
114 if ( isset( $settings[ 'values' ] ) ) {
115 $settings[ 'values' ][ 'git_provider' ] = $this->get_raw_field( 'git_provider', 'github' );
116 $settings[ 'values' ][ 'git_repository_url' ] = $this->get_raw_field( 'git_repository_url', '' );
117 $settings[ 'values' ][ 'git_branch' ] = $this->get_raw_field( 'git_branch', '' );
118 $settings[ 'values' ][ 'git_docs_directory' ] = $this->get_raw_field( 'git_docs_directory', '' );
119 }
120
121 betterdocs()->assets->localize( 'betterdocs-admin', 'betterdocsAdminSettings', $settings );
122 betterdocs()->assets->enqueue( 'betterdocs-icons', 'admin/btd-icon/style.css' );
123 }
124
125 public function enqueue_old( $hook ) {
126 // FREE & Pro Version Compatibility Check
127 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
128 return;
129 }
130
131 $this->enqueue( 'betterdocs_page_betterdocs-settings' );
132 }
133
134 /**
135 * This method is responsible for printing header in dashboard settings page.
136 *
137 * @param string $hook
138 *
139 * @return void
140 * @since 2.5.0
141 */
142 public function header( $hook ) {
143 if ( 'settings' !== $hook ) {
144 return;
145 }
146
147 betterdocs()->views->get( 'admin/template-parts/settings-header' );
148 betterdocs()->views->get( 'admin/template-parts/settings-header-2' );
149 }
150
151 /**
152 * A list of deprecated settings keys.
153 *
154 * @return array
155 * @since 2.5.0
156 */
157 public function deprecated_settings() {
158 return array();
159 }
160
161 /**
162 * Dynamic migration caller.
163 *
164 * @return void
165 * @since 2.5.0
166 */
167 public function migration( $version ) {
168 if ( $version > 250 ) {
169 for ( $v = 250; $v <= $version; ++$v ) {
170 $_func = "v{$v}";
171 if ( method_exists( $this, $_func ) ) {
172 call_user_func( array( $this, $_func ) );
173 }
174 }
175 }
176 }
177
178 /**
179 * Migration for version 2.5.0
180 *
181 * @return void
182 * @since 2.5.0
183 */
184 public function v250() {
185 if ( $this->get( 'alphabetically_order_term', false ) ) {
186 $this->save( 'terms_orderby', 'name' );
187 }
188
189 if ( $orderby = $this->get( 'alphabetically_order_post', false ) ) {
190 if ( '1' === $orderby ) {
191 $this->save( 'alphabetically_order_post', 'title' );
192 }
193 }
194 }
195
196 /**
197 * A list of default settings data.
198 *
199 * @return array
200 * @since 1.0.0
201 *
202 */
203 public function get_default() {
204 $_default = array(
205 'multiple_kb' => '',
206 'enable_ai_sample_docs' => true,
207 'enable_export_faq' => true,
208 'builtin_doc_page' => true,
209 'breadcrumb_doc_title' => __( 'Docs', 'betterdocs' ),
210 'enable_category_hierarchy_slugs' => false,
211 'docs_slug' => 'docs',
212 'docs_page' => 0,
213 'category_slug' => 'docs-category',
214 'tag_slug' => 'docs-tag',
215 'permalink_structure' => 'docs/',
216 'enable_faq_schema' => false,
217 'live_search' => true,
218 'advance_search' => false,
219 'popular_keyword_limit' => 5,
220 'search_letter_limit' => 3,
221 'search_placeholder' => __( 'Search...', 'betterdocs' ),
222 'search_not_found_text' => __( 'Sorry, no docs were found.', 'betterdocs' ),
223 'search_result_image' => true,
224 'search_modal_search_type' => 'all',
225 'masonry_layout' => true,
226 'docs_list_icon' => array(),
227 'category_title_link' => false,
228 'terms_orderby' => 'betterdocs_order',
229 'alphabetically_order_term' => false,
230 'terms_order' => 'ASC',
231 'alphabetically_order_post' => 'betterdocs_order',
232 'docs_order' => 'ASC',
233 'nested_subcategory' => false,
234 'column_number' => 3,
235 'posts_number' => 10,
236 'post_count' => true,
237 'count_text' => __( 'Docs', 'betterdocs' ),
238 'count_text_singular' => __( 'Doc', 'betterdocs' ),
239 'exploremore_btn' => true,
240 'exploremore_btn_txt' => __( 'Explore More', 'betterdocs' ),
241 'doc_single' => 1,
242 'enable_toc' => true,
243 'toc_title' => __( 'Table of Contents', 'betterdocs' ),
244 'toc_hierarchy' => true,
245 'toc_list_number' => false,
246 'toc_dynamic_title' => false,
247 'enable_sticky_toc' => true,
248 'sticky_toc_offset' => 100,
249 'collapsible_toc_mobile' => false,
250 'supported_heading_tag' => array( '1', '2', '3', '4', '5', '6' ),
251 'enable_post_title' => true,
252 'title_link_ctc' => true,
253 'enable_breadcrumb' => true,
254 'breadcrumb_home_text' => __( 'Home', 'betterdocs' ),
255 'enable_breadcrumb_home_text' => true,
256 'breadcrumb_home_url' => get_home_url(),
257 'enable_breadcrumb_category' => true,
258 'enable_breadcrumb_title' => true,
259 'enable_sidebar_cat_list' => true,
260 'enable_print_icon' => true,
261 'enable_tags' => true,
262 'email_feedback' => true,
263 'feedback_link_text' => __( 'Still stuck? How can we help?', 'betterdocs' ),
264 'reaction_feedback_text' => __( 'Thanks for your feedback', 'betterdocs' ),
265 'feedback_url' => '',
266 'feedback_form_title' => __( 'How can we help?', 'betterdocs' ),
267 'email_address' => get_option( 'admin_email' ),
268 'show_last_update_time' => true,
269 'enable_navigation' => true,
270 'enable_comment' => true,
271 'enable_credit' => false,
272 'enable_archive_sidebar' => true,
273 'archive_nested_subcategory' => true,
274 'archive_enable_pagination' => false,
275 'enable_content_restriction' => false,
276 'enable_reporting' => false,
277 'enable_sample_data' => false,
278 'reporting_day' => 'monday',
279 'reporting_email' => get_option( 'admin_email' ),
280 'enable_write_with_ai' => true,
281 'enable_faq_write_with_ai' => true,
282 'enable_glossaries_write_with_ai' => true,
283 'write_with_ai_model' => 'gpt-4o-mini',
284 'ai_autowrite_api_key' => '',
285 'ai_autowrite_max_token' => 2500,
286 'enable_article_summary' => false,
287 'article_summary_model' => 'gpt-4o-mini',
288 'article_summary_max_token' => 1500,
289 'enable_estimated_reading_time' => true,
290 'enable_encyclopedia' => false,
291 'enable_glossaries' => false,
292 'show_glossary_suggestions' => true,
293 'enable_ai_chatbot' => false,
294 'estimated_reading_time_title' => '',
295 'estimated_reading_time_text' => __( 'min read', 'betterdocs' ),
296 'singular_estimated_reading_time_text' => __( 'min read', 'betterdocs' ),
297 'betterdocs_access_control_repeater' => array(),
298 'internal_knowledge_base_type' => 'basic',
299 'betterdocs_access_control_repeater_kb' => array(),
300 'enable_git_integration' => false
301 );
302
303 $_default = apply_filters( 'betterdocs_default_settings', $_default );
304 // $_default = apply_filters_deprecated(
305 // 'betterdocs_option_default_settings', [$_default], '2.5.0',
306 // 'betterdocs_default_settings', 'betterdocs_option_default_settings will be removed from v3.5.0.'
307 // );
308
309 return $_default;
310 }
311
312 /**
313 * A list of default settings for pro plugins.
314 *
315 * @return array
316 * @since 2.5.0
317 */
318 public function get_pro_defaults() {
319 return array();
320 }
321
322 public function is_elementor_pro() {
323 return is_plugin_active( 'elementor-pro/elementor-pro.php' );
324 }
325
326 /**
327 * Get full site editor links for docs page.
328 *
329 * @return string
330 * @since 3.5.8
331 */
332 public function gutenberg_link() {
333 if ( betterdocs()->helper->current_theme_is_fse_theme() ) {
334 return admin_url( 'site-editor.php?postType=wp_template&postId=betterdocs/betterdocs//archive-docs' );
335 } else {
336 return 'https://betterdocs.co/docs/betterdocs-provides-full-site-editor-support/';
337 }
338 }
339
340 /**
341 * Get elementor theme builder link for docs page.
342 *
343 * @return string
344 * @since 3.5.8
345 */
346 public function elementor_link() {
347 if ( $this->is_elementor_pro() ) {
348 return admin_url( 'admin.php?page=elementor-app#/site-editor/templates/doc-archive' );
349 } else {
350 return 'https://betterdocs.co/docs/docs-page-with-elementor/';
351 }
352 }
353
354 public function customizer_link() {
355 $query[ 'autofocus[panel]' ] = 'betterdocs_customize_options';
356 $query[ 'return' ] = admin_url( 'edit.php?post_type=docs' );
357 $builtin_doc_page = betterdocs()->settings->get( 'builtin_doc_page' );
358 $docs_slug = betterdocs()->settings->get( 'docs_slug' );
359 $docs_page = betterdocs()->settings->get( 'builtin_doc_page' );
360
361 if ( 1 == $builtin_doc_page && $docs_slug ) {
362 $query[ 'url' ] = site_url( '/' . $docs_slug );
363 } elseif ( 1 != $builtin_doc_page && $docs_page ) {
364 $post_info = get_post( $docs_page );
365 $query[ 'url' ] = site_url( '/' . $post_info->post_name );
366 }
367
368 return add_query_arg( $query, admin_url( 'customize.php' ) );
369 }
370
371 public function design_tab() {
372 $settings = array();
373
374 $settings[ 'gutenberg_link' ] = array(
375 'name' => 'gutenberg_link',
376 'type' => 'action',
377 'action' => 'betterdocs_settings_gutenberg_link',
378 'button' => betterdocs()->helper->current_theme_is_fse_theme() ? __( 'Design with Gutenberg', 'betterdocs' ) : __( 'Learn More', 'betterdocs' ),
379 'url' => $this->gutenberg_link(),
380 'customizer_img' => betterdocs()->assets->icon( 'customizer/gutenberg-preview.png', true ),
381 'priority' => 1
382 );
383
384 $settings[ 'elementor_link' ] = array(
385 'name' => 'elementor_link',
386 'type' => 'action',
387 'action' => 'betterdocs_settings_elementor_link',
388 'button' => $this->is_elementor_pro() ? __( 'Design with Elementor', 'betterdocs' ) : __( 'Learn More', 'betterdocs' ),
389 'url' => $this->elementor_link(),
390 'customizer_img' => betterdocs()->assets->icon( 'customizer/elementor-preview.png', true ),
391 'priority' => 2
392 );
393
394 if ( ! betterdocs()->helper->current_theme_is_fse_theme() ) {
395 $settings[ 'customizer_link' ] = array(
396 'name' => 'customizer_link',
397 'type' => 'action',
398 'action' => 'betterdocs_settings_customizer_link',
399 'button' => __( 'Customize in BetterDocs', 'betterdocs' ),
400 'url' => $this->customizer_link(),
401 'customizer_img' => betterdocs()->assets->icon( 'customizer/customizer-preview.png', true ),
402 'priority' => 3
403 );
404 }
405
406 return $settings;
407 }
408
409 /**
410 * Get All Roles
411 * dynamically
412 *
413 * @return array
414 */
415 public function get_roles() {
416 $roles = wp_roles()->role_names;
417 unset( $roles[ 'subscriber' ] );
418
419 return $roles;
420 }
421
422 /**
423 * Set dark mode
424 *
425 * @return void
426 * @since 1.0.0
427 */
428 public function dark_mode() {
429 if ( ! check_ajax_referer( 'doc_cat_order_nonce', 'nonce', false ) ) {
430 wp_send_json_error();
431 }
432
433 if ( isset( $_POST[ 'mode' ] ) ) {
434 $mode = sanitize_text_field( wp_unslash( $_POST[ 'mode' ] ) );
435 if ( $this->save( 'dark_mode', rest_sanitize_boolean( $mode ) ) ) {
436 wp_send_json_success();
437 }
438 }
439
440 wp_send_json_error();
441 }
442
443 public function get_normalized_value( $key, $value, $default = null ) {
444 $_origin_value = $_value = $value;
445
446 if ( in_array( $_value, array( 'on', 'off', '1', 'false', 'true' ), true ) ) {
447 switch ( $_value ) {
448 case 'on':
449 case 'ON':
450 case '1':
451 case 'true':
452 $_value = true;
453 break;
454 case 'off':
455 case 'OFF':
456 case '':
457 case 'false':
458 $_value = false;
459 break;
460 }
461 }
462
463 $this->type_validation( $_value, $default );
464
465 return $_value;
466 }
467
468 public function get_normalized_values( $values, $default_values = array() ) {
469 if ( empty( $values ) ) {
470 return array();
471 }
472
473 $_settings = array();
474 foreach ( $values as $key => $value ) {
475 $_default_value = isset( $default_values[ $key ] ) ? $default_values[ $key ] : null;
476 $_settings[ $key ] = $this->get_normalized_value( $key, $value, $_default_value );
477 }
478
479 return $_settings;
480 }
481
482 public function get_all( $raw = false ) {
483 $_default_settings = $raw ? array() : array_merge( $this->get_default(), $this->get_pro_defaults() );
484 $_settings = $this->database->get( $this->base_key, $_default_settings );
485
486 return $this->get_normalized_values( $_settings, $_default_settings );
487 }
488
489 public function type_validation( &$value, $defaultValue = null ) {
490 if ( null !== $defaultValue ) {
491 /**
492 * Check if value is not in same type
493 */
494 $_default_type = gettype( $defaultValue );
495
496 if ( ! ( is_scalar( $defaultValue ) && is_scalar( $value ) ) && empty( $value ) ) {
497 $value = $defaultValue;
498 }
499
500 settype( $value, $_default_type );
501 }
502 }
503
504 /**
505 * Get settings value by key
506 *
507 * @param string $key
508 * @param mixed $default
509 * @param bool $get_all
510 *
511 * @return mixed
512 * @since 2.5.0
513 *
514 */
515 public function get( $key, $default = null ) {
516 $_default_settings = array_merge( $this->get_default(), $this->get_pro_defaults() );
517 $_settings = $this->database->get( $this->base_key, $_default_settings );
518
519 $_value = $default;
520 switch ( true ) {
521 // Check if it's a PRO Option
522 case ! isset( $_default_settings[ $key ] ):
523 $_value = $default;
524 break;
525 // Check if it's a FREE Option and not in DB.
526 case ! isset( $_settings[ $key ] ) && isset( $_default_settings[ $key ] ):
527 $_value = null !== $default ? $default : $_default_settings[ $key ];
528 break;
529 // Check if it's a FREE Option
530 case isset( $_settings[ $key ] ) && isset( $_default_settings[ $key ] ):
531 $_value = $_settings[ $key ];
532 break;
533 }
534
535 $_value = $this->get_normalized_value( $key, $_value, isset( $_default_settings[ $key ] ) ? $_default_settings[ $key ] : null );
536
537 if ( gettype( $_value ) === 'string' ) {
538 if ( empty( $_value ) && null != $default ) {
539 $_value = $default;
540 } elseif ( empty( $_value ) && null === $default && isset( $_default_settings[ $key ] ) ) {
541 $_value = $_default_settings[ $key ];
542 }
543 }
544
545 return $_value;
546 }
547
548 public function get_raw_field( $key, $default = null ) {
549 $_settings = $this->database->get( $this->base_key, array() );
550
551 if ( isset( $_settings[ $key ] ) ) {
552 return $this->get_normalized_value( $key, $_settings[ $key ], $default );
553 }
554
555 return $default;
556 }
557
558 public function save( $key, $value ) {
559 $_settings = $this->database->get( $this->base_key, array() );
560 $_settings[ $key ] = $value;
561
562 return $this->database->save( $this->base_key, $_settings );
563 }
564
565 public function save_settings( $settings ) {
566 $existing_plugins = betterdocs()->kbmigration->knowledge_base_plugins();
567 if ( ! current_user_can( 'edit_docs_settings' ) ) {
568 return new WP_Error( 'unauthorized_action', __( 'You don\'t have any rights for saving settings.', 'betterdocs' ) );
569 }
570
571 // The frontend sends the currently-active settings tab as a transport-only hint so
572 // tab-scoped validation (the AI min-token floor below) only runs when that tab is being
573 // saved. It must never be persisted into the settings option.
574 $active_tab = '';
575 if ( array_key_exists( '_active_tab', $settings ) ) {
576 $active_tab = (string) $settings[ '_active_tab' ];
577 unset( $settings[ '_active_tab' ] );
578 }
579
580 // Quickbuilder sends back the full UI-loaded payload. To avoid overwriting values that we
581 // asynchronously updated in the DB via AJAX (like Git integration fields), we strictly remove them
582 // from the incoming save payload so that the freshly loaded `$_old_settings` values persist.
583 $exclude_ajax_keys = array( 'git_provider', 'git_repository_url', 'git_branch', 'git_docs_directory' );
584 foreach ( $exclude_ajax_keys as $key ) {
585 if ( array_key_exists( $key, $settings ) ) {
586 unset( $settings[ $key ] );
587 }
588 if ( isset( $settings[ 'values' ] ) && is_array( $settings[ 'values' ] ) && array_key_exists( $key, $settings[ 'values' ] ) ) {
589 unset( $settings[ 'values' ][ $key ] );
590 }
591 }
592
593 $_old_settings = $this->database->get( $this->base_key, $this->get_default() );
594
595 // The frontend only ever sees masked API keys. If a submitted value matches the mask of
596 // the stored value, the user did not change it — restore the original so the mask string
597 // is never persisted.
598 $sensitive_api_keys = array( 'ai_autowrite_api_key', 'ai_chatbot_api_key' );
599 foreach ( $sensitive_api_keys as $api_key_field ) {
600 if ( ! isset( $settings[ $api_key_field ] ) ) {
601 continue;
602 }
603 $stored = isset( $_old_settings[ $api_key_field ] ) ? $_old_settings[ $api_key_field ] : '';
604 if ( '' !== $stored && trim( (string) $settings[ $api_key_field ] ) === Helper::mask_api_key( $stored ) ) {
605 $settings[ $api_key_field ] = $stored;
606 }
607 }
608
609 // Minimum-token policy: reject saves where a feature's max_token field is below the
610 // per-model floor defined by AIHelper::get_min_tokens(). The model may be unchanged in
611 // this submission, so fall back to the stored value when it isn't part of the payload.
612 // Both token fields live under the AI Content Suite tab, so enforce the floor only when
613 // that tab is the one being saved — saving any other settings page never trips it (e.g.
614 // old users whose stored value predates the floor). When the active-tab hint is absent
615 // (stale cached JS, the quick-setup wizard, or any programmatic caller) the loop is
616 // skipped and the save is allowed through.
617 $token_pairs = array(
618 array(
619 'tab' => 'tab-betterdocs-ai',
620 'context' => 'write_with_ai',
621 'token_key' => 'ai_autowrite_max_token',
622 'model_key' => 'write_with_ai_model',
623 'label' => __( 'Write with AI', 'betterdocs' )
624 ),
625 array(
626 'tab' => 'tab-betterdocs-ai',
627 'context' => 'article_summary',
628 'token_key' => 'article_summary_max_token',
629 'model_key' => 'article_summary_model',
630 'label' => __( 'AI Doc Summarizer', 'betterdocs' )
631 )
632 );
633 foreach ( $token_pairs as $pair ) {
634 if ( $active_tab !== $pair[ 'tab' ] ) {
635 continue;
636 }
637 if ( ! array_key_exists( $pair[ 'token_key' ], $settings ) ) {
638 continue;
639 }
640 $incoming_tokens = (int) $settings[ $pair[ 'token_key' ] ];
641 $incoming_model = isset( $settings[ $pair[ 'model_key' ] ] )
642 ? $settings[ $pair[ 'model_key' ] ]
643 : ( isset( $_old_settings[ $pair[ 'model_key' ] ] ) ? $_old_settings[ $pair[ 'model_key' ] ] : '' );
644 $min = AIHelper::get_min_tokens( $pair[ 'context' ], $incoming_model );
645 if ( $min > 0 && $incoming_tokens < $min ) {
646 return new WP_Error(
647 'min_tokens_below_threshold',
648 sprintf(
649 /* translators: 1: feature label, 2: minimum tokens, 3: model id */
650 __( '%1$s max tokens must be at least %2$d for %3$s.', 'betterdocs' ),
651 $pair[ 'label' ],
652 $min,
653 $incoming_model
654 )
655 );
656 }
657 }
658
659 // @todo: sanitize the data before inject in DB.
660 $_normalized_settings = $this->get_normalized_values( $settings );
661 if ( $existing_plugins && isset( $_normalized_settings[ 'migration_step' ] ) && true == $_normalized_settings[ 'migration_step' ] ) {
662 betterdocs()->kbmigration->migrate();
663 }
664 $_settings = wp_parse_args( $_normalized_settings, $_old_settings );
665
666 // Check if there are actual changes before saving.
667 // update_option returns false when values serialize identically, which can happen
668 // due to object caching or type normalization even when user made changes.
669 $_has_changes = $_settings != $_old_settings;
670
671 $_saved = $this->database->save( $this->base_key, $_settings );
672
673 do_action_ref_array( 'betterdocs::settings::saved', array( $_saved, $_settings, $_old_settings, &$this ) );
674
675 // Return true if save succeeded OR if there were changes to attempt saving.
676 // This handles cases where update_option returns false due to identical serialization
677 // (e.g., object caching, type coercion during serialization).
678 return $_saved || $_has_changes;
679 }
680
681 public function views( $hook ) {
682 return betterdocs()->views->get( 'admin/settings' );
683 }
684
685 public function save_default_settings() {
686 $_settings = $this->get_all();
687
688 return $this->database->save( $this->base_key, $_settings );
689 }
690
691 public function get_pages() {
692 $_pages = betterdocs()->query->get_posts( array(
693 'post_type' => 'page',
694 'numberposts' => -1,
695 'post_status' => 'publish',
696 'posts_per_page' => -1
697 ) );
698
699 $__pages = array();
700
701 if ( ! empty( $_pages ) ) {
702 $__pages[ 0 ] = __( 'Select a Page', 'betterdocs' );
703 foreach ( $_pages->posts as $page ) {
704 $__pages[ $page->ID ] = esc_html( $page->post_title );
705 }
706 }
707
708 return $__pages;
709 }
710
711 public function settings_args() {
712 $wp_roles = $this->normalize_options( $this->get_roles() );
713
714 $roles_for_ikb = $this->normalize_options( array_merge( array( 'all' => __( 'All logged in users', 'betterdocs' ) ), wp_roles()->role_names ) );
715
716 unset( $roles_for_ikb[ 'administrator' ] );
717
718 $settings = array(
719 'id' => 'betterdocs_settings_metabox_wrapper',
720 'title' => __( 'betterdocs', 'betterdocs' ),
721 'object_types' => array( 'betterdocs' ),
722 'context' => 'normal',
723 'priority' => 'high',
724 'show_header' => false,
725 'tabnumber' => false,
726 'is_pro_active' => betterdocs()->is_pro_active(),
727 'logoURL' => betterdocs()->assets->icon( 'betterdocs-icon.svg', true ),
728 'layout' => 'vertical',
729 'config' => array(
730 'active' => 'tab-general',
731 'sidebar' => true,
732 'title' => false
733 ),
734 'submit' => array(
735 'show' => true,
736 'label' => __( 'Save', 'betterdocs' ),
737 'loadingLabel' => __( 'Saving...', 'betterdocs' ),
738 'class' => 'save-settings',
739 'rules' => Rules::logicalRule( array(
740 Rules::is( 'config.active', 'tab-design', true ),
741 Rules::is( 'config.active', 'tab-shortcodes', true ),
742 Rules::is( 'config.active', 'tab-instant-answer', true ),
743 Rules::is( 'config.active', 'tab-import-export', true ),
744 Rules::is( 'config.active', 'tab-migration', true )
745 ), 'and' )
746 ),
747 'values' => betterdocs()->is_pro_active() ? $this->get_all() : array_merge( $this->get_all(), $this->pro_settings_default_values() ),
748 'tabs' => apply_filters( 'betterdocs_settings_tabs', array(
749 'tab-general' => apply_filters( 'betterdocs_settings_tab_general', array(
750 'id' => 'tab-general',
751 'label' => __( 'General', 'betterdocs' ),
752 'classes' => 'tab-general',
753 'priority' => 10,
754 'fields' => array(
755 'title-general' => apply_filters( 'betterdocs_encyclopedia_settings', array(
756 'name' => 'title-general-tab',
757 'type' => 'section',
758 'label' => __( 'General Settings', 'betterdocs' ),
759 'priority' => 10,
760 'fields' => array(
761 'multiple_kb' => apply_filters( 'betterdocs_multi_kb_settings', array(
762 'name' => 'multiple_kb',
763 'type' => 'toggle',
764 'label' => __( 'Multiple Knowledge Base', 'betterdocs' ),
765 'enable_disable_text_active' => true,
766 'default' => '',
767 'priority' => 1,
768 'is_pro' => true
769 ) ),
770 'builtin_doc_page' => array(
771 'name' => 'builtin_doc_page',
772 'type' => 'toggle',
773 'label' => __( 'Built-in Documentation Page', 'betterdocs' ),
774 'enable_disable_text_active' => true,
775 'default' => 1,
776 'priority' => 2
777 ),
778 'enable_category_hierarchy_slugs' => array(
779 'name' => 'enable_category_hierarchy_slugs',
780 'type' => 'toggle',
781 'label' => __( 'Enable Category Hierarchy Slug', 'betterdocs' ),
782 'enable_disable_text_active' => true,
783 'default' => false,
784 'priority' => 3,
785 'label_subtitle' => __( "Shows Hierarchy Based Permalink Slugs For Doc Categories & Single Doc Page", 'betterdocs' )
786 ),
787 'breadcrumb_doc_title' => array(
788 'name' => 'breadcrumb_doc_title',
789 'type' => 'text',
790 'label' => __( 'Documentation Page Title', 'betterdocs' ),
791 'default' => __( 'Docs', 'betterdocs' ),
792 'priority' => 4,
793 'rules' => Rules::is( 'builtin_doc_page', true )
794 ),
795 'docs_slug' => array(
796 'name' => 'docs_slug',
797 'type' => 'text',
798 'label' => __( 'BetterDocs Root Slug', 'betterdocs' ),
799 'default' => 'docs',
800 'priority' => 5,
801 'rules' => Rules::is( 'builtin_doc_page', true )
802 ),
803 'docs_page' => array(
804 'name' => 'docs_page',
805 'label' => __( 'Docs Page', 'betterdocs' ),
806 'type' => 'select',
807 'default' => 0,
808 'priority' => 6,
809 'search' => true,
810 'options' => $this->normalize_options( $this->get_pages() ),
811 'label_subtitle' => __( 'You will need to insert BetterDocs Shortcode inside the page. This page will be used as docs permalink.', 'betterdocs' ),
812 'rules' => Rules::is( 'builtin_doc_page', false )
813 ),
814
815 'category_slug' => array(
816 'name' => 'category_slug',
817 'type' => 'text',
818 'label' => __( 'Custom Category Slug', 'betterdocs' ),
819 'default' => 'docs-category',
820 'priority' => 7
821 ),
822 'tag_slug' => array(
823 'name' => 'tag_slug',
824 'type' => 'text',
825 'label' => __( 'Custom Tag Slug', 'betterdocs' ),
826 'default' => 'docs-tag',
827 'priority' => 8
828 ),
829 'permalink_structure' => array(
830 'name' => 'permalink_structure',
831 'type' => 'permalink_structure',
832 'label' => __( 'Single Docs Permalink', 'betterdocs' ),
833 'default' => PostType::permalink_structure(),
834 'priority' => 9,
835 'tags' => $this->normalize_options( array(
836 '%doc_category%' => '%doc_category%',
837 '%knowledge_base%' => '%knowledge_base%'
838 ) ),
839 'label_subtitle' => __( 'Make sure to keep Docs Root Slug in the Single Docs Permalink. You are not able to keep it blank. You can use the available tags from below.', 'betterdocs' )
840 ),
841 'enable_glossaries' => array(
842 'name' => 'enable_glossaries',
843 'type' => 'toggle',
844 'label' => __( 'Show Glossary', 'betterdocs' ),
845 'label_subtitle' => __( 'Enable the glossary feature to allow users to look up definitions for terms used within your encyclopedia or glossaries themselves.', 'betterdocs' ),
846 'enable_disable_text_active' => true,
847 'default' => false,
848 'priority' => 10,
849 'is_pro' => true
850 ),
851 'enable_encyclopedia' => array(
852 'name' => 'enable_encyclopedia',
853 'type' => 'toggle',
854 'label' => __( 'Built-in Encyclopedia Page', 'betterdocs' ),
855 'enable_disable_text_active' => true,
856 'default' => false,
857 'priority' => 11,
858 'is_pro' => true
859 ),
860 'enable_faq_schema' => array(
861 'name' => 'enable_faq_schema',
862 'type' => 'toggle',
863 'label' => __( 'FAQ Schema', 'betterdocs' ),
864 'enable_disable_text_active' => true,
865 'default' => '',
866 'priority' => 12
867 ),
868 'analytics_from' => array(
869 'name' => 'analytics_from',
870 'type' => 'select',
871 'label' => __( 'Analytics From', 'betterdocs' ),
872 'options' => $this->normalize_options( array(
873 'everyone' => __( 'Everyone', 'betterdocs' ),
874 'guests' => __( 'Guests Only', 'betterdocs' ),
875 'registered_users' => __( 'Registered Users Only', 'betterdocs' )
876 ) ),
877 'default' => 'everyone',
878 'priority' => 13,
879 'is_pro' => true
880 ),
881 'unique_visitor_count' => array(
882 'name' => 'unique_visitor_count',
883 'type' => 'toggle',
884 'label' => __( 'Unique Visitor Count', 'betterdocs' ),
885 'enable_disable_text_active' => true,
886 'default' => false,
887 'priority' => 14,
888 'is_pro' => true
889 ),
890 'exclude_bot_analytics' => array(
891 'name' => 'exclude_bot_analytics',
892 'type' => 'toggle',
893 'label' => __( 'Exclude Bot Analytics', 'betterdocs' ),
894 'enable_disable_text_active' => true,
895 'default' => false,
896 'priority' => 15,
897 'is_pro' => true
898 )
899
900 )
901 ) )
902 )
903 ) ),
904 'tab-layout' => apply_filters( 'betterdocs_settings_tab_layout', array(
905 'id' => 'tab-layout',
906 'label' => __( 'Layout', 'betterdocs' ),
907 'classes' => 'tab-layout',
908 'priority' => 20,
909 'fields' => array(
910 'title-layout' => array(
911 'name' => 'title-layout-tab',
912 'type' => 'section',
913 'label' => __( 'Layout Settings', 'betterdocs' ),
914 'priority' => 20,
915 'fields' => array(
916 'tab-sidebar-layout' => apply_filters( 'betterdocs_settings_tab_sidebar_layout', array(
917 'id' => 'tab-sidebar-layout',
918 'name' => 'tab_sidebar_layout',
919 'label' => __( 'Layout Settings', 'betterdocs' ),
920 'classes' => 'tab-layout',
921 'type' => 'tab',
922 'active' => 'layout_documentation_page',
923 'completionTrack' => true,
924 'sidebar' => false,
925 'save' => false,
926 'title' => false,
927 'config' => array(
928 'active' => 'layout_documentation_page',
929 'sidebar' => false,
930 'title' => false
931 ),
932 'submit' => array(
933 'show' => false
934 ),
935 'step' => array(
936 'show' => false
937 ),
938 'priority' => 20,
939 'fields' => array(
940 'layout_documentation_page' => array(
941 'id' => 'layout_documentation_page',
942 'name' => 'layout_documentation_page',
943 'type' => 'section',
944 'label' => __( 'Documentation Page', 'betterdocs' ),
945 'priority' => 1,
946 'fields' => array(
947 'tab-nested-layout-1' => array(
948 'id' => 'tab-nested-layout-1',
949 'name' => 'tab_nested_layout_1',
950 'label' => __( 'Documentation Page', 'betterdocs' ),
951 'classes' => 'tab-nested-layout',
952 'type' => 'tab',
953 'active' => 'layout_documentation_page_general',
954 'completionTrack' => true,
955 'sidebar' => false,
956 'save' => false,
957 'title' => false,
958 'config' => array(
959 'active' => 'layout_documentation_page_general',
960 'sidebar' => false,
961 'title' => false
962 ),
963 'submit' => array(
964 'show' => false
965 ),
966 'step' => array(
967 'show' => false
968 ),
969 'priority' => 1,
970 'fields' => array(
971 'layout_documentation_page_general' => array(
972 'id' => 'layout_documentation_page_general',
973 'name' => 'layout_documentation_page_general',
974 'type' => 'section',
975 'label' => __( 'General', 'betterdocs' ),
976 'priority' => 1,
977 'fields' => array(
978 'docs_list_icon' => array(
979 'name' => 'docs_list_icon',
980 'type' => 'media',
981 'value' => '',
982 'label' => __( 'Docs List Icon', 'betterdocs' ),
983 'label_subtitle' => __( 'Upload your own preferred document list icon', 'betterdocs' ),
984 'priority' => 0
985 ),
986 'category_title_link' => array(
987 'name' => 'category_title_link',
988 'type' => 'toggle',
989 'label' => __( 'Category Title Link', 'betterdocs' ),
990 'label_subtitle' => __( 'This setting is applicable for category grid layout', 'betterdocs' ),
991 'enable_disable_text_active' => true,
992 'default' => false,
993 'priority' => 0
994 ),
995 'masonry_layout' => array(
996 'name' => 'masonry_layout',
997 'type' => 'toggle',
998 'label' => __( 'Masonry', 'betterdocs' ),
999 'enable_disable_text_active' => true,
1000 'default' => 1,
1001 'priority' => 1
1002 ),
1003 'nested_subcategory' => array(
1004 'name' => 'nested_subcategory',
1005 'type' => 'toggle',
1006 'label' => __( 'Nested Sub Category', 'betterdocs' ),
1007 'enable_disable_text_active' => true,
1008 'default' => '',
1009 'priority' => 2
1010 ),
1011 'column_number' => array(
1012 'name' => 'column_number',
1013 'type' => 'number',
1014 'label' => __( 'Number Of Columns', 'betterdocs' ),
1015 'label_subtitle' => __( 'This setting is not applicable for sleek layout.', 'betterdocs' ),
1016 'default' => 3,
1017 'priority' => 3
1018 ),
1019 'posts_number' => apply_filters( 'betterdocs_posts_number', array(
1020 'name' => 'posts_number',
1021 'type' => 'number',
1022 'label' => __( 'Number Of Docs', 'betterdocs' ),
1023 'label_subtitle' => __( 'This setting is not applicable for handbook layout.', 'betterdocs' ),
1024 'default' => 10,
1025 'priority' => 4
1026 ) ),
1027 'post_count' => array(
1028 'name' => 'post_count',
1029 'type' => 'toggle',
1030 'label' => __( 'Doc Count', 'betterdocs' ),
1031 'enable_disable_text_active' => true,
1032 'default' => 1,
1033 'priority' => 5
1034 ),
1035 'count_text' => array(
1036 'name' => 'count_text',
1037 'type' => 'text',
1038 'label' => __( 'Count Text', 'betterdocs' ),
1039 'default' => __( 'Docs', 'betterdocs' ),
1040 'priority' => 6
1041 ),
1042 'count_text_singular' => array(
1043 'name' => 'count_text_singular',
1044 'type' => 'text',
1045 'label' => __( 'Count Text Singular', 'betterdocs' ),
1046 'default' => __( 'Doc', 'betterdocs' ),
1047 'priority' => 7
1048 ),
1049 'exploremore_btn' => array(
1050 'name' => 'exploremore_btn',
1051 'type' => 'toggle',
1052 'label' => __( 'Explore More Button', 'betterdocs' ),
1053 'enable_disable_text_active' => true,
1054 'default' => true,
1055 'priority' => 8
1056 ),
1057 'exploremore_btn_txt' => array(
1058 'name' => 'exploremore_btn_txt',
1059 'type' => 'text',
1060 'label' => __( 'Explore More Button Text', 'betterdocs' ),
1061 'default' => __( 'Explore More', 'betterdocs' ),
1062 'priority' => 9,
1063 'rules' => Rules::is( 'exploremore_btn', true )
1064 ),
1065 'betterdocs_popular_docs_text' => array(
1066 'name' => 'betterdocs_popular_docs_text',
1067 'type' => 'text',
1068 'label' => __( 'Popular Docs Text', 'betterdocs' ),
1069 'default' => __( 'Popular Docs', 'betterdocs' ),
1070 'priority' => 10,
1071 'is_pro' => true
1072 ),
1073 'betterdocs_popular_docs_number' => array(
1074 'name' => 'betterdocs_popular_docs_number',
1075 'type' => 'number',
1076 'label' => __( 'Popular Docs Number', 'betterdocs' ),
1077 'default' => 10,
1078 'priority' => 11,
1079 'is_pro' => true
1080 )
1081 )
1082 ),
1083 'layout_documentation_page_search' => array(
1084 'id' => 'layout_documentation_page_search',
1085 'name' => 'layout_documentation_page_search',
1086 'type' => 'section',
1087 'label' => __( 'Search', 'betterdocs' ),
1088 'priority' => 2,
1089 'fields' => array(
1090 'live_search' => array(
1091 'name' => 'live_search',
1092 'type' => 'toggle',
1093 'label' => __( 'Live Search', 'betterdocs' ),
1094 'enable_disable_text_active' => true,
1095 'default' => 1,
1096 'priority' => 1
1097 ),
1098 'advance_search' => apply_filters( 'betterdocs_advance_search_settings', array(
1099 'name' => 'advance_search',
1100 'type' => 'toggle',
1101 'label' => __( 'Advanced Search', 'betterdocs' ),
1102 'enable_disable_text_active' => true,
1103 'default' => '',
1104 'priority' => 2,
1105 'is_pro' => true
1106 ) ),
1107 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- legacy public filter name for category-exclude settings field, retained for back-compat.
1108 'child_category_exclude' => apply_filters( 'child_category_exclude', array(
1109 'name' => 'child_category_exclude',
1110 'type' => 'toggle',
1111 'label' => __( 'Exclude Child Terms In Category Search', 'betterdocs' ),
1112 'enable_disable_text_active' => true,
1113 'default' => '',
1114 'priority' => 3,
1115 'is_pro' => true
1116 ) ),
1117 'popular_keyword_limit' => apply_filters( 'betterdocs_popular_keyword_limit_settings', array(
1118 'name' => 'popular_keyword_limit',
1119 'type' => 'number',
1120 'label' => __( 'Minimum amount of Keywords Search', 'betterdocs' ),
1121 'default' => 5,
1122 'priority' => 4,
1123 'is_pro' => true
1124 ) ),
1125 'search_letter_limit' => array(
1126 'name' => 'search_letter_limit',
1127 'type' => 'number',
1128 'label' => __( 'Minimum Character Limit For Search Result', 'betterdocs' ),
1129 'priority' => 5,
1130 'default' => 3
1131 ),
1132 'search_placeholder' => array(
1133 'name' => 'search_placeholder',
1134 'type' => 'text',
1135 'label' => __( 'Search Placeholder', 'betterdocs' ),
1136 'default' => __( 'Search..', 'betterdocs' ),
1137 'priority' => 6
1138 ),
1139 'search_button_text' => apply_filters( 'betterdocs_search_button_text', array(
1140 'name' => 'search_button_text',
1141 'type' => 'text',
1142 'label' => __( 'Search Button Text', 'betterdocs' ),
1143 'priority' => 7,
1144 'default' => __( 'Search', 'betterdocs' )
1145 ) ),
1146 'search_not_found_text' => array(
1147 'name' => 'search_not_found_text',
1148 'type' => 'text',
1149 'label' => __( 'Search Not Found Text', 'betterdocs' ),
1150 'default' => 'Sorry, no docs were found.',
1151 'priority' => 8
1152 ),
1153 'search_result_image' => array(
1154 'name' => 'search_result_image',
1155 'type' => 'toggle',
1156 'label' => __( 'Search Result Image', 'betterdocs' ),
1157 'enable_disable_text_active' => true,
1158 'default' => 1,
1159 'priority' => 9
1160 ),
1161 'kb_based_search' => apply_filters( 'betterdocs_kb_based_search_settings', array(
1162 'name' => 'kb_based_search',
1163 'type' => 'toggle',
1164 'label' => __( 'KB Based Search', 'betterdocs' ),
1165 'enable_disable_text_active' => true,
1166 'default' => '',
1167 'priority' => 10,
1168 'is_pro' => true,
1169 'rules' => Rules::is( 'multiple_kb', true )
1170 ) ),
1171 'search_modal_search_type' => array(
1172 'name' => 'search_modal_search_type',
1173 'type' => 'select',
1174 'label' => __( 'Search Modal Source', 'betterdocs' ),
1175 'label_subtitle' => __( 'Choose the content type to be shown in the search modal. <br> <b>Note:</b> This is only applicable on Modal Search.', 'betterdocs' ),
1176 'default' => 'all',
1177 'options' => $this->normalize_options( array(
1178 'all' => __( 'Both (Docs + FAQs)', 'betterdocs' ),
1179 'docs' => __( 'Docs only', 'betterdocs' ),
1180 'faq' => __( 'FAQs only', 'betterdocs' )
1181 ) ),
1182 'priority' => 11
1183 )
1184 )
1185 ),
1186 'layout_documentation_page_order_by' => array(
1187 'id' => 'layout_documentation_page_order_by',
1188 'name' => 'layout_documentation_page_order_by',
1189 'type' => 'section',
1190 'label' => __( 'Order By', 'betterdocs' ),
1191 'priority' => 3,
1192 'fields' => array(
1193 'terms_orderby' => array(
1194 'name' => 'terms_orderby',
1195 'type' => 'select',
1196 'label' => __( 'Terms Order By', 'betterdocs' ),
1197 'default' => 'betterdocs_order',
1198 'options' => $this->normalize_options( apply_filters( 'betterdocs_terms_orderby_options', array(
1199 'none' => __( 'No order', 'betterdocs' ),
1200 'name' => __( 'Name', 'betterdocs' ),
1201 'slug' => __( 'Slug', 'betterdocs' ),
1202 'term_group' => __( 'Term Group', 'betterdocs' ),
1203 'term_id' => __( 'Term ID', 'betterdocs' ),
1204 'id' => __( 'ID', 'betterdocs' ),
1205 'description' => __( 'Description', 'betterdocs' ),
1206 'parent' => __( 'Parent', 'betterdocs' ),
1207 'betterdocs_order' => __( 'BetterDocs Order', 'betterdocs' )
1208 ) ) ),
1209 'priority' => 1
1210 ),
1211 'terms_order' => array(
1212 'name' => 'terms_order',
1213 'type' => 'select',
1214 'label' => __( 'Terms Order', 'betterdocs' ),
1215 'default' => 'ASC',
1216 'options' => $this->normalize_options( array(
1217 'ASC' => 'Ascending',
1218 'DESC' => 'Descending'
1219 ) ),
1220 'priority' => 3,
1221 'rules' => Rules::includes( 'terms_orderby', 'betterdocs_order', true )
1222 ),
1223 'alphabetically_order_post' => array(
1224 'name' => 'alphabetically_order_post',
1225 'type' => 'select',
1226 'label' => __( 'Docs Order By', 'betterdocs' ),
1227 'default' => 'betterdocs_order',
1228 'options' => $this->normalize_options( array(
1229 'none' => __( 'No order', 'betterdocs' ),
1230 'ID' => __( 'Docs ID', 'betterdocs' ),
1231 'author' => __( 'Docs Author', 'betterdocs' ),
1232 'title' => __( 'Title', 'betterdocs' ),
1233 'date' => __( 'Date', 'betterdocs' ),
1234 'modified' => __( 'Last Modified Date', 'betterdocs' ),
1235 'parent' => __( 'Parent Id', 'betterdocs' ),
1236 'rand' => __( 'Random', 'betterdocs' ),
1237 'comment_count' => __( 'Comment Count', 'betterdocs' ),
1238 'menu_order' => __( 'Menu Order', 'betterdocs' ),
1239 'betterdocs_order' => __( 'BetterDocs Order', 'betterdocs' )
1240 ) ),
1241 'priority' => 4
1242 ),
1243 'docs_order' => array(
1244 'name' => 'docs_order',
1245 'type' => 'select',
1246 'label' => __( 'Docs Order', 'betterdocs' ),
1247 'default' => 'ASC',
1248 'options' => $this->normalize_options( array(
1249 'ASC' => 'Ascending',
1250 'DESC' => 'Descending'
1251 ) ),
1252 'priority' => 5,
1253 'rules' => Rules::includes( 'alphabetically_order_post', 'betterdocs_order', true )
1254 )
1255 )
1256 )
1257 )
1258 )
1259 )
1260 ),
1261 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- legacy public filter name for single-doc setting section, retained for back-compat.
1262 'layout_single_doc' => apply_filters( 'single_doc_setting_section', array(
1263 'id' => 'layout_single_doc',
1264 'name' => 'layout_single_doc',
1265 'type' => 'section',
1266 'label' => __( 'Single Doc', 'betterdocs' ),
1267 'priority' => 2,
1268 'fields' => array(
1269 'tab-nested-layout-2' => array(
1270 'id' => 'tab-nested-layout-2',
1271 'name' => 'tab_nested_layout_2',
1272 'label' => __( 'Single Doc', 'betterdocs' ),
1273 'classes' => 'tab-nested-layout',
1274 'type' => 'tab',
1275 'active' => 'layout_single_doc_general',
1276 'completionTrack' => true,
1277 'sidebar' => false,
1278 'save' => false,
1279 'title' => false,
1280 'config' => array(
1281 'active' => 'layout_single_doc_general',
1282 'sidebar' => false,
1283 'title' => false
1284 ),
1285 'submit' => array(
1286 'show' => false
1287 ),
1288 'step' => array(
1289 'show' => false
1290 ),
1291 'priority' => 20,
1292 'fields' => array(
1293 'layout_single_doc_general' => array(
1294 'id' => 'layout_single_doc_general',
1295 'name' => 'layout_single_doc_general',
1296 'type' => 'section',
1297 'label' => __( 'General', 'betterdocs' ),
1298 'priority' => 5,
1299 'fields' => array(
1300 'enable_post_title' => array(
1301 'name' => 'enable_post_title',
1302 'type' => 'toggle',
1303 'label' => __( 'Doc Title', 'betterdocs' ),
1304 'enable_disable_text_active' => true,
1305 'default' => 1,
1306 'priority' => 1
1307 ),
1308 'enable_sidebar_cat_list' => array(
1309 'name' => 'enable_sidebar_cat_list',
1310 'type' => 'toggle',
1311 'label' => __( 'Sidebar Category List', 'betterdocs' ),
1312 'enable_disable_text_active' => true,
1313 'default' => 1,
1314 'priority' => 2
1315 ),
1316 'enable_print_icon' => array(
1317 'name' => 'enable_print_icon',
1318 'type' => 'toggle',
1319 'label' => __( 'Print Icon', 'betterdocs' ),
1320 'enable_disable_text_active' => true,
1321 'default' => 1,
1322 'priority' => 3
1323 ),
1324 'enable_tags' => array(
1325 'name' => 'enable_tags',
1326 'type' => 'toggle',
1327 'label' => __( 'Tags', 'betterdocs' ),
1328 'enable_disable_text_active' => true,
1329 'default' => 1,
1330 'priority' => 4
1331 ),
1332 'show_last_update_time' => array(
1333 'name' => 'show_last_update_time',
1334 'type' => 'toggle',
1335 'label' => __( 'Last Update Time', 'betterdocs' ),
1336 'enable_disable_text_active' => true,
1337 'default' => 1,
1338 'priority' => 5
1339 ),
1340 'enable_navigation' => array(
1341 'name' => 'enable_navigation',
1342 'type' => 'toggle',
1343 'label' => __( 'Navigation', 'betterdocs' ),
1344 'enable_disable_text_active' => true,
1345 'default' => 1,
1346 'priority' => 6
1347 ),
1348 'enable_comment' => array(
1349 'name' => 'enable_comment',
1350 'type' => 'toggle',
1351 'label' => __( 'Comment', 'betterdocs' ),
1352 'enable_disable_text_active' => true,
1353 'default' => '',
1354 'priority' => 7
1355 ),
1356 'enable_credit' => array(
1357 'name' => 'enable_credit',
1358 'type' => 'toggle',
1359 'label' => __( 'Show Powered by BetterDocs', 'betterdocs' ),
1360 'enable_disable_text_active' => true,
1361 'default' => '',
1362 'priority' => 8
1363 ),
1364 'reaction_feedback_text' => array(
1365 'name' => 'reaction_feedback_text',
1366 'type' => 'text',
1367 'label' => __( 'Reaction Feedback Text', 'betterdocs' ),
1368 'default' => __( 'Thanks for your feedback.', 'betterdocs' ),
1369 'priority' => 9
1370 ),
1371 'enable_estimated_reading_time' => array(
1372 'name' => 'enable_estimated_reading_time',
1373 'type' => 'toggle',
1374 'label' => __( 'Estimated Reading Time', 'betterdocs' ),
1375 'enable_disable_text_active' => true,
1376 'default' => 0,
1377 'priority' => 10
1378 ),
1379 'estimated_reading_time_title' => array(
1380 'name' => 'estimated_reading_time_title',
1381 'type' => 'text',
1382 'label' => __( 'Estimated Reading Time Title', 'betterdocs' ),
1383 'default' => '',
1384 'priority' => 11,
1385 'rules' => Rules::is( 'enable_estimated_reading_time', true )
1386 ),
1387 'estimated_reading_time_text' => array(
1388 'name' => 'estimated_reading_time_text',
1389 'type' => 'text',
1390 'label' => __( 'Estimated Reading Time Text', 'betterdocs' ),
1391 'default' => __( 'min read', 'betterdocs' ),
1392 'priority' => 12,
1393 'rules' => Rules::is( 'enable_estimated_reading_time', true )
1394 ),
1395 'singular_estimated_reading_time_text' => array(
1396 'name' => 'singular_estimated_reading_time_text',
1397 'type' => 'text',
1398 'label' => __( 'Estimated Reading Time Text Singular', 'betterdocs' ),
1399 'default' => __( 'min read', 'betterdocs' ),
1400 'priority' => 13,
1401 'rules' => Rules::is( 'enable_estimated_reading_time', true )
1402 )
1403 )
1404 ),
1405 'layout_single_doc_TOC' => array(
1406 'id' => 'layout_single_doc_TOC',
1407 'name' => 'layout_single_doc_TOC',
1408 'type' => 'section',
1409 'label' => __( 'TOC', 'betterdocs' ),
1410 'priority' => 5,
1411 'fields' => array(
1412 'enable_toc' => array(
1413 'name' => 'enable_toc',
1414 'type' => 'toggle',
1415 'label' => __( 'Table of Contents', 'betterdocs' ),
1416 'enable_disable_text_active' => true,
1417 'default' => 1,
1418 'priority' => 1
1419 ),
1420 'toc_title' => array(
1421 'name' => 'toc_title',
1422 'type' => 'text',
1423 'label' => __( 'TOC Title', 'betterdocs' ),
1424 'default' => __( 'Table of Contents', 'betterdocs' ),
1425 'priority' => 2,
1426 'rules' => Rules::is( 'enable_toc', true )
1427
1428 ),
1429 'toc_hierarchy' => array(
1430 'name' => 'toc_hierarchy',
1431 'type' => 'toggle',
1432 'label' => __( 'TOC Hierarchy', 'betterdocs' ),
1433 'enable_disable_text_active' => true,
1434 'default' => 1,
1435 'priority' => 3,
1436 'rules' => Rules::is( 'enable_toc', true )
1437 ),
1438 'toc_list_number' => array(
1439 'name' => 'toc_list_number',
1440 'type' => 'toggle',
1441 'label' => __( 'TOC List Number', 'betterdocs' ),
1442 'enable_disable_text_active' => true,
1443 'default' => 1,
1444 'priority' => 4,
1445 'rules' => Rules::is( 'enable_toc', true )
1446 ),
1447 'toc_dynamic_title' => array(
1448 'name' => 'toc_dynamic_title',
1449 'type' => 'toggle',
1450 'label' => __( 'Show TOC Title in Anchor Links', 'betterdocs' ),
1451 'enable_disable_text_active' => true,
1452 'default' => 0,
1453 'priority' => 5,
1454 'rules' => Rules::is( 'enable_toc', true )
1455 ),
1456 'enable_sticky_toc' => array(
1457 'name' => 'enable_sticky_toc',
1458 'type' => 'toggle',
1459 'label' => __( 'Sticky TOC', 'betterdocs' ),
1460 'enable_disable_text_active' => true,
1461 'default' => 1,
1462 'priority' => 6,
1463 'rules' => Rules::is( 'enable_toc', true )
1464 ),
1465 'collapsible_toc_mobile' => array(
1466 'name' => 'collapsible_toc_mobile',
1467 'type' => 'toggle',
1468 'label' => __( 'Collapsible TOC on small devices', 'betterdocs' ),
1469 'enable_disable_text_active' => true,
1470 'default' => '',
1471 'priority' => 7,
1472 'rules' => Rules::is( 'enable_toc', true )
1473 ),
1474 'title_link_ctc' => array(
1475 'name' => 'title_link_ctc',
1476 'type' => 'toggle',
1477 'label' => __( 'Title Link Copy To Clipboard', 'betterdocs' ),
1478 'enable_disable_text_active' => true,
1479 'default' => 1,
1480 'priority' => 8
1481 ),
1482 'supported_heading_tag' => array(
1483 'name' => 'supported_heading_tag',
1484 'label' => __( 'TOC Supported Heading Tag', 'betterdocs' ),
1485 'type' => 'checkbox-select',
1486 'multiple' => true,
1487 'priority' => 10,
1488 'default' => array(
1489 '1',
1490 '2',
1491 '3',
1492 '4',
1493 '5',
1494 '6'
1495 ),
1496 'options' => $this->normalize_options( array(
1497 '1' => 'H1',
1498 '2' => 'H2',
1499 '3' => 'H3',
1500 '4' => 'H4',
1501 '5' => 'H5',
1502 '6' => 'H6'
1503 ) ),
1504 'priority' => 9,
1505 'rules' => Rules::is( 'enable_toc', true )
1506 ),
1507 'sticky_toc_offset' => array(
1508 'name' => 'sticky_toc_offset',
1509 'type' => 'number',
1510 'label' => __( 'Content Offset', 'betterdocs' ),
1511 'default' => 100,
1512 'priority' => 10,
1513 'label_subtitle' => __( 'content offset from top on scroll.', 'betterdocs' ),
1514 'rules' => Rules::is( 'enable_toc', true )
1515 )
1516 )
1517 ),
1518 'layout_single_doc_breadcrumb' => array(
1519 'id' => 'layout_single_doc_breadcrumb',
1520 'name' => 'layout_single_doc_breadcrumb',
1521 'type' => 'section',
1522 'label' => __( 'Breadcrumb', 'betterdocs' ),
1523 'priority' => 5,
1524 'fields' => array(
1525 'enable_breadcrumb' => array(
1526 'name' => 'enable_breadcrumb',
1527 'type' => 'toggle',
1528 'label' => __( 'Breadcrumb', 'betterdocs' ),
1529 'enable_disable_text_active' => true,
1530 'default' => 1,
1531 'priority' => 1
1532 ),
1533 'enable_breadcrumb_home_text' => array(
1534 'name' => 'enable_breadcrumb_home_text',
1535 'type' => 'toggle',
1536 'label' => __( 'Enable Breadcrumb Home Text', 'betterdocs' ),
1537 'enable_disable_text_active' => true,
1538 'default' => true,
1539 'priority' => 2,
1540 'rules' => Rules::is( 'enable_breadcrumb', true )
1541 ),
1542 'breadcrumb_home_text' => array(
1543 'name' => 'breadcrumb_home_text',
1544 'type' => 'text',
1545 'label' => __( 'Breadcrumb Home Text', 'betterdocs' ),
1546 'default' => __( 'Home', 'betterdocs' ),
1547 'priority' => 3,
1548 'rules' => Rules::logicalRule(
1549 array(
1550 Rules::is( 'enable_breadcrumb', true ),
1551 Rules::is( 'enable_breadcrumb_home_text', true )
1552 ),
1553 'and'
1554 )
1555 ),
1556 'breadcrumb_home_url' => array(
1557 'name' => 'breadcrumb_home_url',
1558 'type' => 'text',
1559 'label' => __( 'Breadcrumb Home URL', 'betterdocs' ),
1560 'priority' => 4,
1561 'default' => get_home_url(),
1562 'rules' => Rules::is( 'enable_breadcrumb', true )
1563 ),
1564 'enable_breadcrumb_category' => array(
1565 'name' => 'enable_breadcrumb_category',
1566 'type' => 'toggle',
1567 'label' => __( 'Category on Breadcrumb', 'betterdocs' ),
1568 'enable_disable_text_active' => true,
1569 'default' => 1,
1570 'priority' => 5,
1571 'rules' => Rules::is( 'enable_breadcrumb', true )
1572 ),
1573 'enable_breadcrumb_title' => array(
1574 'name' => 'enable_breadcrumb_title',
1575 'type' => 'toggle',
1576 'label' => __( 'Title on Breadcrumb', 'betterdocs' ),
1577 'enable_disable_text_active' => true,
1578 'default' => 1,
1579 'priority' => 6,
1580 'rules' => Rules::is( 'enable_breadcrumb', true )
1581 )
1582 )
1583 ),
1584 'layout_single_doc_email_feedback' => array(
1585 'id' => 'layout_single_doc_email_feedback',
1586 'name' => 'layout_single_doc_email_feedback',
1587 'type' => 'section',
1588 'label' => __( 'Email Feedback', 'betterdocs' ),
1589 'priority' => 5,
1590 'fields' => array(
1591 'email_feedback' => array(
1592 'name' => 'email_feedback',
1593 'type' => 'toggle',
1594 'label' => __( 'Email Feedback', 'betterdocs' ),
1595 'enable_disable_text_active' => true,
1596 'default' => 1,
1597 'priority' => 1
1598 ),
1599 'feedback_link_text' => array(
1600 'name' => 'feedback_link_text',
1601 'type' => 'text',
1602 'label' => __( 'Feedback Link Text', 'betterdocs' ),
1603 'default' => __( 'Still stuck? How can we help?', 'betterdocs' ),
1604 'priority' => 2,
1605 'rules' => Rules::is( 'email_feedback', true )
1606 ),
1607 'feedback_form_title' => array(
1608 'name' => 'feedback_form_title',
1609 'type' => 'text',
1610 'label' => __( 'Feedback Form Title', 'betterdocs' ),
1611 'default' => __( 'Still stuck? How can we help?', 'betterdocs' ),
1612 'priority' => 3,
1613 'rules' => Rules::is( 'email_feedback', true )
1614 ),
1615 'email_address' => array(
1616 'name' => 'email_address',
1617 'type' => 'text',
1618 'label' => __( 'Email Address', 'betterdocs' ),
1619 'default' => get_option( 'admin_email' ),
1620 'priority' => 4,
1621 'label_subtitle' => __( 'The email address where the Feedback form will be sent', 'betterdocs' ),
1622 'rules' => Rules::is( 'email_feedback', true )
1623 ),
1624 'feedback_url' => array(
1625 'name' => 'feedback_url',
1626 'type' => 'text',
1627 'label' => __( 'Feedback URL', 'betterdocs' ),
1628 'default' => '',
1629 'priority' => 5,
1630 'rules' => Rules::is( 'email_feedback', true )
1631 )
1632 )
1633 ),
1634 array(
1635 'id' => 'layout_single_doc_attachments',
1636 'name' => 'layout_single_doc_attachments',
1637 'type' => 'section',
1638 'label' => __( 'Attachments', 'betterdocs' ),
1639 'priority' => 6,
1640 'fields' => apply_filters( 'betterdocs_single_doc_attachments', array(
1641 'show_attachment' => array(
1642 'name' => 'show_attachment',
1643 'type' => 'toggle',
1644 'is_pro' => true,
1645 'priority' => 1,
1646 'label' => __( 'Show Attachment', 'betterdocs' ),
1647 'enable_disable_text_active' => true,
1648 'default' => false
1649 )
1650 ) )
1651 ),
1652 array(
1653 'id' => 'layout_single_doc_related_docs',
1654 'name' => 'layout_single_doc_related_docs',
1655 'type' => 'section',
1656 'label' => __( 'Related Docs', 'betterdocs' ),
1657 'priority' => 7,
1658 'fields' => apply_filters( 'betterdocs_single_doc_related_docs', array(
1659 'show_related_docs' => array(
1660 'name' => 'show_related_docs',
1661 'type' => 'toggle',
1662 'is_pro' => true,
1663 'priority' => 1,
1664 'label' => __( 'Show Related Docs', 'betterdocs' ),
1665 'enable_disable_text_active' => true,
1666 'default' => false
1667 )
1668 ) )
1669 )
1670 )
1671 )
1672 )
1673 ) ),
1674 'layout_archive_page' => array(
1675 'id' => 'layout_archive_page',
1676 'name' => 'layout_archive_page',
1677 'type' => 'section',
1678 'label' => __( 'Archive Page', 'betterdocs' ),
1679 'priority' => 3,
1680 'fields' => array(
1681 'enable_archive_sidebar' => array(
1682 'name' => 'enable_archive_sidebar',
1683 'type' => 'toggle',
1684 'label' => __( 'Sidebar Category List', 'betterdocs' ),
1685 'enable_disable_text_active' => true,
1686 'default' => 1,
1687 'priority' => 31
1688 ),
1689 'archive_nested_subcategory' => array(
1690 'name' => 'archive_nested_subcategory',
1691 'type' => 'toggle',
1692 'label' => __( 'Nested Subcategory', 'betterdocs' ),
1693 'enable_disable_text_active' => true,
1694 'default' => 1,
1695 'priority' => 32
1696 ),
1697 'archive_enable_pagination' => array(
1698 'name' => 'archive_enable_pagination',
1699 'type' => 'toggle',
1700 'label' => __( 'Enable Pagination', 'betterdocs' ),
1701 'enable_disable_text_active' => true,
1702 'default' => false,
1703 'priority' => 33
1704 )
1705 )
1706 )
1707 )
1708 ) )
1709 )
1710 )
1711 )
1712 ) ),
1713 'tab-design' => apply_filters( 'betterdocs_settings_tab_design', array(
1714 'id' => 'tab-design',
1715 'label' => __( 'Design', 'betterdocs' ),
1716 'priority' => 30,
1717 'fields' => array(
1718 'title-design' => array(
1719 'name' => 'title-design-tab',
1720 'type' => 'section',
1721 'label' => __( 'Design', 'betterdocs' ),
1722 'priority' => 30,
1723 'fields' => $this->design_tab()
1724 )
1725 )
1726 ) ),
1727 'tab-shortcodes' => apply_filters( 'betterdocs_settings_tab_shortcodes', array(
1728 'label' => __( 'Shortcodes', 'betterdocs' ),
1729 'id' => 'tab-shortcodes',
1730 'classes' => 'tab-shortcodes',
1731 'priority' => 40,
1732 'fields' => array(
1733 'title-shortcodes' => array(
1734 'name' => 'title-shortcodes-tab',
1735 'type' => 'section',
1736 'label' => __( 'Shortcodes', 'betterdocs' ),
1737 'priority' => 40,
1738 'searchable' => true,
1739 'searchPlaceholder' => __( 'Search for shortcode', 'betterdocs' ),
1740 'searchNotFoundMessage' => '<img src="' . betterdocs()->assets->icon( 'not-found.svg', true ) . '"/><p>' . __( 'No Shortcodes Found with these keywords', 'betterdocs' ) . '</p>',
1741 'fields' => apply_filters( 'betterdocs_shortcode_fields', array(
1742 'search_form' => array(
1743 'name' => 'search_form',
1744 'type' => 'copy-to-clipboard',
1745 'label' => __( 'Search Form', 'betterdocs' ),
1746 'default' => '[betterdocs_search_form]',
1747 'readOnly' => true,
1748 'priority' => 1,
1749 'description' => __( '[betterdocs_search_form placeholder="Search..." heading="Heading" subheading="Subheading" category_search="true" search_button="true" popular_search="true"]', 'betterdocs' ),
1750 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1751 'descriptionCopyable' => true
1752 ),
1753 'feedback_form' => array(
1754 'name' => 'feedback_form',
1755 'type' => 'copy-to-clipboard',
1756 'label' => __( 'Feedback Form', 'betterdocs' ),
1757 'default' => '[betterdocs_feedback_form]',
1758 'readOnly' => true,
1759 'priority' => 2,
1760 'description' => __( '[betterdocs_feedback_form button_text="Send"]', 'betterdocs' ),
1761 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1762 'descriptionCopyable' => true
1763 ),
1764 'category_grid' => array(
1765 'name' => 'category_grid',
1766 'type' => 'copy-to-clipboard',
1767 'label' => __( 'Category Grid- Layout 1', 'betterdocs' ),
1768 'default' => '[betterdocs_category_grid]',
1769 'readOnly' => true,
1770 'priority' => 3,
1771 'description' => __( '[betterdocs_category_grid show_count="true" show_icon="true" masonry="true" column="3" posts_per_page="5" nested_subcategory="true" terms="term_ID, term_ID" terms_orderby="" terms_order="" multiple_knowledge_base="" kb_slug="" title_tag="h2" orderby="" order="" ]', 'betterdocs' ),
1772 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1773 'descriptionCopyable' => true
1774 ),
1775 'category_box' => array(
1776 'name' => 'category_box',
1777 'type' => 'copy-to-clipboard',
1778 'label' => __( 'Category Box- Layout 2', 'betterdocs' ),
1779 'default' => '[betterdocs_category_box]',
1780 'readOnly' => true,
1781 'priority' => 4,
1782 'description' => __( '[betterdocs_category_box orderby="" column="" nested_subcategory="" terms="" terms_orderby="" show_icon="" kb_slug="" title_tag="h2" multiple_knowledge_base="false" border_bottom="false"]', 'betterdocs' ),
1783 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1784 'descriptionCopyable' => true
1785 ),
1786 'category_list' => array(
1787 'name' => 'category_list',
1788 'type' => 'copy-to-clipboard',
1789 'label' => __( 'Category List', 'betterdocs' ),
1790 'default' => '[betterdocs_category_list]',
1791 'readOnly' => true,
1792 'priority' => 5,
1793 'description' => __( '[betterdocs_category_list orderby="" order="" posts_per_page="" nested_subcategory="" terms="" terms_orderby="" terms_order="" kb_slug="" multiple_knowledge_base="false" title_tag="h2"]', 'betterdocs' ),
1794 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1795 'descriptionCopyable' => true
1796 ),
1797 'faq_modern_layout' => array(
1798 'name' => 'faq_modern_layout',
1799 'type' => 'copy-to-clipboard',
1800 'label' => __( 'FAQ Layout - 1', 'betterdocs' ),
1801 'default' => '[betterdocs_faq_list_modern]',
1802 'readOnly' => true,
1803 'priority' => 13,
1804 'description' => __( '[betterdocs_faq_list_modern groups="group_id" class="" group_exclude="group_id" faq_heading="Frequently Asked Questions"]', 'betterdocs' ),
1805 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1806 'descriptionCopyable' => true
1807 ),
1808 'faq_classic_layout' => array(
1809 'name' => 'faq_classic_layout',
1810 'type' => 'copy-to-clipboard',
1811 'label' => __( 'FAQ Layout - 2', 'betterdocs' ),
1812 'default' => '[betterdocs_faq_list_classic]',
1813 'readOnly' => true,
1814 'priority' => 14,
1815 'description' => __( '[betterdocs_faq_list_classic groups="group_id" class="" group_exclude="group_id" faq_heading="Frequently Asked Questions"]', 'betterdocs' ),
1816 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1817 'descriptionCopyable' => true
1818 ),
1819 'betterdocs_faq_list_layout_3' => array(
1820 'name' => 'betterdocs_faq_list_layout_3',
1821 'type' => 'copy-to-clipboard',
1822 'label' => __( 'FAQ Layout - 3', 'betterdocs' ),
1823 'default' => '[betterdocs_faq_list_layout_3 class="faq-doc betterdocs-faq-layout-3"]',
1824 'readOnly' => true,
1825 'priority' => 15,
1826 'description' => __( '[betterdocs_faq_list_layout_3 class="faq-doc betterdocs-faq-layout-3" groups="group_id" class="" group_exclude="group_id" faq_heading="Frequently Asked Questions"]', 'betterdocs' ),
1827 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1828 'descriptionCopyable' => true
1829 ),
1830 'betterdocs_faq_tab' => array(
1831 'name' => 'betterdocs_faq_tab',
1832 'type' => 'copy-to-clipboard',
1833 'label' => __( 'FAQ Layout - 4', 'betterdocs' ),
1834 'default' => '[betterdocs_faq_tab class="faq-doc betterdocs-faq-layout-4"]',
1835 'readOnly' => true,
1836 'priority' => 16,
1837 'description' => __( '[betterdocs_faq_tab class="faq-doc betterdocs-faq-layout-4" groups="group_id" group_exclude="group_id" faq_heading="Frequently Asked Questions"]', 'betterdocs' ),
1838 'descriptionLabel' => __( 'Example with parameters:', 'betterdocs' ),
1839 'descriptionCopyable' => true
1840 )
1841 ) )
1842 )
1843 )
1844 ) ),
1845 'tab-advance-settings' => apply_filters( 'betterdocs_settings_tab_advance', array(
1846 'id' => 'tab-advance-settings',
1847 'label' => __( 'Access & Restrictions', 'betterdocs' ),
1848 'classes' => 'tab-layout',
1849 'priority' => 50,
1850 'fields' => array(
1851 'title_advance_settings' => array(
1852 'name' => 'title-advance-settings-tab',
1853 'type' => 'section',
1854 'label' => __( 'Access & Restrictions', 'betterdocs' ),
1855 'priority' => 50,
1856 'fields' => array(
1857 'tab-advanced-settings' => array(
1858 'id' => 'tab-advanced-settings',
1859 'name' => 'tab-advanced-settings',
1860 'label' => __( 'Access & Restrictions', 'betterdocs' ),
1861 'classes' => 'tab-layout',
1862 'type' => 'tab',
1863 'active' => 'global_role_management',
1864 'completionTrack' => true,
1865 'sidebar' => false,
1866 'save' => false,
1867 'title' => false,
1868 'config' => array(
1869 'active' => '',
1870 'sidebar' => false,
1871 'title' => false
1872 ),
1873 'submit' => array(
1874 'show' => false
1875 ),
1876 'step' => array(
1877 'show' => false
1878 ),
1879 'priority' => 50,
1880 'fields' => array(
1881 'global_role_management' => array(
1882 'id' => 'global_role_management',
1883 'name' => 'global_role_management',
1884 'type' => 'section',
1885 'label' => __( 'Global Role Management', 'betterdocs' ),
1886 'priority' => 1,
1887 'fields' => array(
1888 'article_roles' => array(
1889 'name' => 'article_roles',
1890 'type' => 'checkbox-select',
1891 'label' => __( 'Who Can Write Docs?', 'betterdocs' ),
1892 'priority' => 1,
1893 'multiple' => true,
1894 'search' => true,
1895 'is_pro' => true,
1896 'default' => array( 'administrator' ),
1897 'options' => $wp_roles
1898 ),
1899 'settings_roles' => array(
1900 'name' => 'settings_roles',
1901 'type' => 'checkbox-select',
1902 'label' => __( 'Who Can Edit Settings?', 'betterdocs' ),
1903 'priority' => 2,
1904 'multiple' => true,
1905 'is_pro' => true,
1906 'search' => true,
1907 'default' => array( 'administrator' ),
1908 'options' => $wp_roles
1909 ),
1910 'analytics_roles' => array(
1911 'name' => 'analytics_roles',
1912 'type' => 'checkbox-select',
1913 'label' => __( 'Who Can Check Analytics?', 'betterdocs' ),
1914 'priority' => 3,
1915 'multiple' => true,
1916 'is_pro' => true,
1917 'search' => true,
1918 'default' => array( 'administrator' ),
1919 'options' => $wp_roles
1920 ),
1921 'faq_roles' => array(
1922 'name' => 'faq_roles',
1923 'type' => 'checkbox-select',
1924 'label' => __( 'Who Can Check FAQ Builder?', 'betterdocs' ),
1925 'priority' => 4,
1926 'multiple' => true,
1927 'is_pro' => true,
1928 'search' => true,
1929 'default' => array( 'administrator' ),
1930 'options' => $wp_roles
1931 )
1932
1933 )
1934 ),
1935 'internal_knowledge_base' => array(
1936 'id' => 'internal_knowledge_base',
1937 'name' => 'internal_knowledge_base',
1938 'type' => 'section',
1939 'label' => __( 'Internal Knowledge Base', 'betterdocs' ),
1940 'priority' => 1,
1941 'fields' => apply_filters( 'betterdocs_settings_content_restriction_fields', array(
1942 'enable_content_restriction' => array(
1943 'name' => 'enable_content_restriction',
1944 'type' => 'toggle',
1945 'is_pro' => true,
1946 'priority' => 5,
1947 'label' => __( 'Internal Knowledge Base', 'betterdocs' ),
1948 'enable_disable_text_active' => true,
1949 'default' => array( 'all' )
1950 ),
1951 'internal_knowledge_base_type' => array(
1952 'name' => 'internal_knowledge_base_type',
1953 'type' => 'radio-card',
1954 'label' => __( 'Choose a Rule Type', 'betterdocs' ),
1955 'label_subtitle' => __( 'Choose a rule type: apply access globally (Basic), or configure detailed restrictions (Advanced) for docs, categories, and KBs.', 'betterdocs' ),
1956 'priority' => 6,
1957 'multiple' => true,
1958 'search' => true,
1959 'default' => array( 'all' ),
1960 'placeholder' => __( 'Select any', 'betterdocs' ),
1961 'options' => array(
1962 array(
1963 'label' => 'Basic',
1964 'value' => 'basic'
1965 ),
1966 array(
1967 'label' => 'Advanced',
1968 'value' => 'advanced'
1969 )
1970 ),
1971 'filterValue' => 'all',
1972 'rules' => Rules::is( 'enable_content_restriction', true )
1973 ),
1974 'content_visibility' => array(
1975 'name' => 'content_visibility',
1976 'type' => 'checkbox-select',
1977 'label' => __( 'Restrict Access to', 'betterdocs' ),
1978 'label_subtitle' => __( 'Only selected User Roles will be able to view your Knowledge Base', 'betterdocs' ),
1979 'is_pro' => true,
1980 'priority' => 7,
1981 'multiple' => true,
1982 'search' => true,
1983 'default' => array( 'all' ),
1984 'placeholder' => __( 'Select any', 'betterdocs' ),
1985 'options' => $roles_for_ikb,
1986 'rules' => Rules::logicalRule(
1987 array(
1988 Rules::is( 'enable_content_restriction', true ),
1989 Rules::is( 'internal_knowledge_base_type', 'basic' )
1990 ),
1991 'and'
1992 ),
1993 'filterValue' => 'all'
1994 ),
1995 'restrict_template' => array(
1996 'name' => 'restrict_template',
1997 'type' => 'checkbox-select',
1998 'label' => __( 'Restriction on Docs', 'betterdocs' ),
1999 'label_subtitle' => __( 'Selected Docs pages will be restricted', 'betterdocs' ),
2000 'is_pro' => true,
2001 'priority' => 8,
2002 'multiple' => true,
2003 'search' => true,
2004 'default' => array( 'all' ),
2005 'placeholder' => __( 'Select any', 'betterdocs' ),
2006 'options' => $this->get_texanomy(),
2007 'rules' => Rules::logicalRule(
2008 array(
2009 Rules::is( 'enable_content_restriction', true ),
2010 Rules::is( 'internal_knowledge_base_type', 'basic' )
2011 ),
2012 'and'
2013 ),
2014 'filterValue' => 'all'
2015 ),
2016 'restrict_category' => array(
2017 'name' => 'restrict_category',
2018 'type' => 'checkbox-select',
2019 'label' => __( 'Restriction on Docs Categories', 'betterdocs' ),
2020 'label_subtitle' => __( 'Selected Docs categories will be restricted', 'betterdocs' ),
2021 'is_pro' => true,
2022 'priority' => 9,
2023 'multiple' => true,
2024 'search' => true,
2025 'default' => array( 'all' ),
2026 'placeholder' => __( 'Select any', 'betterdocs' ),
2027 'options' => $this->get_terms( 'doc_category' ),
2028 'rules' => Rules::logicalRule(
2029 array(
2030 Rules::is( 'enable_content_restriction', true ),
2031 Rules::is( 'internal_knowledge_base_type', 'basic' )
2032 ),
2033 'and'
2034 ),
2035 'filterValue' => 'all'
2036 ),
2037 'restricted_redirect_url' => array(
2038 'name' => 'restricted_redirect_url',
2039 'type' => 'text',
2040 'label' => __( 'Redirect URL', 'betterdocs' ),
2041 'label_subtitle' => __( 'Set a custom URL to redirect users without permissions when they try to access internal knowledge base. By default, restricted content will redirect to the "404 not found" page', 'betterdocs' ),
2042 'default' => '',
2043 'placeholder' => 'https://',
2044 'is_pro' => true,
2045 'priority' => 20,
2046 'rules' => Rules::logicalRule(
2047 array(
2048 Rules::is( 'enable_content_restriction', true )
2049 ),
2050 'and'
2051 )
2052 )
2053 ) )
2054 )
2055 )
2056 )
2057 )
2058 )
2059 )
2060 ) ),
2061 'tab-email-reporting' => apply_filters( 'betterdocs_settings_tab_email_reporting', array(
2062 'id' => 'tab-email-reporting',
2063 'label' => __( 'Email Reporting', 'betterdocs' ),
2064 'priority' => 60,
2065 'fields' => array(
2066 'title-email-reporting' => array(
2067 'name' => 'title-email-reporting-tab',
2068 'type' => 'section',
2069 'label' => __( 'Email Reporting', 'betterdocs' ),
2070 'priority' => 60,
2071 'fields' => array(
2072 'enable_reporting' => array(
2073 'name' => 'enable_reporting',
2074 'label' => __( 'Email Reporting', 'betterdocs' ),
2075 'enable_disable_text_active' => true,
2076 'type' => 'toggle',
2077 'priority' => 1,
2078 'default' => 0
2079 ),
2080 'reporting_frequency' => apply_filters( 'betterdocs_reporting_frequency_settings', array(
2081 'name' => 'reporting_frequency',
2082 'type' => 'select',
2083 'label' => __( 'Reporting Frequency', 'betterdocs' ),
2084 'default' => 'betterdocs_weekly',
2085 'priority' => 2,
2086 'is_pro' => true,
2087 'options' => $this->normalize_options( array(
2088 'betterdocs_daily' => __( 'Once Daily', 'betterdocs' ),
2089 'betterdocs_weekly' => __( 'Once Weekly', 'betterdocs' ),
2090 'betterdocs_monthly' => __( 'Once Monthly', 'betterdocs' )
2091 ) ),
2092 'rules' => Rules::is( 'enable_reporting', true )
2093 ) ),
2094 'reporting_day' => array(
2095 'name' => 'reporting_day',
2096 'type' => 'select',
2097 'label' => __( 'Reporting Day', 'betterdocs' ),
2098 'default' => 'monday',
2099 'rules' => Rules::logicalRule( array(
2100 Rules::is( 'enable_reporting', true ),
2101 Rules::is( 'reporting_frequency', 'betterdocs_weekly' )
2102 ), 'and' ),
2103 'priority' => 3,
2104 'options' => $this->normalize_options( array(
2105 'sunday' => __( 'Sunday', 'betterdocs' ),
2106 'monday' => __( 'Monday', 'betterdocs' ),
2107 'tuesday' => __( 'Tuesday', 'betterdocs' ),
2108 'wednesday' => __( 'Wednesday', 'betterdocs' ),
2109 'thursday' => __( 'Thursday', 'betterdocs' ),
2110 'friday' => __( 'Friday', 'betterdocs' ),
2111 'saturday' => __( 'Saturday', 'betterdocs' )
2112 ) ),
2113 'label_subtitle' => __( 'This is only applicable for the “Weekly” report', 'betterdocs' )
2114 ),
2115 'select_reporting_data' => apply_filters( 'betterdocs_select_reporting_data_settings', array(
2116 'name' => 'select_reporting_data',
2117 'type' => 'checkbox-select',
2118 'label' => __( 'Select Reporting Data', 'betterdocs' ),
2119 'priority' => 4,
2120 'multiple' => true,
2121 'options' => $this->normalize_options( array(
2122 'overview' => 'Overview',
2123 'top-docs' => 'Top Docs',
2124 'most-search' => 'Most Searched Keywords'
2125 ) ),
2126 'default' => array( 'overview', 'top-docs', 'most-search' ),
2127 'is_pro' => true,
2128 'rules' => Rules::is( 'enable_reporting', true )
2129 ) ),
2130 'reporting_email' => array(
2131 'name' => 'reporting_email',
2132 'type' => 'text',
2133 'label' => __( 'Reporting Email', 'betterdocs' ),
2134 'default' => get_option( 'admin_email' ),
2135 'priority' => 5,
2136 'rules' => Rules::is( 'enable_reporting', true )
2137 ),
2138 'reporting_subject' => apply_filters( 'betterdocs_reporting_subject_settings', array(
2139 'name' => 'reporting_subject',
2140 'type' => 'textarea',
2141 'label' => __( 'Reporting Email Subject', 'betterdocs' ),
2142 'default' => wp_sprintf( // Translators: %s is replaced with the website name.
2143 __( 'Your Documentation Performance of %s Website', 'betterdocs' ), get_bloginfo( 'name' ) ),
2144 'priority' => 6,
2145 'is_pro' => true,
2146 'rules' => Rules::is( 'enable_reporting', true )
2147 ) ),
2148 'test_report' => array(
2149 'name' => 'test_report',
2150 'label' => __( 'Reporting Test', 'betterdocs' ),
2151 'text' => __( 'Test Report', 'betterdocs' ),
2152 'type' => 'button',
2153 'priority' => 7,
2154 'rules' => Rules::is( 'enable_reporting', true ),
2155 'ajax' => array(
2156 'on' => 'click',
2157 'api' => '/betterdocs/v1/reporting-test',
2158 'data' => array(
2159 'enable_reporting' => '@enable_reporting',
2160 'select_reporting_data' => '@select_reporting_data',
2161 'reporting_subject' => '@reporting_subject',
2162 'reporting_email' => '@reporting_email',
2163 'reporting_day' => '@reporting_day',
2164 'reporting_frequency' => '@reporting_frequency'
2165 ),
2166 'swal' => array(
2167 'text' => __( 'Successfully Sent a Test Report in Your Email.', 'betterdocs' ),
2168 'icon' => 'success',
2169 'autoClose' => 2000
2170 )
2171 )
2172 )
2173 )
2174 )
2175 )
2176 ) ),
2177 'tab-git-sync' => apply_filters( 'betterdocs_settings_tab_github_integration', array(
2178 'id' => 'tab-git-sync',
2179 'label' => __( 'Git Sync', 'betterdocs' ),
2180 'priority' => 60,
2181 'fields' => array(
2182 'title-git-sync' => array(
2183 'name' => 'title-git-sync-tab',
2184 'type' => 'section',
2185 'label' => __( 'Git Sync Settings', 'betterdocs' ),
2186 'priority' => 60,
2187 'fields' => array(
2188 'enable_git_integration' => array(
2189 'name' => 'enable_git_integration',
2190 'type' => 'toggle',
2191 'label' => __( 'Enable Git Sync', 'betterdocs' ),
2192 'enable_disable_text_active' => true,
2193 'default' => false,
2194 'priority' => 1,
2195 'is_pro' => true,
2196 'label_subtitle' => __( 'Enable bidirectional synchronization between BetterDocs and Git repositories', 'betterdocs' )
2197 )
2198 )
2199 )
2200 )
2201 ) ),
2202 'tab-instant-answer' => apply_filters( 'betterdocs_settings_tab_instant_answer', array(
2203 'id' => 'tab-instant-answer',
2204 'name' => 'tab-instant-answer',
2205 'type' => 'section',
2206 'label' => __( 'Instant Answer', 'betterdocs' ),
2207 'save' => false,
2208 'priority' => 70,
2209 'fields' => array(
2210 'title-instant-answer' => array(
2211 'name' => 'title-instant-answer-tab',
2212 'type' => 'section',
2213 'label' => __( 'Instant Answer', 'betterdocs' ),
2214 'priority' => 80,
2215 'save' => false,
2216 'showSubmit' => false,
2217 'fields' => apply_filters( 'betterdocs_instant_answer_fields', array(
2218 'enable_disable_wrapper' => array(
2219 'name' => 'enable_disable_wrapper',
2220 'type' => 'section',
2221 'priority' => 0,
2222 'save' => false,
2223 'fields' => array(
2224 'enable_disable' => array(
2225 'name' => 'enable_disable',
2226 'type' => 'toggle',
2227 'priority' => 100,
2228 'description' => __( 'Enable Instant Answer', 'betterdocs' ),
2229 'enable_disable_text_active' => false,
2230 'default' => false,
2231 'is_pro' => true
2232 )
2233 )
2234 )
2235 ) )
2236 )
2237 )
2238 ) ),
2239 'tab-betterdocs-ai' => array(
2240 'id' => 'tab-betterdocs-ai',
2241 'name' => 'tab-betterdocs-ai',
2242 'type' => 'section',
2243 'label' => __( 'AI Content Suite', 'betterdocs' ),
2244 'priority' => 74,
2245 'fields' => array(
2246 'sections-betterdocs-ai' => array(
2247 'name' => 'sections-betterdocs-ai',
2248 'type' => 'section',
2249 'label' => __( 'AI Content Suite', 'betterdocs' ),
2250 'priority' => 10,
2251 'fields' => array(
2252 'all-betterdocs-ai' => array(
2253 'id' => 'all-tab-betterdocs-ai',
2254 'name' => 'all-tab-betterdocs-ai',
2255 'label' => __( 'AI Content Suite Settings', 'betterdocs' ),
2256 'classes' => 'tab-layout',
2257 'type' => 'tab',
2258 'active' => 'open-ai-settings',
2259 'completionTrack' => true,
2260 'sidebar' => false,
2261 'save' => false,
2262 'title' => false,
2263 'config' => array(
2264 'active' => 'open-ai-settings',
2265 'sidebar' => false,
2266 'title' => false
2267 ),
2268 'submit' => array(
2269 'show' => false
2270 ),
2271 'step' => array(
2272 'show' => false
2273 ),
2274 'priority' => 20,
2275 'fields' => apply_filters(
2276 'betterdocs_migration_tab_sections',
2277 array(
2278 'open-ai-settings' => array(
2279 'id' => 'open-ai-settings',
2280 'name' => 'open-ai-settings',
2281 'type' => 'section',
2282 'label' => __( 'API Settings', 'betterdocs' ),
2283 'priority' => 1,
2284 'fields' => array(
2285 'ai_autowrite_api_key' => array(
2286 'name' => 'ai_autowrite_api_key',
2287 'type' => 'text',
2288 'label' => __( 'API Key', 'betterdocs' ),
2289 'label_subtitle' => sprintf( /* translators: %s is a link to the documentation about generating an OpenAI API key. */__( 'Check out this <a target="_blank" href="%s">documentation</a> to find out how to generate your OpenAI API Key.', 'betterdocs' ), esc_url( 'https://betterdocs.co/docs/write-with-ai/' ) ),
2290 'default' => '',
2291 'priority' => 1
2292 )
2293 )
2294 ),
2295 'write-with-ai' => array(
2296 'id' => 'write-with-ai',
2297 'name' => 'write-with-ai',
2298 'type' => 'section',
2299 'label' => __( 'Write with AI', 'betterdocs' ),
2300 'priority' => 5,
2301 'fields' => array(
2302 'enable_write_with_ai' => array(
2303 'name' => 'enable_write_with_ai',
2304 'type' => 'toggle',
2305 'priority' => 0,
2306 'label' => __( 'Write Docs with AI', 'betterdocs' ),
2307 'label_subtitle' => __( 'Generate AI based Documentation in your Gutenberg Editor', 'betterdocs' ),
2308 'enable_disable_text_active' => true,
2309 'default' => true
2310 ),
2311 'enable_faq_write_with_ai' => array(
2312 'name' => 'enable_faq_write_with_ai',
2313 'type' => 'toggle',
2314 'priority' => 5,
2315 'label' => __( 'Write FAQ with AI', 'betterdocs' ),
2316 'label_subtitle' => __( 'Generate AI based FAQ in your Editor', 'betterdocs' ),
2317 'enable_disable_text_active' => true,
2318 'default' => true
2319 ),
2320 'enable_glossaries_write_with_ai' => array(
2321 'name' => 'enable_glossaries_write_with_ai',
2322 'type' => 'toggle',
2323 'priority' => 6,
2324 'label' => __( 'Write Glossaries with AI', 'betterdocs' ),
2325 'label_subtitle' => __( 'Generate AI based Glossary definitions from the Glossaries admin page', 'betterdocs' ),
2326 'enable_disable_text_active' => true,
2327 'default' => true
2328 ),
2329 'write_with_ai_model' => array(
2330 'name' => 'write_with_ai_model',
2331 'type' => 'select',
2332 'label' => __( 'OpenAI Model*', 'betterdocs' ),
2333 'priority' => 20,
2334 'multiple' => false,
2335 'default' => 'gpt-4o-mini',
2336 'options' => GlobalFields::normalize_fields( array(
2337 'gpt-4o-mini' => 'GPT-4o Mini',
2338 'gpt-4o' => 'GPT-4o',
2339 'gpt-4.1-nano' => 'GPT-4.1 Nano',
2340 'gpt-4.1-mini' => 'GPT-4.1 Mini',
2341 'gpt-4.1' => 'GPT-4.1',
2342 'gpt-5-nano' => 'GPT-5 Nano',
2343 'gpt-5-mini' => 'GPT-5 Mini',
2344 'gpt-5' => 'GPT-5',
2345 'gpt-5.5' => 'GPT-5.5'
2346 ) )
2347 ),
2348 'ai_autowrite_max_token' => array(
2349 'name' => 'ai_autowrite_max_token',
2350 'type' => 'min_token_number',
2351 'label' => __( 'Set Max Tokens', 'betterdocs' ),
2352 'label_subtitle' => sprintf( // translators: %s is a link to more information about token limits.
2353 __( 'Documentation will be generated based on the Token Limits you have set. For more information on Token Limits, you can check out this <a target="_blank" href="%s">link</a>.', 'betterdocs' ), esc_url( 'https://platform.openai.com/account/limits' ) ),
2354 'default' => 2500,
2355 'priority' => 10,
2356 'model_field' => 'write_with_ai_model',
2357 'context' => 'write_with_ai',
2358 'min_token_map' => AIHelper::get_min_tokens_map( 'write_with_ai' ),
2359 'classes' => 'wprf-type-text'
2360 )
2361 )
2362 ),
2363 'article-summary' => array(
2364 'id' => 'article-summary',
2365 'name' => 'article-summary',
2366 'type' => 'section',
2367 'label' => __( 'AI Doc Summarizer', 'betterdocs' ),
2368 'priority' => 10,
2369 'fields' => array(
2370 'enable_article_summary' => array(
2371 'name' => 'enable_article_summary',
2372 'type' => 'toggle',
2373 'priority' => 1,
2374 'label' => __( 'AI Powered Doc Summarizer', 'betterdocs' ),
2375 'label_subtitle' => __( 'Enable AI-powered article summaries on single doc pages. Requires OpenAI API key.', 'betterdocs' ),
2376 'enable_disable_text_active' => true,
2377 'default' => false
2378 ),
2379 'article_summary_max_token' => array(
2380 'name' => 'article_summary_max_token',
2381 'type' => 'min_token_number',
2382 'label' => __( 'Set Max Tokens', 'betterdocs' ),
2383 'label_subtitle' => sprintf( // translators: %s is a link to more information about token limits.
2384 __( 'Single Doc summarizer will be generated based on the token limits you have set. For more information on Token Limits, you can check out this <a target="_blank" href="%s">link</a>.', 'betterdocs' ), esc_url( 'https://platform.openai.com/account/limits' ) ),
2385 'default' => 1500,
2386 'priority' => 5,
2387 'model_field' => 'article_summary_model',
2388 'context' => 'article_summary',
2389 'min_token_map' => AIHelper::get_min_tokens_map( 'article_summary' ),
2390 'classes' => 'wprf-type-text'
2391 ),
2392 'article_summary_model' => array(
2393 'name' => 'article_summary_model',
2394 'type' => 'select',
2395 'label' => __( 'OpenAI Model*', 'betterdocs' ),
2396 'priority' => 10,
2397 'multiple' => false,
2398 'default' => 'gpt-4o-mini',
2399 'options' => GlobalFields::normalize_fields( array(
2400 'gpt-4o-mini' => 'GPT-4o Mini',
2401 'gpt-4o' => 'GPT-4o',
2402 'gpt-4.1-nano' => 'GPT-4.1 Nano',
2403 'gpt-4.1-mini' => 'GPT-4.1 Mini',
2404 'gpt-4.1' => 'GPT-4.1',
2405 'gpt-5-nano' => 'GPT-5 Nano',
2406 'gpt-5-mini' => 'GPT-5 Mini',
2407 'gpt-5' => 'GPT-5',
2408 'gpt-5.5' => 'GPT-5.5'
2409 ) )
2410 )
2411 )
2412 )
2413 )
2414 )
2415 )
2416 )
2417 )
2418 )
2419 ),
2420 'tab-ai-chatbot' => apply_filters( 'betterdocs_settings_tab_ai_chatbot', array(
2421 'id' => 'tab-ai-chatbot',
2422 'name' => 'tab-ai-chatbot',
2423 'type' => 'section',
2424 'label' => __( 'AI Chatbot', 'betterdocs' ),
2425 'submit' => array(
2426 'show' => false
2427 ),
2428 'save' => false,
2429 'priority' => 75,
2430 'fields' => array(
2431 'title-ai-chatbot-tab' => array(
2432 'name' => 'title-ai-chatbot-tab',
2433 'type' => 'section',
2434 'label' => __( 'AI Chatbot', 'betterdocs' ),
2435 'priority' => 80,
2436 'submit' => array(
2437 'show' => false
2438 ),
2439 'save' => false,
2440 'fields' => apply_filters( 'betterdocs_ai_chatbot_fields', array(
2441 'ai_chatbot_fields' => array(
2442 'name' => 'ai_chatbot_fields',
2443 'type' => 'section',
2444 'priority' => 0,
2445 'fields' => array(
2446 'enable_ai_chatbot' => array(
2447 'name' => 'enable_ai_chatbot',
2448 'label' => __( 'AI Chatbot', 'betterdocs' ),
2449 'description' => __( 'Enable AI Chatbot', 'betterdocs' ),
2450 'type' => 'toggle',
2451 'priority' => 5,
2452 'default' => 0,
2453 'is_pro' => true,
2454 'is_license_active' => false,
2455 'disabled' => ! betterdocs()->is_pro_active() || ! defined( 'BETTERDOCS_CHATBOT_FILE' )
2456 ),
2457 'instant_answer_warning' => array(
2458 'name' => 'instant_answer_warning',
2459 'type' => 'html',
2460 'priority' => 6,
2461 'html' => sprintf(
2462 '<div class="betterdocs-ia-warning" style="margin:8px 0 0;padding:12px 16px;background:#fffaeb;border-left:4px solid #fdb022;border-radius:4px;display:flex;align-items:flex-start;gap:10px;"><span style="font-size:18px;line-height:1;flex-shrink:0;color:#b54708;">&#9888;</span><div style="font-size:13px;color:#202223;line-height:1.5;">%1$s<br><a href="?page=betterdocs-settings&amp;tab=tab-instant-answer" style="display:inline-block;margin-top:6px;color:#5a6bff;text-decoration:none;font-weight:500;">%2$s &rarr;</a></div></div>',
2463 esc_html__( 'Instant Answer is currently disabled. The AI Chatbot won\'t appear on your site until Instant Answer is enabled.', 'betterdocs' ),
2464 esc_html__( 'Enable Instant Answer', 'betterdocs' )
2465 ),
2466 'rules' => Rules::logicalRule( array(
2467 Rules::is( 'enable_ai_chatbot', true ),
2468 Rules::is( 'enable_disable', false ),
2469 ), 'and' ),
2470 )
2471 )
2472 )
2473 ) )
2474 )
2475 )
2476 ) )
2477 ) ),
2478 'TAB_AI_CHATBOT' => get_option( 'enable_ai_chatbot' ),
2479 'CHATBOT_LICENSE' => get_option( 'betterdocs_chatbot_software__license_status' ),
2480 'PRO_ACTIVE' => is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ),
2481 'PRO_LICENSE' => get_option( 'betterdocs_pro_software__license_status' )
2482 );
2483
2484 $settings = array_merge( $settings, $this->chatbot_active_localize() );
2485
2486 return apply_filters( 'betterdocs_settings_args', $settings );
2487 }
2488
2489 /**
2490 * @return array
2491 */
2492 public function chatbot_active_localize() {
2493 $chatbot_active = is_plugin_active( 'betterdocs-ai-chatbot/betterdocs-ai-chatbot.php' );
2494 $chatbot_license_valid = get_option( 'betterdocs_chatbot_software__license_status' ) === 'valid';
2495 $chatbot_enabled = $this->get( 'enable_ai_chatbot', false );
2496
2497 // AI Search Suggestions are enabled if all conditions are met
2498 $ai_search_suggestions_enabled = betterdocs()->helper->is_ai_chatbot_enabled();
2499
2500 return array(
2501 'CHATBOT_ACTIVE' => $chatbot_active,
2502 'CHATBOT_LICENSE_VALID' => $chatbot_license_valid,
2503 'CHATBOT_ENABLED' => $chatbot_enabled,
2504 'AI_SEARCH_SUGGESTIONS_ENABLED' => $ai_search_suggestions_enabled
2505 );
2506 }
2507
2508 /**
2509 * Call This Function As Helper, When Pro Is Deactivated, To Be Used As Settings Default Values, When Betterdocs Pro Is Deactivated
2510 *
2511 * @return array
2512 */
2513 public function pro_settings_default_values() {
2514 return array(
2515 'multiple_kb' => false,
2516 'enable_glossaries' => false,
2517 'enable_encyclopedia' => false,
2518 'analytics_from' => false,
2519 'unique_visitor_count' => false,
2520 'exclude_bot_analytics' => false,
2521 'show_attachment' => false,
2522 'show_related_docs' => false,
2523 'advance_search' => false,
2524 'child_category_exclude' => false,
2525 'kb_based_search' => false,
2526 'enable_disable' => false,
2527 'enable_content_restriction' => false
2528 );
2529 }
2530
2531 public function import_export_settings( $settings ) {
2532 if ( ! current_user_can( 'import' ) ) {
2533 return $settings;
2534 }
2535
2536 $settings[ 'tab-import-export' ] = apply_filters( 'betterdocs_settings_tab_import_export', array(
2537 'id' => 'tab-import-export',
2538 'name' => 'tab-import-export',
2539 'classes' => 'tab-import-export',
2540 'label' => __( 'Import / Export', 'betterdocs' ),
2541 'priority' => 80,
2542 'fields' => array(
2543 'sections-import-export' => array(
2544 'name' => 'sections-import-export',
2545 'type' => 'section',
2546 'label' => __( 'Import / Export', 'betterdocs' ),
2547 'priority' => 30,
2548 'fields' => array(
2549 'all-tab-import-export' => array(
2550 'id' => 'all-tab-import-export',
2551 'name' => 'all-tab-import-export',
2552 'label' => __( 'Import Export Settings', 'betterdocs' ),
2553 'classes' => 'tab-layout',
2554 'type' => 'tab',
2555 'active' => 'import',
2556 'completionTrack' => true,
2557 'sidebar' => false,
2558 'save' => false,
2559 'title' => false,
2560 'config' => array(
2561 'active' => 'import',
2562 'sidebar' => false,
2563 'title' => false
2564 ),
2565 'submit' => array(
2566 'show' => false
2567 ),
2568 'step' => array(
2569 'show' => false
2570 ),
2571 'priority' => 20,
2572 'fields' => array(
2573 'import' => array(
2574 'id' => 'import',
2575 'name' => 'import',
2576 'type' => 'section',
2577 'label' => __( 'Import', 'betterdocs' ),
2578 'priority' => 1,
2579 'fields' => array(
2580 'import_tab_nested' => array(
2581 'id' => 'import_tab_nested',
2582 'name' => 'import_tab_nested',
2583 'label' => __( 'Import', 'betterdocs' ),
2584 'classes' => 'tab-nested-layout',
2585 'type' => 'tab',
2586 'active' => 'import_docs_nested',
2587 'completionTrack' => true,
2588 'sidebar' => false,
2589 'save' => false,
2590 'title' => false,
2591 'config' => array(
2592 'active' => 'import_docs_nested',
2593 'sidebar' => false,
2594 'title' => false
2595 ),
2596 'submit' => array(
2597 'show' => false
2598 ),
2599 'step' => array(
2600 'show' => false
2601 ),
2602 'priority' => 1,
2603 'fields' => array(
2604 'import_docs_nested' => array(
2605 'id' => 'import_docs_nested',
2606 'name' => 'import_docs_nested',
2607 'type' => 'section',
2608 'label' => __( 'Import Docs', 'betterdocs' ),
2609 'priority' => 1,
2610 'fields' => array(
2611 'import_docs' => array(
2612 'name' => 'import_docs',
2613 'type' => 'importerupload',
2614 'label' => __( 'Import Docs', 'betterdocs' ),
2615 'label_subtitle' => wp_sprintf( // Translators: %1$s is a link to download a sample CSV file.
2616 __( 'To import your Docs, please upload the .xml / .csv file here. <a href="%1$s">Download sample csv file</a>', 'betterdocs' ), betterdocs()->assets->icon( 'BetterDocs-sample-data.csv', true ) ),
2617 'text' => array(
2618 'normal' => __( 'Proceed', 'betterdocs' ),
2619 'saved' => __( 'Proceed', 'betterdocs' ),
2620 'loading' => __( 'Importing...', 'betterdocs' ),
2621 'exists_notice' => __( 'It seems like documentations with same slugs already exist on your website. What would you like to do?', 'betterdocs' )
2622 ),
2623 'ajax' => array(
2624 'on' => 'click',
2625 'api' => '/betterdocs/v1/import-docs',
2626 'swal' => array(
2627 'text' => __( 'Import completed successfully.', 'betterdocs' ),
2628 'icon' => 'success',
2629 'autoClose' => 2000
2630 )
2631 ),
2632 'file_type' => '.xml, .csv',
2633 'priority' => 1
2634 )
2635 )
2636 ),
2637
2638 'import_settings_nested' => array(
2639 'id' => 'import_settings_nested',
2640 'name' => 'import_settings_nested',
2641 'type' => 'section',
2642 'label' => __( 'Import Settings', 'betterdocs' ),
2643 'priority' => 1,
2644 'fields' => array(
2645 'settings_importer' => array(
2646 'name' => 'settings_importer',
2647 'type' => 'settingsuploader',
2648 'label' => __( 'Import Settings', 'betterdocs' ),
2649 'label_subtitle' => __( 'To import BetterDocs Settings, please upload BetterDocs settings you have exported from another website in .json format', 'betterdocs' ),
2650 'reset' => __( 'Change', 'betterdocs' ),
2651 'priority' => 1
2652 ),
2653 'import_settings' => array(
2654 'name' => 'import_settings',
2655 'type' => 'button',
2656 'rules' => Rules::is( 'settings_importer', null, true ),
2657 'text' => array(
2658 'normal' => __( 'Proceed', 'betterdocs' ),
2659 'saved' => __( 'Proceed', 'betterdocs' ),
2660 'loading' => __( 'Importing...', 'betterdocs' )
2661 ),
2662 'ajax' => array(
2663 'on' => 'click',
2664 'api' => '/betterdocs/v1/import-settings',
2665 'data' => array(
2666 'settings' => '@settings_importer'
2667 ),
2668 'swal' => array(
2669 'text' => __( 'Import completed successfully.', 'betterdocs' ),
2670 'icon' => 'success',
2671 'autoClose' => 1000
2672 ),
2673 'reload' => true
2674 ),
2675 'priority' => 2
2676 )
2677 )
2678 )
2679 )
2680 )
2681 )
2682 ),
2683 'export' => array(
2684 'id' => 'export',
2685 'name' => 'export',
2686 'type' => 'section',
2687 'label' => __( 'Export', 'betterdocs' ),
2688 'priority' => 1,
2689 'fields' => array(
2690 'export_tab_nested' => array(
2691 'id' => 'export_tab_nested',
2692 'name' => 'export_tab_nested',
2693 'label' => __( 'Export', 'betterdocs' ),
2694 'classes' => 'tab-nested-layout',
2695 'type' => 'tab',
2696 'active' => 'export_docs_nested',
2697 'completionTrack' => true,
2698 'sidebar' => false,
2699 'save' => false,
2700 'title' => false,
2701 'config' => array(
2702 'active' => 'export_docs_nested',
2703 'sidebar' => false,
2704 'title' => false
2705 ),
2706 'submit' => array(
2707 'show' => false
2708 ),
2709 'step' => array(
2710 'show' => false
2711 ),
2712 'priority' => 1,
2713 'fields' => array(
2714 'export_docs_nested' => array(
2715 'id' => 'export_docs_nested',
2716 'name' => 'export_docs_nested',
2717 'type' => 'section',
2718 'label' => __( 'Export Docs', 'betterdocs' ),
2719 'priority' => 1,
2720 'fields' => apply_filters( 'betterdocs_export_fields', array(
2721 'export_type' => array(
2722 'name' => 'export_type',
2723 'label' => __( 'Select Docs Type', 'betterdocs' ),
2724 'label_subtitle' => __( 'Choose an export type: All Docs, a specific Knowledge Base, or a Doc Category', 'betterdocs' ),
2725 'type' => 'select',
2726 'default' => 'docs',
2727 'priority' => 3,
2728 'search' => true,
2729 'options' => $this->normalize_options( apply_filters( 'betterdocs_export_type_options', array(
2730 'docs' => __( 'Docs', 'betterdocs' ),
2731 'doc_category' => __( 'Docs Category', 'betterdocs' ),
2732 'glossaries' => __( 'Glossaries', 'betterdocs' )
2733 ) ) )
2734 ),
2735 'export_docs' => array(
2736 'name' => 'export_docs',
2737 'type' => 'checkbox-select',
2738 'label' => __( 'Select Docs', 'betterdocs' ),
2739 'label_subtitle' => __( 'Selected docs will be included in the export.', 'betterdocs' ),
2740 'priority' => 4,
2741 'multiple' => true,
2742 'search' => true,
2743 'default' => array( 'all' ),
2744 'placeholder' => __( 'Select any', 'betterdocs' ),
2745 'options' => array_merge( array(
2746 array(
2747 'value' => 'all',
2748 'label' => 'All'
2749 )
2750 ), $this->docs() ),
2751 'filterValue' => 'all',
2752 'rules' => Rules::is( 'export_type', 'docs' )
2753 ),
2754 'export_categories' => array(
2755 'name' => 'export_categories',
2756 'type' => 'checkbox-select',
2757 'label' => __( 'Select Categories', 'betterdocs' ),
2758 'label_subtitle' => __( 'Selected categories and its docs will be included in the export.', 'betterdocs' ),
2759 'priority' => 6,
2760 'multiple' => true,
2761 'search' => true,
2762 'default' => array( 'all' ),
2763 'placeholder' => __( 'Select any', 'betterdocs' ),
2764 'options' => $this->get_terms( 'doc_category', false ),
2765 'filterValue' => 'all',
2766 'rules' => Rules::is( 'export_type', 'doc_category' )
2767 ),
2768 'export_glossaries' => array(
2769 'name' => 'export_glossaries',
2770 'type' => 'checkbox-select',
2771 'label' => __( 'Select Glossaries', 'betterdocs' ),
2772 'label_subtitle' => __( 'Selected glossary terms will be exported.', 'betterdocs' ),
2773 'priority' => 7,
2774 'multiple' => true,
2775 'search' => true,
2776 'default' => array( 'all' ),
2777 'placeholder' => __( 'Select any', 'betterdocs' ),
2778 'options' => $this->get_terms( 'glossaries' ),
2779 'filterValue' => 'all',
2780 'rules' => Rules::is( 'export_type', 'glossaries' )
2781 ),
2782 'file_type' => array(
2783 'name' => 'file_type',
2784 'label' => __( 'Select File Type', 'betterdocs' ),
2785 'label_subtitle' => __( 'Choose a file type', 'betterdocs' ),
2786 'type' => 'select',
2787 'default' => 'xml',
2788 'priority' => 8,
2789 'search' => true,
2790 'options' => $this->normalize_options( apply_filters( 'betterdocs_export_file_type_options', array(
2791 'xml' => __( '.xml', 'betterdocs' ),
2792 'csv' => __( '.csv', 'betterdocs' )
2793 ) ) )
2794 ),
2795 'enable_export_faq' => array(
2796 'name' => 'enable_export_faq',
2797 'type' => 'toggle',
2798 'priority' => 9,
2799 'label' => __( 'Export FAQ', 'betterdocs' ),
2800 'label_subtitle' => __( 'Export FAQ Related Terms & Posts', 'betterdocs' ),
2801 'enable_disable_text_active' => true,
2802 'default' => true,
2803 'rules' => Rules::is( 'export_type', 'glossaries', true )
2804 ),
2805 'export_docs_btn' => array(
2806 'name' => 'export_docs_btn',
2807 'text' => array(
2808 'normal' => __( 'Proceed', 'betterdocs' ),
2809 'saved' => __( 'Proceed', 'betterdocs' ),
2810 'loading' => __( 'Exporting...', 'betterdocs' )
2811 ),
2812 'type' => 'button',
2813 'priority' => 10,
2814 'ajax' => array(
2815 'on' => 'click',
2816 'api' => '/betterdocs/v1/export-docs',
2817 'data' => array(
2818 'export_type' => '@export_type',
2819 'export_docs' => '@export_docs',
2820 'export_kbs' => '@export_kbs',
2821 'export_categories' => '@export_categories',
2822 'export_glossaries' => '@export_glossaries',
2823 'file_type' => '@file_type',
2824 'enable_export_faq' => '@enable_export_faq'
2825 ),
2826 'swal' => array(
2827 'text' => __( 'Exported Successfully.', 'betterdocs' ),
2828 'icon' => 'success',
2829 'autoClose' => 2000
2830 )
2831 )
2832 )
2833 ) )
2834 ),
2835
2836 'export_settings_nested' => array(
2837 'id' => 'export_settings_nested',
2838 'name' => 'export_settings_nested',
2839 'type' => 'section',
2840 'label' => __( 'Export Settings', 'betterdocs' ),
2841 'priority' => 1,
2842 'fields' => array(
2843 'export_settings' => array(
2844 'name' => 'export_settings',
2845 'label' => __( 'Export Settings', 'betterdocs' ),
2846 'label_subtitle' => __( 'Simply click on “Export Settings” button to download your BetterDocs settings in .json format', 'betterdocs' ),
2847 'text' => array(
2848 'normal' => __( 'Export Settings', 'betterdocs' ),
2849 'saved' => __( 'Export Settings', 'betterdocs' ),
2850 'loading' => __( 'Exporting...', 'betterdocs' )
2851 ),
2852 'type' => 'button',
2853 'priority' => 8,
2854 'ajax' => array(
2855 'on' => 'click',
2856 'api' => '/betterdocs/v1/export-settings',
2857 'data' => array(
2858 'betterdocs_settings' => get_option( 'betterdocs_settings' )
2859 ),
2860 'swal' => array(
2861 'text' => __( 'File downloaded successfully.', 'betterdocs' ),
2862 'icon' => 'success',
2863 'autoClose' => 2000
2864 )
2865 )
2866 )
2867 )
2868 )
2869 )
2870 )
2871 )
2872 )
2873 )
2874 )
2875 )
2876 )
2877 )
2878 ) );
2879
2880 return $settings;
2881 }
2882
2883 public function maybe_remove_git_tab( $tabs ) {
2884 $pro_active = is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' );
2885 $pro_has_git = apply_filters( 'betterdocs_pro_has_git_integration', false );
2886
2887 if ( $pro_active && ! $pro_has_git ) {
2888 unset( $tabs[ 'tab-git-sync' ] );
2889 }
2890
2891 return $tabs;
2892 }
2893
2894 public function normalize_options( $options ) {
2895 return GlobalFields::normalize_fields( $options );
2896 }
2897
2898 public function get_texanomy() {
2899 $docs_tax = $this->database->get_cache( 'betterdocs::settings::taxonomies' );
2900
2901 if ( $docs_tax ) {
2902 return $docs_tax;
2903 }
2904
2905 $taxonomies = get_taxonomies( array(
2906 'object_type' => array( 'docs' )
2907 ), 'objects' );
2908
2909 $docs_tax = array(
2910 'all' => 'All Docs Archive',
2911 'docs' => 'Docs Page'
2912 );
2913 foreach ( $taxonomies as $key => $value ) {
2914 $docs_tax[ $key ] = $value->label;
2915 }
2916 unset( $docs_tax[ 'doc_tag' ] );
2917
2918 $docs_tax = $this->normalize_options( $docs_tax );
2919 if ( count( $docs_tax ) > 2 ) {
2920 $this->database->set_cache( 'betterdocs::settings::taxonomies', $docs_tax );
2921 }
2922
2923 return $docs_tax;
2924 }
2925
2926 public function get_terms( $taxonomy, $hide_empty = true ) {
2927 $_cache_key = 'betterdocs::settings::terms::' . trim( $taxonomy );
2928 $docs_tax = $this->database->get_cache( $_cache_key );
2929
2930 if ( $docs_tax ) {
2931 return $docs_tax;
2932 }
2933
2934 $get_terms = get_terms( array(
2935 'taxonomy' => $taxonomy,
2936 'hide_empty' => $hide_empty
2937 ) );
2938
2939 $terms = array(
2940 'all' => 'All'
2941 );
2942
2943 if ( ! empty( $get_terms ) && ! is_wp_error( $get_terms ) ) {
2944 foreach ( $get_terms as $value ) {
2945 if ( isset( $value->slug ) && isset( $value->name ) ) {
2946 $terms[ $value->slug ] = $value->name;
2947 }
2948 }
2949 }
2950
2951 $terms = $this->normalize_options( $terms );
2952 if ( count( $terms ) > 1 ) {
2953 $this->database->set_cache( $_cache_key, $terms );
2954 }
2955
2956 return $terms;
2957 }
2958
2959 public function get_terms_with_ids( $taxonomy ) {
2960 $_cache_key = 'betterdocs::settings::terms::ids' . trim( $taxonomy );
2961 $docs_tax = $this->database->get_cache( $_cache_key );
2962
2963 if ( $docs_tax ) {
2964 return $docs_tax;
2965 }
2966
2967 $get_terms = get_terms( array(
2968 'taxonomy' => $taxonomy,
2969 'hide_empty' => false,
2970 'suppress_filter' => true
2971 ) );
2972
2973 $terms = array();
2974
2975 if ( ! empty( $get_terms ) && ! is_wp_error( $get_terms ) ) {
2976 foreach ( $get_terms as $value ) {
2977 if ( isset( $value->term_id ) && isset( $value->name ) ) {
2978 $terms[ $value->term_id ] = $value->name;
2979 }
2980 }
2981 }
2982
2983 $terms = $this->normalize_options( $terms );
2984 if ( count( $terms ) > 1 ) {
2985 $this->database->set_cache( $_cache_key, $terms );
2986 }
2987
2988 return $terms;
2989 }
2990
2991 /**
2992 * Get all docs
2993 */
2994 public function docs() {
2995 $docs = $this->database->get_cache( 'betterdocs::settings::all_docs' );
2996
2997 if ( $docs ) {
2998 return $docs;
2999 }
3000
3001 $docs = array();
3002
3003 $_docs = get_posts( array(
3004 'post_type' => 'docs',
3005 'numberposts' => -1,
3006 'posts_per_page' => -1
3007 ) );
3008
3009 if ( ! empty( $_docs ) ) {
3010 foreach ( $_docs as $doc ) {
3011 $docs[ $doc->ID ] = betterdocs()->template_helper->kses( $doc->post_title );
3012 }
3013 $docs = GlobalFields::normalize_fields( $docs );
3014 $this->database->set_cache( 'betterdocs::settings::all_docs', $docs );
3015 }
3016
3017 return $docs;
3018 }
3019
3020 public function hide_roles_management( $tabData = array() ) {
3021 global $current_user;
3022
3023 if ( $current_user instanceof WP_User && ! in_array( 'administrator', $current_user->roles ) ) {
3024 unset( $tabData[ 'fields' ][ 'title-advance-settings' ][ 'fields' ][ 'article_roles' ] );
3025 unset( $tabData[ 'fields' ][ 'title-advance-settings' ][ 'fields' ][ 'settings_roles' ] );
3026 unset( $tabData[ 'fields' ][ 'title-advance-settings' ][ 'fields' ][ 'analytics_roles' ] );
3027 unset( $tabData[ 'fields' ][ 'title-advance-settings' ][ 'fields' ][ 'faq_roles' ] );
3028 }
3029
3030 return $tabData;
3031 }
3032 }
3033