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