PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.1.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.1.0
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
betterdocs / includes / Core / Admin.php

Admin.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.1.0, at includes/Core/Admin.php

1,175 lines 41.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDeveloper\BetterDocs\Core;
4
5 use Exception;
6 use PriyoMukul\WPNotice\Notices;
7 use WPDeveloper\BetterDocs\Utils\Base;
8 use PriyoMukul\WPNotice\Utils\CacheBank;
9 use WPDeveloper\BetterDocs\Utils\Helper;
10 use WPDeveloper\BetterDocs\Utils\Enqueue;
11 use WPDeveloper\BetterDocs\Utils\Insights;
12 use PriyoMukul\WPNotice\Utils\NoticeRemover;
13 use WPDeveloper\BetterDocs\Core\PluginInstaller;
14 use WPDeveloper\BetterDocs\Dependencies\DI\Container;
15
16 class Admin extends Base {
17 /**
18 * @var CacheBank
19 */
20 private static $cache_bank;
21 /**
22 * Admin Root Menu Slug
23 * @var string
24 */
25 private $slug = 'betterdocs-dashboard';
26 /**
27 * Insights
28 *
29 * @var Insights
30 */
31 private $insights = null;
32
33 /**
34 * DI\Container
35 *
36 * @var Container
37 */
38 private $container;
39
40 /**
41 * Database Wrapper
42 *
43 * @var Settings
44 */
45 private $settings;
46
47 /**
48 * KBMigration
49 *
50 * @var KBMigration
51 */
52 private $kbmigration;
53
54 /**
55 * Enqueue
56 * @var Enqueue
57 */
58 private $assets;
59
60 // modules
61 protected $installer;
62
63 /**
64 * FAQBuilder
65 * @var FAQBuilder
66 */
67 private $faq_builder;
68 private $glossaries;
69
70 public function __construct( Container $container, PostType $type, Enqueue $assets, Settings $settings, KBMigration $kbmigration ) {
71 $this->container = $container;
72 $this->assets = $assets;
73 $this->settings = $settings;
74 $this->kbmigration = $kbmigration;
75 $this->slug = 'betterdocs-dashboard';
76
77 add_action( 'init', [ $type, 'register' ], 9 );
78
79 $type->init();
80 $type->admin_init();
81
82 $this->faq_builder = $this->container->get( FAQBuilder::class );
83 $this->glossaries = $this->container->get( Glossaries::class );
84
85 if ( ! is_admin() ) {
86 return;
87 }
88
89 $this->installer = new PluginInstaller();
90
91 $this->plugin_insights();
92 add_action( 'admin_notices', [ $this, 'compatibility_notices' ] );
93 // add_action( 'admin_init', [$this, 'notices'], 9 );
94 add_filter( 'admin_init', [ $this, 'save_admin_page' ], 99 );
95
96 add_action( 'admin_menu', [ $this, 'menus' ] );
97 add_action( 'admin_menu', [ $this, 'reset_submenu' ] );
98 add_action( 'admin_head', [ $this, 'add_custom_classes_to_menu_items' ] );
99 add_filter( 'plugin_action_links_' . BETTERDOCS_PLUGIN_BASENAME, [ $this, 'insert_plugin_links' ] );
100
101 // $this->container->get( SetupWizard::class )->init();
102
103 add_action( 'admin_enqueue_scripts', [ $this, 'styles' ] );
104 add_action( 'admin_enqueue_scripts', [ $this, 'scripts' ] );
105 //add_action( 'betterdocs_listing_header', [ $this, 'header' ], 10, 1 );
106 add_action( 'admin_bar_menu', [ $this, 'toolbar_menu' ], 32 );
107
108 add_filter( 'admin_body_class', [ $this, 'body_classes' ] );
109 add_filter( 'parent_file', [ $type, 'highlight_admin_menu' ] );
110 add_filter( 'submenu_file', [ $type, 'highlight_admin_submenu' ], 10, 2 );
111 add_filter( 'betterdocs_admin_menu', [ $this, 'quick_setup_menu' ], 10, 1 );
112
113 /**
114 * Remove Comments Column from List Table.
115 */
116 add_filter( 'manage_docs_posts_columns', [ $this, 'set_custom_edit_action_columns' ] );
117 add_filter( 'manage_docs_posts_custom_column', [ $this, 'manage_custom_columns' ], 10, 2 );
118
119 /**
120 * Add New Column
121 */
122 add_filter( 'manage_users_columns', [ $this, 'add_users_total_docs_column' ], 10, 1 );
123 add_filter( 'manage_users_custom_column', [ $this, 'popular_users_docs_data' ], 10, 3 );
124 if ( is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' ) ) {
125 add_action( 'admin_footer-plugins.php', array( $this, 'disable_deactivation' ) );
126 }
127
128 if ( $this->settings->get( 'enable_estimated_reading_time' ) ) {
129 add_action( 'add_meta_boxes', [ $this, 'reading_meta_box_' ], 10 );
130 }
131
132 self::$cache_bank = CacheBank::get_instance();
133
134 // Remove OLD notice from 1.0.0 (if other WPDeveloper plugin has notice)
135 NoticeRemover::get_instance( '1.0.0' );
136
137 try {
138 $this->notices();
139 } catch ( Exception $e ) {
140 unset( $e );
141 }
142 }
143
144 public function disable_deactivation() {
145 $tooltip_text = esc_html__( 'Deactivate BetterDocs Pro First', 'betterdocs' );
146 ?>
147 <style type="text/css">
148 #deactivate-betterdocs {
149 color: #cccccc;
150 position: relative;
151 }
152
153 /* Tooltip styling */
154 #deactivate-betterdocs[title]:hover::after {
155 content: attr(title);
156 position: absolute;
157 bottom: 100%;
158 left: 50%;
159 transform: translateX(-50%);
160 background-color: #333;
161 color: #fff;
162 padding: 5px 10px;
163 border-radius: 4px;
164 font-size: 12px;
165 white-space: nowrap;
166 box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2);
167 z-index: 10;
168 }
169 #deactivate-betterdocs:focus {
170 box-shadow: none;
171 outline: none;
172 }
173 </style>
174 <script type="text/javascript">
175 jQuery(document).ready(function($) {
176 // Disable the default action and add class with tooltip by default
177 const tooltipText = "<?php echo esc_attr( $tooltip_text ); ?>";
178 $("#deactivate-betterdocs")
179 .addClass("disabled-tooltip")
180 .attr("title", tooltipText)
181 .on("click", function(e) {
182 e.preventDefault(); // Prevent any action on click
183 });
184 });
185 </script>
186 <?php
187 }
188
189 public function add_users_total_docs_column( $columns ) {
190 $new_column = [
191 'docs' => __( 'Docs', 'betterdocs' )
192 ];
193 $columns = array_merge( $columns, $new_column );
194 return $columns;
195 }
196
197 public function popular_users_docs_data( $output, $column_name, $user_id ) {
198 if ( $column_name == 'docs' ) {
199 $total_count = count_user_posts( $user_id, 'docs', true );
200 return '<a href="edit.php?post_type=docs&author=' . $user_id . '" class="edit"><span aria-hidden="true">' . $total_count . '</span></a>';
201 }
202 return $output;
203 }
204
205 public function reading_meta_box_() {
206 add_meta_box(
207 'betterdocs_estimated_time_metabox',
208 __( 'Estimated Reading Time', 'betterdocs' ),
209 [
210 $this,
211 'render_estimated_time_markup'
212 ],
213 'docs'
214 );
215 }
216
217 public function render_estimated_time_markup() {
218 betterdocs()->views->get( 'admin/metabox/estimated-reading-box' );
219 }
220
221 public function compatibility_notices() {
222 if ( betterdocs()->is_pro_active() ) {
223 $plugins = Helper::get_plugins();
224 $plugin_data = $plugins['betterdocs-pro/betterdocs-pro.php'];
225
226 if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '2.5.0', '>=' ) ) {
227 return;
228 }
229
230 betterdocs()->views->get( 'admin/notices/compatibility', [ 'version' => $plugin_data['Version'] ] );
231 }
232 }
233
234 public function plugin_insights( $prevent_init = false ) {
235 $this->insights = Insights::get_instance(
236 BETTERDOCS_PLUGIN_FILE,
237 [
238 'opt_in' => true,
239 'goodbye_form' => true,
240 'item_id' => 'c7b16777b4f1b83f6083'
241 ]
242 );
243
244 $this->insights->set_notice_options(
245 [
246 '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' ),
247 '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' )
248 ]
249 );
250
251 if ( ! $prevent_init ) {
252 $this->insights->init();
253 }
254
255 return $this->insights;
256 }
257
258 /**
259 * Admin notices for Review and others.
260 *
261 * @return void
262 * @throws Exception
263 */
264 public function notices() {
265 $notices = new Notices(
266 [
267 'id' => 'betterdocs',
268 'storage_key' => 'notices',
269 'lifetime' => 3,
270 'stylesheet_url' => $this->assets->asset_url( 'admin/css/notices.css' ),
271 'styles' => $this->assets->asset_url( 'admin/css/notices.css' ),
272 'priority' => 4
273 ]
274 );
275
276 /**
277 * Review Notice
278 * @var mixed $message
279 */
280
281 $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' );
282
283 $_review_notice = [
284 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
285 'html' => '<p>' . $message . '</p>',
286 'links' => [
287 'later' => [
288 'link' => 'https://wordpress.org/plugins/betterdocs/#reviews',
289 'target' => '_blank',
290 'label' => __( 'Sure, you deserve it!', 'betterdocs' ),
291 'icon_class' => 'dashicons dashicons-external'
292 ],
293 'allready' => [
294 'label' => __( 'I already did', 'betterdocs' ),
295 'icon_class' => 'dashicons dashicons-smiley',
296 'attributes' => [
297 'data-dismiss' => true
298 ]
299 ],
300 'maybe_later' => [
301 'label' => __( 'Maybe Later', 'betterdocs' ),
302 'icon_class' => 'dashicons dashicons-calendar-alt',
303 'attributes' => [
304 'data-later' => true,
305 'class' => 'dismiss-btn'
306 ]
307 ],
308 'support' => [
309 'link' => 'https://wpdeveloper.com/support',
310 'attributes' => [
311 'target' => '_blank'
312 ],
313 'label' => __( 'I need help', 'betterdocs' ),
314 'icon_class' => 'dashicons dashicons-sos'
315 ],
316 'never_show_again' => [
317 'label' => __( 'Never show again', 'betterdocs' ),
318 'icon_class' => 'dashicons dashicons-dismiss',
319 'attributes' => [
320 'data-dismiss' => true
321 ]
322 ]
323 ]
324 ];
325
326 $notices->add(
327 'review',
328 $_review_notice,
329 [
330 'start' => $notices->strtotime( '+10 days' ),
331 'recurrence' => 30,
332 'dismissible' => true
333 ]
334 );
335
336 if ( $this->kbmigration->existing_plugins && ! in_array( $this->kbmigration->existing_plugins[0][0], $this->kbmigration->migrated_plugins ) ) {
337 $plugin_name = '<strong>' . esc_html( $this->kbmigration->existing_plugins[0][1] ) . '</strong>';
338
339 $message = sprintf(
340 /* translators: %s is the name of the existing knowledge base plugin. */
341 __( 'Already using %s? Power up your Knowledge Base by migrating all your docs and settings to BetterDocs with just 1 click.', 'betterdocs' ),
342 esc_html( $plugin_name )
343 );
344
345 $migration_message = sprintf(
346 '<p class="migration-message">%s</p><a class="button button-primary betterdocs-migration-notice" href="%s">%s</a>',
347 $message,
348 esc_url( admin_url( 'admin.php?page=betterdocs-settings&tab=tab-migration' ) ),
349 esc_html__( 'Start Migration', 'betterdocs' )
350 );
351
352 $_migration_notice = [
353 'thumbnail' => '',
354 'html' => $migration_message,
355 'links' => [
356 'maybe_later' => [
357 'label' => __( 'Maybe Later', 'betterdocs' ),
358 'icon_class' => 'dashicons dashicons-calendar-alt',
359 'attributes' => [
360 'data-later' => true,
361 'class' => 'dismiss-btn'
362 ]
363 ],
364 'never_show_again' => [
365 'label' => __( 'Never show again', 'betterdocs' ),
366 'icon_class' => 'dashicons dashicons-dismiss',
367 'attributes' => [
368 'data-dismiss' => true
369 ]
370 ]
371 ]
372 ];
373
374 $notices->add(
375 'migration',
376 $_migration_notice,
377 [
378 'start' => $notices->time(),
379 'recurrence' => false,
380 'dismissible' => true
381 ]
382 );
383 }
384
385 /**
386 * Opt-In Notice
387 */
388 $allow_tracking = get_option( 'wpins_allow_tracking' );
389 if ( $this->insights != null && ! isset( $allow_tracking['betterdocs'] ) ) {
390 $notices->add(
391 'opt_in',
392 [ $this->insights, 'notice' ],
393 [
394 'classes' => 'updated put-dismiss-notice',
395 'start' => $notices->time(),
396 'refresh' => BETTERDOCS_VERSION,
397 'dismissible' => true,
398 'do_action' => 'wpdeveloper_notice_clicked_for_betterdocs',
399 'display_if' => ! function_exists( 'betterdocs_pro' ),
400 'screens' => [ 'dashboard' ]
401 ]
402 );
403 }
404
405 // $blackfriday_message = '<div class="betterdocs-notice-body"><p style="margin-top: 0; margin-bottom: 0;"><strong>🛍️ Black Friday Specials:</strong> Save up to 35% OFF on BetterDocs PRO plans & manage docs/FAQs seamlessly.</p><a class="button button-primary" href="https://betterdocs.co/bfcm24-pricing" target="_blank"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
406 // <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"/>
407 // <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"/>
408 // </svg> Upgrade To PRO</a></div>';
409 // $_blackfriday_notice = [
410 // 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
411 // 'html' => $blackfriday_message
412 // ];
413
414 // $notices->add(
415 // 'blackfriday24',
416 // $_blackfriday_notice,
417 // [
418 // 'start' => $notices->time(),
419 // 'recurrence' => false,
420 // 'dismissible' => true,
421 // 'refresh' => BETTERDOCS_VERSION,
422 // 'expire' => strtotime( '11:59:59pm December 5, 2024' ),
423 // 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
424 // ]
425 // );
426
427 $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">
428 <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"/>
429 <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"/>
430 </svg>Upgrade To PRO</a></div></div>';
431 $_offer_notice = [
432 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
433 'html' => $offer_message
434 ];
435
436 $notices->add(
437 '40k_offer',
438 $_offer_notice,
439 [
440 'start' => $notices->time(),
441 'recurrence' => false,
442 'dismissible' => true,
443 'refresh' => BETTERDOCS_VERSION,
444 'expire' => strtotime( '11:59:59pm April 30, 2025' ),
445 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
446 ]
447 );
448
449 self::$cache_bank->create_account( $notices );
450 self::$cache_bank->calculate_deposits( $notices );
451 if ( method_exists( self::$cache_bank, 'clear_notices_in_' ) ) {
452 self::$cache_bank->clear_notices_in_(
453 [
454 'toplevel_page_betterdocs-dashboard',
455 'admin_page_betterdocs-admin',
456 'betterdocs_page_betterdocs-admin',
457 'betterdocs_page_betterdocs-settings',
458 'betterdocs_page_betterdocs-faq',
459 'betterdocs_page_betterdocs-analytics',
460 'betterdocs_page_betterdocs-glossaries',
461 'betterdocs_page_betterdocs-ai-chatbot',
462 'edit-doc_category',
463 'edit-doc_tag'
464 ],
465 $notices,
466 true
467 );
468 }
469 }
470
471 public function body_classes( $classes ) {
472 $saved_settings = get_option( 'betterdocs_settings', false );
473 $dark_mode = isset( $saved_settings['dark_mode'] ) ? $saved_settings['dark_mode'] : false;
474 $dark_mode = ! empty( $dark_mode ) ? boolval( $dark_mode ) : false;
475 $current_screen_id = get_current_screen() != null ? str_replace( 'betterdocs_page_', '', str_replace( 'toplevel_page_', '', str_replace( 'admin_page_', '', get_current_screen()->id ) ) ) : '';
476 $registered_screens = [
477 'betterdocs-settings',
478 'betterdocs-admin',
479 'betterdocs-dashboard',
480 'betterdocs-analytics',
481 'betterdocs-glossaries',
482 'betterdocs-faq',
483 'edit-doc_category',
484 'edit-doc_tag',
485 'edit-knowledge_base',
486 'betterdocs-ai-chatbot'
487 ];
488
489 if( in_array( $current_screen_id, $registered_screens ) ) {
490 $classes .= ' betterdocs-admin ';
491 }
492
493 if ( $dark_mode === true && in_array( $current_screen_id, $registered_screens ) ) {
494 $classes .= ' betterdocs-dark-mode ';
495 }
496
497 return $classes;
498 }
499
500 /**
501 * Remove Comments Column From List Table
502 *
503 * @param array $columns
504 *
505 * @return array
506 * @since 1.0.0
507 */
508 public function set_custom_edit_action_columns( $columns ) {
509 unset( $columns['comments'] );
510 $new_columns = [];
511 foreach ( $columns as $key => $value ) {
512 if ( $key == 'date' ) {
513 $new_columns['betterdocs_word_count'] = __( 'Word Count', 'betterdocs' ); // put the tags column before it
514 $new_columns['betterdocs_reaction'] = __( 'Reactions', 'betterdocs' );
515 }
516 $new_columns[ $key ] = $value;
517 }
518
519 return $new_columns;
520 }
521
522 public function manage_custom_columns( $column, $post_id ) {
523 global $wpdb;
524 switch ( $column ) {
525 case 'betterdocs_word_count':
526 $content_without_html_tags = trim( strip_tags( get_post_field( 'post_content', $post_id ) ) );
527 preg_match_all( '/<[^>]*>|[\p{L}\p{M}]+/u', $content_without_html_tags, $matches );
528 $total_words = ! empty( $matches[0] ) ? count( $matches[0] ) : count( [] );
529 $word_count = $total_words;
530 echo '<span>' . esc_html( intval( $word_count ) ) . '</span>';
531 break;
532 case 'betterdocs_reaction':
533 $where = "WHERE post_id='" . esc_sql( $post_id ) . "'";
534 $analytics = $wpdb->get_results(
535 "SELECT
536 sum(impressions) as totalViews,
537 sum(unique_visit) as totalUniqueViews,
538 sum(happy + sad + normal) as totalReactions,
539 sum(happy) as totalHappy,
540 sum(normal) as totalNormal,
541 sum(sad) as totalSad
542 FROM {$wpdb->prefix}betterdocs_analytics
543 $where"
544 );
545
546 echo '<ul class="reactions-count">
547 <li>
548 <a title="happy" class="betterdocs-feelings happy" data-feelings="happy" href="#">
549 <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">
550 <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
551 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
552 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
553 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" />
554 <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
555 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
556 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
557 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" />
558 </svg>
559 <span>' . esc_html( ( intval( $analytics[0]->totalHappy ) !== null ? intval( $analytics[0]->totalHappy ) : 0 ) ) . '</span>
560 </a>
561 </li>
562 <li>
563 <a title="normal" class="betterdocs-feelings normal" data-feelings="normal" href="#">
564 <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">
565 <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
566 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
567 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
568 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" />
569 </svg>
570 <span>' . esc_html( ( intval( $analytics[0]->totalNormal ) !== null ? intval( $analytics[0]->totalNormal ) : 0 ) ) . '</span>
571 </a>
572 </li>
573 <li>
574 <a title="sad" class="betterdocs-feelings sad" data-feelings="sad" href="#">
575 <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">
576 <circle class="st0" cx="27.5" cy="0.6" r="1.9" />
577 <circle class="st0" cx="36" cy="0.6" r="1.9" />
578 <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
579 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
580 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
581 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
582 c1.8,0,3.5,0.8,4.6,2.1C15,14.3,14.7,15,14.1,15z" />
583 </svg>
584 <span>' . esc_html( ( intval( $analytics[0]->totalNormal ) !== null ? intval( $analytics[0]->totalNormal ) : 0 ) ) . '</span>
585 </a>
586 </li>
587 </ul>';
588 break;
589 }
590 }
591
592 /**
593 * Enqueue Assets for Admin ( Styles )
594 *
595 * @param string $hook
596 *
597 * @return void
598 * @since 1.0.0
599 */
600 public function styles( $hook ) {
601 $this->assets->enqueue( 'betterdocs-global', 'admin/css/global.css', [], 'all' );
602
603 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
604 return;
605 }
606
607 $this->assets->enqueue( 'betterdocs-select2', 'vendor/css/select2.min.css', [], 'all' );
608 $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/css/daterangepicker.css', [], 'all' );
609 $this->assets->enqueue( 'betterdocs-old', 'admin/css/betterdocs.css', [], 'all' );
610
611 /**
612 * This scripts enqueued for Dashboard App.
613 */
614 $this->assets->enqueue( 'betterdocs', 'admin/css/dashboard.css', [ 'betterdocs-old' ], '', BETTERDOCS_VERSION );
615 $this->assets->enqueue( 'betterdocs-icons', 'admin/btd-icon/style.css' );
616 }
617
618 /**
619 * Enqueue Assets for Admin ( Scripts )
620 *
621 * @param string $hook
622 *
623 * @return void
624 * @since 1.0.0
625 */
626 public function scripts( $hook ) {
627 if ( ( $hook === 'edit.php' ) && get_post_type() == 'docs' ) {
628 $this->assets->enqueue(
629 'betterdocs-switcher',
630 'admin/js/switcher.js',
631 [
632 'jquery'
633 ]
634 );
635
636 $this->assets->localize(
637 'betterdocs-switcher',
638 'betterdocsSwitcher',
639 [
640 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
641 'site_address' => get_bloginfo( 'url' ),
642 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
643 'betterdocs_pro_version' => betterdocs()->pro_version()
644 ]
645 );
646
647 return;
648 }
649
650 wp_enqueue_script( 'wp-editor' ); // enqueue this for yoast related issue
651
652 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
653 return;
654 }
655
656 wp_enqueue_media(); // load early to fix problems with media upload issues on settings for wordpress 6.0.9
657 $this->assets->register( 'betterdocs-admin', 'admin/js/dashboard.js' );
658
659 $saved_settings = get_option( 'betterdocs_settings', false );
660 $dark_mode = $saved_settings['dark_mode'] ?? false;
661 $dark_mode = ! empty( $dark_mode ) && boolval( $dark_mode );
662 $this->assets->localize(
663 'betterdocs-admin',
664 'betterdocs_admin',
665 [
666 'ajaxurl' => admin_url( 'admin-ajax.php' ),
667 'doc_cat_order_nonce' => wp_create_nonce( 'doc_cat_order_nonce' ),
668 'knowledge_base_order_nonce' => wp_create_nonce( 'knowledge_base_order_nonce' ),
669 'paged' => isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 0, // phpcs:ignore WordPress.Security.NonceVerification.Missing
670 'per_page_id' => 'edit_doc_category_per_page',
671 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
672 'dark_mode' => $dark_mode,
673 'text' => __( 'Copied!', 'betterdocs' ),
674 'test_report' => __( 'Test Report!', 'betterdocs' ),
675 'sending' => __( 'Sending...', 'betterdocs' ),
676 'dir_url' => BETTERDOCS_ABSURL,
677 'rest_url' => esc_url_raw( rest_url() ),
678 'free_version' => betterdocs()->version,
679 'generate_data_url' => get_rest_url( null, '/betterdocs/v1/create-sample-docs' ),
680 'nonce' => wp_create_nonce( 'wp_rest' ),
681 'sync_nonce' => wp_create_nonce( 'ai_chatbot_embed' ),
682 'count_all_docs' => array_sum((array) wp_count_posts('docs')),
683 'count_all_faq' => array_sum((array) wp_count_posts('betterdocs_faq')),
684 'count_new_docs' => count(get_option('saved_docs_post_ids', [])) + count(get_option('betterdocs_ai_chatbot_error_posts', [])),
685 'admin_url' => admin_url(),
686 'ia_preview' => betterdocs()->settings->get( 'ia_enable_preview', false ),
687 'multiple_kb' => betterdocs()->settings->get( 'multiple_kb' ),
688 'previewMode' => betterdocs()->settings->get( 'ia_enable_preview', false ),
689 'dashboard_mode' => get_option( 'dashboard_mode' ),
690 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
691 'betterdocs_pro_version' => betterdocs()->pro_version(),
692 'analytics_older' => version_compare( betterdocs()->pro_version(), '3.3.4', '<=' ),
693 'disabled_embed_model_option' => get_option('disabled_embed_model_option'),
694 'betterdocs_ChatBot_plugin' => is_plugin_active( 'betterdocs-ai-chatbot/betterdocs-ai-chatbot.php' ),
695 'total_doc_category_terms' => wp_count_terms( 'doc_category')
696 ]
697 );
698
699 // If wp-date (which includes moment.js) is not registered, enqueue your custom moment.js
700 if ( ! wp_script_is( 'wp-date', 'registered' ) ) {
701 $this->assets->enqueue( 'moment', 'vendor/js/moment.min.js', [] );
702 }
703 wp_enqueue_script( 'betterdocs-admin' );
704
705 /**
706 * Duplicate Codes Need to Be Removed From Here Onwards
707 */
708
709 //FAQ Builder Related Localization
710 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/css/faq.css' );
711 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/js/faq.js' );
712
713 // removing emoji support
714 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
715 remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
716
717 betterdocs()->assets->localize(
718 'betterdocs-admin-faq',
719 'betterdocsFaq',
720 [
721 'dir_url' => BETTERDOCS_ABSURL,
722 'rest_url' => esc_url_raw( rest_url() ),
723 'free_version' => betterdocs()->version,
724 'nonce' => wp_create_nonce( 'wp_rest' ),
725 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
726 ]
727 );
728
729 //Glossaries Related Localization
730 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/css/faq.css' );
731
732 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/js/glossaries.js' );
733
734 betterdocs()->assets->localize(
735 'betterdocs-admin-glossaries',
736 'betterdocsGlossary',
737 [
738 'dir_url' => BETTERDOCS_ABSURL,
739 'rest_url' => esc_url_raw( rest_url() ),
740 'free_version' => betterdocs()->version,
741 'nonce' => wp_create_nonce( 'wp_rest' ),
742 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
743 ]
744 );
745 }
746
747 /**
748 * All admin pages header
749 *
750 * @return void
751 * @since 1.0.0
752 */
753 public function header( $admin_tab_name ) {
754 $quick_links = [
755 'switch_view' => sprintf(
756 '<a href="%s" class="betterdocs-button betterdocs-button-secondary">%s</a>',
757 add_query_arg(
758 [
759 'post_type' => 'docs',
760 'bdocs_view' => 'classic'
761 ],
762 'edit.php'
763 ),
764 __( 'Switch to Classic UI', 'betterdocs' )
765 ),
766 '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' ) )
767 ];
768
769 $quick_links = apply_filters( 'betterdocs_quick_links', $quick_links );
770
771 betterdocs()->views->get(
772 'admin/header',
773 [
774 'quick_links' => $quick_links,
775 'active_tab' => $admin_tab_name
776 ]
777 );
778 }
779
780 /**
781 * Register all the menus for BetterDocs
782 *
783 * @return void
784 * @since 1.0.0
785 */
786 public function menus() {
787 $default_args = [
788 'page_title' => 'BetterDocs',
789 'menu_title' => 'BetterDocs',
790 'capability' => 'edit_docs', // Unified capability
791 'menu_slug' => $this->slug,
792 'callback' => [ $this, 'output' ],
793 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
794 'position' => 5
795 ];
796
797 $_menu_position = 5;
798 global $submenu;
799
800 // Always register both UI endpoints
801 $this->register_modern_ui_fallback();
802
803 foreach ( $this->menu_list() as $key => $value ) {
804 if ( $key === 'betterdocs' ) {
805 $callable = 'add_menu_page';
806 $value = wp_parse_args( $value, $default_args );
807 call_user_func_array( $callable, $value );
808 } else {
809 $is_core_page = strpos($value['menu_slug'], '?') !== false;
810
811 if ($is_core_page) {
812 // Add classic UI directly
813 $submenu[$this->slug][] = [
814 $value['menu_title'],
815 $value['capability'],
816 $value['menu_slug'],
817 $value['page_title']
818 ];
819 } else {
820 // Add modern UI through WordPress API
821 add_submenu_page(
822 $this->slug,
823 $value['page_title'],
824 $value['menu_title'],
825 $value['capability'],
826 $value['menu_slug'],
827 $value['callback']
828 );
829 }
830 $_menu_position++;
831 }
832 }
833 }
834
835 private function register_modern_ui_fallback() {
836 // Add the submenu with valid parent slug
837 add_submenu_page(
838 'betterdocs', // Valid parent slug
839 __('All Docs', 'betterdocs'),
840 '', // Empty menu title hides it
841 'edit_docs',
842 'betterdocs-admin',
843 [ $this, 'output' ]
844 );
845
846 // Hide the menu item from appearing in the admin sidebar
847 global $submenu;
848 if (isset($submenu['betterdocs'])) {
849 foreach ($submenu['betterdocs'] as $key => $item) {
850 if ($item[2] === 'betterdocs-admin') {
851 unset($submenu['betterdocs'][$key]);
852 break;
853 }
854 }
855 }
856 }
857
858 /**
859 * BetterDocs Admin Page Output
860 *
861 * @return void
862 * @since 1.0.0
863 */
864 public function output() {
865 if ( betterdocs()->is_pro_active()
866 && version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
867 && get_current_screen()->id == 'betterdocs_page_betterdocs-analytics' ) {
868 betterdocs_pro()->views->get( 'admin/analytics-pro' );
869 } else {
870 betterdocs()->views->get(
871 'admin/main',
872 [
873 'admin_ui' => 'dnd'
874 ]
875 );
876 }
877 }
878
879 /**
880 * Menu creator helper
881 *
882 * @param string $title
883 * @param string $slug
884 * @param string $cap
885 * @param array $callback
886 *
887 * @return array
888 * @since 2.5.0
889 *
890 */
891 private function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null, $optional = [] ) {
892 return Helper::normalize_menu( $title, $slug, $cap, $callback, $optional );
893 }
894
895 /**
896 * BetterDocs Menu List
897 *
898 * @return array
899 * @since 1.0.0
900 */
901 private function menu_list() {
902 $parent_slug = [];
903
904 $betterdocs_admin_pages = [
905 'betterdocs' => [
906 'menu_slug' => $this->slug,
907 'page_title' => 'BetterDocs',
908 'menu_title' => 'BetterDocs',
909 'capability' => 'edit_docs',
910 'callback' => [ $this, 'output' ],
911 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
912 'position' => 5
913 ],
914 'dashboard' => $this->normalize_menu(
915 __( 'Dashboard', 'betterdocs' ),
916 'betterdocs-dashboard',
917 'edit_docs',
918 [
919 $this,
920 'output'
921 ]
922 ),
923 'all_docs' => $this->normalize_menu(
924 __( 'All Docs', 'betterdocs' ),
925 $this->ui_slug(),
926 'edit_docs',
927 [ $this, 'output' ],
928 $parent_slug
929 ),
930 'add_new' => $this->normalize_menu(
931 __( 'Add New', 'betterdocs' ),
932 'post-new.php?post_type=docs'
933 ),
934 'categories' => $this->normalize_menu(
935 __( 'Categories', 'betterdocs' ),
936 'edit-tags.php?taxonomy=doc_category&post_type=docs',
937 'manage_doc_terms'
938 ),
939 'tags' => $this->normalize_menu(
940 __( 'Tags', 'betterdocs' ),
941 'edit-tags.php?taxonomy=doc_tag&post_type=docs',
942 'manage_doc_terms'
943 ),
944 'settings' => $this->normalize_menu(
945 __( 'Settings', 'betterdocs' ),
946 'betterdocs-settings',
947 'edit_docs_settings',
948 [
949 $this,
950 'output'
951 ],
952 $parent_slug
953 ),
954 'analytics' => $this->normalize_menu(
955 __( 'Analytics', 'betterdocs' ),
956 'betterdocs-analytics',
957 'read_docs_analytics',
958 [
959 $this,
960 'output'
961 ],
962 $parent_slug
963 ),
964 'faq' => $this->normalize_menu(
965 __( 'FAQ Builder', 'betterdocs' ),
966 'betterdocs-faq',
967 'read_faq_builder',
968 [
969 $this,
970 'output'
971 ],
972 $parent_slug
973 )
974 ];
975
976 if ( betterdocs()->is_pro_active() && betterdocs()->settings->get( 'enable_glossaries' ) == true ) {
977 $betterdocs_admin_pages['glossaries'] = $this->normalize_menu(
978 __( 'Glossaries', 'betterdocs' ),
979 'betterdocs-glossaries',
980 'read_docs_analytics',
981 [
982 $this,
983 'output'
984 ],
985 $parent_slug
986 );
987 }
988
989
990 if (!betterdocs()->is_chatbot_active()) {
991 $betterdocs_admin_pages['ai_chatbot'] = $this->normalize_menu(
992 __('AI Chatbot', 'betterdocs'),
993 'betterdocs-ai-chatbot',
994 'edit_docs_settings',
995 [
996 $this,
997 'output'
998 ],
999 $parent_slug
1000 );
1001 }
1002
1003 return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages, [$this, 'output'], $parent_slug);
1004
1005 }
1006
1007 public function add_custom_classes_to_menu_items() {
1008 global $menu, $submenu;
1009
1010 $menu_items = [
1011 'betterdocs' => 'betterdocs',
1012 'betterdocs_page_all_docs' => 'betterdocs-all-docs',
1013 'betterdocs_page_add_new' => 'betterdocs-add-new',
1014 'edit-tags.php?taxonomy=doc_category&post_type=docs' => 'betterdocs-categories',
1015 'edit-tags.php?taxonomy=doc_tag&post_type=docs' => 'betterdocs-tags',
1016 'betterdocs-settings' => 'betterdocs-settings',
1017 'betterdocs-analytics' => 'betterdocs-analytics',
1018 'betterdocs-faq' => 'betterdocs-faq',
1019 'betterdocs-glossaries' => 'betterdocs-glossaries',
1020 'betterdocs-ai-chatbot' => 'betterdocs-ai-chatbot',
1021 'edit-tags.php?taxonomy=knowledge_base&post_type=docs' => 'betterdocs-multiplekb'
1022 ];
1023
1024 foreach ( $menu as &$item ) {
1025 if ( isset( $menu_items[ $item[2] ] ) ) {
1026 if ( ! isset( $item[4] ) ) {
1027 $item[4] = '';
1028 }
1029 $item[4] .= '' . $menu_items[ $item[2] ];
1030 }
1031 }
1032
1033 foreach ( $submenu as &$submenu_items ) {
1034 foreach ( $submenu_items as &$sub_item ) {
1035 if ( isset( $menu_items[ $sub_item[2] ] ) ) {
1036 if ( ! isset( $sub_item[4] ) ) {
1037 $sub_item[4] = '';
1038 }
1039 $sub_item[4] .= '' . $menu_items[ $sub_item[2] ];
1040 }
1041 }
1042 }
1043 }
1044
1045 public function quick_setup_menu( $menus ) {
1046 $betterdocs_settings = get_option( 'betterdocs_settings' );
1047 if ( $betterdocs_settings ) {
1048 return $menus;
1049 } else {
1050 $menus['quick_setup'] = $this->normalize_menu(
1051 __( 'Quick Setup', 'betterdocs' ),
1052 'betterdocs-setup',
1053 'delete_users',
1054 [
1055 $this->container->get( SetupWizard::class ),
1056 'views'
1057 ]
1058 );
1059 }
1060
1061 return $menus;
1062 }
1063
1064 public function insert_plugin_links( $links ) {
1065 $links[] = '<a href="admin.php?page=betterdocs-settings">' . __( 'Settings', 'betterdocs' ) . '</a>';
1066
1067 return $links;
1068 }
1069
1070 public function toolbar_menu( $admin_bar ) {
1071 if ( ! is_admin() || ! is_admin_bar_showing() ) {
1072 return;
1073 }
1074
1075 // Show only when the user is a member of this site, or they're a super admin.
1076 if ( ! is_user_member_of_blog() && ! is_super_admin() ) {
1077 return;
1078 }
1079
1080 $docs_url = '';
1081 $encyclopedia_url = '';
1082
1083 if ( $this->settings->get( 'builtin_doc_page' ) ) {
1084 $docs_url = get_post_type_archive_link( 'docs' );
1085 } elseif ( intval( $docs_page = $this->settings->get( 'docs_page' ) ) ) {
1086 $docs_url = ! empty( $docs_page ) ? get_page_link( $docs_page ) : false;
1087 }
1088
1089 if ( ! $docs_url ) {
1090 return;
1091 }
1092
1093 $slug = $this->settings->get( 'encyclopedia_root_slug' );
1094
1095 $encyclopedia_url = home_url( $slug );
1096
1097 $admin_bar->add_node(
1098 [
1099 'parent' => 'site-name',
1100 'id' => 'view-docs',
1101 'title' => __( 'Visit Documentation', 'betterdocs' ),
1102 'href' => $docs_url
1103 ]
1104 );
1105
1106 $is_enable_encyclopedia = betterdocs()->settings->get( 'enable_encyclopedia' );
1107
1108 if ( $is_enable_encyclopedia && betterdocs()->is_pro_active() ) {
1109 $admin_bar->add_node(
1110 [
1111 'parent' => 'site-name',
1112 'id' => 'view-encyclopedia',
1113 'title' => __( 'Visit Encyclopedia', 'betterdocs' ),
1114 'href' => $encyclopedia_url
1115 ]
1116 );
1117 }
1118 }
1119
1120 /**
1121 * Save last visited admin ui
1122 *
1123 * @since 3.0.1
1124 *
1125 */
1126 public function save_admin_page() {
1127 if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'docs' && isset( $_GET['bdocs_view'] ) && $_GET['bdocs_view'] === 'classic' ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1128 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'classic_ui' );
1129 } elseif ( isset( $_GET['page'] ) && $_GET['page'] === 'betterdocs-admin' ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
1130 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'modern_ui' );
1131 }
1132 }
1133
1134 /**
1135 * Return last visited admin ui slug
1136 *
1137 * @return string
1138 * @since 3.0.1
1139 */
1140 public function ui_slug() {
1141 $last_visited = get_user_meta(get_current_user_id(), 'last_visited_docs_admin_page', true);
1142 $docs_exist = get_posts([
1143 'post_type' => 'docs',
1144 'post_status' => 'any',
1145 'numberposts' => 1
1146 ]);
1147
1148 return ($last_visited === 'modern_ui' || empty($docs_exist))
1149 ? 'betterdocs-admin'
1150 : 'edit.php?post_type=docs&bdocs_view=classic';
1151 }
1152
1153 /**
1154 * Resets a duplicate submenu in WordPress if the parent main menu and the first submenu permalink are not the same.
1155 *
1156 * @return string
1157 * @since 3.0.1
1158 */
1159 public function reset_submenu() {
1160 global $submenu;
1161
1162 $docs = get_posts( [ 'post_type' => 'docs' ] );
1163 if ( count( $docs ) == 0 ) {
1164 return;
1165 }
1166
1167 $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
1168
1169 if ( $last_visited === 'classic_ui' && isset( $submenu['betterdocs-admin'] ) && in_array( 'betterdocs-admin', $submenu['betterdocs-admin'][0] ) ) {
1170 unset( $submenu['betterdocs-admin'][0] );
1171 $submenu['betterdocs-admin'] = array_values( $submenu['betterdocs-admin'] );
1172 }
1173 }
1174 }
1175