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 +1113 -598 3.5.24.2.6 View file →
@@ -3,350 +3,569 @@
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 - * KBMigration
50 - *
51 - * @var KBMigration
52 - */
53 - private $kbmigration;
48 + /**
49 + * KBMigration
50 + *
51 + * @var KBMigration
52 + */
53 + private $kbmigration;
54 54
55 - /**
56 - * Enqueue
57 - * @var Enqueue
58 - */
59 - private $assets;
55 + /**
56 + * Enqueue
57 + * @var Enqueue
58 + */
59 + private $assets;
60 60
61 - /**
62 - * FAQBuilder
63 - * @var FAQBuilder
64 - */
65 - private $faq_builder;
61 + // modules
62 + protected $installer;
66 63
67 - public function __construct( Container $container, PostType $type, Enqueue $assets, Settings $settings, KBMigration $kbmigration ) {
68 - $this->container = $container;
69 - $this->assets = $assets;
70 - $this->settings = $settings;
71 - $this->kbmigration = $kbmigration;
72 - $this->slug = 'betterdocs-admin';
64 + /**
65 + * FAQBuilder
66 + * @var FAQBuilder
67 + */
68 + private $faq_builder;
69 + private $glossaries;
73 70
74 - add_action( 'init', [ $type, 'register' ], 9 );
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';
75 77
76 - $type->init();
77 - $type->admin_init();
78 + add_action( 'init', [ $type, 'register' ], 9 );
79 + add_action('rest_api_init', [$this, 'order_terms_in_wp_terms_admin_table']);
78 80
79 - $this->faq_builder = $this->container->get( FAQBuilder::class );
81 + $type->init();
82 + $type->admin_init();
80 83
81 - if ( ! is_admin() ) {
82 - return;
83 - }
84 + $this->faq_builder = $this->container->get( FAQBuilder::class );
85 + $this->glossaries = $this->container->get( Glossaries::class );
84 86
85 - $this->plugin_insights();
86 - add_action( 'admin_notices', [$this, 'compatibility_notices'] );
87 - // add_action( 'admin_init', [$this, 'notices'], 9 );
88 - add_filter( 'admin_init', [$this, 'save_admin_page'], 99 );
87 + if ( ! is_admin() ) {
88 + return;
89 + }
89 90
90 - add_action( 'admin_menu', [$this, 'menus'] );
91 - add_action( 'admin_menu', [$this, 'reset_submenu'] );
92 - add_filter( 'plugin_action_links_' . BETTERDOCS_PLUGIN_BASENAME, [$this, 'insert_plugin_links'] );
91 + $this->installer = new PluginInstaller();
93 92
94 - // $this->container->get( SetupWizard::class )->init();
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 );
95 97
96 - add_action( 'admin_enqueue_scripts', [ $this, 'styles' ] );
97 - add_action( 'admin_enqueue_scripts', [ $this, 'scripts' ] );
98 - add_action( 'betterdocs_listing_header', [ $this, 'header' ], 10, 1 );
99 - add_action( 'admin_bar_menu', [ $this, 'toolbar_menu' ], 32 );
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' ] );
100 102
101 - add_filter( 'admin_body_class', [ $this, 'body_classes' ] );
102 - add_filter( 'parent_file', [ $type, 'highlight_admin_menu' ] );
103 - add_filter( 'submenu_file', [ $type, 'highlight_admin_submenu' ], 10, 2 );
104 - add_filter( 'betterdocs_admin_menu', [ $this, 'quick_setup_menu' ], 10, 1 );
103 + // $this->container->get( SetupWizard::class )->init();
105 104
106 - /**
107 - * Remove Comments Column from List Table.
108 - */
109 - add_filter( 'manage_docs_posts_columns', [ $this, 'set_custom_edit_action_columns' ] );
110 - add_filter( 'manage_docs_posts_custom_column', [ $this, 'manage_custom_columns' ], 10, 2 );
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 );
111 109
112 - self::$cache_bank = CacheBank::get_instance();
113 - try {
114 - // $this->notices();
115 - add_action('admin_init', [$this, 'notices']);
116 - } catch ( Exception $e ) {
117 - unset( $e );
118 - }
119 - // Remove OLD notice from 1.0.0 (if other WPDeveloper plugin has notice)
120 - NoticeRemover::get_instance( '1.0.0' );
121 - }
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 );
122 114
123 - public function compatibility_notices() {
124 - if ( betterdocs()->is_pro_active() ) {
125 - $plugins = Helper::get_plugins();
126 - $plugin_data = $plugins['betterdocs-pro/betterdocs-pro.php'];
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 );
127 120
128 - if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '2.5.0', '>=' ) ) {
129 - return;
130 - }
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 + }
131 129
132 - betterdocs()->views->get( 'admin/notices/compatibility', [ 'version' => $plugin_data['Version'] ] );
133 - }
134 - }
130 + if ( $this->settings->get( 'enable_estimated_reading_time' ) ) {
131 + add_action( 'add_meta_boxes', [ $this, 'reading_meta_box_' ], 10 );
132 + }
135 133
136 - public function plugin_insights( $prevent_init = false ) {
137 - $this->insights = Insights::get_instance( BETTERDOCS_PLUGIN_FILE, [
138 - 'opt_in' => true,
139 - 'goodbye_form' => true,
140 - 'item_id' => 'c7b16777b4f1b83f6083'
141 - ] );
134 + self::$cache_bank = CacheBank::get_instance();
142 135
143 - $this->insights->set_notice_options( [
144 - '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' ),
145 - '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' )
146 - ] );
136 + // Remove OLD notice from 1.0.0 (if other WPDeveloper plugin has notice)
137 + NoticeRemover::get_instance( '1.0.0' );
147 138
148 - if ( ! $prevent_init ) {
149 - $this->insights->init();
150 - }
139 + try {
140 + $this->notices();
141 + } catch ( Exception $e ) {
142 + unset( $e );
143 + }
151 144
152 - return $this->insights;
153 - }
145 + // Initialize Black Friday Pointer
146 + $this->init_black_friday_pointer();
154 147
155 - /**
156 - * Admin notices for Review and others.
157 - *
158 - * @return void
159 - * @throws Exception
160 - */
161 - public function notices() {
162 - $notices = new Notices( [
163 - 'id' => 'betterdocs',
164 - 'storage_key' => 'notices',
165 - 'lifetime' => 3,
166 - 'stylesheet_url' => $this->assets->asset_url( 'admin/css/notices.css' ),
167 - 'styles' => $this->assets->asset_url( 'admin/css/notices.css' ),
168 - 'priority' => 4
169 - ] );
148 + // Register AJAX handler for pointer dismissal
149 + add_action( 'wp_ajax_betterdocs_dismiss_black_friday_pointer', [ $this, 'ajax_dismiss_black_friday_pointer' ] );
150 + }
170 151
171 - /**
172 - * Review Notice
173 - * @var mixed $message
174 - */
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 + }
175 160
176 - $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' );
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 + }
177 169
178 - $_review_notice = [
179 - 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
180 - 'html' => '<p>' . $message . '</p>',
181 - 'links' => [
182 - 'later' => [
183 - 'link' => 'https://wordpress.org/plugins/betterdocs/#reviews',
184 - 'target' => '_blank',
185 - 'label' => __( 'Sure, you deserve it!', 'betterdocs' ),
186 - 'icon_class' => 'dashicons dashicons-external'
187 - ],
188 - 'allready' => [
189 - 'label' => __( 'I already did', 'betterdocs' ),
190 - 'icon_class' => 'dashicons dashicons-smiley',
191 - 'attributes' => [
192 - 'data-dismiss' => true
193 - ]
194 - ],
195 - 'maybe_later' => [
196 - 'label' => __( 'Maybe Later', 'betterdocs' ),
197 - 'icon_class' => 'dashicons dashicons-calendar-alt',
198 - 'attributes' => [
199 - 'data-later' => true,
200 - 'class' => 'dismiss-btn'
201 - ]
202 - ],
203 - 'support' => [
204 - 'link' => 'https://wpdeveloper.com/support',
205 - 'attributes' => [
206 - 'target' => '_blank'
207 - ],
208 - 'label' => __( 'I need help', 'betterdocs' ),
209 - 'icon_class' => 'dashicons dashicons-sos'
210 - ],
211 - 'never_show_again' => [
212 - 'label' => __( 'Never show again', 'betterdocs' ),
213 - 'icon_class' => 'dashicons dashicons-dismiss',
214 - 'attributes' => [
215 - 'data-dismiss' => true
216 - ]
217 - ]
218 - ]
219 - ];
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 + }
220 205
221 - $notices->add( 'review', $_review_notice, [
222 - 'start' => $notices->strtotime( '+10 days' ),
223 - 'recurrence' => 30,
224 - 'dismissible' => true
225 - ] );
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 + }
226 213
227 - if ( $this->kbmigration->existing_plugins && ! in_array( $this->kbmigration->existing_plugins[0][0], $this->kbmigration->migrated_plugins ) ) {
228 - $migration_message = sprintf(
229 - '<p class="migration-message">%s</p><a class="button button-primary betterdocs-migration-notice" href="%s">%s</a>',
230 - __(
231 - sprintf(
232 - 'Already using %s? Power up your Knowledge Base by migrating all your docs, settings to BetterDocs with just 1 click.',
233 - '<strong>' . esc_html($this->kbmigration->existing_plugins[0][1]) . '</strong>',
234 - '<strong>' . esc_html($this->kbmigration->existing_plugins[0][1]) . '</strong>'
235 - ),
236 - 'betterdocs'
237 - ),
238 - esc_url(admin_url('admin.php?page=betterdocs-settings&tab=tab-migration')),
239 - __('Start Migration', 'betterdocs')
240 - );
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 + }
241 221
242 - $_migration_notice = [
243 - 'thumbnail' => '',
244 - 'html' => $migration_message,
245 - 'links' => [
246 - 'maybe_later' => [
247 - 'label' => __( 'Maybe Later', 'betterdocs' ),
248 - 'icon_class' => 'dashicons dashicons-calendar-alt',
249 - 'attributes' => [
250 - 'data-later' => true,
251 - 'class' => 'dismiss-btn'
252 - ]
253 - ],
254 - 'never_show_again' => [
255 - 'label' => __( 'Never show again', 'betterdocs' ),
256 - 'icon_class' => 'dashicons dashicons-dismiss',
257 - 'attributes' => [
258 - 'data-dismiss' => true
259 - ]
260 - ]
261 - ]
262 - ];
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 + }
263 233
264 - $notices->add( 'migration', $_migration_notice, [
265 - 'start' => $notices->time(),
266 - 'recurrence' => false,
267 - 'dismissible' => true,
268 - 'display_if' => current_user_can( 'delete_users' )
269 - ] );
270 - }
234 + public function render_estimated_time_markup() {
235 + betterdocs()->views->get( 'admin/metabox/estimated-reading-box' );
236 + }
271 237
272 - /**
273 - * Opt-In Notice
274 - */
275 - if ( $this->insights != null ) {
276 - $notices->add( 'opt_in', [ $this->insights, 'notice' ], [
277 - 'classes' => 'updated put-dismiss-notice',
278 - 'start' => $notices->strtotime( '+20 days' ),
279 - 'dismissible' => true,
280 - 'do_action' => 'wpdeveloper_notice_clicked_for_betterdocs',
281 - 'display_if' => ! function_exists( 'betterdocs_pro' )
282 - ] );
283 - }
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'];
284 242
285 - $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>';
286 - $_black_friday_notice = [
287 - 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
288 - 'html' => $b_message,
289 - ];
243 + if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '2.5.0', '>=' ) ) {
244 + return;
245 + }
290 246
291 - $notices->add( 'black_friday_notice', $_black_friday_notice, [
292 - 'start' => $notices->time(),
293 - 'recurrence' => false,
294 - 'dismissible' => true,
295 - 'refresh' => BETTERDOCS_VERSION,
296 - "expire" => strtotime( '11:59:59pm 2nd December, 2023' ),
297 - 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
298 - ] );
247 + betterdocs()->views->get( 'admin/notices/compatibility', [ 'version' => $plugin_data['Version'] ] );
248 + }
249 + }
299 250
300 - self::$cache_bank->create_account( $notices );
301 - self::$cache_bank->calculate_deposits( $notices );
302 - }
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 + );
303 260
304 - public function body_classes( $classes ) {
305 - $saved_settings = get_option( 'betterdocs_settings', false );
306 - $dark_mode = isset( $saved_settings['dark_mode'] ) ? $saved_settings['dark_mode'] : false;
307 - $dark_mode = ! empty( $dark_mode ) ? boolval( $dark_mode ) : false;
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 + );
308 267
309 - if ( $dark_mode === true ) {
310 - $classes .= ' betterdocs-dark-mode ';
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 ';
311 523 }
312 524
313 - return $classes;
314 - }
525 + if ( $dark_mode === true && in_array( $current_screen_id, $registered_screens ) ) {
526 + $classes .= ' betterdocs-dark-mode ';
527 + }
315 528
316 - /**
317 - * Remove Comments Column From List Table
318 - *
319 - * @param array $columns
320 - *
321 - * @return array
322 - * @since 1.0.0
323 - */
324 - public function set_custom_edit_action_columns( $columns ) {
325 - unset( $columns['comments'] );
326 - $new_columns = [];
327 - foreach ( $columns as $key => $value ) {
328 - if ( $key == 'date' ) {
329 - $new_columns['betterdocs_word_count'] = __( 'Word Count', 'betterdocs' ); // put the tags column before it
330 - $new_columns['betterdocs_reaction'] = __( 'Reactions', 'betterdocs' );
331 - }
332 - $new_columns[ $key ] = $value;
333 - }
529 + return $classes;
530 + }
334 531
335 - return $new_columns;
336 - }
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 + }
337 550
338 - public function manage_custom_columns( $column, $post_id ) {
339 - global $wpdb;
340 - switch ( $column ) {
341 - case 'betterdocs_word_count':
342 - $word_count = str_word_count( trim( strip_tags( get_post_field( 'post_content', $post_id ) ) ) );
343 - echo '<span>' . $word_count . '</span>';
344 - break;
345 - case 'betterdocs_reaction' :
346 - $where = "WHERE post_id='" . esc_sql($post_id) . "'";
347 - $analytics = $wpdb->get_results(
348 - "SELECT
551 + return $new_columns;
552 + }
553 +
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
349 568 sum(impressions) as totalViews,
350 569 sum(unique_visit) as totalUniqueViews,
351 570 sum(happy + sad + normal) as totalReactions,
352 571 sum(happy) as totalHappy,
@@ -353,12 +572,11 @@
353 572 sum(normal) as totalNormal,
354 573 sum(sad) as totalSad
355 574 FROM {$wpdb->prefix}betterdocs_analytics
356 575 $where"
357 - );
358 - //echo '<span>'. ($analytics[0]->totalHappy != NULL ? $analytics[0]->totalHappy : 0) .'</span>';
359 - // var_dump($analytics);
360 - echo '<ul class="reactions-count">
576 + );
577 +
578 + echo '<ul class="reactions-count">
361 579 <li>
362 580 <a title="happy" class="betterdocs-feelings happy" data-feelings="happy" href="#">
363 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">
364 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
@@ -369,9 +587,9 @@
369 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
370 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
371 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" />
372 590 </svg>
373 - <span>'. ($analytics[0]->totalHappy != NULL ? $analytics[0]->totalHappy : 0) .'</span>
591 + <span>' . esc_html( ( intval( $analytics[0]->totalHappy ) !== null ? intval( $analytics[0]->totalHappy ) : 0 ) ) . '</span>
374 592 </a>
375 593 </li>
376 594 <li>
377 595 <a title="normal" class="betterdocs-feelings normal" data-feelings="normal" href="#">
@@ -380,9 +598,9 @@
380 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
381 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
382 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" />
383 601 </svg>
384 - <span>'. ($analytics[0]->totalNormal != NULL ? $analytics[0]->totalNormal : 0) .'</span>
602 + <span>' . esc_html( ( intval( $analytics[0]->totalNormal ) !== null ? intval( $analytics[0]->totalNormal ) : 0 ) ) . '</span>
385 603 </a>
386 604 </li>
387 605 <li>
388 606 <a title="sad" class="betterdocs-feelings sad" data-feelings="sad" href="#">
@@ -394,348 +612,645 @@
394 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
395 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
396 614 c1.8,0,3.5,0.8,4.6,2.1C15,14.3,14.7,15,14.1,15z" />
397 615 </svg>
398 - <span>'. ($analytics[0]->totalSad != NULL ? $analytics[0]->totalSad : 0) .'</span>
616 + <span>' . esc_html( ( intval( $analytics[0]->totalNormal ) !== null ? intval( $analytics[0]->totalNormal ) : 0 ) ) . '</span>
399 617 </a>
400 618 </li>
401 619 </ul>';
402 - break;
403 - }
404 - }
620 + break;
621 + }
622 + }
405 623
406 - /**
407 - * Enqueue Assets for Admin ( Styles )
408 - *
409 - * @param string $hook
410 - *
411 - * @return void
412 - * @since 1.0.0
413 - */
414 - public function styles( $hook ) {
415 - $this->assets->enqueue( 'betterdocs-global', 'admin/css/global.css', [], 'all' );
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' );
416 634
417 - if ( ! in_array( $hook, [
418 - 'toplevel_page_betterdocs-admin',
419 - 'betterdocs_page_betterdocs-settings',
420 - 'betterdocs_page_betterdocs-analytics'
421 - ] ) ) {
422 - return;
423 - }
635 + if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
636 + return;
637 + }
424 638
425 - $this->assets->enqueue( 'betterdocs-select2', 'vendor/css/select2.min.css', [], 'all' );
426 - $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/css/daterangepicker.css', [], 'all' );
427 - $this->assets->enqueue( 'betterdocs-icons', 'admin/btd-icon/style.css' );
428 - $this->assets->enqueue( 'betterdocs', 'admin/css/betterdocs.css', [], 'all' );
429 - }
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' );
430 642
431 - /**
432 - * Enqueue Assets for Admin ( Scripts )
433 - *
434 - * @param string $hook
435 - *
436 - * @return void
437 - * @since 1.0.0
438 - */
439 - public function scripts( $hook ) {
440 - $this->assets->register( 'betterdocs-admin', 'admin/js/betterdocs.js', [ 'jquery', 'jquery-ui-sortable' ] );
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 + }
441 649
442 - $saved_settings = get_option( 'betterdocs_settings', false );
443 - $dark_mode = isset( $saved_settings['dark_mode'] ) ? $saved_settings['dark_mode'] : false;
444 - $dark_mode = ! empty( $dark_mode ) ? boolval( $dark_mode ) : false;
445 - $this->assets->localize( 'betterdocs-admin', 'betterdocs_admin', [
446 - 'ajaxurl' => admin_url( 'admin-ajax.php' ),
447 - 'doc_cat_order_nonce' => wp_create_nonce( 'doc_cat_order_nonce' ),
448 - 'knowledge_base_order_nonce' => wp_create_nonce( 'knowledge_base_order_nonce' ),
449 - 'paged' => isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 0,
450 - 'per_page_id' => "edit_doc_category_per_page",
451 - 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
452 - 'dark_mode' => ! empty( $dark_mode ) ? boolval( $dark_mode ) : false,
453 - 'text' => __( 'Copied!', 'betterdocs' ),
454 - 'test_report' => __( 'Test Report!', 'betterdocs' ),
455 - 'sending' => __( 'Sending...', 'betterdocs' ),
456 - 'generate_data_url' => get_rest_url( null, '/betterdocs/v1/create-sample-docs' ),
457 - 'nonce' => wp_create_nonce( 'wp_rest' )
458 - ] );
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 + );
459 667
460 - if ( ( $hook === 'edit.php' || $hook === 'toplevel_page_betterdocs-admin' ) && get_post_type() == 'docs' ) {
461 - $this->assets->enqueue( 'betterdocs-switcher', 'admin/js/switcher.js', [
462 - 'jquery'
463 - ] );
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 + );
464 678
465 - $this->assets->localize( 'betterdocs-switcher', 'betterdocsSwitcher', [
466 - 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
467 - 'site_address' => get_bloginfo( 'url' ),
468 - 'betterdocs_pro_plugin' => betterdocs()->is_pro_active()
469 - ] );
470 - }
679 + return;
680 + }
471 681
472 - if ( ! in_array( $hook, ['term.php', 'edit-tags.php','toplevel_page_betterdocs-admin', 'betterdocs_page_betterdocs-analytics' ] ) ) {
473 - return;
682 + wp_enqueue_script( 'wp-editor' ); // enqueue this for yoast related issue
683 +
684 + if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
685 + return;
686 + }
687 +
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' );
690 +
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 + );
730 +
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' );
736 +
737 + /**
738 + * Duplicate Codes Need to Be Removed From Here Onwards
739 + */
740 +
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' );
744 +
745 + // removing emoji support
746 + remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
747 + remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
748 +
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 + );
760 +
761 + //Glossaries Related Localization
762 + betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/css/faq.css' );
763 +
764 + betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/js/glossaries.js' );
765 +
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 + }
778 +
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 + ];
800 +
801 + $quick_links = apply_filters( 'betterdocs_quick_links', $quick_links );
802 +
803 + betterdocs()->views->get(
804 + 'admin/header',
805 + [
806 + 'quick_links' => $quick_links,
807 + 'active_tab' => $admin_tab_name
808 + ]
809 + );
810 + }
811 +
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 + ];
828 +
829 + $_menu_position = 5;
830 + global $submenu;
831 +
832 + // Always register both UI endpoints
833 + $this->register_modern_ui_fallback();
834 +
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;
842 +
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 + }
866 +
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 + );
877 +
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 + }
889 +
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 + }
910 +
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 + );
474 1033 }
475 1034
476 - wp_enqueue_script('wp-editor'); //enqueued on betterdocs-term pages to show SEO data from Yoast
477 - wp_enqueue_script( 'wp-color-picker' );
1035 + return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages, [$this, 'output'], $parent_slug);
478 1036
479 - $this->assets->enqueue( 'betterdocs-select2', 'vendor/js/select2.min.js', [] );
480 - $this->assets->enqueue( 'betterdocs-sweetalert', 'vendor/js/sweetalert.min.js', [] );
481 - $this->assets->enqueue( 'moment', 'vendor/js/moment.min.js', [] );
482 - $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/js/daterangepicker.min.js', [] );
483 - wp_enqueue_script( 'betterdocs-admin' );
484 1037 }
485 1038
486 - /**
487 - * All admin pages header
488 - *
489 - * @return void
490 - * @since 1.0.0
491 - */
492 - public function header( $admin_tab_name ) {
493 - $quick_links = [
494 - 'switch_view' => sprintf( '<a href="%s" class="betterdocs-button betterdocs-button-secondary">%s</a>', add_query_arg( [
495 - 'post_type' => 'docs',
496 - 'bdocs_view' => 'classic'
497 - ], 'edit.php' ), __( 'Switch to Classic UI', 'betterdocs' ) ),
498 - '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' ) )
499 - ];
1039 + public function add_custom_classes_to_menu_items() {
1040 + global $menu, $submenu;
500 1041
501 - $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 + ];
502 1055
503 - betterdocs()->views->get( 'admin/header', [
504 - 'quick_links' => $quick_links,
505 - 'active_tab' => $admin_tab_name
506 - ] );
507 - }
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 + }
508 1064
509 - /**
510 - * Register all the menus for BetterDocs
511 - *
512 - * @return void
513 - * @since 1.0.0
514 - */
515 - // public function menus() {
516 - // add_menu_page(
517 - // 'BetterDocs',
518 - // 'BetterDocs',
519 - // 'edit_posts',
520 - // $this->slug,
521 - // [$this, 'output'],
522 - // betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
523 - // 5 // Position on the menu (use a unique number)
524 - // );
525 - // }
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 + }
526 1076
527 - public function menus() {
528 - $default_args = [
529 - 'page_title' => 'BetterDocs',
530 - 'menu_title' => 'BetterDocs',
531 - 'capability' => 'edit_posts',
532 - 'menu_slug' => $this->slug,
533 - 'callback' => [ $this, 'output' ],
534 - 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
535 - 'position' => 5
536 - ];
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 + }
537 1092
538 - $_menu_position = 5;
1093 + return $menus;
1094 + }
539 1095
540 - foreach ( $this->menu_list() as $key => $value ) {
541 - if ( $key === 'betterdocs' ) {
542 - $callable = 'add_menu_page';
543 - $value = wp_parse_args( $value, $default_args );
544 - } else {
545 - $callable = 'add_submenu_page';
546 - $default_args['callback'] = '';
547 - $default_args['position'] = $_menu_position;
548 - unset( $default_args['icon_url'] );
549 - $value = wp_parse_args( $value, array_merge( [ 'parent_slug' => $this->slug ], $default_args ) );
550 - }
1096 + public function insert_plugin_links( $links ) {
1097 + $links[] = '<a href="admin.php?page=betterdocs-settings">' . __( 'Settings', 'betterdocs' ) . '</a>';
551 1098
552 - $_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 + }
553 1102
554 - call_user_func_array( $callable, $value );
555 - }
556 - }
1103 + return $links;
1104 + }
557 1105
558 - /**
559 - * BetterDocs Admin Page Output
560 - *
561 - * @return void
562 - * @since 1.0.0
563 - */
564 - public function output() {
565 - betterdocs()->views->get( 'admin/main', [
566 - 'admin_ui' => 'dnd'
567 - ] );
568 - }
1106 + public function toolbar_menu( $admin_bar ) {
1107 + if ( ! is_admin() || ! is_admin_bar_showing() ) {
1108 + return;
1109 + }
569 1110
570 - /**
571 - * Menu creator helper
572 - *
573 - * @param string $title
574 - * @param string $slug
575 - * @param string $cap
576 - * @param array $callback
577 - *
578 - * @return array
579 - * @since 2.5.0
580 - *
581 - */
582 - private function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null ) {
583 - return Helper::normalize_menu( $title, $slug, $cap, $callback );
584 - }
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 + }
585 1115
586 - /**
587 - * BetterDocs Menu List
588 - *
589 - * @return array
590 - * @since 1.0.0
591 - */
592 - private function menu_list() {
593 - $betterdocs_admin_pages = [
594 - 'betterdocs' => [
595 - 'menu_slug' => $this->slug,
596 - 'page_title' => 'BetterDocs',
597 - 'menu_title' => 'BetterDocs',
598 - 'capability' => 'edit_docs',
599 - 'callback' => [ $this, 'output' ],
600 - 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
601 - 'position' => 5
602 - ],
603 - 'all_docs' => $this->normalize_menu( __( 'All Docs', 'betterdocs' ), $this->ui_slug() ),
604 - 'add_new' => $this->normalize_menu( __( 'Add New', 'betterdocs' ), 'post-new.php?post_type=docs' ),
605 - 'categories' => $this->normalize_menu(
606 - __( 'Categories', 'betterdocs' ),
607 - 'edit-tags.php?taxonomy=doc_category&post_type=docs',
608 - 'manage_doc_terms'
609 - ),
610 - 'tags' => $this->normalize_menu(
611 - __( 'Tags', 'betterdocs' ),
612 - 'edit-tags.php?taxonomy=doc_tag&post_type=docs',
613 - 'manage_doc_terms'
614 - ),
615 - 'settings' => $this->normalize_menu(
616 - __( 'Settings', 'betterdocs' ),
617 - 'betterdocs-settings',
618 - 'edit_docs_settings',
619 - [$this->container->get( Settings::class ), 'views']
620 - ),
621 - 'analytics' => $this->normalize_menu(
622 - __( 'Analytics', 'betterdocs' ),
623 - 'betterdocs-analytics',
624 - 'read_docs_analytics',
625 - [$this->container->get( Analytics::class ), 'views']
626 - ),
627 - 'faq' => $this->normalize_menu(
628 - __( 'FAQ Builder', 'betterdocs' ),
629 - 'betterdocs-faq',
630 - 'read_docs_analytics',
631 - [$this->faq_builder, 'output']
632 - )
633 - ];
1116 + $docs_url = '';
1117 + $encyclopedia_url = '';
634 1118
635 - return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages );
636 - }
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 + }
637 1124
638 - public function quick_setup_menu( $menus ) {
639 - $betterdocs_settings = get_option( 'betterdocs_settings' );
640 - if ( $betterdocs_settings ) {
641 - return $menus;
642 - } else {
643 - $menus['quick_setup'] = $this->normalize_menu( __( 'Quick Setup', 'betterdocs' ), 'betterdocs-setup', 'delete_users', [
644 - $this->container->get( SetupWizard::class ),
645 - 'views'
646 - ] );
647 - }
1125 + if ( ! $docs_url ) {
1126 + return;
1127 + }
648 1128
649 - return $menus;
650 - }
1129 + $slug = $this->settings->get( 'encyclopedia_root_slug' );
651 1130
652 - public function insert_plugin_links( $links ) {
653 - $links[] = '<a href="admin.php?page=betterdocs-settings">' . __( 'Settings', 'betterdocs' ) . '</a>';
1131 + $encyclopedia_url = home_url( $slug );
654 1132
655 - return $links;
656 - }
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 + );
657 1141
658 - public function toolbar_menu( $admin_bar ) {
659 - if ( ! is_admin() || ! is_admin_bar_showing() ) {
660 - return;
661 - }
1142 + $is_enable_encyclopedia = betterdocs()->settings->get( 'enable_encyclopedia' );
662 1143
663 - // Show only when the user is a member of this site, or they're a super admin.
664 - if ( ! is_user_member_of_blog() && ! is_super_admin() ) {
665 - return;
666 - }
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 + }
667 1155
668 - $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 + }
669 1169
670 - if ( $this->settings->get( 'builtin_doc_page' ) ) {
671 - $docs_url = get_post_type_archive_link( 'docs' );
672 - } elseif ( intval( $docs_page = $this->settings->get( 'docs_page' ) ) ) {
673 - $docs_url = ! empty( $docs_page ) ? get_page_link( $docs_page ) : false;
674 - }
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 + ]);
675 1183
676 - if ( ! $docs_url ) {
677 - return;
678 - }
1184 + return ($last_visited === 'modern_ui' || empty($docs_exist))
1185 + ? 'betterdocs-admin'
1186 + : 'edit.php?post_type=docs&bdocs_view=classic';
1187 + }
679 1188
680 - $admin_bar->add_node( [
681 - 'parent' => 'site-name',
682 - 'id' => 'view-docs',
683 - 'title' => __( 'Visit Documentation', 'betterdocs' ),
684 - 'href' => $docs_url
685 - ] );
686 - }
687 - /**
688 - * Save last visited admin ui
689 - *
690 - * @since 3.0.1
691 - *
692 - */
693 - public function save_admin_page() {
694 - if (isset($_GET['post_type']) && $_GET['post_type'] === 'docs' && isset($_GET['bdocs_view']) && $_GET['bdocs_view'] === 'classic') {
695 - update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'classic_ui' );
696 - } elseif (isset($_GET['page']) && $_GET['page'] === 'betterdocs-admin') {
697 - update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'modern_ui' );
698 - }
699 - }
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;
700 1197
701 - /**
702 - * Return last visited admin ui slug
703 - *
704 - * @since 3.0.1
705 - * @return string
706 - */
707 - public function ui_slug() {
708 - $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true);
709 - $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 + }
710 1202
711 - if ($last_visited === 'modern_ui' || count($docs) == 0 ) {
712 - $slug = 'betterdocs-admin';
713 - } else {
714 - $slug = admin_url('edit.php?post_type=docs&bdocs_view=classic');
715 - }
1203 + $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
716 1204
717 - return $slug;
718 - }
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 + }
719 1210
720 - /**
721 - * Resets a duplicate submenu in WordPress if the parent main menu and the first submenu permalink are not the same.
722 - *
723 - * @since 3.0.1
724 - * @return string
725 - */
726 - public function reset_submenu() {
727 - 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 + }
728 1223
729 - $docs = get_posts( ['post_type' => 'docs'] );
730 - if ( count($docs) == 0 ) {
731 - return;
732 - }
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 + }
733 1235
734 - $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 + }
735 1240
736 - if ($last_visited === 'classic_ui' && isset($submenu['betterdocs-admin']) && in_array("betterdocs-admin", $submenu['betterdocs-admin'][0])) {
737 - unset($submenu['betterdocs-admin'][0]);
738 - $submenu['betterdocs-admin'] = array_values($submenu['betterdocs-admin']);
739 - }
740 - }
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 + }
741 1256 }