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

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