PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.2.6
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.2.6
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 3.5.0 3.5.1 All 200 releases
← All changes | includes/Core/Admin.php +355 -391 4.5.54.2.6 View file →
@@ -1,12 +1,8 @@
1 1 <?php
2 +
2 3 namespace WPDeveloper\BetterDocs\Core;
3 4
4 -if ( ! defined( 'ABSPATH' ) ) {
5 - exit;
6 -}
7 -
8 -
9 5 use Exception;
10 6 use PriyoMukul\WPNotice\Notices;
11 7 use WPDeveloper\BetterDocs\Admin\NoticePointers;
12 8 use WPDeveloper\BetterDocs\Utils\Base;
@@ -24,9 +20,8 @@
24 20 */
25 21 private static $cache_bank;
26 22 /**
27 23 * Admin Root Menu Slug
28 - *
29 24 * @var string
30 25 */
31 26 private $slug = 'betterdocs-dashboard';
32 27 /**
@@ -58,19 +53,17 @@
58 53 private $kbmigration;
59 54
60 55 /**
61 56 * Enqueue
62 - *
63 57 * @var Enqueue
64 58 */
65 59 private $assets;
66 60
67 61 // modules
68 - protected $installer;
62 + protected $installer;
69 63
70 64 /**
71 65 * FAQBuilder
72 - *
73 66 * @var FAQBuilder
74 67 */
75 68 private $faq_builder;
76 69 private $glossaries;
@@ -81,10 +74,10 @@
81 74 $this->settings = $settings;
82 75 $this->kbmigration = $kbmigration;
83 76 $this->slug = 'betterdocs-dashboard';
84 77
85 - add_action( 'init', array( $type, 'register' ), 9 );
86 - add_action( 'rest_api_init', array( $this, 'order_terms_in_wp_terms_admin_table' ) );
78 + add_action( 'init', [ $type, 'register' ], 9 );
79 + add_action('rest_api_init', [$this, 'order_terms_in_wp_terms_admin_table']);
87 80
88 81 $type->init();
89 82 $type->admin_init();
90 83
@@ -97,47 +90,46 @@
97 90
98 91 $this->installer = new PluginInstaller();
99 92
100 93 $this->plugin_insights();
101 - add_action( 'admin_notices', array( $this, 'compatibility_notices' ) );
94 + add_action( 'admin_notices', [ $this, 'compatibility_notices' ] );
102 95 // add_action( 'admin_init', [$this, 'notices'], 9 );
103 - add_filter( 'admin_init', array( $this, 'save_admin_page' ), 99 );
96 + add_filter( 'admin_init', [ $this, 'save_admin_page' ], 99 );
104 97
105 - add_action( 'admin_menu', array( $this, 'menus' ) );
106 - add_action( 'admin_menu', array( $this, 'reset_submenu' ) );
107 - add_action( 'admin_head', array( $this, 'add_custom_classes_to_menu_items' ) );
108 - add_filter( 'plugin_action_links_' . BETTERDOCS_PLUGIN_BASENAME, array( $this, 'insert_plugin_links' ) );
98 + add_action( 'admin_menu', [ $this, 'menus' ] );
99 + add_action( 'admin_menu', [ $this, 'reset_submenu' ] );
100 + add_action( 'admin_head', [ $this, 'add_custom_classes_to_menu_items' ] );
101 + add_filter( 'plugin_action_links_' . BETTERDOCS_PLUGIN_BASENAME, [ $this, 'insert_plugin_links' ] );
109 102
110 103 // $this->container->get( SetupWizard::class )->init();
111 104
112 - add_action( 'admin_enqueue_scripts', array( $this, 'styles' ) );
113 - add_action( 'admin_enqueue_scripts', array( $this, 'scripts' ) );
114 - // add_action( 'betterdocs_listing_header', [ $this, 'header' ], 10, 1 );
115 - add_action( 'admin_bar_menu', array( $this, 'toolbar_menu' ), 32 );
105 + add_action( 'admin_enqueue_scripts', [ $this, 'styles' ] );
106 + add_action( 'admin_enqueue_scripts', [ $this, 'scripts' ] );
107 + //add_action( 'betterdocs_listing_header', [ $this, 'header' ], 10, 1 );
108 + add_action( 'admin_bar_menu', [ $this, 'toolbar_menu' ], 32 );
116 109
117 - add_filter( 'admin_body_class', array( $this, 'body_classes' ) );
118 - add_filter( 'parent_file', array( $type, 'highlight_admin_menu' ) );
119 - add_filter( 'submenu_file', array( $type, 'highlight_admin_submenu' ), 10, 2 );
120 - add_filter( 'betterdocs_admin_menu', array( $this, 'quick_setup_menu' ), 10, 1 );
110 + add_filter( 'admin_body_class', [ $this, 'body_classes' ] );
111 + add_filter( 'parent_file', [ $type, 'highlight_admin_menu' ] );
112 + add_filter( 'submenu_file', [ $type, 'highlight_admin_submenu' ], 10, 2 );
113 + add_filter( 'betterdocs_admin_menu', [ $this, 'quick_setup_menu' ], 10, 1 );
121 114
122 115 /**
123 116 * Remove Comments Column from List Table.
124 117 */
125 - add_filter( 'manage_docs_posts_columns', array( $this, 'set_custom_edit_action_columns' ) );
126 - add_filter( 'manage_docs_posts_custom_column', array( $this, 'manage_custom_columns' ), 10, 2 );
118 + add_filter( 'manage_docs_posts_columns', [ $this, 'set_custom_edit_action_columns' ] );
119 + add_filter( 'manage_docs_posts_custom_column', [ $this, 'manage_custom_columns' ], 10, 2 );
127 120
128 121 /**
129 122 * Add New Column
130 123 */
131 - add_filter( 'manage_users_columns', array( $this, 'add_users_total_docs_column' ), 10, 1 );
132 - add_filter( 'manage_users_custom_column', array( $this, 'popular_users_docs_data' ), 10, 3 );
124 + add_filter( 'manage_users_columns', [ $this, 'add_users_total_docs_column' ], 10, 1 );
125 + add_filter( 'manage_users_custom_column', [ $this, 'popular_users_docs_data' ], 10, 3 );
133 126 if ( is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ) ) {
134 127 add_action( 'admin_footer-plugins.php', array( $this, 'disable_deactivation' ) );
135 128 }
136 129
137 130 if ( $this->settings->get( 'enable_estimated_reading_time' ) ) {
138 - // Hook into unified metabox instead of creating separate metabox
139 - add_action( 'betterdocs_reading_time_tab_content', array( $this, 'render_estimated_time_markup' ) );
131 + add_action( 'add_meta_boxes', [ $this, 'reading_meta_box_' ], 10 );
140 132 }
141 133
142 134 self::$cache_bank = CacheBank::get_instance();
143 135
@@ -153,23 +145,18 @@
153 145 // Initialize Black Friday Pointer
154 146 $this->init_black_friday_pointer();
155 147
156 148 // Register AJAX handler for pointer dismissal
157 - add_action( 'wp_ajax_betterdocs_dismiss_black_friday_pointer', array( $this, 'ajax_dismiss_black_friday_pointer' ) );
149 + add_action( 'wp_ajax_betterdocs_dismiss_black_friday_pointer', [ $this, 'ajax_dismiss_black_friday_pointer' ] );
158 150 }
159 151
160 152 public function order_terms_in_wp_terms_admin_table() {
161 - // order the terms correctly to be shown on the admin panel categories menu with betterdocs order
162 - add_action(
163 - 'rest_insert_doc_category',
164 - function ( $term, $request, $bool ) {
165 - $max_order = Helper::get_max_doc_category_order_from_term_meta() ?? 0;
166 - $next_order = $max_order + 1;
167 - update_term_meta( $term->term_id, 'doc_category_order', $next_order );
168 - },
169 - 10,
170 - 3
171 - );
153 + //order the terms correctly to be shown on the admin panel categories menu with betterdocs order
154 + add_action('rest_insert_doc_category', function( $term, $request, $bool ) {
155 + $max_order = Helper::get_max_doc_category_order_from_term_meta() ?? 0;
156 + $next_order = $max_order + 1;
157 + update_term_meta( $term->term_id, 'doc_category_order', $next_order );
158 + }, 10, 3);
172 159 }
173 160
174 161 public function disable_deactivation() {
175 162 $tooltip_text = esc_html__( 'Deactivate BetterDocs Pro First', 'betterdocs' );
@@ -216,17 +203,17 @@
216 203 <?php
217 204 }
218 205
219 206 public function add_users_total_docs_column( $columns ) {
220 - $new_column = array(
221 - 'docs' => __( 'Docs', 'betterdocs' ),
222 - );
207 + $new_column = [
208 + 'docs' => __( 'Docs', 'betterdocs' )
209 + ];
223 210 $columns = array_merge( $columns, $new_column );
224 211 return $columns;
225 212 }
226 213
227 214 public function popular_users_docs_data( $output, $column_name, $user_id ) {
228 - if ( 'docs' == $column_name ) {
215 + if ( $column_name == 'docs' ) {
229 216 $total_count = count_user_posts( $user_id, 'docs', true );
230 217 return '<a href="edit.php?post_type=docs&author=' . $user_id . '" class="edit"><span aria-hidden="true">' . $total_count . '</span></a>';
231 218 }
232 219 return $output;
@@ -231,8 +218,20 @@
231 218 }
232 219 return $output;
233 220 }
234 221
222 + public function reading_meta_box_() {
223 + add_meta_box(
224 + 'betterdocs_estimated_time_metabox',
225 + __( 'Estimated Reading Time', 'betterdocs' ),
226 + [
227 + $this,
228 + 'render_estimated_time_markup'
229 + ],
230 + 'docs'
231 + );
232 + }
233 +
235 234 public function render_estimated_time_markup() {
236 235 betterdocs()->views->get( 'admin/metabox/estimated-reading-box' );
237 236 }
238 237
@@ -244,9 +243,9 @@
244 243 if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '2.5.0', '>=' ) ) {
245 244 return;
246 245 }
247 246
248 - betterdocs()->views->get( 'admin/notices/compatibility', array( 'version' => $plugin_data['Version'] ) );
247 + betterdocs()->views->get( 'admin/notices/compatibility', [ 'version' => $plugin_data['Version'] ] );
249 248 }
250 249 }
251 250
252 251 public function plugin_insights( $prevent_init = false ) {
@@ -251,20 +250,20 @@
251 250
252 251 public function plugin_insights( $prevent_init = false ) {
253 252 $this->insights = Insights::get_instance(
254 253 BETTERDOCS_PLUGIN_FILE,
255 - array(
254 + [
256 255 'opt_in' => true,
257 256 'goodbye_form' => true,
258 - 'item_id' => 'c7b16777b4f1b83f6083',
259 - )
257 + 'item_id' => 'c7b16777b4f1b83f6083'
258 + ]
260 259 );
261 260
262 261 $this->insights->set_notice_options(
263 - array(
262 + [
264 263 'notice' => __( 'Want to help make <strong>BetterDocs</strong> even more awesome? You can get a <strong>10% discount coupon</strong> for Premium extensions if you allow us to track the usage.', 'betterdocs' ),
265 - 'extra_notice' => __( 'We collect non-sensitive diagnostic data and plugin usage information. Your site URL, WordPress & PHP version, plugins & themes and email address to send you the discount coupon. This data lets us make sure this plugin always stays compatible with the most popular plugins and themes. No spam, I promise.', 'betterdocs' ),
266 - )
264 + 'extra_notice' => __( 'We collect non-sensitive diagnostic data and plugin usage information. Your site URL, WordPress & PHP version, plugins & themes and email address to send you the discount coupon. This data lets us make sure this plugin always stays compatible with the most popular plugins and themes. No spam, I promise.', 'betterdocs' )
265 + ]
267 266 );
268 267
269 268 if ( ! $prevent_init ) {
270 269 $this->insights->init();
@@ -280,77 +279,76 @@
280 279 * @throws Exception
281 280 */
282 281 public function notices() {
283 282 $notices = new Notices(
284 - array(
283 + [
285 284 'id' => 'betterdocs',
286 285 'storage_key' => 'notices',
287 286 'lifetime' => 3,
288 287 'stylesheet_url' => $this->assets->asset_url( 'admin/css/notices.css' ),
289 288 'styles' => $this->assets->asset_url( 'admin/css/notices.css' ),
290 - 'priority' => 4,
291 - )
289 + 'priority' => 4
290 + ]
292 291 );
293 292
294 293 /**
295 - * Review Notice
296 - *
297 - * @var mixed $message
298 - */
294 + * Review Notice
295 + * @var mixed $message
296 + */
299 297
300 298 $message = __( 'We hope you\'re enjoying BetterDocs! Could you please do us a BIG favor and give it a 5-star rating on WordPress to help us spread the word and boost our motivation?', 'betterdocs' );
301 299
302 - $_review_notice = array(
300 + $_review_notice = [
303 301 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
304 302 'html' => '<p>' . $message . '</p>',
305 - 'links' => array(
306 - 'later' => array(
303 + 'links' => [
304 + 'later' => [
307 305 'link' => 'https://wordpress.org/plugins/betterdocs/#reviews',
308 306 'target' => '_blank',
309 307 'label' => __( 'Sure, you deserve it!', 'betterdocs' ),
310 - 'icon_class' => 'dashicons dashicons-external',
311 - ),
312 - 'allready' => array(
308 + 'icon_class' => 'dashicons dashicons-external'
309 + ],
310 + 'allready' => [
313 311 'label' => __( 'I already did', 'betterdocs' ),
314 312 'icon_class' => 'dashicons dashicons-smiley',
315 - 'attributes' => array(
316 - 'data-dismiss' => true,
317 - ),
318 - ),
319 - 'maybe_later' => array(
313 + 'attributes' => [
314 + 'data-dismiss' => true
315 + ]
316 + ],
317 + 'maybe_later' => [
320 318 'label' => __( 'Maybe Later', 'betterdocs' ),
321 319 'icon_class' => 'dashicons dashicons-calendar-alt',
322 - 'attributes' => array(
320 + 'attributes' => [
323 321 'data-later' => true,
324 - 'class' => 'dismiss-btn',
325 - ),
326 - ),
327 - 'support' => array(
322 + 'class' => 'dismiss-btn'
323 + ]
324 + ],
325 + 'support' => [
328 326 'link' => 'https://wpdeveloper.com/support',
329 - 'attributes' => array(
330 - 'target' => '_blank',
331 - ),
327 + 'attributes' => [
328 + 'target' => '_blank'
329 + ],
332 330 'label' => __( 'I need help', 'betterdocs' ),
333 - 'icon_class' => 'dashicons dashicons-sos',
334 - ),
335 - 'never_show_again' => array(
331 + 'icon_class' => 'dashicons dashicons-sos'
332 + ],
333 + 'never_show_again' => [
336 334 'label' => __( 'Never show again', 'betterdocs' ),
337 335 'icon_class' => 'dashicons dashicons-dismiss',
338 - 'attributes' => array(
339 - 'data-dismiss' => true,
340 - ),
341 - ),
342 - ),
343 - );
336 + 'attributes' => [
337 + 'data-dismiss' => true
338 + ]
339 + ]
340 + ]
341 + ];
344 342
345 343 $notices->add(
346 344 'review',
347 345 $_review_notice,
348 - array(
346 + [
349 347 'start' => $notices->strtotime( '+10 days' ),
350 348 'recurrence' => 30,
351 - 'dismissible' => true,
352 - )
349 + 'dismissible' => true
350 + ]
353 351 );
354 352
355 353 if ( $this->kbmigration->existing_plugins && ! in_array( $this->kbmigration->existing_plugins[0][0], $this->kbmigration->migrated_plugins ) ) {
356 354 $plugin_name = '<strong>' . esc_html( $this->kbmigration->existing_plugins[0][1] ) . '</strong>';
@@ -355,9 +353,9 @@
355 353 if ( $this->kbmigration->existing_plugins && ! in_array( $this->kbmigration->existing_plugins[0][0], $this->kbmigration->migrated_plugins ) ) {
356 354 $plugin_name = '<strong>' . esc_html( $this->kbmigration->existing_plugins[0][1] ) . '</strong>';
357 355
358 356 $message = sprintf(
359 - /* translators: %s is the name of the existing knowledge base plugin. */
357 + /* translators: %s is the name of the existing knowledge base plugin. */
360 358 __( 'Already using %s? Power up your Knowledge Base by migrating all your docs and settings to BetterDocs with just 1 click.', 'betterdocs' ),
361 359 esc_html( $plugin_name )
362 360 );
363 361
@@ -367,51 +365,50 @@
367 365 esc_url( admin_url( 'admin.php?page=betterdocs-settings&tab=tab-migration' ) ),
368 366 esc_html__( 'Start Migration', 'betterdocs' )
369 367 );
370 368
371 - $_migration_notice = array(
369 + $_migration_notice = [
372 370 'thumbnail' => '',
373 371 'html' => $migration_message,
374 - 'links' => array(
375 - 'maybe_later' => array(
372 + 'links' => [
373 + 'maybe_later' => [
376 374 'label' => __( 'Maybe Later', 'betterdocs' ),
377 375 'icon_class' => 'dashicons dashicons-calendar-alt',
378 - 'attributes' => array(
376 + 'attributes' => [
379 377 'data-later' => true,
380 - 'class' => 'dismiss-btn',
381 - ),
382 - ),
383 - 'never_show_again' => array(
378 + 'class' => 'dismiss-btn'
379 + ]
380 + ],
381 + 'never_show_again' => [
384 382 'label' => __( 'Never show again', 'betterdocs' ),
385 383 'icon_class' => 'dashicons dashicons-dismiss',
386 - 'attributes' => array(
387 - 'data-dismiss' => true,
388 - ),
389 - ),
390 - ),
391 - );
384 + 'attributes' => [
385 + 'data-dismiss' => true
386 + ]
387 + ]
388 + ]
389 + ];
392 390
393 391 $notices->add(
394 392 'migration',
395 393 $_migration_notice,
396 - array(
394 + [
397 395 'start' => $notices->time(),
398 396 'recurrence' => false,
399 - 'dismissible' => true,
400 - )
397 + 'dismissible' => true
398 + ]
401 399 );
402 400 }
403 401
404 402 /**
405 - *
406 403 * Opt-In Notice
407 404 */
408 405 $allow_tracking = get_option( 'wpins_allow_tracking' );
409 - if ( null != $this->insights && ! isset( $allow_tracking['betterdocs'] ) ) {
406 + if ( $this->insights != null && ! isset( $allow_tracking['betterdocs'] ) ) {
410 407 $notices->add(
411 408 'opt_in',
412 - array( $this->insights, 'notice' ),
413 - array(
409 + [ $this->insights, 'notice' ],
410 + [
414 411 'classes' => 'updated put-dismiss-notice',
415 412 'start' => $notices->time(),
416 413 'refresh' => BETTERDOCS_VERSION,
417 414 'dismissible' => true,
@@ -416,48 +413,70 @@
416 413 'refresh' => BETTERDOCS_VERSION,
417 414 'dismissible' => true,
418 415 'do_action' => 'wpdeveloper_notice_clicked_for_betterdocs',
419 416 'display_if' => ! function_exists( 'betterdocs_pro' ),
420 - 'screens' => array( 'dashboard' ),
421 - )
417 + 'screens' => [ 'dashboard' ]
418 + ]
422 419 );
423 420 }
424 421
425 - $summer_campaign_message = '<div class="betterdocs-summer-notice-body"><p style="margin-top: 0; margin-bottom: 0;">🏖️ <strong>Summer Savings:</strong> Build AI-powered Knowledge Bases & FAQs to cut support tickets and improve user experience – now <strong>up to $100 OFF!</strong></p></div>';
426 - $_summer_campaign_notice = array(
422 + $blackfriday_message = '<div class="betterdocs-blackfriday-notice-body"><p style="margin-top: 0; margin-bottom: 0;"><strong>Black Friday Mega Sale:</strong> Build <strong>AI-Powered Knowledge Base</strong> & FAQs to empower support and improve user experience – now <strong>up to $120 OFF!</strong> 🎁</p></div>';
423 + $_blackfriday_notice = [
427 424 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
428 - 'html' => $summer_campaign_message,
429 - 'links' => array(
430 - 'support' => array(
431 - 'link' => 'https://betterdocs.co/summer2026-admin-notice',
432 - 'attributes' => array(
425 + 'html' => $blackfriday_message,
426 + 'links' => [
427 + 'support' => [
428 + 'link' => 'https://betterdocs.co/bfcm2025-admin-notice',
429 + 'attributes' => [
433 430 'target' => '_blank',
434 - 'class' => 'offer-button',
435 - ),
436 - 'label' => __( 'Upgrade To PRO Now', 'betterdocs' ),
437 - ),
438 - 'maybe_later' => array(
431 + 'class' => 'offer-button'
432 + ],
433 + 'label' => __( 'Upgrade To PRO', 'betterdocs' )
434 + ],
435 + 'maybe_later' => [
439 436 'label' => __( 'I’ll Grab It Later', 'betterdocs' ),
440 - 'attributes' => array(
441 - 'target' => '_blank',
437 + 'attributes' => [
438 + 'target' => '_blank',
442 439 'data-later' => true,
443 - 'class' => 'dismiss-btn',
444 - ),
445 - ),
446 - ),
440 + 'class' => 'dismiss-btn'
441 + ]
442 + ],
443 + ]
444 + ];
445 +
446 + $notices->add(
447 + 'blackfriday25',
448 + $_blackfriday_notice,
449 + [
450 + 'start' => $notices->time(),
451 + 'recurrence' => false,
452 + 'dismissible' => true,
453 + 'refresh' => BETTERDOCS_VERSION,
454 + 'expire' => strtotime( '11:59:59pm December 4, 2025' ),
455 + 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
456 + ]
447 457 );
448 458
459 + $offer_message = '<div class="betterdocs-notice-body betterdocs-holiday-notice-body"><p style="margin-top: 0; margin-bottom: 0;"><strong>🎉 BetterDocs Just Hit 40,000+ Users!</strong> Join the celebration with 20% OFF & unlock even more power with premium features today!</p><div class="betterdocs-notice-actions"><a class="button button-primary" href="https://betterdocs.co/40K-admin-notice" target="_blank"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
460 + <path d="M15.7431 10.9381L15.904 9.35966C15.9898 8.5175 16.0464 7.9614 16.002 7.61102L16.0175 7.61112C16.7442 7.61112 17.3333 6.98929 17.3333 6.22223C17.3333 5.45517 16.7442 4.83334 16.0175 4.83334C15.2908 4.83334 14.7017 5.45517 14.7017 6.22223C14.7017 6.56914 14.8222 6.88634 15.0214 7.12975C14.7354 7.31608 14.3615 7.70926 13.7987 8.30106L13.7986 8.30107L13.7986 8.30108C13.365 8.75699 13.1482 8.98495 12.9064 9.02025C12.7724 9.03981 12.6358 9.01971 12.5121 8.96219C12.2887 8.85838 12.1398 8.57656 11.842 8.01293L10.2723 5.04204C10.0886 4.69433 9.9348 4.40331 9.79616 4.16913C10.3649 3.86285 10.7543 3.23869 10.7543 2.51852C10.7543 1.49577 9.96888 0.666672 8.99996 0.666672C8.03104 0.666672 7.24557 1.49577 7.24557 2.51852C7.24557 3.23869 7.63503 3.86285 8.20376 4.16913C8.06511 4.40333 7.91137 4.6943 7.72763 5.04204L6.1579 8.01293C5.8601 8.57656 5.71119 8.85838 5.48786 8.96219C5.36411 9.01971 5.22757 9.03981 5.09355 9.02025C4.85169 8.98495 4.63488 8.75699 4.20127 8.30107C3.63844 7.70928 3.26449 7.31608 2.97849 7.12975C3.17771 6.88634 3.29821 6.56914 3.29821 6.22223C3.29821 5.45517 2.70911 4.83334 1.98242 4.83334C1.25572 4.83334 0.666626 5.45517 0.666626 6.22223C0.666626 6.98929 1.25572 7.61112 1.98242 7.61112L1.99795 7.61102C1.95348 7.96139 2.01015 8.51749 2.09596 9.35965L2.2568 10.938C2.34608 11.8142 2.42032 12.6478 2.51125 13.3982H15.4887C15.5796 12.6478 15.6538 11.8142 15.7431 10.9381Z" fill="white"/>
461 + <path d="M8.04563 17.3333H9.95429C12.4419 17.3333 13.6858 17.3333 14.5157 16.5492C14.8779 16.207 15.1073 15.59 15.2728 14.787H2.72711C2.89263 15.59 3.12201 16.207 3.48424 16.5492C4.31414 17.3333 5.55797 17.3333 8.04563 17.3333Z" fill="white"/>
462 + </svg>Upgrade To PRO</a></div></div>';
463 + $_offer_notice = [
464 + 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
465 + 'html' => $offer_message
466 + ];
467 +
449 468 $notices->add(
450 - 'summer-campaign-26',
451 - $_summer_campaign_notice,
452 - array(
469 + '40k_offer',
470 + $_offer_notice,
471 + [
453 472 'start' => $notices->time(),
454 473 'recurrence' => false,
455 474 'dismissible' => true,
456 475 'refresh' => BETTERDOCS_VERSION,
457 - 'expire' => strtotime( '11:59:59pm June 25, 2026' ),
458 - 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ),
459 - )
476 + 'expire' => strtotime( '11:59:59pm April 30, 2025' ),
477 + 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
478 + ]
460 479 );
461 480
462 481 self::$cache_bank->create_account( $notices );
463 482 self::$cache_bank->calculate_deposits( $notices );
@@ -462,9 +481,9 @@
462 481 self::$cache_bank->create_account( $notices );
463 482 self::$cache_bank->calculate_deposits( $notices );
464 483 if ( method_exists( self::$cache_bank, 'clear_notices_in_' ) ) {
465 484 self::$cache_bank->clear_notices_in_(
466 - array(
485 + [
467 486 'toplevel_page_betterdocs-dashboard',
468 487 'admin_page_betterdocs-admin',
469 488 'betterdocs_page_betterdocs-admin',
470 489 'betterdocs_page_betterdocs-settings',
@@ -472,10 +491,10 @@
472 491 'betterdocs_page_betterdocs-analytics',
473 492 'betterdocs_page_betterdocs-glossaries',
474 493 'betterdocs_page_betterdocs-ai-chatbot',
475 494 'edit-doc_category',
476 - 'edit-doc_tag',
477 - ),
495 + 'edit-doc_tag'
496 + ],
478 497 $notices,
479 498 true
480 499 );
481 500 }
@@ -485,26 +504,26 @@
485 504 $saved_settings = get_option( 'betterdocs_settings', false );
486 505 $dark_mode = isset( $saved_settings['dark_mode'] ) ? $saved_settings['dark_mode'] : false;
487 506 $dark_mode = ! empty( $dark_mode ) ? boolval( $dark_mode ) : false;
488 507 $current_screen_id = get_current_screen() != null ? str_replace( 'betterdocs_page_', '', str_replace( 'toplevel_page_', '', str_replace( 'admin_page_', '', get_current_screen()->id ) ) ) : '';
489 - $registered_screens = array(
490 - 'betterdocs-settings',
491 - 'betterdocs-admin',
492 - 'betterdocs-dashboard',
493 - 'betterdocs-analytics',
494 - 'betterdocs-glossaries',
495 - 'betterdocs-faq',
496 - 'edit-doc_category',
497 - 'edit-doc_tag',
498 - 'edit-knowledge_base',
499 - 'betterdocs-ai-chatbot',
500 - );
508 + $registered_screens = [
509 + 'betterdocs-settings',
510 + 'betterdocs-admin',
511 + 'betterdocs-dashboard',
512 + 'betterdocs-analytics',
513 + 'betterdocs-glossaries',
514 + 'betterdocs-faq',
515 + 'edit-doc_category',
516 + 'edit-doc_tag',
517 + 'edit-knowledge_base',
518 + 'betterdocs-ai-chatbot'
519 + ];
501 520
502 - if ( in_array( $current_screen_id, $registered_screens ) ) {
503 - $classes .= ' betterdocs-admin ';
504 - }
521 + if( in_array( $current_screen_id, $registered_screens ) ) {
522 + $classes .= ' betterdocs-admin ';
523 + }
505 524
506 - if ( true === $dark_mode && in_array( $current_screen_id, $registered_screens ) ) {
525 + if ( $dark_mode === true && in_array( $current_screen_id, $registered_screens ) ) {
507 526 $classes .= ' betterdocs-dark-mode ';
508 527 }
509 528
510 529 return $classes;
@@ -519,11 +538,11 @@
519 538 * @since 1.0.0
520 539 */
521 540 public function set_custom_edit_action_columns( $columns ) {
522 541 unset( $columns['comments'] );
523 - $new_columns = array();
542 + $new_columns = [];
524 543 foreach ( $columns as $key => $value ) {
525 - if ( 'date' == $key ) {
544 + if ( $key == 'date' ) {
526 545 $new_columns['betterdocs_word_count'] = __( 'Word Count', 'betterdocs' ); // put the tags column before it
527 546 $new_columns['betterdocs_reaction'] = __( 'Reactions', 'betterdocs' );
528 547 }
529 548 $new_columns[ $key ] = $value;
@@ -535,29 +554,26 @@
535 554 public function manage_custom_columns( $column, $post_id ) {
536 555 global $wpdb;
537 556 switch ( $column ) {
538 557 case 'betterdocs_word_count':
539 - $content_without_html_tags = trim( wp_strip_all_tags( get_post_field( 'post_content', $post_id ) ) );
558 + $content_without_html_tags = trim( strip_tags( get_post_field( 'post_content', $post_id ) ) );
540 559 preg_match_all( '/<[^>]*>|[\p{L}\p{M}]+/u', $content_without_html_tags, $matches );
541 - $total_words = ! empty( $matches[0] ) ? count( $matches[0] ) : count( array() );
560 + $total_words = ! empty( $matches[0] ) ? count( $matches[0] ) : count( [] );
542 561 $word_count = $total_words;
543 562 echo '<span>' . esc_html( intval( $word_count ) ) . '</span>';
544 563 break;
545 564 case 'betterdocs_reaction':
546 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- per-post analytics aggregation rendered in admin list table; cache would mask live reactions.
565 + $where = "WHERE post_id='" . esc_sql( $post_id ) . "'";
547 566 $analytics = $wpdb->get_results(
548 - $wpdb->prepare(
549 - "SELECT
550 - sum(impressions) as totalViews,
551 - sum(unique_visit) as totalUniqueViews,
552 - sum(happy + sad + normal) as totalReactions,
553 - sum(happy) as totalHappy,
554 - sum(normal) as totalNormal,
555 - sum(sad) as totalSad
556 - FROM {$wpdb->prefix}betterdocs_analytics
557 - WHERE post_id = %d",
558 - $post_id
559 - )
567 + "SELECT
568 + sum(impressions) as totalViews,
569 + sum(unique_visit) as totalUniqueViews,
570 + sum(happy + sad + normal) as totalReactions,
571 + sum(happy) as totalHappy,
572 + sum(normal) as totalNormal,
573 + sum(sad) as totalSad
574 + FROM {$wpdb->prefix}betterdocs_analytics
575 + $where"
560 576 );
561 577
562 578 echo '<ul class="reactions-count">
563 579 <li>
@@ -613,22 +629,22 @@
613 629 * @return void
614 630 * @since 1.0.0
615 631 */
616 632 public function styles( $hook ) {
617 - $this->assets->enqueue( 'betterdocs-global', 'admin/css/global.css', array(), 'all' );
633 + $this->assets->enqueue( 'betterdocs-global', 'admin/css/global.css', [], 'all' );
618 634
619 635 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
620 636 return;
621 637 }
622 638
623 - $this->assets->enqueue( 'betterdocs-select2', 'vendor/css/select2.min.css', array(), 'all' );
624 - $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/css/daterangepicker.css', array(), 'all' );
625 - $this->assets->enqueue( 'betterdocs-old', 'admin/css/betterdocs.css', array(), 'all' );
639 + $this->assets->enqueue( 'betterdocs-select2', 'vendor/css/select2.min.css', [], 'all' );
640 + $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/css/daterangepicker.css', [], 'all' );
641 + $this->assets->enqueue( 'betterdocs-old', 'admin/css/betterdocs.css', [], 'all' );
626 642
627 643 /**
628 - * This scripts enqueued for Dashboard App.
629 - */
630 - $this->assets->enqueue( 'betterdocs', 'admin/css/dashboard.css', array( 'betterdocs-old' ), '', BETTERDOCS_VERSION );
644 + * This scripts enqueued for Dashboard App.
645 + */
646 + $this->assets->enqueue( 'betterdocs', 'admin/css/dashboard.css', [ 'betterdocs-old' ], '', BETTERDOCS_VERSION );
631 647 $this->assets->enqueue( 'betterdocs-icons', 'admin/btd-icon/style.css' );
632 648 }
633 649
634 650 /**
@@ -639,26 +655,26 @@
639 655 * @return void
640 656 * @since 1.0.0
641 657 */
642 658 public function scripts( $hook ) {
643 - if ( ( 'edit.php' === $hook ) && get_post_type() == 'docs' ) {
659 + if ( ( $hook === 'edit.php' ) && get_post_type() == 'docs' ) {
644 660 $this->assets->enqueue(
645 661 'betterdocs-switcher',
646 662 'admin/js/switcher.js',
647 - array(
648 - 'jquery',
649 - )
663 + [
664 + 'jquery'
665 + ]
650 666 );
651 667
652 668 $this->assets->localize(
653 669 'betterdocs-switcher',
654 670 'betterdocsSwitcher',
655 - array(
671 + [
656 672 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
657 673 'site_address' => get_bloginfo( 'url' ),
658 674 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
659 - 'betterdocs_pro_version' => betterdocs()->pro_version(),
660 - )
675 + 'betterdocs_pro_version' => betterdocs()->pro_version()
676 + ]
661 677 );
662 678
663 679 return;
664 680 }
@@ -668,9 +684,9 @@
668 684 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
669 685 return;
670 686 }
671 687
672 - wp_enqueue_media(); // load early to fix problems with media upload issues on settings for WordPress 6.0.9
688 + wp_enqueue_media(); // load early to fix problems with media upload issues on settings for wordpress 6.0.9
673 689 $this->assets->register( 'betterdocs-admin', 'admin/js/dashboard.js' );
674 690
675 691 $saved_settings = get_option( 'betterdocs_settings', false );
676 692 $dark_mode = $saved_settings['dark_mode'] ?? false;
@@ -677,55 +693,53 @@
677 693 $dark_mode = ! empty( $dark_mode ) && boolval( $dark_mode );
678 694 $this->assets->localize(
679 695 'betterdocs-admin',
680 696 'betterdocs_admin',
681 - array(
697 + [
682 698 'ajaxurl' => admin_url( 'admin-ajax.php' ),
683 699 'doc_cat_order_nonce' => wp_create_nonce( 'doc_cat_order_nonce' ),
684 700 'knowledge_base_order_nonce' => wp_create_nonce( 'knowledge_base_order_nonce' ),
685 - 'paged' => isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pagination read from URL.
686 - 'per_page_id' => 'edit_doc_category_per_page',
687 - 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
688 - 'dark_mode' => $dark_mode,
689 - 'text' => __( 'Copied!', 'betterdocs' ),
690 - 'test_report' => __( 'Test Report!', 'betterdocs' ),
691 - 'sending' => __( 'Sending...', 'betterdocs' ),
692 - 'dir_url' => BETTERDOCS_ABSURL,
693 - 'rest_url' => esc_url_raw( rest_url() ),
694 - 'free_version' => betterdocs()->version,
695 - 'generate_data_url' => get_rest_url( null, '/betterdocs/v1/create-sample-docs' ),
696 - 'nonce' => wp_create_nonce( 'wp_rest' ),
697 - 'sync_nonce' => wp_create_nonce( 'ai_chatbot_embed' ),
698 - 'count_all_docs' => array_sum( (array) wp_count_posts( 'docs' ) ),
699 - 'count_all_faq' => array_sum( (array) wp_count_posts( 'betterdocs_faq' ) ),
700 - 'count_new_docs' => $this->get_not_synced_docs_count(),
701 - 'admin_url' => admin_url(),
702 - 'ia_preview' => betterdocs()->settings->get( 'ia_enable_preview', false ),
703 - 'multiple_kb' => betterdocs()->settings->get( 'multiple_kb' ),
704 - 'previewMode' => betterdocs()->settings->get( 'ia_enable_preview', false ),
705 - 'dashboard_mode' => get_option( 'dashboard_mode' ),
706 - 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
707 - 'betterdocs_pro_version' => betterdocs()->pro_version(),
708 - 'analytics_older' => version_compare( betterdocs()->pro_version(), '3.3.4', '<=' ),
709 - 'disabled_embed_model_option' => get_option( 'disabled_embed_model_option' ),
710 - 'betterdocs_ChatBot_plugin' => is_plugin_active( 'betterdocs-ai-chatbot/betterdocs-ai-chatbot.php' ),
711 - 'total_doc_category_terms' => wp_count_terms( 'doc_category' ),
712 - 'current_admin_language' => Helper::get_current_admin_language(),
713 - 'is_multilingual' => Helper::is_multilingual_active(),
714 - )
701 + 'paged' => isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Missing
702 + 'per_page_id' => 'edit_doc_category_per_page',
703 + 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
704 + 'dark_mode' => $dark_mode,
705 + 'text' => __( 'Copied!', 'betterdocs' ),
706 + 'test_report' => __( 'Test Report!', 'betterdocs' ),
707 + 'sending' => __( 'Sending...', 'betterdocs' ),
708 + 'dir_url' => BETTERDOCS_ABSURL,
709 + 'rest_url' => esc_url_raw( rest_url() ),
710 + 'free_version' => betterdocs()->version,
711 + 'generate_data_url' => get_rest_url( null, '/betterdocs/v1/create-sample-docs' ),
712 + 'nonce' => wp_create_nonce( 'wp_rest' ),
713 + 'sync_nonce' => wp_create_nonce( 'ai_chatbot_embed' ),
714 + 'count_all_docs' => array_sum((array) wp_count_posts('docs')),
715 + 'count_all_faq' => array_sum((array) wp_count_posts('betterdocs_faq')),
716 + 'count_new_docs' => count(get_option('saved_docs_post_ids', [])) + count(get_option('betterdocs_ai_chatbot_error_posts', [])),
717 + 'admin_url' => admin_url(),
718 + 'ia_preview' => betterdocs()->settings->get( 'ia_enable_preview', false ),
719 + 'multiple_kb' => betterdocs()->settings->get( 'multiple_kb' ),
720 + 'previewMode' => betterdocs()->settings->get( 'ia_enable_preview', false ),
721 + 'dashboard_mode' => get_option( 'dashboard_mode' ),
722 + 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
723 + 'betterdocs_pro_version' => betterdocs()->pro_version(),
724 + 'analytics_older' => version_compare( betterdocs()->pro_version(), '3.3.4', '<=' ),
725 + 'disabled_embed_model_option' => get_option('disabled_embed_model_option'),
726 + 'betterdocs_ChatBot_plugin' => is_plugin_active( 'betterdocs-ai-chatbot/betterdocs-ai-chatbot.php' ),
727 + 'total_doc_category_terms' => wp_count_terms( 'doc_category')
728 + ]
715 729 );
716 730
717 731 // If wp-date (which includes moment.js) is not registered, enqueue your custom moment.js
718 732 if ( ! wp_script_is( 'wp-date', 'registered' ) ) {
719 - $this->assets->enqueue( 'moment', 'vendor/js/moment.min.js', array() );
733 + $this->assets->enqueue( 'moment', 'vendor/js/moment.min.js', [] );
720 734 }
721 735 wp_enqueue_script( 'betterdocs-admin' );
722 736
723 737 /**
724 - * Duplicate Codes Need to Be Removed From Here Onwards
725 - */
738 + * Duplicate Codes Need to Be Removed From Here Onwards
739 + */
726 740
727 - // FAQ Builder Related Localization
741 + //FAQ Builder Related Localization
728 742 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/css/faq.css' );
729 743 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/js/faq.js' );
730 744
731 745 // removing emoji support
@@ -731,28 +745,21 @@
731 745 // removing emoji support
732 746 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
733 747 remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
734 748
735 - // Get settings and remove unnecessary keys
736 - $betterdocs_settings = get_option( 'betterdocs_settings', false );
737 - if ( is_array( $betterdocs_settings ) && ! current_user_can( 'edit_docs_settings' ) ) {
738 - unset( $betterdocs_settings['ai_autowrite_api_key'] );
739 - unset( $betterdocs_settings['ai_chatbot_api_key'] );
740 - }
741 -
742 749 betterdocs()->assets->localize(
743 750 'betterdocs-admin-faq',
744 751 'betterdocsFaq',
745 - array(
752 + [
746 753 'dir_url' => BETTERDOCS_ABSURL,
747 754 'rest_url' => esc_url_raw( rest_url() ),
748 755 'free_version' => betterdocs()->version,
749 756 'nonce' => wp_create_nonce( 'wp_rest' ),
750 - 'betterdocs_settings' => $betterdocs_settings,
751 - )
757 + 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
758 + ]
752 759 );
753 760
754 - // Glossaries Related Localization
761 + //Glossaries Related Localization
755 762 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/css/faq.css' );
756 763
757 764 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/js/glossaries.js' );
758 765
@@ -758,15 +765,15 @@
758 765
759 766 betterdocs()->assets->localize(
760 767 'betterdocs-admin-glossaries',
761 768 'betterdocsGlossary',
762 - array(
769 + [
763 770 'dir_url' => BETTERDOCS_ABSURL,
764 771 'rest_url' => esc_url_raw( rest_url() ),
765 772 'free_version' => betterdocs()->version,
766 773 'nonce' => wp_create_nonce( 'wp_rest' ),
767 - 'betterdocs_settings' => $betterdocs_settings,
768 - )
774 + 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
775 + ]
769 776 );
770 777 }
771 778
772 779 /**
@@ -775,31 +782,31 @@
775 782 * @return void
776 783 * @since 1.0.0
777 784 */
778 785 public function header( $admin_tab_name ) {
779 - $quick_links = array(
786 + $quick_links = [
780 787 'switch_view' => sprintf(
781 788 '<a href="%s" class="betterdocs-button betterdocs-button-secondary">%s</a>',
782 789 add_query_arg(
783 - array(
790 + [
784 791 'post_type' => 'docs',
785 - 'bdocs_view' => 'classic',
786 - ),
792 + 'bdocs_view' => 'classic'
793 + ],
787 794 'edit.php'
788 795 ),
789 796 __( 'Switch to Classic UI', 'betterdocs' )
790 797 ),
791 - 'add_new_doc' => sprintf( '<a href="%s" class="betterdocs-button betterdocs-button-primary">%s</a>', add_query_arg( array( 'post_type' => 'docs' ), 'post-new.php' ), __( 'Add New Doc', 'betterdocs' ) ),
792 - );
798 + 'add_new_doc' => sprintf( '<a href="%s" class="betterdocs-button betterdocs-button-primary">%s</a>', add_query_arg( [ 'post_type' => 'docs' ], 'post-new.php' ), __( 'Add New Doc', 'betterdocs' ) )
799 + ];
793 800
794 801 $quick_links = apply_filters( 'betterdocs_quick_links', $quick_links );
795 802
796 803 betterdocs()->views->get(
797 804 'admin/header',
798 - array(
805 + [
799 806 'quick_links' => $quick_links,
800 - 'active_tab' => $admin_tab_name,
801 - )
807 + 'active_tab' => $admin_tab_name
808 + ]
802 809 );
803 810 }
804 811
805 812 /**
@@ -808,17 +815,17 @@
808 815 * @return void
809 816 * @since 1.0.0
810 817 */
811 818 public function menus() {
812 - $default_args = array(
819 + $default_args = [
813 820 'page_title' => 'BetterDocs',
814 821 'menu_title' => 'BetterDocs',
815 - 'capability' => 'edit_docs', // Unified capability
822 + 'capability' => 'edit_docs', // Unified capability
816 823 'menu_slug' => $this->slug,
817 - 'callback' => array( $this, 'output' ),
824 + 'callback' => [ $this, 'output' ],
818 825 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
819 - 'position' => 5,
820 - );
826 + 'position' => 5
827 + ];
821 828
822 829 $_menu_position = 5;
823 830 global $submenu;
824 831
@@ -825,23 +832,23 @@
825 832 // Always register both UI endpoints
826 833 $this->register_modern_ui_fallback();
827 834
828 835 foreach ( $this->menu_list() as $key => $value ) {
829 - if ( 'betterdocs' === $key ) {
836 + if ( $key === 'betterdocs' ) {
830 837 $callable = 'add_menu_page';
831 838 $value = wp_parse_args( $value, $default_args );
832 839 call_user_func_array( $callable, $value );
833 840 } else {
834 - $is_core_page = strpos( $value['menu_slug'], '?' ) !== false;
841 + $is_core_page = strpos($value['menu_slug'], '?') !== false;
835 842
836 - if ( $is_core_page ) {
843 + if ($is_core_page) {
837 844 // Add classic UI directly
838 - $submenu[ $this->slug ][] = array(
845 + $submenu[$this->slug][] = [
839 846 $value['menu_title'],
840 847 $value['capability'],
841 848 $value['menu_slug'],
842 - $value['page_title'],
843 - );
849 + $value['page_title']
850 + ];
844 851 } else {
845 852 // Add modern UI through WordPress API
846 853 add_submenu_page(
847 854 $this->slug,
@@ -851,9 +858,9 @@
851 858 $value['menu_slug'],
852 859 $value['callback']
853 860 );
854 861 }
855 - ++$_menu_position;
862 + $_menu_position++;
856 863 }
857 864 }
858 865 }
859 866
@@ -860,21 +867,21 @@
860 867 private function register_modern_ui_fallback() {
861 868 // Add the submenu with valid parent slug
862 869 add_submenu_page(
863 870 'betterdocs', // Valid parent slug
864 - __( 'All Docs', 'betterdocs' ),
871 + __('All Docs', 'betterdocs'),
865 872 '', // Empty menu title hides it
866 873 'edit_docs',
867 874 'betterdocs-admin',
868 - array( $this, 'output' )
875 + [ $this, 'output' ]
869 876 );
870 877
871 878 // Hide the menu item from appearing in the admin sidebar
872 879 global $submenu;
873 - if ( isset( $submenu['betterdocs'] ) ) {
874 - foreach ( $submenu['betterdocs'] as $key => $item ) {
875 - if ( 'betterdocs-admin' === $item[2] ) {
876 - unset( $submenu['betterdocs'][ $key ] );
880 + if (isset($submenu['betterdocs'])) {
881 + foreach ($submenu['betterdocs'] as $key => $item) {
882 + if ($item[2] === 'betterdocs-admin') {
883 + unset($submenu['betterdocs'][$key]);
877 884 break;
878 885 }
879 886 }
880 887 }
@@ -887,17 +894,17 @@
887 894 * @since 1.0.0
888 895 */
889 896 public function output() {
890 897 if ( betterdocs()->is_pro_active()
891 - && version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
892 - && get_current_screen()->id == 'betterdocs_page_betterdocs-analytics' ) {
898 + && version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
899 + && get_current_screen()->id == 'betterdocs_page_betterdocs-analytics' ) {
893 900 betterdocs_pro()->views->get( 'admin/analytics-pro' );
894 901 } else {
895 902 betterdocs()->views->get(
896 903 'admin/main',
897 - array(
898 - 'admin_ui' => 'dnd',
899 - )
904 + [
905 + 'admin_ui' => 'dnd'
906 + ]
900 907 );
901 908 }
902 909 }
903 910
@@ -910,10 +917,11 @@
910 917 * @param array $callback
911 918 *
912 919 * @return array
913 920 * @since 2.5.0
921 + *
914 922 */
915 - private function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null, $optional = array() ) {
923 + private function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null, $optional = [] ) {
916 924 return Helper::normalize_menu( $title, $slug, $cap, $callback, $optional );
917 925 }
918 926
919 927 /**
@@ -922,34 +930,34 @@
922 930 * @return array
923 931 * @since 1.0.0
924 932 */
925 933 private function menu_list() {
926 - $parent_slug = array();
934 + $parent_slug = [];
927 935
928 - $betterdocs_admin_pages = array(
929 - 'betterdocs' => array(
936 + $betterdocs_admin_pages = [
937 + 'betterdocs' => [
930 938 'menu_slug' => $this->slug,
931 939 'page_title' => 'BetterDocs',
932 940 'menu_title' => 'BetterDocs',
933 941 'capability' => 'edit_docs',
934 - 'callback' => array( $this, 'output' ),
942 + 'callback' => [ $this, 'output' ],
935 943 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
936 - 'position' => 5,
937 - ),
938 - 'dashboard' => $this->normalize_menu(
944 + 'position' => 5
945 + ],
946 + 'dashboard' => $this->normalize_menu(
939 947 __( 'Dashboard', 'betterdocs' ),
940 948 'betterdocs-dashboard',
941 949 'edit_docs',
942 - array(
950 + [
943 951 $this,
944 - 'output',
945 - )
952 + 'output'
953 + ]
946 954 ),
947 955 'all_docs' => $this->normalize_menu(
948 956 __( 'All Docs', 'betterdocs' ),
949 957 $this->ui_slug(),
950 958 'edit_docs',
951 - array( $this, 'output' ),
959 + [ $this, 'output' ],
952 960 $parent_slug
953 961 ),
954 962 'add_new' => $this->normalize_menu(
955 963 __( 'Add New', 'betterdocs' ),
@@ -968,12 +976,12 @@
968 976 'settings' => $this->normalize_menu(
969 977 __( 'Settings', 'betterdocs' ),
970 978 'betterdocs-settings',
971 979 'edit_docs_settings',
972 - array(
980 + [
973 981 $this,
974 - 'output',
975 - ),
982 + 'output'
983 + ],
976 984 $parent_slug
977 985 ),
978 986 'analytics' => $this->normalize_menu(
979 987 __( 'Analytics', 'betterdocs' ),
@@ -978,12 +986,12 @@
978 986 'analytics' => $this->normalize_menu(
979 987 __( 'Analytics', 'betterdocs' ),
980 988 'betterdocs-analytics',
981 989 'read_docs_analytics',
982 - array(
990 + [
983 991 $this,
984 - 'output',
985 - ),
992 + 'output'
993 + ],
986 994 $parent_slug
987 995 ),
988 996 'faq' => $this->normalize_menu(
989 997 __( 'FAQ Builder', 'betterdocs' ),
@@ -988,15 +996,15 @@
988 996 'faq' => $this->normalize_menu(
989 997 __( 'FAQ Builder', 'betterdocs' ),
990 998 'betterdocs-faq',
991 999 'read_faq_builder',
992 - array(
1000 + [
993 1001 $this,
994 - 'output',
995 - ),
1002 + 'output'
1003 + ],
996 1004 $parent_slug
997 - ),
998 - );
1005 + )
1006 + ];
999 1007
1000 1008 if ( betterdocs()->is_pro_active() && betterdocs()->settings->get( 'enable_glossaries' ) == true ) {
1001 1009 $betterdocs_admin_pages['glossaries'] = $this->normalize_menu(
1002 1010 __( 'Glossaries', 'betterdocs' ),
@@ -1001,36 +1009,38 @@
1001 1009 $betterdocs_admin_pages['glossaries'] = $this->normalize_menu(
1002 1010 __( 'Glossaries', 'betterdocs' ),
1003 1011 'betterdocs-glossaries',
1004 1012 'read_docs_analytics',
1005 - array(
1013 + [
1006 1014 $this,
1007 - 'output',
1008 - ),
1015 + 'output'
1016 + ],
1009 1017 $parent_slug
1010 1018 );
1011 1019 }
1012 1020
1013 - if ( ! betterdocs()->is_chatbot_active() ) {
1014 - $betterdocs_admin_pages['ai_chatbot'] = $this->normalize_menu(
1015 - __( 'AI Chatbot', 'betterdocs' ),
1016 - 'betterdocs-ai-chatbot',
1017 - 'edit_docs_settings',
1018 - array(
1021 +
1022 + if (!betterdocs()->is_chatbot_active()) {
1023 + $betterdocs_admin_pages['ai_chatbot'] = $this->normalize_menu(
1024 + __('AI Chatbot', 'betterdocs'),
1025 + 'betterdocs-ai-chatbot',
1026 + 'edit_docs_settings',
1027 + [
1019 1028 $this,
1020 - 'output',
1021 - ),
1022 - $parent_slug
1023 - );
1024 - }
1029 + 'output'
1030 + ],
1031 + $parent_slug
1032 + );
1033 + }
1025 1034
1026 - return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages, array( $this, 'output' ), $parent_slug );
1027 - }
1035 + return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages, [$this, 'output'], $parent_slug);
1028 1036
1037 + }
1038 +
1029 1039 public function add_custom_classes_to_menu_items() {
1030 1040 global $menu, $submenu;
1031 1041
1032 - $menu_items = array(
1042 + $menu_items = [
1033 1043 'betterdocs' => 'betterdocs',
1034 1044 'betterdocs_page_all_docs' => 'betterdocs-all-docs',
1035 1045 'betterdocs_page_add_new' => 'betterdocs-add-new',
1036 1046 'edit-tags.php?taxonomy=doc_category&post_type=docs' => 'betterdocs-categories',
@@ -1039,10 +1049,10 @@
1039 1049 'betterdocs-analytics' => 'betterdocs-analytics',
1040 1050 'betterdocs-faq' => 'betterdocs-faq',
1041 1051 'betterdocs-glossaries' => 'betterdocs-glossaries',
1042 1052 'betterdocs-ai-chatbot' => 'betterdocs-ai-chatbot',
1043 - 'edit-tags.php?taxonomy=knowledge_base&post_type=docs' => 'betterdocs-multiplekb',
1044 - );
1053 + 'edit-tags.php?taxonomy=knowledge_base&post_type=docs' => 'betterdocs-multiplekb'
1054 + ];
1045 1055
1046 1056 foreach ( $menu as &$item ) {
1047 1057 if ( isset( $menu_items[ $item[2] ] ) ) {
1048 1058 if ( ! isset( $item[4] ) ) {
@@ -1072,12 +1082,12 @@
1072 1082 $menus['quick_setup'] = $this->normalize_menu(
1073 1083 __( 'Quick Setup', 'betterdocs' ),
1074 1084 'betterdocs-setup',
1075 1085 'delete_users',
1076 - array(
1086 + [
1077 1087 $this->container->get( SetupWizard::class ),
1078 - 'views',
1079 - )
1088 + 'views'
1089 + ]
1080 1090 );
1081 1091 }
1082 1092
1083 1093 return $menus;
@@ -1085,10 +1095,10 @@
1085 1095
1086 1096 public function insert_plugin_links( $links ) {
1087 1097 $links[] = '<a href="admin.php?page=betterdocs-settings">' . __( 'Settings', 'betterdocs' ) . '</a>';
1088 1098
1089 - if ( ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ) ) {
1090 - $links[] = '<a href="https://betterdocs.co/upgrade-to-pro-plugins-wp" target="_blank" style="color: #000; font-weight: bold;">' . __( 'Upgrade to Pro', 'betterdocs' ) . '</a>';
1099 + if (! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ) ) {
1100 + $links[] = '<a href="https://betterdocs.co/bfcm-2025-plugins-wp" target="_blank" style="color: #000; font-weight: bold;">' . __( 'Save 40% Today', 'betterdocs' ) . '</a>';
1091 1101 }
1092 1102
1093 1103 return $links;
1094 1104 }
@@ -1117,22 +1127,17 @@
1117 1127 }
1118 1128
1119 1129 $slug = $this->settings->get( 'encyclopedia_root_slug' );
1120 1130
1121 - global $wp_rewrite;
1122 - if ( $wp_rewrite->using_index_permalinks() ) {
1123 - $slug = $wp_rewrite->index . '/' . $slug;
1124 - }
1125 -
1126 1131 $encyclopedia_url = home_url( $slug );
1127 1132
1128 1133 $admin_bar->add_node(
1129 - array(
1134 + [
1130 1135 'parent' => 'site-name',
1131 1136 'id' => 'view-docs',
1132 1137 'title' => __( 'Visit Documentation', 'betterdocs' ),
1133 - 'href' => $docs_url,
1134 - )
1138 + 'href' => $docs_url
1139 + ]
1135 1140 );
1136 1141
1137 1142 $is_enable_encyclopedia = betterdocs()->settings->get( 'enable_encyclopedia' );
1138 1143
@@ -1137,14 +1142,14 @@
1137 1142 $is_enable_encyclopedia = betterdocs()->settings->get( 'enable_encyclopedia' );
1138 1143
1139 1144 if ( $is_enable_encyclopedia && betterdocs()->is_pro_active() ) {
1140 1145 $admin_bar->add_node(
1141 - array(
1146 + [
1142 1147 'parent' => 'site-name',
1143 1148 'id' => 'view-encyclopedia',
1144 1149 'title' => __( 'Visit Encyclopedia', 'betterdocs' ),
1145 - 'href' => $encyclopedia_url,
1146 - )
1150 + 'href' => $encyclopedia_url
1151 + ]
1147 1152 );
1148 1153 }
1149 1154 }
1150 1155
@@ -1151,20 +1156,14 @@
1151 1156 /**
1152 1157 * Save last visited admin ui
1153 1158 *
1154 1159 * @since 3.0.1
1160 + *
1155 1161 */
1156 1162 public function save_admin_page() {
1157 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen detection.
1158 - $post_type = isset( $_GET['post_type'] ) ? sanitize_text_field( wp_unslash( $_GET['post_type'] ) ) : '';
1159 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen detection.
1160 - $bdocs_view = isset( $_GET['bdocs_view'] ) ? sanitize_text_field( wp_unslash( $_GET['bdocs_view'] ) ) : '';
1161 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen detection.
1162 - $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
1163 -
1164 - if ( 'docs' === $post_type && 'classic' === $bdocs_view ) {
1163 + if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'docs' && isset( $_GET['bdocs_view'] ) && $_GET['bdocs_view'] === 'classic' ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1165 1164 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'classic_ui' );
1166 - } elseif ( 'betterdocs-admin' === $page ) {
1165 + } elseif ( isset( $_GET['page'] ) && $_GET['page'] === 'betterdocs-admin' ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1167 1166 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'modern_ui' );
1168 1167 }
1169 1168 }
1170 1169
@@ -1174,20 +1173,18 @@
1174 1173 * @return string
1175 1174 * @since 3.0.1
1176 1175 */
1177 1176 public function ui_slug() {
1178 - $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
1179 - $docs_exist = get_posts(
1180 - array(
1181 - 'post_type' => 'docs',
1182 - 'post_status' => 'any',
1183 - 'numberposts' => 1,
1184 - )
1185 - );
1177 + $last_visited = get_user_meta(get_current_user_id(), 'last_visited_docs_admin_page', true);
1178 + $docs_exist = get_posts([
1179 + 'post_type' => 'docs',
1180 + 'post_status' => 'any',
1181 + 'numberposts' => 1
1182 + ]);
1186 1183
1187 - return ( 'modern_ui' === $last_visited || empty( $docs_exist ) )
1188 - ? 'betterdocs-admin'
1189 - : 'edit.php?post_type=docs&bdocs_view=classic';
1184 + return ($last_visited === 'modern_ui' || empty($docs_exist))
1185 + ? 'betterdocs-admin'
1186 + : 'edit.php?post_type=docs&bdocs_view=classic';
1190 1187 }
1191 1188
1192 1189 /**
1193 1190 * Resets a duplicate submenu in WordPress if the parent main menu and the first submenu permalink are not the same.
@@ -1197,9 +1194,9 @@
1197 1194 */
1198 1195 public function reset_submenu() {
1199 1196 global $submenu;
1200 1197
1201 - $docs = get_posts( array( 'post_type' => 'docs' ) );
1198 + $docs = get_posts( [ 'post_type' => 'docs' ] );
1202 1199 if ( count( $docs ) == 0 ) {
1203 1200 return;
1204 1201 }
1205 1202
@@ -1204,9 +1201,9 @@
1204 1201 }
1205 1202
1206 1203 $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
1207 1204
1208 - if ( 'classic_ui' === $last_visited && isset( $submenu['betterdocs-admin'] ) && in_array( 'betterdocs-admin', $submenu['betterdocs-admin'][0] ) ) {
1205 + if ( $last_visited === 'classic_ui' && isset( $submenu['betterdocs-admin'] ) && in_array( 'betterdocs-admin', $submenu['betterdocs-admin'][0] ) ) {
1209 1206 unset( $submenu['betterdocs-admin'][0] );
1210 1207 $submenu['betterdocs-admin'] = array_values( $submenu['betterdocs-admin'] );
1211 1208 }
1212 1209 }
@@ -1231,23 +1228,22 @@
1231 1228 * @since 3.7.0
1232 1229 */
1233 1230 public function ajax_dismiss_black_friday_pointer() {
1234 1231 // Verify nonce
1235 - $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
1236 - if ( ! wp_verify_nonce( $nonce, 'betterdocs_dismiss_pointer' ) ) {
1237 - wp_send_json_error( array( 'message' => __( 'Invalid nonce', 'betterdocs' ) ) );
1232 + if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'betterdocs_dismiss_pointer' ) ) {
1233 + wp_send_json_error( [ 'message' => __( 'Invalid nonce', 'betterdocs' ) ] );
1238 1234 }
1239 1235
1240 1236 // Check if user has permission
1241 1237 if ( ! current_user_can( 'manage_options' ) && ! current_user_can( 'edit_docs' ) ) {
1242 - wp_send_json_error( array( 'message' => __( 'Permission denied', 'betterdocs' ) ) );
1238 + wp_send_json_error( [ 'message' => __( 'Permission denied', 'betterdocs' ) ] );
1243 1239 }
1244 1240
1245 1241 // Get the introduction key
1246 - $introduction_key = isset( $_POST['introduction_key'] ) ? sanitize_text_field( wp_unslash( $_POST['introduction_key'] ) ) : '';
1242 + $introduction_key = isset( $_POST['introduction_key'] ) ? sanitize_text_field( $_POST['introduction_key'] ) : '';
1247 1243
1248 1244 if ( empty( $introduction_key ) ) {
1249 - wp_send_json_error( array( 'message' => __( 'Invalid introduction key', 'betterdocs' ) ) );
1245 + wp_send_json_error( [ 'message' => __( 'Invalid introduction key', 'betterdocs' ) ] );
1250 1246 }
1251 1247
1252 1248 // Set the introduction as viewed
1253 1249 NoticePointers::set_introduction_viewed( $introduction_key );
@@ -1254,39 +1250,7 @@
1254 1250
1255 1251 // Clear the priority option so other plugins can set their priority
1256 1252 delete_option( '_wpdeveloper_plugin_pointer_priority' );
1257 1253
1258 - wp_send_json_success( array( 'message' => __( 'Pointer dismissed successfully', 'betterdocs' ) ) );
1259 - }
1260 -
1261 - /**
1262 - * Get count of docs that are not yet synced
1263 - * Similar to Helper::get_not_synced_post_ids() in betterdocs-ai-chatbot plugin
1264 - *
1265 - * @return int
1266 - * @since 3.7.0
1267 - */
1268 - private function get_not_synced_docs_count() {
1269 - $new_post_ids = get_option( 'saved_docs_post_ids', array() );
1270 - $error_posts_data = get_option( 'betterdocs_ai_chatbot_error_posts', array() );
1271 -
1272 - // Extract post IDs from error posts (handle both old and new formats)
1273 - $error_post_ids = array();
1274 - if ( is_array( $error_posts_data ) && ! empty( $error_posts_data ) ) {
1275 - foreach ( $error_posts_data as $key => $value ) {
1276 - if ( is_numeric( $key ) && is_numeric( $value ) ) {
1277 - // Old format: numeric key with post ID as value
1278 - $error_post_ids[] = $value;
1279 - } elseif ( is_numeric( $key ) && is_array( $value ) && isset( $value['post_id'] ) ) {
1280 - // New format: post ID as key with structured data
1281 - $error_post_ids[] = $key;
1282 - } elseif ( is_numeric( $key ) ) {
1283 - // New format: post ID as key
1284 - $error_post_ids[] = $key;
1285 - }
1286 - }
1287 - }
1288 -
1289 - // Merge both arrays and remove duplicates, then count
1290 - return count( array_unique( array_merge( $new_post_ids, $error_post_ids ) ) );
1254 + wp_send_json_success( [ 'message' => __( 'Pointer dismissed successfully', 'betterdocs' ) ] );
1291 1255 }
1292 1256 }