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