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