PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.2.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.2.0
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 +348 -584 4.6.24.2.0 View file →
@@ -1,20 +1,15 @@
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 -use WPDeveloper\BetterDocs\Admin\NoticePointers;
12 7 use WPDeveloper\BetterDocs\Utils\Base;
13 8 use PriyoMukul\WPNotice\Utils\CacheBank;
14 9 use WPDeveloper\BetterDocs\Utils\Helper;
15 10 use WPDeveloper\BetterDocs\Utils\Enqueue;
16 -use WPDeveloper\BetterDocs\Insights\Insights;
11 +use WPDeveloper\BetterDocs\Utils\Insights;
17 12 use PriyoMukul\WPNotice\Utils\NoticeRemover;
18 13 use WPDeveloper\BetterDocs\Core\PluginInstaller;
19 14 use WPDeveloper\BetterDocs\Dependencies\DI\Container;
20 15
@@ -24,9 +19,8 @@
24 19 */
25 20 private static $cache_bank;
26 21 /**
27 22 * Admin Root Menu Slug
28 - *
29 23 * @var string
30 24 */
31 25 private $slug = 'betterdocs-dashboard';
32 26 /**
@@ -58,19 +52,17 @@
58 52 private $kbmigration;
59 53
60 54 /**
61 55 * Enqueue
62 - *
63 56 * @var Enqueue
64 57 */
65 58 private $assets;
66 59
67 60 // modules
68 - protected $installer;
61 + protected $installer;
69 62
70 63 /**
71 64 * FAQBuilder
72 - *
73 65 * @var FAQBuilder
74 66 */
75 67 private $faq_builder;
76 68 private $glossaries;
@@ -81,10 +73,10 @@
81 73 $this->settings = $settings;
82 74 $this->kbmigration = $kbmigration;
83 75 $this->slug = 'betterdocs-dashboard';
84 76
85 - add_action( 'init', array( $type, 'register' ), 9 );
86 - add_action( 'rest_api_init', array( $this, 'order_terms_in_wp_terms_admin_table' ) );
77 + add_action( 'init', [ $type, 'register' ], 9 );
78 + add_action('rest_api_init', [$this, 'order_terms_in_wp_terms_admin_table']);
87 79
88 80 $type->init();
89 81 $type->admin_init();
90 82
@@ -90,18 +82,8 @@
90 82
91 83 $this->faq_builder = $this->container->get( FAQBuilder::class );
92 84 $this->glossaries = $this->container->get( Glossaries::class );
93 85
94 - /**
95 - * Register usage tracking (including the daily `put_do_weekly_action` cron
96 - * handler) on every request — WP-Cron runs with is_admin() === false, so
97 - * this MUST sit above the admin guard or the cron send never fires. The
98 - * admin-only UI hooks inside Insights::init() (deactivation form, footer
99 - * scripts, plugin_action_links) are context-specific and simply never run
100 - * outside wp-admin.
101 - */
102 - $this->plugin_insights();
103 -
104 86 if ( ! is_admin() ) {
105 87 return;
106 88 }
107 89
@@ -106,47 +88,47 @@
106 88 }
107 89
108 90 $this->installer = new PluginInstaller();
109 91
110 - add_action( 'admin_notices', array( $this, 'compatibility_notices' ) );
92 + $this->plugin_insights();
93 + add_action( 'admin_notices', [ $this, 'compatibility_notices' ] );
111 94 // add_action( 'admin_init', [$this, 'notices'], 9 );
112 - add_filter( 'admin_init', array( $this, 'save_admin_page' ), 99 );
95 + add_filter( 'admin_init', [ $this, 'save_admin_page' ], 99 );
113 96
114 - add_action( 'admin_menu', array( $this, 'menus' ) );
115 - add_action( 'admin_menu', array( $this, 'reset_submenu' ) );
116 - add_action( 'admin_head', array( $this, 'add_custom_classes_to_menu_items' ) );
117 - add_filter( 'plugin_action_links_' . BETTERDOCS_PLUGIN_BASENAME, array( $this, 'insert_plugin_links' ) );
97 + add_action( 'admin_menu', [ $this, 'menus' ] );
98 + add_action( 'admin_menu', [ $this, 'reset_submenu' ] );
99 + add_action( 'admin_head', [ $this, 'add_custom_classes_to_menu_items' ] );
100 + add_filter( 'plugin_action_links_' . BETTERDOCS_PLUGIN_BASENAME, [ $this, 'insert_plugin_links' ] );
118 101
119 102 // $this->container->get( SetupWizard::class )->init();
120 103
121 - add_action( 'admin_enqueue_scripts', array( $this, 'styles' ) );
122 - add_action( 'admin_enqueue_scripts', array( $this, 'scripts' ) );
123 - // add_action( 'betterdocs_listing_header', [ $this, 'header' ], 10, 1 );
124 - add_action( 'admin_bar_menu', array( $this, 'toolbar_menu' ), 32 );
104 + add_action( 'admin_enqueue_scripts', [ $this, 'styles' ] );
105 + add_action( 'admin_enqueue_scripts', [ $this, 'scripts' ] );
106 + //add_action( 'betterdocs_listing_header', [ $this, 'header' ], 10, 1 );
107 + add_action( 'admin_bar_menu', [ $this, 'toolbar_menu' ], 32 );
125 108
126 - add_filter( 'admin_body_class', array( $this, 'body_classes' ) );
127 - add_filter( 'parent_file', array( $type, 'highlight_admin_menu' ) );
128 - add_filter( 'submenu_file', array( $type, 'highlight_admin_submenu' ), 10, 2 );
129 - add_filter( 'betterdocs_admin_menu', array( $this, 'quick_setup_menu' ), 10, 1 );
109 + add_filter( 'admin_body_class', [ $this, 'body_classes' ] );
110 + add_filter( 'parent_file', [ $type, 'highlight_admin_menu' ] );
111 + add_filter( 'submenu_file', [ $type, 'highlight_admin_submenu' ], 10, 2 );
112 + add_filter( 'betterdocs_admin_menu', [ $this, 'quick_setup_menu' ], 10, 1 );
130 113
131 114 /**
132 115 * Remove Comments Column from List Table.
133 116 */
134 - add_filter( 'manage_docs_posts_columns', array( $this, 'set_custom_edit_action_columns' ) );
135 - add_filter( 'manage_docs_posts_custom_column', array( $this, 'manage_custom_columns' ), 10, 2 );
117 + add_filter( 'manage_docs_posts_columns', [ $this, 'set_custom_edit_action_columns' ] );
118 + add_filter( 'manage_docs_posts_custom_column', [ $this, 'manage_custom_columns' ], 10, 2 );
136 119
137 120 /**
138 121 * Add New Column
139 122 */
140 - add_filter( 'manage_users_columns', array( $this, 'add_users_total_docs_column' ), 10, 1 );
141 - add_filter( 'manage_users_custom_column', array( $this, 'popular_users_docs_data' ), 10, 3 );
123 + add_filter( 'manage_users_columns', [ $this, 'add_users_total_docs_column' ], 10, 1 );
124 + add_filter( 'manage_users_custom_column', [ $this, 'popular_users_docs_data' ], 10, 3 );
142 125 if ( is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ) ) {
143 126 add_action( 'admin_footer-plugins.php', array( $this, 'disable_deactivation' ) );
144 127 }
145 128
146 129 if ( $this->settings->get( 'enable_estimated_reading_time' ) ) {
147 - // Hook into unified metabox instead of creating separate metabox
148 - add_action( 'betterdocs_reading_time_tab_content', array( $this, 'render_estimated_time_markup' ) );
130 + add_action( 'add_meta_boxes', [ $this, 'reading_meta_box_' ], 10 );
149 131 }
150 132
151 133 self::$cache_bank = CacheBank::get_instance();
152 134
@@ -157,28 +139,17 @@
157 139 $this->notices();
158 140 } catch ( Exception $e ) {
159 141 unset( $e );
160 142 }
161 -
162 - // Initialize Black Friday Pointer
163 - $this->init_black_friday_pointer();
164 -
165 - // Register AJAX handler for pointer dismissal
166 - add_action( 'wp_ajax_betterdocs_dismiss_black_friday_pointer', array( $this, 'ajax_dismiss_black_friday_pointer' ) );
167 143 }
168 144
169 145 public function order_terms_in_wp_terms_admin_table() {
170 - // order the terms correctly to be shown on the admin panel categories menu with betterdocs order
171 - add_action(
172 - 'rest_insert_doc_category',
173 - function ( $term, $request, $bool ) {
174 - $max_order = Helper::get_max_doc_category_order_from_term_meta() ?? 0;
175 - $next_order = $max_order + 1;
176 - update_term_meta( $term->term_id, 'doc_category_order', $next_order );
177 - },
178 - 10,
179 - 3
180 - );
146 + //order the terms correctly to be shown on the admin panel categories menu with betterdocs order
147 + add_action('rest_insert_doc_category', function( $term, $request, $bool ) {
148 + $max_order = Helper::get_max_doc_category_order_from_term_meta() ?? 0;
149 + $next_order = $max_order + 1;
150 + update_term_meta( $term->term_id, 'doc_category_order', $next_order );
151 + }, 10, 3);
181 152 }
182 153
183 154 public function disable_deactivation() {
184 155 $tooltip_text = esc_html__( 'Deactivate BetterDocs Pro First', 'betterdocs' );
@@ -225,17 +196,17 @@
225 196 <?php
226 197 }
227 198
228 199 public function add_users_total_docs_column( $columns ) {
229 - $new_column = array(
230 - 'docs' => __( 'Docs', 'betterdocs' ),
231 - );
200 + $new_column = [
201 + 'docs' => __( 'Docs', 'betterdocs' )
202 + ];
232 203 $columns = array_merge( $columns, $new_column );
233 204 return $columns;
234 205 }
235 206
236 207 public function popular_users_docs_data( $output, $column_name, $user_id ) {
237 - if ( 'docs' == $column_name ) {
208 + if ( $column_name == 'docs' ) {
238 209 $total_count = count_user_posts( $user_id, 'docs', true );
239 210 return '<a href="edit.php?post_type=docs&author=' . $user_id . '" class="edit"><span aria-hidden="true">' . $total_count . '</span></a>';
240 211 }
241 212 return $output;
@@ -240,8 +211,20 @@
240 211 }
241 212 return $output;
242 213 }
243 214
215 + public function reading_meta_box_() {
216 + add_meta_box(
217 + 'betterdocs_estimated_time_metabox',
218 + __( 'Estimated Reading Time', 'betterdocs' ),
219 + [
220 + $this,
221 + 'render_estimated_time_markup'
222 + ],
223 + 'docs'
224 + );
225 + }
226 +
244 227 public function render_estimated_time_markup() {
245 228 betterdocs()->views->get( 'admin/metabox/estimated-reading-box' );
246 229 }
247 230
@@ -253,9 +236,9 @@
253 236 if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '2.5.0', '>=' ) ) {
254 237 return;
255 238 }
256 239
257 - betterdocs()->views->get( 'admin/notices/compatibility', array( 'version' => $plugin_data['Version'] ) );
240 + betterdocs()->views->get( 'admin/notices/compatibility', [ 'version' => $plugin_data['Version'] ] );
258 241 }
259 242 }
260 243
261 244 public function plugin_insights( $prevent_init = false ) {
@@ -260,20 +243,20 @@
260 243
261 244 public function plugin_insights( $prevent_init = false ) {
262 245 $this->insights = Insights::get_instance(
263 246 BETTERDOCS_PLUGIN_FILE,
264 - array(
247 + [
265 248 'opt_in' => true,
266 249 'goodbye_form' => true,
267 - 'item_id' => 'c7b16777b4f1b83f6083',
268 - )
250 + 'item_id' => 'c7b16777b4f1b83f6083'
251 + ]
269 252 );
270 253
271 254 $this->insights->set_notice_options(
272 - array(
255 + [
273 256 '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' ),
274 - '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' ),
275 - )
257 + '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' )
258 + ]
276 259 );
277 260
278 261 if ( ! $prevent_init ) {
279 262 $this->insights->init();
@@ -289,77 +272,76 @@
289 272 * @throws Exception
290 273 */
291 274 public function notices() {
292 275 $notices = new Notices(
293 - array(
276 + [
294 277 'id' => 'betterdocs',
295 278 'storage_key' => 'notices',
296 279 'lifetime' => 3,
297 280 'stylesheet_url' => $this->assets->asset_url( 'admin/css/notices.css' ),
298 281 'styles' => $this->assets->asset_url( 'admin/css/notices.css' ),
299 - 'priority' => 4,
300 - )
282 + 'priority' => 4
283 + ]
301 284 );
302 285
303 286 /**
304 - * Review Notice
305 - *
306 - * @var mixed $message
307 - */
287 + * Review Notice
288 + * @var mixed $message
289 + */
308 290
309 291 $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' );
310 292
311 - $_review_notice = array(
293 + $_review_notice = [
312 294 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
313 295 'html' => '<p>' . $message . '</p>',
314 - 'links' => array(
315 - 'later' => array(
296 + 'links' => [
297 + 'later' => [
316 298 'link' => 'https://wordpress.org/plugins/betterdocs/#reviews',
317 299 'target' => '_blank',
318 300 'label' => __( 'Sure, you deserve it!', 'betterdocs' ),
319 - 'icon_class' => 'dashicons dashicons-external',
320 - ),
321 - 'allready' => array(
301 + 'icon_class' => 'dashicons dashicons-external'
302 + ],
303 + 'allready' => [
322 304 'label' => __( 'I already did', 'betterdocs' ),
323 305 'icon_class' => 'dashicons dashicons-smiley',
324 - 'attributes' => array(
325 - 'data-dismiss' => true,
326 - ),
327 - ),
328 - 'maybe_later' => array(
306 + 'attributes' => [
307 + 'data-dismiss' => true
308 + ]
309 + ],
310 + 'maybe_later' => [
329 311 'label' => __( 'Maybe Later', 'betterdocs' ),
330 312 'icon_class' => 'dashicons dashicons-calendar-alt',
331 - 'attributes' => array(
313 + 'attributes' => [
332 314 'data-later' => true,
333 - 'class' => 'dismiss-btn',
334 - ),
335 - ),
336 - 'support' => array(
315 + 'class' => 'dismiss-btn'
316 + ]
317 + ],
318 + 'support' => [
337 319 'link' => 'https://wpdeveloper.com/support',
338 - 'attributes' => array(
339 - 'target' => '_blank',
340 - ),
320 + 'attributes' => [
321 + 'target' => '_blank'
322 + ],
341 323 'label' => __( 'I need help', 'betterdocs' ),
342 - 'icon_class' => 'dashicons dashicons-sos',
343 - ),
344 - 'never_show_again' => array(
324 + 'icon_class' => 'dashicons dashicons-sos'
325 + ],
326 + 'never_show_again' => [
345 327 'label' => __( 'Never show again', 'betterdocs' ),
346 328 'icon_class' => 'dashicons dashicons-dismiss',
347 - 'attributes' => array(
348 - 'data-dismiss' => true,
349 - ),
350 - ),
351 - ),
352 - );
329 + 'attributes' => [
330 + 'data-dismiss' => true
331 + ]
332 + ]
333 + ]
334 + ];
353 335
354 336 $notices->add(
355 337 'review',
356 338 $_review_notice,
357 - array(
339 + [
358 340 'start' => $notices->strtotime( '+10 days' ),
359 341 'recurrence' => 30,
360 - 'dismissible' => true,
361 - )
342 + 'dismissible' => true
343 + ]
362 344 );
363 345
364 346 if ( $this->kbmigration->existing_plugins && ! in_array( $this->kbmigration->existing_plugins[0][0], $this->kbmigration->migrated_plugins ) ) {
365 347 $plugin_name = '<strong>' . esc_html( $this->kbmigration->existing_plugins[0][1] ) . '</strong>';
@@ -364,9 +346,9 @@
364 346 if ( $this->kbmigration->existing_plugins && ! in_array( $this->kbmigration->existing_plugins[0][0], $this->kbmigration->migrated_plugins ) ) {
365 347 $plugin_name = '<strong>' . esc_html( $this->kbmigration->existing_plugins[0][1] ) . '</strong>';
366 348
367 349 $message = sprintf(
368 - /* translators: %s is the name of the existing knowledge base plugin. */
350 + /* translators: %s is the name of the existing knowledge base plugin. */
369 351 __( 'Already using %s? Power up your Knowledge Base by migrating all your docs and settings to BetterDocs with just 1 click.', 'betterdocs' ),
370 352 esc_html( $plugin_name )
371 353 );
372 354
@@ -376,51 +358,50 @@
376 358 esc_url( admin_url( 'admin.php?page=betterdocs-settings&tab=tab-migration' ) ),
377 359 esc_html__( 'Start Migration', 'betterdocs' )
378 360 );
379 361
380 - $_migration_notice = array(
362 + $_migration_notice = [
381 363 'thumbnail' => '',
382 364 'html' => $migration_message,
383 - 'links' => array(
384 - 'maybe_later' => array(
365 + 'links' => [
366 + 'maybe_later' => [
385 367 'label' => __( 'Maybe Later', 'betterdocs' ),
386 368 'icon_class' => 'dashicons dashicons-calendar-alt',
387 - 'attributes' => array(
369 + 'attributes' => [
388 370 'data-later' => true,
389 - 'class' => 'dismiss-btn',
390 - ),
391 - ),
392 - 'never_show_again' => array(
371 + 'class' => 'dismiss-btn'
372 + ]
373 + ],
374 + 'never_show_again' => [
393 375 'label' => __( 'Never show again', 'betterdocs' ),
394 376 'icon_class' => 'dashicons dashicons-dismiss',
395 - 'attributes' => array(
396 - 'data-dismiss' => true,
397 - ),
398 - ),
399 - ),
400 - );
377 + 'attributes' => [
378 + 'data-dismiss' => true
379 + ]
380 + ]
381 + ]
382 + ];
401 383
402 384 $notices->add(
403 385 'migration',
404 386 $_migration_notice,
405 - array(
387 + [
406 388 'start' => $notices->time(),
407 389 'recurrence' => false,
408 - 'dismissible' => true,
409 - )
390 + 'dismissible' => true
391 + ]
410 392 );
411 393 }
412 394
413 395 /**
414 - *
415 396 * Opt-In Notice
416 397 */
417 398 $allow_tracking = get_option( 'wpins_allow_tracking' );
418 - if ( null != $this->insights && ! isset( $allow_tracking['betterdocs'] ) ) {
399 + if ( $this->insights != null && ! isset( $allow_tracking['betterdocs'] ) ) {
419 400 $notices->add(
420 401 'opt_in',
421 - array( $this->insights, 'notice' ),
422 - array(
402 + [ $this->insights, 'notice' ],
403 + [
423 404 'classes' => 'updated put-dismiss-notice',
424 405 'start' => $notices->time(),
425 406 'refresh' => BETTERDOCS_VERSION,
426 407 'dismissible' => true,
@@ -425,48 +406,55 @@
425 406 'refresh' => BETTERDOCS_VERSION,
426 407 'dismissible' => true,
427 408 'do_action' => 'wpdeveloper_notice_clicked_for_betterdocs',
428 409 'display_if' => ! function_exists( 'betterdocs_pro' ),
429 - 'screens' => array( 'dashboard' ),
430 - )
410 + 'screens' => [ 'dashboard' ]
411 + ]
431 412 );
432 413 }
433 414
434 - $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>';
435 - $_summer_campaign_notice = array(
415 + // $blackfriday_message = '<div class="betterdocs-notice-body"><p style="margin-top: 0; margin-bottom: 0;"><strong>🛍️ Black Friday Specials:</strong> Save up to 35% OFF on BetterDocs PRO plans & manage docs/FAQs seamlessly.</p><a class="button button-primary" href="https://betterdocs.co/bfcm24-pricing" target="_blank"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
416 + // <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"/>
417 + // <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"/>
418 + // </svg> Upgrade To PRO</a></div>';
419 + // $_blackfriday_notice = [
420 + // 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
421 + // 'html' => $blackfriday_message
422 + // ];
423 +
424 + // $notices->add(
425 + // 'blackfriday24',
426 + // $_blackfriday_notice,
427 + // [
428 + // 'start' => $notices->time(),
429 + // 'recurrence' => false,
430 + // 'dismissible' => true,
431 + // 'refresh' => BETTERDOCS_VERSION,
432 + // 'expire' => strtotime( '11:59:59pm December 5, 2024' ),
433 + // 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
434 + // ]
435 + // );
436 +
437 + $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">
438 + <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"/>
439 + <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"/>
440 + </svg>Upgrade To PRO</a></div></div>';
441 + $_offer_notice = [
436 442 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
437 - 'html' => $summer_campaign_message,
438 - 'links' => array(
439 - 'support' => array(
440 - 'link' => 'https://betterdocs.co/summer2026-admin-notice',
441 - 'attributes' => array(
442 - 'target' => '_blank',
443 - 'class' => 'offer-button',
444 - ),
445 - 'label' => __( 'Upgrade To PRO Now', 'betterdocs' ),
446 - ),
447 - 'maybe_later' => array(
448 - 'label' => __( 'I’ll Grab It Later', 'betterdocs' ),
449 - 'attributes' => array(
450 - 'target' => '_blank',
451 - 'data-later' => true,
452 - 'class' => 'dismiss-btn',
453 - ),
454 - ),
455 - ),
456 - );
443 + 'html' => $offer_message
444 + ];
457 445
458 446 $notices->add(
459 - 'summer-campaign-26',
460 - $_summer_campaign_notice,
461 - array(
447 + '40k_offer',
448 + $_offer_notice,
449 + [
462 450 'start' => $notices->time(),
463 451 'recurrence' => false,
464 452 'dismissible' => true,
465 453 'refresh' => BETTERDOCS_VERSION,
466 - 'expire' => strtotime( '11:59:59pm June 25, 2026' ),
467 - 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ),
468 - )
454 + 'expire' => strtotime( '11:59:59pm April 30, 2025' ),
455 + 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
456 + ]
469 457 );
470 458
471 459 self::$cache_bank->create_account( $notices );
472 460 self::$cache_bank->calculate_deposits( $notices );
@@ -471,9 +459,9 @@
471 459 self::$cache_bank->create_account( $notices );
472 460 self::$cache_bank->calculate_deposits( $notices );
473 461 if ( method_exists( self::$cache_bank, 'clear_notices_in_' ) ) {
474 462 self::$cache_bank->clear_notices_in_(
475 - array(
463 + [
476 464 'toplevel_page_betterdocs-dashboard',
477 465 'admin_page_betterdocs-admin',
478 466 'betterdocs_page_betterdocs-admin',
479 467 'betterdocs_page_betterdocs-settings',
@@ -480,13 +468,11 @@
480 468 'betterdocs_page_betterdocs-faq',
481 469 'betterdocs_page_betterdocs-analytics',
482 470 'betterdocs_page_betterdocs-glossaries',
483 471 'betterdocs_page_betterdocs-ai-chatbot',
484 - 'betterdocs_page_betterdocs-doc-categories',
485 - 'betterdocs_page_betterdocs-doc-tags',
486 472 'edit-doc_category',
487 - 'edit-doc_tag',
488 - ),
473 + 'edit-doc_tag'
474 + ],
489 475 $notices,
490 476 true
491 477 );
492 478 }
@@ -491,85 +477,31 @@
491 477 );
492 478 }
493 479 }
494 480
495 - /**
496 - * Resolve the admin dark-mode preference.
497 - *
498 - * The mode switcher stores the choice in a client cookie (no DB write, shared
499 - * across every admin screen). Fall back to the legacy
500 - * `betterdocs_settings['dark_mode']` value for installs that set it before this
501 - * change and haven't toggled since.
502 - *
503 - * @return bool
504 - */
505 - public function is_dark_mode() {
506 - if ( isset( $_COOKIE['betterdocs_admin_dark_mode'] ) ) {
507 - return '1' === $_COOKIE['betterdocs_admin_dark_mode']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
508 - }
509 -
510 - $saved = get_option( 'betterdocs_settings', array() );
511 - return ! empty( $saved['dark_mode'] );
512 - }
513 -
514 - /**
515 - * Whether the knowledge base is genuinely empty (no doc categories and no
516 - * non-trash docs). Localized to the admin so the All Docs panel can render a
517 - * skeleton shaped like the "No Category Found" empty card on first paint —
518 - * instead of a category/docs skeleton it would immediately replace — without
519 - * waiting for the REST fetch to reveal the count.
520 - *
521 - * @return bool
522 - */
523 - public function kb_is_empty() {
524 - $cats = wp_count_terms( array( 'taxonomy' => 'doc_category', 'hide_empty' => false ) );
525 - $cats = is_wp_error( $cats ) ? 0 : (int) $cats;
526 - if ( $cats > 0 ) {
527 - return false;
528 - }
529 -
530 - $counts = (array) wp_count_posts( 'docs' );
531 - $total = 0;
532 - foreach ( array( 'publish', 'future', 'draft', 'pending', 'private' ) as $status ) {
533 - $total += isset( $counts[ $status ] ) ? (int) $counts[ $status ] : 0;
534 - }
535 -
536 - return 0 === $total;
537 - }
538 -
539 481 public function body_classes( $classes ) {
540 - $dark_mode = $this->is_dark_mode();
482 + $saved_settings = get_option( 'betterdocs_settings', false );
483 + $dark_mode = isset( $saved_settings['dark_mode'] ) ? $saved_settings['dark_mode'] : false;
484 + $dark_mode = ! empty( $dark_mode ) ? boolval( $dark_mode ) : false;
541 485 $current_screen_id = get_current_screen() != null ? str_replace( 'betterdocs_page_', '', str_replace( 'toplevel_page_', '', str_replace( 'admin_page_', '', get_current_screen()->id ) ) ) : '';
542 - /**
543 - * Filter the list of (prefix-stripped) screen ids that receive the
544 - * `betterdocs-admin` body class (and dark-mode class). Pro/add-ons can
545 - * register their own React admin pages, e.g. the Knowledge Base page.
546 - *
547 - * @param string[] $registered_screens Screen ids with the page prefix removed.
548 - */
549 - $registered_screens = apply_filters( 'betterdocs_admin_screen_slugs', array(
550 - 'betterdocs-settings',
551 - 'betterdocs-admin',
552 - 'betterdocs-dashboard',
553 - 'betterdocs-analytics',
554 - 'betterdocs-glossaries',
555 - 'betterdocs-faq',
556 - 'betterdocs-doc-categories',
557 - 'betterdocs-doc-tags',
558 - 'edit-doc_category',
559 - 'edit-doc_tag',
560 - 'edit-knowledge_base',
561 - 'betterdocs-ai-chatbot',
562 - ) );
486 + $registered_screens = [
487 + 'betterdocs-settings',
488 + 'betterdocs-admin',
489 + 'betterdocs-dashboard',
490 + 'betterdocs-analytics',
491 + 'betterdocs-glossaries',
492 + 'betterdocs-faq',
493 + 'edit-doc_category',
494 + 'edit-doc_tag',
495 + 'edit-knowledge_base',
496 + 'betterdocs-ai-chatbot'
497 + ];
563 498
564 - if ( in_array( $current_screen_id, $registered_screens ) ) {
565 - $classes .= ' betterdocs-admin ';
566 - }
499 + if( in_array( $current_screen_id, $registered_screens ) ) {
500 + $classes .= ' betterdocs-admin ';
501 + }
567 502
568 - // Dark mode also applies on the Quick Setup wizard, whose self-scoped chrome
569 - // keys off `.betterdocs_page_betterdocs-setup.betterdocs-dark-mode`.
570 - $dark_screens = array_merge( $registered_screens, array( 'betterdocs-setup' ) );
571 - if ( $dark_mode && in_array( $current_screen_id, $dark_screens, true ) ) {
503 + if ( $dark_mode === true && in_array( $current_screen_id, $registered_screens ) ) {
572 504 $classes .= ' betterdocs-dark-mode ';
573 505 }
574 506
575 507 return $classes;
@@ -584,11 +516,11 @@
584 516 * @since 1.0.0
585 517 */
586 518 public function set_custom_edit_action_columns( $columns ) {
587 519 unset( $columns['comments'] );
588 - $new_columns = array();
520 + $new_columns = [];
589 521 foreach ( $columns as $key => $value ) {
590 - if ( 'date' == $key ) {
522 + if ( $key == 'date' ) {
591 523 $new_columns['betterdocs_word_count'] = __( 'Word Count', 'betterdocs' ); // put the tags column before it
592 524 $new_columns['betterdocs_reaction'] = __( 'Reactions', 'betterdocs' );
593 525 }
594 526 $new_columns[ $key ] = $value;
@@ -600,29 +532,26 @@
600 532 public function manage_custom_columns( $column, $post_id ) {
601 533 global $wpdb;
602 534 switch ( $column ) {
603 535 case 'betterdocs_word_count':
604 - $content_without_html_tags = trim( wp_strip_all_tags( get_post_field( 'post_content', $post_id ) ) );
536 + $content_without_html_tags = trim( strip_tags( get_post_field( 'post_content', $post_id ) ) );
605 537 preg_match_all( '/<[^>]*>|[\p{L}\p{M}]+/u', $content_without_html_tags, $matches );
606 - $total_words = ! empty( $matches[0] ) ? count( $matches[0] ) : count( array() );
538 + $total_words = ! empty( $matches[0] ) ? count( $matches[0] ) : count( [] );
607 539 $word_count = $total_words;
608 540 echo '<span>' . esc_html( intval( $word_count ) ) . '</span>';
609 541 break;
610 542 case 'betterdocs_reaction':
611 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- per-post analytics aggregation rendered in admin list table; cache would mask live reactions.
543 + $where = "WHERE post_id='" . esc_sql( $post_id ) . "'";
612 544 $analytics = $wpdb->get_results(
613 - $wpdb->prepare(
614 - "SELECT
615 - sum(impressions) as totalViews,
616 - sum(unique_visit) as totalUniqueViews,
617 - sum(happy + sad + normal) as totalReactions,
618 - sum(happy) as totalHappy,
619 - sum(normal) as totalNormal,
620 - sum(sad) as totalSad
621 - FROM {$wpdb->prefix}betterdocs_analytics
622 - WHERE post_id = %d",
623 - $post_id
624 - )
545 + "SELECT
546 + sum(impressions) as totalViews,
547 + sum(unique_visit) as totalUniqueViews,
548 + sum(happy + sad + normal) as totalReactions,
549 + sum(happy) as totalHappy,
550 + sum(normal) as totalNormal,
551 + sum(sad) as totalSad
552 + FROM {$wpdb->prefix}betterdocs_analytics
553 + $where"
625 554 );
626 555
627 556 echo '<ul class="reactions-count">
628 557 <li>
@@ -678,22 +607,22 @@
678 607 * @return void
679 608 * @since 1.0.0
680 609 */
681 610 public function styles( $hook ) {
682 - $this->assets->enqueue( 'betterdocs-global', 'admin/css/global.css', array(), 'all' );
611 + $this->assets->enqueue( 'betterdocs-global', 'admin/css/global.css', [], 'all' );
683 612
684 613 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
685 614 return;
686 615 }
687 616
688 - $this->assets->enqueue( 'betterdocs-select2', 'vendor/css/select2.min.css', array(), 'all' );
689 - $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/css/daterangepicker.css', array(), 'all' );
690 - $this->assets->enqueue( 'betterdocs-old', 'admin/css/betterdocs.css', array(), 'all' );
617 + $this->assets->enqueue( 'betterdocs-select2', 'vendor/css/select2.min.css', [], 'all' );
618 + $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/css/daterangepicker.css', [], 'all' );
619 + $this->assets->enqueue( 'betterdocs-old', 'admin/css/betterdocs.css', [], 'all' );
691 620
692 621 /**
693 - * This scripts enqueued for Dashboard App.
694 - */
695 - $this->assets->enqueue( 'betterdocs', 'admin/css/dashboard.css', array( 'betterdocs-old' ), '', BETTERDOCS_VERSION );
622 + * This scripts enqueued for Dashboard App.
623 + */
624 + $this->assets->enqueue( 'betterdocs', 'admin/css/dashboard.css', [ 'betterdocs-old' ], '', BETTERDOCS_VERSION );
696 625 $this->assets->enqueue( 'betterdocs-icons', 'admin/btd-icon/style.css' );
697 626 }
698 627
699 628 /**
@@ -704,70 +633,26 @@
704 633 * @return void
705 634 * @since 1.0.0
706 635 */
707 636 public function scripts( $hook ) {
708 - // Classic-UI screens that should offer a "Switch to BetterDocs UI"
709 - // button: All Docs, FAQ list, FAQ groups, Product FAQ groups,
710 - // Doc Categories, Doc Tags. Maps each to the React admin page to
711 - // return to; $switch_args carries extra query args (e.g. the FAQ
712 - // Builder tab) appended to the React page URL.
713 - $switch_page = '';
714 - $switch_args = array();
715 - if ( 'edit.php' === $hook && 'docs' === get_post_type() ) {
716 - $switch_page = 'betterdocs-admin';
717 - } elseif ( 'edit.php' === $hook && 'betterdocs_faq' === get_post_type() ) {
718 - $switch_page = 'betterdocs-faq';
719 - } elseif ( 'edit-tags.php' === $hook ) {
720 - $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
721 - $taxonomy = $screen && ! empty( $screen->taxonomy )
722 - ? $screen->taxonomy
723 - : ( isset( $_GET['taxonomy'] ) ? sanitize_key( wp_unslash( $_GET['taxonomy'] ) ) : '' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
724 - if ( 'betterdocs_faq_category' === $taxonomy ) {
725 - $switch_page = 'betterdocs-faq';
726 - } elseif ( 'betterdocs_product_faq_category' === $taxonomy ) {
727 - // Product FAQ groups live on the FAQ Builder's WooCommerce tab.
728 - $switch_page = 'betterdocs-faq';
729 - $switch_args = array( 'faq_tab' => 'woocommerce' );
730 - } elseif ( 'doc_category' === $taxonomy ) {
731 - $switch_page = 'betterdocs-doc-categories';
732 - } elseif ( 'doc_tag' === $taxonomy ) {
733 - $switch_page = 'betterdocs-doc-tags';
734 - }
735 - }
736 -
737 - /**
738 - * Allow Pro/add-ons to map their own classic-UI taxonomy screens to a
739 - * React admin page for the "Switch to BetterDocs UI" button — e.g. the
740 - * Knowledge Base taxonomy, which only exists when Pro is active.
741 - *
742 - * @param string $switch_page React page slug, or '' for no switcher.
743 - * @param string $hook Current admin page hook.
744 - */
745 - $switch_page = apply_filters( 'betterdocs_classic_switch_page', $switch_page, $hook );
746 -
747 - if ( $switch_page ) {
637 + if ( ( $hook === 'edit.php' ) && get_post_type() == 'docs' ) {
748 638 $this->assets->enqueue(
749 639 'betterdocs-switcher',
750 640 'admin/js/switcher.js',
751 - array(
752 - 'jquery',
753 - )
641 + [
642 + 'jquery'
643 + ]
754 644 );
755 645
756 646 $this->assets->localize(
757 647 'betterdocs-switcher',
758 648 'betterdocsSwitcher',
759 - array(
649 + [
760 650 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
761 - 'page' => $switch_page,
762 - 'url' => add_query_arg(
763 - array_merge( array( 'page' => $switch_page ), $switch_args ),
764 - admin_url( 'admin.php' )
765 - ),
766 651 'site_address' => get_bloginfo( 'url' ),
767 652 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
768 - 'betterdocs_pro_version' => betterdocs()->pro_version(),
769 - )
653 + 'betterdocs_pro_version' => betterdocs()->pro_version()
654 + ]
770 655 );
771 656
772 657 return;
773 658 }
@@ -777,106 +662,82 @@
777 662 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
778 663 return;
779 664 }
780 665
781 - wp_enqueue_media(); // load early to fix problems with media upload issues on settings for WordPress 6.0.9
666 + wp_enqueue_media(); // load early to fix problems with media upload issues on settings for wordpress 6.0.9
782 667 $this->assets->register( 'betterdocs-admin', 'admin/js/dashboard.js' );
783 668
784 669 $saved_settings = get_option( 'betterdocs_settings', false );
785 - $dark_mode = $this->is_dark_mode();
670 + $dark_mode = $saved_settings['dark_mode'] ?? false;
671 + $dark_mode = ! empty( $dark_mode ) && boolval( $dark_mode );
786 672 $this->assets->localize(
787 673 'betterdocs-admin',
788 674 'betterdocs_admin',
789 - array(
675 + [
790 676 'ajaxurl' => admin_url( 'admin-ajax.php' ),
791 677 'doc_cat_order_nonce' => wp_create_nonce( 'doc_cat_order_nonce' ),
792 678 'knowledge_base_order_nonce' => wp_create_nonce( 'knowledge_base_order_nonce' ),
793 - 'paged' => isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- pagination read from URL.
794 - 'per_page_id' => 'edit_doc_category_per_page',
795 - 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
796 - 'dark_mode' => $dark_mode,
797 - 'kb_is_empty' => $this->kb_is_empty(),
798 - 'text' => __( 'Copied!', 'betterdocs' ),
799 - 'test_report' => __( 'Test Report!', 'betterdocs' ),
800 - 'sending' => __( 'Sending...', 'betterdocs' ),
801 - 'dir_url' => BETTERDOCS_ABSURL,
802 - 'rest_url' => esc_url_raw( rest_url() ),
803 - 'free_version' => betterdocs()->version,
804 - 'generate_data_url' => get_rest_url( null, '/betterdocs/v1/create-sample-docs' ),
805 - 'ai_sample_docs' => array(
806 - 'enabled' => (bool) betterdocs()->settings->get( 'enable_ai_sample_docs', true ),
807 - 'rest_base' => esc_url_raw( get_rest_url( null, '/betterdocs/v1/sample-docs' ) ),
808 - ),
809 - 'nonce' => wp_create_nonce( 'wp_rest' ),
810 - 'sync_nonce' => wp_create_nonce( 'ai_chatbot_embed' ),
811 - 'count_all_docs' => array_sum( (array) wp_count_posts( 'docs' ) ),
812 - 'count_all_faq' => array_sum( (array) wp_count_posts( 'betterdocs_faq' ) ),
813 - 'faq_order' => get_option( 'betterdocs_faq_order', 'default' ),
814 - 'count_new_docs' => $this->get_not_synced_docs_count(),
815 - 'admin_url' => admin_url(),
816 - 'ia_preview' => betterdocs()->settings->get( 'ia_enable_preview', false ),
817 - 'multiple_kb' => betterdocs()->settings->get( 'multiple_kb' ),
818 - 'previewMode' => betterdocs()->settings->get( 'ia_enable_preview', false ),
819 - 'dashboard_mode' => get_option( 'dashboard_mode' ),
820 - 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
821 - 'betterdocs_pro_version' => betterdocs()->pro_version(),
822 - 'analytics_older' => version_compare( betterdocs()->pro_version(), '3.3.4', '<=' ),
823 - 'disabled_embed_model_option' => get_option( 'disabled_embed_model_option' ),
824 - 'betterdocs_ChatBot_plugin' => is_plugin_active( 'betterdocs-ai-chatbot/betterdocs-ai-chatbot.php' ),
825 - 'is_woocommerce_active' => class_exists( 'WooCommerce' ),
826 - 'total_doc_category_terms' => wp_count_terms( 'doc_category' ),
827 - 'current_admin_language' => Helper::get_current_admin_language(),
828 - 'is_multilingual' => Helper::is_multilingual_active(),
829 - 'languages' => Helper::get_admin_languages(),
830 - )
679 + 'paged' => isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Missing
680 + 'per_page_id' => 'edit_doc_category_per_page',
681 + 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
682 + 'dark_mode' => $dark_mode,
683 + 'text' => __( 'Copied!', 'betterdocs' ),
684 + 'test_report' => __( 'Test Report!', 'betterdocs' ),
685 + 'sending' => __( 'Sending...', 'betterdocs' ),
686 + 'dir_url' => BETTERDOCS_ABSURL,
687 + 'rest_url' => esc_url_raw( rest_url() ),
688 + 'free_version' => betterdocs()->version,
689 + 'generate_data_url' => get_rest_url( null, '/betterdocs/v1/create-sample-docs' ),
690 + 'nonce' => wp_create_nonce( 'wp_rest' ),
691 + 'sync_nonce' => wp_create_nonce( 'ai_chatbot_embed' ),
692 + 'count_all_docs' => array_sum((array) wp_count_posts('docs')),
693 + 'count_all_faq' => array_sum((array) wp_count_posts('betterdocs_faq')),
694 + 'count_new_docs' => count(get_option('saved_docs_post_ids', [])) + count(get_option('betterdocs_ai_chatbot_error_posts', [])),
695 + 'admin_url' => admin_url(),
696 + 'ia_preview' => betterdocs()->settings->get( 'ia_enable_preview', false ),
697 + 'multiple_kb' => betterdocs()->settings->get( 'multiple_kb' ),
698 + 'previewMode' => betterdocs()->settings->get( 'ia_enable_preview', false ),
699 + 'dashboard_mode' => get_option( 'dashboard_mode' ),
700 + 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
701 + 'betterdocs_pro_version' => betterdocs()->pro_version(),
702 + 'analytics_older' => version_compare( betterdocs()->pro_version(), '3.3.4', '<=' ),
703 + 'disabled_embed_model_option' => get_option('disabled_embed_model_option'),
704 + 'betterdocs_ChatBot_plugin' => is_plugin_active( 'betterdocs-ai-chatbot/betterdocs-ai-chatbot.php' ),
705 + 'total_doc_category_terms' => wp_count_terms( 'doc_category')
706 + ]
831 707 );
832 708
833 709 // If wp-date (which includes moment.js) is not registered, enqueue your custom moment.js
834 710 if ( ! wp_script_is( 'wp-date', 'registered' ) ) {
835 - $this->assets->enqueue( 'moment', 'vendor/js/moment.min.js', array() );
711 + $this->assets->enqueue( 'moment', 'vendor/js/moment.min.js', [] );
836 712 }
837 713 wp_enqueue_script( 'betterdocs-admin' );
838 714
839 715 /**
840 - * Duplicate Codes Need to Be Removed From Here Onwards
841 - */
716 + * Duplicate Codes Need to Be Removed From Here Onwards
717 + */
842 718
843 - // FAQ Builder Related Localization
719 + //FAQ Builder Related Localization
844 720 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/css/faq.css' );
845 721 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/js/faq.js' );
846 722
847 - // Load the classic editor (TinyMCE + QuickTags) so the FAQ rich-text editor can mount via wp.editor.initialize().
848 - if ( function_exists( 'wp_enqueue_editor' ) ) {
849 - wp_enqueue_editor();
850 - }
851 - if ( function_exists( 'wp_enqueue_media' ) ) {
852 - wp_enqueue_media();
853 - }
854 -
855 723 // removing emoji support
856 724 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
857 725 remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
858 726
859 - // Get settings and remove unnecessary keys
860 - $betterdocs_settings = get_option( 'betterdocs_settings', false );
861 - if ( is_array( $betterdocs_settings ) && ! current_user_can( 'edit_docs_settings' ) ) {
862 - unset( $betterdocs_settings['ai_autowrite_api_key'] );
863 - unset( $betterdocs_settings['ai_chatbot_api_key'] );
864 - }
865 -
866 727 betterdocs()->assets->localize(
867 728 'betterdocs-admin-faq',
868 729 'betterdocsFaq',
869 - array(
730 + [
870 731 'dir_url' => BETTERDOCS_ABSURL,
871 732 'rest_url' => esc_url_raw( rest_url() ),
872 733 'free_version' => betterdocs()->version,
873 734 'nonce' => wp_create_nonce( 'wp_rest' ),
874 - 'betterdocs_settings' => $betterdocs_settings,
875 - )
735 + 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
736 + ]
876 737 );
877 738
878 - // Glossaries Related Localization
739 + //Glossaries Related Localization
879 740 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/css/faq.css' );
880 741
881 742 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/js/glossaries.js' );
882 743
@@ -882,15 +743,15 @@
882 743
883 744 betterdocs()->assets->localize(
884 745 'betterdocs-admin-glossaries',
885 746 'betterdocsGlossary',
886 - array(
747 + [
887 748 'dir_url' => BETTERDOCS_ABSURL,
888 749 'rest_url' => esc_url_raw( rest_url() ),
889 750 'free_version' => betterdocs()->version,
890 751 'nonce' => wp_create_nonce( 'wp_rest' ),
891 - 'betterdocs_settings' => $betterdocs_settings,
892 - )
752 + 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
753 + ]
893 754 );
894 755 }
895 756
896 757 /**
@@ -899,31 +760,31 @@
899 760 * @return void
900 761 * @since 1.0.0
901 762 */
902 763 public function header( $admin_tab_name ) {
903 - $quick_links = array(
764 + $quick_links = [
904 765 'switch_view' => sprintf(
905 766 '<a href="%s" class="betterdocs-button betterdocs-button-secondary">%s</a>',
906 767 add_query_arg(
907 - array(
768 + [
908 769 'post_type' => 'docs',
909 - 'bdocs_view' => 'classic',
910 - ),
770 + 'bdocs_view' => 'classic'
771 + ],
911 772 'edit.php'
912 773 ),
913 774 __( 'Switch to Classic UI', 'betterdocs' )
914 775 ),
915 - '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' ) ),
916 - );
776 + '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' ) )
777 + ];
917 778
918 779 $quick_links = apply_filters( 'betterdocs_quick_links', $quick_links );
919 780
920 781 betterdocs()->views->get(
921 782 'admin/header',
922 - array(
783 + [
923 784 'quick_links' => $quick_links,
924 - 'active_tab' => $admin_tab_name,
925 - )
785 + 'active_tab' => $admin_tab_name
786 + ]
926 787 );
927 788 }
928 789
929 790 /**
@@ -932,17 +793,17 @@
932 793 * @return void
933 794 * @since 1.0.0
934 795 */
935 796 public function menus() {
936 - $default_args = array(
797 + $default_args = [
937 798 'page_title' => 'BetterDocs',
938 799 'menu_title' => 'BetterDocs',
939 - 'capability' => 'edit_docs', // Unified capability
800 + 'capability' => 'edit_docs', // Unified capability
940 801 'menu_slug' => $this->slug,
941 - 'callback' => array( $this, 'output' ),
802 + 'callback' => [ $this, 'output' ],
942 803 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
943 - 'position' => 5,
944 - );
804 + 'position' => 5
805 + ];
945 806
946 807 $_menu_position = 5;
947 808 global $submenu;
948 809
@@ -949,23 +810,23 @@
949 810 // Always register both UI endpoints
950 811 $this->register_modern_ui_fallback();
951 812
952 813 foreach ( $this->menu_list() as $key => $value ) {
953 - if ( 'betterdocs' === $key ) {
814 + if ( $key === 'betterdocs' ) {
954 815 $callable = 'add_menu_page';
955 816 $value = wp_parse_args( $value, $default_args );
956 817 call_user_func_array( $callable, $value );
957 818 } else {
958 - $is_core_page = strpos( $value['menu_slug'], '?' ) !== false;
819 + $is_core_page = strpos($value['menu_slug'], '?') !== false;
959 820
960 - if ( $is_core_page ) {
821 + if ($is_core_page) {
961 822 // Add classic UI directly
962 - $submenu[ $this->slug ][] = array(
823 + $submenu[$this->slug][] = [
963 824 $value['menu_title'],
964 825 $value['capability'],
965 826 $value['menu_slug'],
966 - $value['page_title'],
967 - );
827 + $value['page_title']
828 + ];
968 829 } else {
969 830 // Add modern UI through WordPress API
970 831 add_submenu_page(
971 832 $this->slug,
@@ -975,9 +836,9 @@
975 836 $value['menu_slug'],
976 837 $value['callback']
977 838 );
978 839 }
979 - ++$_menu_position;
840 + $_menu_position++;
980 841 }
981 842 }
982 843 }
983 844
@@ -984,21 +845,21 @@
984 845 private function register_modern_ui_fallback() {
985 846 // Add the submenu with valid parent slug
986 847 add_submenu_page(
987 848 'betterdocs', // Valid parent slug
988 - __( 'All Docs', 'betterdocs' ),
849 + __('All Docs', 'betterdocs'),
989 850 '', // Empty menu title hides it
990 851 'edit_docs',
991 852 'betterdocs-admin',
992 - array( $this, 'output' )
853 + [ $this, 'output' ]
993 854 );
994 855
995 856 // Hide the menu item from appearing in the admin sidebar
996 857 global $submenu;
997 - if ( isset( $submenu['betterdocs'] ) ) {
998 - foreach ( $submenu['betterdocs'] as $key => $item ) {
999 - if ( 'betterdocs-admin' === $item[2] ) {
1000 - unset( $submenu['betterdocs'][ $key ] );
858 + if (isset($submenu['betterdocs'])) {
859 + foreach ($submenu['betterdocs'] as $key => $item) {
860 + if ($item[2] === 'betterdocs-admin') {
861 + unset($submenu['betterdocs'][$key]);
1001 862 break;
1002 863 }
1003 864 }
1004 865 }
@@ -1011,17 +872,17 @@
1011 872 * @since 1.0.0
1012 873 */
1013 874 public function output() {
1014 875 if ( betterdocs()->is_pro_active()
1015 - && version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
1016 - && get_current_screen()->id == 'betterdocs_page_betterdocs-analytics' ) {
876 + && version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
877 + && get_current_screen()->id == 'betterdocs_page_betterdocs-analytics' ) {
1017 878 betterdocs_pro()->views->get( 'admin/analytics-pro' );
1018 879 } else {
1019 880 betterdocs()->views->get(
1020 881 'admin/main',
1021 - array(
1022 - 'admin_ui' => 'dnd',
1023 - )
882 + [
883 + 'admin_ui' => 'dnd'
884 + ]
1024 885 );
1025 886 }
1026 887 }
1027 888
@@ -1034,10 +895,11 @@
1034 895 * @param array $callback
1035 896 *
1036 897 * @return array
1037 898 * @since 2.5.0
899 + *
1038 900 */
1039 - private function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null, $optional = array() ) {
901 + private function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null, $optional = [] ) {
1040 902 return Helper::normalize_menu( $title, $slug, $cap, $callback, $optional );
1041 903 }
1042 904
1043 905 /**
@@ -1046,34 +908,34 @@
1046 908 * @return array
1047 909 * @since 1.0.0
1048 910 */
1049 911 private function menu_list() {
1050 - $parent_slug = array();
912 + $parent_slug = [];
1051 913
1052 - $betterdocs_admin_pages = array(
1053 - 'betterdocs' => array(
914 + $betterdocs_admin_pages = [
915 + 'betterdocs' => [
1054 916 'menu_slug' => $this->slug,
1055 917 'page_title' => 'BetterDocs',
1056 918 'menu_title' => 'BetterDocs',
1057 919 'capability' => 'edit_docs',
1058 - 'callback' => array( $this, 'output' ),
920 + 'callback' => [ $this, 'output' ],
1059 921 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
1060 - 'position' => 5,
1061 - ),
1062 - 'dashboard' => $this->normalize_menu(
922 + 'position' => 5
923 + ],
924 + 'dashboard' => $this->normalize_menu(
1063 925 __( 'Dashboard', 'betterdocs' ),
1064 926 'betterdocs-dashboard',
1065 927 'edit_docs',
1066 - array(
928 + [
1067 929 $this,
1068 - 'output',
1069 - )
930 + 'output'
931 + ]
1070 932 ),
1071 933 'all_docs' => $this->normalize_menu(
1072 934 __( 'All Docs', 'betterdocs' ),
1073 935 $this->ui_slug(),
1074 936 'edit_docs',
1075 - array( $this, 'output' ),
937 + [ $this, 'output' ],
1076 938 $parent_slug
1077 939 ),
1078 940 'add_new' => $this->normalize_menu(
1079 941 __( 'Add New', 'betterdocs' ),
@@ -1080,28 +942,24 @@
1080 942 'post-new.php?post_type=docs'
1081 943 ),
1082 944 'categories' => $this->normalize_menu(
1083 945 __( 'Categories', 'betterdocs' ),
1084 - 'betterdocs-doc-categories',
1085 - 'manage_doc_terms',
1086 - array( $this, 'output' ),
1087 - $parent_slug
946 + 'edit-tags.php?taxonomy=doc_category&post_type=docs',
947 + 'manage_doc_terms'
1088 948 ),
1089 949 'tags' => $this->normalize_menu(
1090 950 __( 'Tags', 'betterdocs' ),
1091 - 'betterdocs-doc-tags',
1092 - 'manage_doc_terms',
1093 - array( $this, 'output' ),
1094 - $parent_slug
951 + 'edit-tags.php?taxonomy=doc_tag&post_type=docs',
952 + 'manage_doc_terms'
1095 953 ),
1096 954 'settings' => $this->normalize_menu(
1097 955 __( 'Settings', 'betterdocs' ),
1098 956 'betterdocs-settings',
1099 957 'edit_docs_settings',
1100 - array(
958 + [
1101 959 $this,
1102 - 'output',
1103 - ),
960 + 'output'
961 + ],
1104 962 $parent_slug
1105 963 ),
1106 964 'analytics' => $this->normalize_menu(
1107 965 __( 'Analytics', 'betterdocs' ),
@@ -1106,12 +964,12 @@
1106 964 'analytics' => $this->normalize_menu(
1107 965 __( 'Analytics', 'betterdocs' ),
1108 966 'betterdocs-analytics',
1109 967 'read_docs_analytics',
1110 - array(
968 + [
1111 969 $this,
1112 - 'output',
1113 - ),
970 + 'output'
971 + ],
1114 972 $parent_slug
1115 973 ),
1116 974 'faq' => $this->normalize_menu(
1117 975 __( 'FAQ Builder', 'betterdocs' ),
@@ -1116,15 +974,15 @@
1116 974 'faq' => $this->normalize_menu(
1117 975 __( 'FAQ Builder', 'betterdocs' ),
1118 976 'betterdocs-faq',
1119 977 'read_faq_builder',
1120 - array(
978 + [
1121 979 $this,
1122 - 'output',
1123 - ),
980 + 'output'
981 + ],
1124 982 $parent_slug
1125 - ),
1126 - );
983 + )
984 + ];
1127 985
1128 986 if ( betterdocs()->is_pro_active() && betterdocs()->settings->get( 'enable_glossaries' ) == true ) {
1129 987 $betterdocs_admin_pages['glossaries'] = $this->normalize_menu(
1130 988 __( 'Glossaries', 'betterdocs' ),
@@ -1129,48 +987,50 @@
1129 987 $betterdocs_admin_pages['glossaries'] = $this->normalize_menu(
1130 988 __( 'Glossaries', 'betterdocs' ),
1131 989 'betterdocs-glossaries',
1132 990 'read_docs_analytics',
1133 - array(
991 + [
1134 992 $this,
1135 - 'output',
1136 - ),
993 + 'output'
994 + ],
1137 995 $parent_slug
1138 996 );
1139 997 }
1140 998
1141 - if ( ! betterdocs()->is_chatbot_active() ) {
1142 - $betterdocs_admin_pages['ai_chatbot'] = $this->normalize_menu(
1143 - __( 'AI Chatbot', 'betterdocs' ),
1144 - 'betterdocs-ai-chatbot',
1145 - 'edit_docs_settings',
1146 - array(
999 +
1000 + if (!betterdocs()->is_chatbot_active()) {
1001 + $betterdocs_admin_pages['ai_chatbot'] = $this->normalize_menu(
1002 + __('AI Chatbot', 'betterdocs'),
1003 + 'betterdocs-ai-chatbot',
1004 + 'edit_docs_settings',
1005 + [
1147 1006 $this,
1148 - 'output',
1149 - ),
1150 - $parent_slug
1151 - );
1152 - }
1007 + 'output'
1008 + ],
1009 + $parent_slug
1010 + );
1011 + }
1153 1012
1154 - return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages, array( $this, 'output' ), $parent_slug );
1155 - }
1013 + return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages, [$this, 'output'], $parent_slug);
1156 1014
1015 + }
1016 +
1157 1017 public function add_custom_classes_to_menu_items() {
1158 1018 global $menu, $submenu;
1159 1019
1160 - $menu_items = array(
1020 + $menu_items = [
1161 1021 'betterdocs' => 'betterdocs',
1162 1022 'betterdocs_page_all_docs' => 'betterdocs-all-docs',
1163 1023 'betterdocs_page_add_new' => 'betterdocs-add-new',
1164 - 'betterdocs-doc-categories' => 'betterdocs-categories',
1165 - 'betterdocs-doc-tags' => 'betterdocs-tags',
1024 + 'edit-tags.php?taxonomy=doc_category&post_type=docs' => 'betterdocs-categories',
1025 + 'edit-tags.php?taxonomy=doc_tag&post_type=docs' => 'betterdocs-tags',
1166 1026 'betterdocs-settings' => 'betterdocs-settings',
1167 1027 'betterdocs-analytics' => 'betterdocs-analytics',
1168 1028 'betterdocs-faq' => 'betterdocs-faq',
1169 1029 'betterdocs-glossaries' => 'betterdocs-glossaries',
1170 1030 'betterdocs-ai-chatbot' => 'betterdocs-ai-chatbot',
1171 - 'edit-tags.php?taxonomy=knowledge_base&post_type=docs' => 'betterdocs-multiplekb',
1172 - );
1031 + 'edit-tags.php?taxonomy=knowledge_base&post_type=docs' => 'betterdocs-multiplekb'
1032 + ];
1173 1033
1174 1034 foreach ( $menu as &$item ) {
1175 1035 if ( isset( $menu_items[ $item[2] ] ) ) {
1176 1036 if ( ! isset( $item[4] ) ) {
@@ -1200,12 +1060,12 @@
1200 1060 $menus['quick_setup'] = $this->normalize_menu(
1201 1061 __( 'Quick Setup', 'betterdocs' ),
1202 1062 'betterdocs-setup',
1203 1063 'delete_users',
1204 - array(
1064 + [
1205 1065 $this->container->get( SetupWizard::class ),
1206 - 'views',
1207 - )
1066 + 'views'
1067 + ]
1208 1068 );
1209 1069 }
1210 1070
1211 1071 return $menus;
@@ -1213,12 +1073,8 @@
1213 1073
1214 1074 public function insert_plugin_links( $links ) {
1215 1075 $links[] = '<a href="admin.php?page=betterdocs-settings">' . __( 'Settings', 'betterdocs' ) . '</a>';
1216 1076
1217 - if ( ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ) ) {
1218 - $links[] = '<a href="https://betterdocs.co/upgrade-to-pro-plugins-wp" target="_blank" style="color: #000; font-weight: bold;">' . __( 'Upgrade to Pro', 'betterdocs' ) . '</a>';
1219 - }
1220 -
1221 1077 return $links;
1222 1078 }
1223 1079
1224 1080 public function toolbar_menu( $admin_bar ) {
@@ -1245,22 +1101,17 @@
1245 1101 }
1246 1102
1247 1103 $slug = $this->settings->get( 'encyclopedia_root_slug' );
1248 1104
1249 - global $wp_rewrite;
1250 - if ( $wp_rewrite->using_index_permalinks() ) {
1251 - $slug = $wp_rewrite->index . '/' . $slug;
1252 - }
1253 -
1254 1105 $encyclopedia_url = home_url( $slug );
1255 1106
1256 1107 $admin_bar->add_node(
1257 - array(
1108 + [
1258 1109 'parent' => 'site-name',
1259 1110 'id' => 'view-docs',
1260 1111 'title' => __( 'Visit Documentation', 'betterdocs' ),
1261 - 'href' => $docs_url,
1262 - )
1112 + 'href' => $docs_url
1113 + ]
1263 1114 );
1264 1115
1265 1116 $is_enable_encyclopedia = betterdocs()->settings->get( 'enable_encyclopedia' );
1266 1117
@@ -1265,14 +1116,14 @@
1265 1116 $is_enable_encyclopedia = betterdocs()->settings->get( 'enable_encyclopedia' );
1266 1117
1267 1118 if ( $is_enable_encyclopedia && betterdocs()->is_pro_active() ) {
1268 1119 $admin_bar->add_node(
1269 - array(
1120 + [
1270 1121 'parent' => 'site-name',
1271 1122 'id' => 'view-encyclopedia',
1272 1123 'title' => __( 'Visit Encyclopedia', 'betterdocs' ),
1273 - 'href' => $encyclopedia_url,
1274 - )
1124 + 'href' => $encyclopedia_url
1125 + ]
1275 1126 );
1276 1127 }
1277 1128 }
1278 1129
@@ -1279,20 +1130,14 @@
1279 1130 /**
1280 1131 * Save last visited admin ui
1281 1132 *
1282 1133 * @since 3.0.1
1134 + *
1283 1135 */
1284 1136 public function save_admin_page() {
1285 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen detection.
1286 - $post_type = isset( $_GET['post_type'] ) ? sanitize_text_field( wp_unslash( $_GET['post_type'] ) ) : '';
1287 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen detection.
1288 - $bdocs_view = isset( $_GET['bdocs_view'] ) ? sanitize_text_field( wp_unslash( $_GET['bdocs_view'] ) ) : '';
1289 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only screen detection.
1290 - $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
1291 -
1292 - if ( 'docs' === $post_type && 'classic' === $bdocs_view ) {
1137 + if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'docs' && isset( $_GET['bdocs_view'] ) && $_GET['bdocs_view'] === 'classic' ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1293 1138 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'classic_ui' );
1294 - } elseif ( 'betterdocs-admin' === $page ) {
1139 + } elseif ( isset( $_GET['page'] ) && $_GET['page'] === 'betterdocs-admin' ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1295 1140 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'modern_ui' );
1296 1141 }
1297 1142 }
1298 1143
@@ -1302,20 +1147,18 @@
1302 1147 * @return string
1303 1148 * @since 3.0.1
1304 1149 */
1305 1150 public function ui_slug() {
1306 - $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
1307 - $docs_exist = get_posts(
1308 - array(
1309 - 'post_type' => 'docs',
1310 - 'post_status' => 'any',
1311 - 'numberposts' => 1,
1312 - )
1313 - );
1151 + $last_visited = get_user_meta(get_current_user_id(), 'last_visited_docs_admin_page', true);
1152 + $docs_exist = get_posts([
1153 + 'post_type' => 'docs',
1154 + 'post_status' => 'any',
1155 + 'numberposts' => 1
1156 + ]);
1314 1157
1315 - return ( 'modern_ui' === $last_visited || empty( $docs_exist ) )
1316 - ? 'betterdocs-admin'
1317 - : 'edit.php?post_type=docs&bdocs_view=classic';
1158 + return ($last_visited === 'modern_ui' || empty($docs_exist))
1159 + ? 'betterdocs-admin'
1160 + : 'edit.php?post_type=docs&bdocs_view=classic';
1318 1161 }
1319 1162
1320 1163 /**
1321 1164 * Resets a duplicate submenu in WordPress if the parent main menu and the first submenu permalink are not the same.
@@ -1325,9 +1168,9 @@
1325 1168 */
1326 1169 public function reset_submenu() {
1327 1170 global $submenu;
1328 1171
1329 - $docs = get_posts( array( 'post_type' => 'docs' ) );
1172 + $docs = get_posts( [ 'post_type' => 'docs' ] );
1330 1173 if ( count( $docs ) == 0 ) {
1331 1174 return;
1332 1175 }
1333 1176
@@ -1332,89 +1175,10 @@
1332 1175 }
1333 1176
1334 1177 $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
1335 1178
1336 - if ( 'classic_ui' === $last_visited && isset( $submenu['betterdocs-admin'] ) && in_array( 'betterdocs-admin', $submenu['betterdocs-admin'][0] ) ) {
1179 + if ( $last_visited === 'classic_ui' && isset( $submenu['betterdocs-admin'] ) && in_array( 'betterdocs-admin', $submenu['betterdocs-admin'][0] ) ) {
1337 1180 unset( $submenu['betterdocs-admin'][0] );
1338 1181 $submenu['betterdocs-admin'] = array_values( $submenu['betterdocs-admin'] );
1339 1182 }
1340 - }
1341 -
1342 - /**
1343 - * Initialize Black Friday Pointer
1344 - *
1345 - * @return void
1346 - * @since 3.7.0
1347 - */
1348 - private function init_black_friday_pointer() {
1349 - // Only initialize if conditions are met
1350 - if ( NoticePointers::should_display_notice() ) {
1351 - new NoticePointers();
1352 - }
1353 - }
1354 -
1355 - /**
1356 - * AJAX handler for dismissing Black Friday pointer
1357 - *
1358 - * @return void
1359 - * @since 3.7.0
1360 - */
1361 - public function ajax_dismiss_black_friday_pointer() {
1362 - // Verify nonce
1363 - $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
1364 - if ( ! wp_verify_nonce( $nonce, 'betterdocs_dismiss_pointer' ) ) {
1365 - wp_send_json_error( array( 'message' => __( 'Invalid nonce', 'betterdocs' ) ) );
1366 - }
1367 -
1368 - // Check if user has permission
1369 - if ( ! current_user_can( 'manage_options' ) && ! current_user_can( 'edit_docs' ) ) {
1370 - wp_send_json_error( array( 'message' => __( 'Permission denied', 'betterdocs' ) ) );
1371 - }
1372 -
1373 - // Get the introduction key
1374 - $introduction_key = isset( $_POST['introduction_key'] ) ? sanitize_text_field( wp_unslash( $_POST['introduction_key'] ) ) : '';
1375 -
1376 - if ( empty( $introduction_key ) ) {
1377 - wp_send_json_error( array( 'message' => __( 'Invalid introduction key', 'betterdocs' ) ) );
1378 - }
1379 -
1380 - // Set the introduction as viewed
1381 - NoticePointers::set_introduction_viewed( $introduction_key );
1382 -
1383 - // Clear the priority option so other plugins can set their priority
1384 - delete_option( '_wpdeveloper_plugin_pointer_priority' );
1385 -
1386 - wp_send_json_success( array( 'message' => __( 'Pointer dismissed successfully', 'betterdocs' ) ) );
1387 - }
1388 -
1389 - /**
1390 - * Get count of docs that are not yet synced
1391 - * Similar to Helper::get_not_synced_post_ids() in betterdocs-ai-chatbot plugin
1392 - *
1393 - * @return int
1394 - * @since 3.7.0
1395 - */
1396 - private function get_not_synced_docs_count() {
1397 - $new_post_ids = get_option( 'saved_docs_post_ids', array() );
1398 - $error_posts_data = get_option( 'betterdocs_ai_chatbot_error_posts', array() );
1399 -
1400 - // Extract post IDs from error posts (handle both old and new formats)
1401 - $error_post_ids = array();
1402 - if ( is_array( $error_posts_data ) && ! empty( $error_posts_data ) ) {
1403 - foreach ( $error_posts_data as $key => $value ) {
1404 - if ( is_numeric( $key ) && is_numeric( $value ) ) {
1405 - // Old format: numeric key with post ID as value
1406 - $error_post_ids[] = $value;
1407 - } elseif ( is_numeric( $key ) && is_array( $value ) && isset( $value['post_id'] ) ) {
1408 - // New format: post ID as key with structured data
1409 - $error_post_ids[] = $key;
1410 - } elseif ( is_numeric( $key ) ) {
1411 - // New format: post ID as key
1412 - $error_post_ids[] = $key;
1413 - }
1414 - }
1415 - }
1416 -
1417 - // Merge both arrays and remove duplicates, then count
1418 - return count( array_unique( array_merge( $new_post_ids, $error_post_ids ) ) );
1419 1183 }
1420 1184 }