PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.7.1
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.7.1
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 3.7.1, at includes/Core/Admin.php

890 lines 37.0 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\Dependencies\DI\Container;
14
15 class Admin extends Base {
16 /**
17 * @var CacheBank
18 */
19 private static $cache_bank;
20 /**
21 * Admin Root Menu Slug
22 * @var string
23 */
24 private $slug = 'betterdocs-admin';
25 /**
26 * Insights
27 *
28 * @var Insights
29 */
30 private $insights = null;
31
32 /**
33 * DI\Container
34 *
35 * @var Container
36 */
37 private $container;
38
39 /**
40 * Database Wrapper
41 *
42 * @var Settings
43 */
44 private $settings;
45
46 /**
47 * KBMigration
48 *
49 * @var KBMigration
50 */
51 private $kbmigration;
52
53 /**
54 * Enqueue
55 * @var Enqueue
56 */
57 private $assets;
58
59 /**
60 * FAQBuilder
61 * @var FAQBuilder
62 */
63 private $faq_builder;
64 private $glossaries;
65
66 public function __construct( Container $container, PostType $type, Enqueue $assets, Settings $settings, KBMigration $kbmigration ) {
67 $this->container = $container;
68 $this->assets = $assets;
69 $this->settings = $settings;
70 $this->kbmigration = $kbmigration;
71 $this->slug = 'betterdocs-admin';
72
73 add_action( 'init', [$type, 'register'], 9 );
74
75 $type->init();
76 $type->admin_init();
77
78 $this->faq_builder = $this->container->get( FAQBuilder::class );
79 $this->glossaries = $this->container->get( Glossaries::class );
80
81 if ( ! is_admin() ) {
82 return;
83 }
84
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 );
89
90 add_action( 'admin_menu', [$this, 'menus'] );
91 add_action( 'admin_menu', [$this, 'reset_submenu'] );
92 add_action( 'admin_head', [$this, 'add_custom_classes_to_menu_items'] );
93 add_filter( 'plugin_action_links_' . BETTERDOCS_PLUGIN_BASENAME, [$this, 'insert_plugin_links'] );
94
95 // $this->container->get( SetupWizard::class )->init();
96
97 add_action( 'admin_enqueue_scripts', [$this, 'styles'] );
98 add_action( 'admin_enqueue_scripts', [$this, 'scripts'] );
99 //add_action( 'betterdocs_listing_header', [ $this, 'header' ], 10, 1 );
100 add_action( 'admin_bar_menu', [$this, 'toolbar_menu'], 32 );
101
102 add_filter( 'admin_body_class', [$this, 'body_classes'] );
103 add_filter( 'parent_file', [$type, 'highlight_admin_menu'] );
104 add_filter( 'submenu_file', [$type, 'highlight_admin_submenu'], 10, 2 );
105 add_filter( 'betterdocs_admin_menu', [$this, 'quick_setup_menu'], 10, 1 );
106
107 /**
108 * Remove Comments Column from List Table.
109 */
110 add_filter( 'manage_docs_posts_columns', [$this, 'set_custom_edit_action_columns'] );
111 add_filter( 'manage_docs_posts_custom_column', [$this, 'manage_custom_columns'], 10, 2 );
112
113 /**
114 * Add New Column
115 */
116 add_filter( 'manage_users_columns', [$this, 'add_users_total_docs_column'], 10, 1 );
117 add_filter( 'manage_users_custom_column', [$this, 'popular_users_docs_data'], 10, 3 );
118
119 if ( $this->settings->get( 'enable_estimated_reading_time' ) ) {
120 add_action( 'add_meta_boxes', [$this, 'reading_meta_box_'], 10 );
121 }
122
123 self::$cache_bank = CacheBank::get_instance();
124
125 // Remove OLD notice from 1.0.0 (if other WPDeveloper plugin has notice)
126 NoticeRemover::get_instance( '1.0.0' );
127
128 try {
129 $this->notices();
130 } catch ( Exception $e ) {
131 unset( $e );
132 }
133 }
134
135 public function add_users_total_docs_column( $columns ) {
136 $new_column = [
137 'docs' => __( 'Docs', 'betterdocs' )
138 ];
139 $columns = array_merge( $columns, $new_column );
140 return $columns;
141 }
142
143 public function popular_users_docs_data( $output, $column_name, $user_id ) {
144 if ( $column_name == 'docs' ) {
145 $total_count = count_user_posts( $user_id, 'docs', true );
146 return '<a href="edit.php?post_type=docs&author=' . $user_id . '" class="edit"><span aria-hidden="true">' . $total_count . '</span></a>';
147 }
148 return $output;
149 }
150
151 public function reading_meta_box_() {
152 add_meta_box( 'betterdocs_estimated_time_metabox', __( 'Estimated Reading Time', 'betterdocs' ), [
153 $this,
154 'render_estimated_time_markup'
155 ], 'docs' );
156 }
157
158 public function render_estimated_time_markup() {
159 betterdocs()->views->get( 'admin/metabox/estimated-reading-box' );
160 }
161
162 public function compatibility_notices() {
163 if ( betterdocs()->is_pro_active() ) {
164 $plugins = Helper::get_plugins();
165 $plugin_data = $plugins['betterdocs-pro/betterdocs-pro.php'];
166
167 if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], '2.5.0', '>=' ) ) {
168 return;
169 }
170
171 betterdocs()->views->get( 'admin/notices/compatibility', ['version' => $plugin_data['Version']] );
172 }
173 }
174
175 public function plugin_insights( $prevent_init = false ) {
176 $this->insights = Insights::get_instance( BETTERDOCS_PLUGIN_FILE, [
177 'opt_in' => true,
178 'goodbye_form' => true,
179 'item_id' => 'c7b16777b4f1b83f6083'
180 ] );
181
182 $this->insights->set_notice_options( [
183 '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' ),
184 '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' )
185 ] );
186
187 if ( ! $prevent_init ) {
188 $this->insights->init();
189 }
190
191 return $this->insights;
192 }
193
194 /**
195 * Admin notices for Review and others.
196 *
197 * @return void
198 * @throws Exception
199 */
200 public function notices() {
201 $notices = new Notices( [
202 'id' => 'betterdocs',
203 'storage_key' => 'notices',
204 'lifetime' => 3,
205 'stylesheet_url' => $this->assets->asset_url( 'admin/css/notices.css' ),
206 'styles' => $this->assets->asset_url( 'admin/css/notices.css' ),
207 'priority' => 4
208 ] );
209
210 /**
211 * Review Notice
212 * @var mixed $message
213 */
214
215 $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' );
216
217 $_review_notice = [
218 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
219 'html' => '<p>' . $message . '</p>',
220 'links' => [
221 'later' => [
222 'link' => 'https://wordpress.org/plugins/betterdocs/#reviews',
223 'target' => '_blank',
224 'label' => __( 'Sure, you deserve it!', 'betterdocs' ),
225 'icon_class' => 'dashicons dashicons-external'
226 ],
227 'allready' => [
228 'label' => __( 'I already did', 'betterdocs' ),
229 'icon_class' => 'dashicons dashicons-smiley',
230 'attributes' => [
231 'data-dismiss' => true
232 ]
233 ],
234 'maybe_later' => [
235 'label' => __( 'Maybe Later', 'betterdocs' ),
236 'icon_class' => 'dashicons dashicons-calendar-alt',
237 'attributes' => [
238 'data-later' => true,
239 'class' => 'dismiss-btn'
240 ]
241 ],
242 'support' => [
243 'link' => 'https://wpdeveloper.com/support',
244 'attributes' => [
245 'target' => '_blank'
246 ],
247 'label' => __( 'I need help', 'betterdocs' ),
248 'icon_class' => 'dashicons dashicons-sos'
249 ],
250 'never_show_again' => [
251 'label' => __( 'Never show again', 'betterdocs' ),
252 'icon_class' => 'dashicons dashicons-dismiss',
253 'attributes' => [
254 'data-dismiss' => true
255 ]
256 ]
257 ]
258 ];
259
260 $notices->add( 'review', $_review_notice, [
261 'start' => $notices->strtotime( '+10 days' ),
262 'recurrence' => 30,
263 'dismissible' => true
264 ] );
265
266 if ( $this->kbmigration->existing_plugins && ! in_array( $this->kbmigration->existing_plugins[0][0], $this->kbmigration->migrated_plugins ) ) {
267 $plugin_name = '<strong>' . esc_html( $this->kbmigration->existing_plugins[0][1] ) . '</strong>';
268
269 $message = sprintf(
270 'Already using %s? Power up your Knowledge Base by migrating all your docs, settings to BetterDocs with just 1 click.',
271 $plugin_name
272 );
273
274 $translated_message = __( $message, 'betterdocs' );
275
276 $migration_message = sprintf(
277 '<p class="migration-message">%s</p><a class="button button-primary betterdocs-migration-notice" href="%s">%s</a>',
278 $translated_message,
279 esc_url( admin_url( 'admin.php?page=betterdocs-settings&tab=tab-migration' ) ),
280 __( 'Start Migration', 'betterdocs' )
281 );
282
283 $_migration_notice = [
284 'thumbnail' => '',
285 'html' => $migration_message,
286 'links' => [
287 'maybe_later' => [
288 'label' => __( 'Maybe Later', 'betterdocs' ),
289 'icon_class' => 'dashicons dashicons-calendar-alt',
290 'attributes' => [
291 'data-later' => true,
292 'class' => 'dismiss-btn'
293 ]
294 ],
295 'never_show_again' => [
296 'label' => __( 'Never show again', 'betterdocs' ),
297 'icon_class' => 'dashicons dashicons-dismiss',
298 'attributes' => [
299 'data-dismiss' => true
300 ]
301 ]
302 ]
303 ];
304
305 $notices->add( 'migration', $_migration_notice, [
306 'start' => $notices->time(),
307 'recurrence' => false,
308 'dismissible' => true
309 //'display_if' => current_user_can( 'delete_users' )
310 ] );
311 }
312
313 /**
314 * Opt-In Notice
315 */
316 if ( $this->insights != null ) {
317 $notices->add( 'opt_in', [$this->insights, 'notice'], [
318 'classes' => 'updated put-dismiss-notice',
319 'start' => $notices->time(),
320 // 'start' => $notices->strtotime( '+20 days' ),
321 'dismissible' => true,
322 'do_action' => 'wpdeveloper_notice_clicked_for_betterdocs',
323 'display_if' => ! function_exists( 'betterdocs_pro' )
324 ] );
325 }
326
327 $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>';
328 $_black_friday_notice = [
329 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
330 'html' => $b_message
331 ];
332
333 $notices->add( 'black_friday_notice', $_black_friday_notice, [
334 'start' => $notices->time(),
335 'recurrence' => false,
336 'dismissible' => true,
337 'refresh' => BETTERDOCS_VERSION,
338 "expire" => strtotime( '11:59:59pm 2nd December, 2023' ),
339 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
340 ] );
341
342 self::$cache_bank->create_account( $notices );
343 self::$cache_bank->calculate_deposits( $notices );
344 if ( method_exists( self::$cache_bank, 'clear_notices_in_' ) ) {
345 self::$cache_bank->clear_notices_in_( [
346 'toplevel_page_betterdocs-admin',
347 'betterdocs_page_betterdocs-admin',
348 'betterdocs_page_betterdocs-settings',
349 'betterdocs_page_betterdocs-faq',
350 'betterdocs_page_betterdocs-analytics',
351 'betterdocs_page_betterdocs-glossaries',
352 'edit-doc_category',
353 'edit-doc_tag'
354 ], $notices, true );
355 }
356 }
357
358 public function body_classes( $classes ) {
359 $saved_settings = get_option( 'betterdocs_settings', false );
360 $dark_mode = isset( $saved_settings['dark_mode'] ) ? $saved_settings['dark_mode'] : false;
361 $dark_mode = ! empty( $dark_mode ) ? boolval( $dark_mode ) : false;
362 $current_screen_id = get_current_screen() != null ? str_replace( 'toplevel_page_', '', get_current_screen()->id ) : '';
363 $registered_screens = [
364 'betterdocs-settings',
365 'betterdocs-admin',
366 'betterdocs-analytics',
367 'betterdocs-glossaries'
368 ];
369 $classes .= ' betterdocs-admin ';
370
371 if ( $dark_mode === true && in_array( $current_screen_id, $registered_screens ) ) {
372 $classes .= ' betterdocs-dark-mode ';
373 }
374
375 return $classes;
376 }
377
378 /**
379 * Remove Comments Column From List Table
380 *
381 * @param array $columns
382 *
383 * @return array
384 * @since 1.0.0
385 */
386 public function set_custom_edit_action_columns( $columns ) {
387 unset( $columns['comments'] );
388 $new_columns = [];
389 foreach ( $columns as $key => $value ) {
390 if ( $key == 'date' ) {
391 $new_columns['betterdocs_word_count'] = __( 'Word Count', 'betterdocs' ); // put the tags column before it
392 $new_columns['betterdocs_reaction'] = __( 'Reactions', 'betterdocs' );
393 }
394 $new_columns[$key] = $value;
395 }
396
397 return $new_columns;
398 }
399
400 public function manage_custom_columns( $column, $post_id ) {
401 global $wpdb;
402 switch ( $column ) {
403 case 'betterdocs_word_count':
404 $content_without_html_tags = trim( strip_tags( get_post_field( 'post_content', $post_id ) ) );
405 preg_match_all( '/<[^>]*>|[\p{L}\p{M}]+/u', $content_without_html_tags, $matches );
406 $total_words = ! empty( $matches[0] ) ? count( $matches[0] ) : count( [] );
407 $word_count = $total_words;
408 echo '<span>' . $word_count . '</span>';
409 break;
410 case 'betterdocs_reaction':
411 $where = "WHERE post_id='" . esc_sql( $post_id ) . "'";
412 $analytics = $wpdb->get_results( "SELECT
413 sum(impressions) as totalViews,
414 sum(unique_visit) as totalUniqueViews,
415 sum(happy + sad + normal) as totalReactions,
416 sum(happy) as totalHappy,
417 sum(normal) as totalNormal,
418 sum(sad) as totalSad
419 FROM {$wpdb->prefix}betterdocs_analytics
420 $where" );
421
422 echo '<ul class="reactions-count">
423 <li>
424 <a title="happy" class="betterdocs-feelings happy" data-feelings="happy" href="#">
425 <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">
426 <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
427 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
428 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
429 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" />
430 <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
431 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
432 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
433 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" />
434 </svg>
435 <span>' . ( $analytics[0]->totalHappy != null ? $analytics[0]->totalHappy : 0 ) . '</span>
436 </a>
437 </li>
438 <li>
439 <a title="normal" class="betterdocs-feelings normal" data-feelings="normal" href="#">
440 <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">
441 <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
442 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
443 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
444 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" />
445 </svg>
446 <span>' . ( $analytics[0]->totalNormal != null ? $analytics[0]->totalNormal : 0 ) . '</span>
447 </a>
448 </li>
449 <li>
450 <a title="sad" class="betterdocs-feelings sad" data-feelings="sad" href="#">
451 <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">
452 <circle class="st0" cx="27.5" cy="0.6" r="1.9" />
453 <circle class="st0" cx="36" cy="0.6" r="1.9" />
454 <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
455 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
456 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
457 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
458 c1.8,0,3.5,0.8,4.6,2.1C15,14.3,14.7,15,14.1,15z" />
459 </svg>
460 <span>' . ( $analytics[0]->totalSad != null ? $analytics[0]->totalSad : 0 ) . '</span>
461 </a>
462 </li>
463 </ul>';
464 break;
465 }
466 }
467
468 /**
469 * Enqueue Assets for Admin ( Styles )
470 *
471 * @param string $hook
472 *
473 * @return void
474 * @since 1.0.0
475 */
476 public function styles( $hook ) {
477 $this->assets->enqueue( 'betterdocs-global', 'admin/css/global.css', [], 'all' );
478
479 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
480 return;
481 }
482
483 $this->assets->enqueue( 'betterdocs-select2', 'vendor/css/select2.min.css', [], 'all' );
484 $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/css/daterangepicker.css', [], 'all' );
485 $this->assets->enqueue( 'betterdocs-old', 'admin/css/betterdocs.css', [], 'all' );
486
487 /**
488 * This scripts enqueued for Dashboard App.
489 */
490 $this->assets->enqueue( 'betterdocs', 'admin/css/dashboard.css', ['betterdocs-old'] );
491 $this->assets->enqueue( 'betterdocs-icons', 'admin/btd-icon/style.css' );
492 }
493
494 /**
495 * Enqueue Assets for Admin ( Scripts )
496 *
497 * @param string $hook
498 *
499 * @return void
500 * @since 1.0.0
501 */
502 public function scripts( $hook ) {
503 if ( ( $hook === 'edit.php' ) && get_post_type() == 'docs' ) {
504 $this->assets->enqueue( 'betterdocs-switcher', 'admin/js/switcher.js', [
505 'jquery'
506 ] );
507
508 $this->assets->localize( 'betterdocs-switcher', 'betterdocsSwitcher', [
509 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
510 'site_address' => get_bloginfo( 'url' ),
511 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
512 'betterdocs_pro_version' => betterdocs()->pro_version()
513 ] );
514
515 return;
516 }
517
518 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
519 return;
520 }
521
522 $this->assets->register( 'betterdocs-admin', 'admin/js/dashboard.js' );
523
524 $saved_settings = get_option( 'betterdocs_settings', false );
525 $dark_mode = $saved_settings['dark_mode'] ?? false;
526 $dark_mode = ! empty( $dark_mode ) && boolval( $dark_mode );
527 $this->assets->localize( 'betterdocs-admin', 'betterdocs_admin', [
528 'ajaxurl' => admin_url( 'admin-ajax.php' ),
529 'doc_cat_order_nonce' => wp_create_nonce( 'doc_cat_order_nonce' ),
530 'knowledge_base_order_nonce' => wp_create_nonce( 'knowledge_base_order_nonce' ),
531 'paged' => isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 0,
532 'per_page_id' => "edit_doc_category_per_page",
533 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
534 'dark_mode' => $dark_mode,
535 'text' => __( 'Copied!', 'betterdocs' ),
536 'test_report' => __( 'Test Report!', 'betterdocs' ),
537 'sending' => __( 'Sending...', 'betterdocs' ),
538 'dir_url' => BETTERDOCS_ABSURL,
539 'rest_url' => esc_url_raw( rest_url() ),
540 'free_version' => betterdocs()->version,
541 'generate_data_url' => get_rest_url( null, '/betterdocs/v1/create-sample-docs' ),
542 'nonce' => wp_create_nonce( 'wp_rest' ),
543 'admin_url' => admin_url(),
544 'ia_preview' => betterdocs()->settings->get( 'ia_enable_preview', false ),
545 'multiple_kb' => betterdocs()->settings->get( 'multiple_kb' ),
546 'previewMode' => betterdocs()->settings->get( 'ia_enable_preview', false ),
547 'dashboard_mode' => get_option( 'dashboard_mode' ),
548 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
549 'betterdocs_pro_version' => betterdocs()->pro_version(),
550 'analytics_older' => version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
551 ] );
552
553 $this->assets->enqueue( 'moment', 'vendor/js/moment.min.js', [] );
554 wp_enqueue_script( 'betterdocs-admin' );
555
556 /**
557 * Duplicate Codes Need to Be Removed From Here Onwards
558 */
559
560 //FAQ Builder Related Localization
561 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/css/faq.css' );
562 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/js/faq.js' );
563
564 // removing emoji support
565 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
566 remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
567
568 betterdocs()->assets->localize( 'betterdocs-admin-faq', 'betterdocsFaq', [
569 'dir_url' => BETTERDOCS_ABSURL,
570 'rest_url' => esc_url_raw( rest_url() ),
571 'free_version' => betterdocs()->version,
572 'nonce' => wp_create_nonce( 'wp_rest' ),
573 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
574 ] );
575
576 //Glossaries Related Localization
577 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/css/faq.css' );
578
579 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/js/glossaries.js' );
580
581 betterdocs()->assets->localize( 'betterdocs-admin-glossaries', 'betterdocsGlossary', [
582 'dir_url' => BETTERDOCS_ABSURL,
583 'rest_url' => esc_url_raw( rest_url() ),
584 'free_version' => betterdocs()->version,
585 'nonce' => wp_create_nonce( 'wp_rest' ),
586 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
587 ] );
588 }
589
590 /**
591 * All admin pages header
592 *
593 * @return void
594 * @since 1.0.0
595 */
596 public function header( $admin_tab_name ) {
597 $quick_links = [
598 'switch_view' => sprintf( '<a href="%s" class="betterdocs-button betterdocs-button-secondary">%s</a>', add_query_arg( [
599 'post_type' => 'docs',
600 'bdocs_view' => 'classic'
601 ], 'edit.php' ), __( 'Switch to Classic UI', 'betterdocs' ) ),
602 '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' ) )
603 ];
604
605 $quick_links = apply_filters( 'betterdocs_quick_links', $quick_links );
606
607 betterdocs()->views->get( 'admin/header', [
608 'quick_links' => $quick_links,
609 'active_tab' => $admin_tab_name
610 ] );
611 }
612
613 /**
614 * Register all the menus for BetterDocs
615 *
616 * @return void
617 * @since 1.0.0
618 */
619
620 public function menus() {
621 $default_args = [
622 'page_title' => 'BetterDocs',
623 'menu_title' => 'BetterDocs',
624 'capability' => 'edit_posts',
625 'menu_slug' => $this->slug,
626 'callback' => [$this, 'output'],
627 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
628 'position' => 5
629 ];
630
631 $_menu_position = 5;
632
633 foreach ( $this->menu_list() as $key => $value ) {
634 if ( $key === 'betterdocs' ) {
635 $callable = 'add_menu_page';
636 $value = wp_parse_args( $value, $default_args );
637 } else {
638 $callable = 'add_submenu_page';
639 $default_args['callback'] = '';
640 $default_args['position'] = $_menu_position;
641 unset( $default_args['icon_url'] );
642 $value = wp_parse_args( $value, array_merge( ['parent_slug' => $this->slug], $default_args ) );
643 }
644
645 $_menu_position++;
646
647 call_user_func_array( $callable, $value );
648 }
649 }
650
651 /**
652 * BetterDocs Admin Page Output
653 *
654 * @return void
655 * @since 1.0.0
656 */
657 public function output() {
658 if ( betterdocs()->is_pro_active()
659 && version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
660 && get_current_screen()->id == 'betterdocs_page_betterdocs-analytics' ) {
661 betterdocs_pro()->views->get( 'admin/analytics-pro' );
662 } else {
663 betterdocs()->views->get( 'admin/main', [
664 'admin_ui' => 'dnd'
665 ] );
666 }
667 }
668
669 /**
670 * Menu creator helper
671 *
672 * @param string $title
673 * @param string $slug
674 * @param string $cap
675 * @param array $callback
676 *
677 * @return array
678 * @since 2.5.0
679 *
680 */
681 private function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null, $optional = [] ) {
682 return Helper::normalize_menu( $title, $slug, $cap, $callback, $optional );
683 }
684
685 /**
686 * BetterDocs Menu List
687 *
688 * @return array
689 * @since 1.0.0
690 */
691 private function menu_list() {
692 $parent_slug = [];
693
694 $betterdocs_admin_pages = [
695 'betterdocs' => [
696 'menu_slug' => $this->slug,
697 'page_title' => 'BetterDocs',
698 'menu_title' => 'BetterDocs',
699 'capability' => 'edit_docs',
700 'callback' => [$this, 'output'],
701 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
702 'position' => 5
703 ],
704 'all_docs' => $this->normalize_menu( __( 'All Docs', 'betterdocs' ), $this->ui_slug() ),
705 'add_new' => $this->normalize_menu( __( 'Add New', 'betterdocs' ), 'post-new.php?post_type=docs' ),
706 'categories' => $this->normalize_menu( __( 'Categories', 'betterdocs' ), 'edit-tags.php?taxonomy=doc_category&post_type=docs', 'manage_doc_terms' ),
707 'tags' => $this->normalize_menu( __( 'Tags', 'betterdocs' ), 'edit-tags.php?taxonomy=doc_tag&post_type=docs', 'manage_doc_terms' ),
708 'settings' => $this->normalize_menu( __( 'Settings', 'betterdocs' ), 'betterdocs-settings', 'edit_docs_settings', [
709 $this,
710 'output'
711 ], $parent_slug ),
712 'analytics' => $this->normalize_menu( __( 'Analytics', 'betterdocs' ), 'betterdocs-analytics', 'read_docs_analytics', [
713 $this,
714 'output'
715 ], $parent_slug ),
716 'faq' => $this->normalize_menu( __( 'FAQ Builder', 'betterdocs' ), 'betterdocs-faq', 'read_docs_analytics', [
717 $this,
718 'output'
719 ], $parent_slug )
720 ];
721
722 if ( betterdocs()->is_pro_active() && betterdocs()->settings->get( 'enable_glossaries' ) == true ) {
723 $betterdocs_admin_pages['glossaries'] = $this->normalize_menu( __( 'Glossaries', 'betterdocs' ), 'betterdocs-glossaries', 'read_docs_analytics', [
724 $this,
725 'output'
726 ], $parent_slug );
727 }
728
729 return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages );
730 }
731
732 public function add_custom_classes_to_menu_items() {
733 global $menu, $submenu;
734
735 $menu_items = [
736 'betterdocs' => 'betterdocs',
737 'betterdocs_page_all_docs' => 'betterdocs-all-docs',
738 'betterdocs_page_add_new' => 'betterdocs-add-new',
739 'edit-tags.php?taxonomy=doc_category&post_type=docs' => 'betterdocs-categories',
740 'edit-tags.php?taxonomy=doc_tag&post_type=docs' => 'betterdocs-tags',
741 'betterdocs-settings' => 'betterdocs-settings',
742 'betterdocs-analytics' => 'betterdocs-analytics',
743 'betterdocs-faq' => 'betterdocs-faq',
744 'betterdocs-glossaries' => 'betterdocs-glossaries',
745 'edit-tags.php?taxonomy=knowledge_base&post_type=docs' => 'betterdocs-multiplekb'
746 ];
747
748 foreach ( $menu as &$item ) {
749 if ( isset( $menu_items[$item[2]] ) ) {
750 if ( ! isset( $item[4] ) ) {
751 $item[4] = '';
752 }
753 $item[4] .= '' . $menu_items[$item[2]];
754 }
755 }
756
757 foreach ( $submenu as &$submenu_items ) {
758 foreach ( $submenu_items as &$sub_item ) {
759 if ( isset( $menu_items[$sub_item[2]] ) ) {
760 if ( ! isset( $sub_item[4] ) ) {
761 $sub_item[4] = '';
762 }
763 $sub_item[4] .= '' . $menu_items[$sub_item[2]];
764 }
765 }
766 }
767 }
768
769 public function quick_setup_menu( $menus ) {
770 $betterdocs_settings = get_option( 'betterdocs_settings' );
771 if ( $betterdocs_settings ) {
772 return $menus;
773 } else {
774 $menus['quick_setup'] = $this->normalize_menu( __( 'Quick Setup', 'betterdocs' ), 'betterdocs-setup', 'delete_users', [
775 $this->container->get( SetupWizard::class ),
776 'views'
777 ] );
778 }
779
780 return $menus;
781 }
782
783 public function insert_plugin_links( $links ) {
784 $links[] = '<a href="admin.php?page=betterdocs-settings">' . __( 'Settings', 'betterdocs' ) . '</a>';
785
786 return $links;
787 }
788
789 public function toolbar_menu( $admin_bar ) {
790 if ( ! is_admin() || ! is_admin_bar_showing() ) {
791 return;
792 }
793
794 // Show only when the user is a member of this site, or they're a super admin.
795 if ( ! is_user_member_of_blog() && ! is_super_admin() ) {
796 return;
797 }
798
799 $docs_url = '';
800 $encyclopedia_url = '';
801
802 if ( $this->settings->get( 'builtin_doc_page' ) ) {
803 $docs_url = get_post_type_archive_link( 'docs' );
804 } elseif ( intval( $docs_page = $this->settings->get( 'docs_page' ) ) ) {
805 $docs_url = ! empty( $docs_page ) ? get_page_link( $docs_page ) : false;
806 }
807
808 if ( ! $docs_url ) {
809 return;
810 }
811
812 $slug = $this->settings->get( 'encyclopedia_root_slug' );
813
814 $encyclopedia_url = home_url( $slug );
815
816 $admin_bar->add_node( [
817 'parent' => 'site-name',
818 'id' => 'view-docs',
819 'title' => __( 'Visit Documentation', 'betterdocs' ),
820 'href' => $docs_url
821 ] );
822
823 $is_enable_encyclopedia = betterdocs()->settings->get( 'enable_encyclopedia' );
824
825 if ( $is_enable_encyclopedia && betterdocs()->is_pro_active() ) {
826 $admin_bar->add_node( [
827 'parent' => 'site-name',
828 'id' => 'view-encyclopedia',
829 'title' => __( 'Visit Encyclopedia', 'betterdocs' ),
830 'href' => $encyclopedia_url
831 ] );
832 }
833 }
834
835 /**
836 * Save last visited admin ui
837 *
838 * @since 3.0.1
839 *
840 */
841 public function save_admin_page() {
842 if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'docs' && isset( $_GET['bdocs_view'] ) && $_GET['bdocs_view'] === 'classic' ) {
843 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'classic_ui' );
844 } elseif ( isset( $_GET['page'] ) && $_GET['page'] === 'betterdocs-admin' ) {
845 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'modern_ui' );
846 }
847 }
848
849 /**
850 * Return last visited admin ui slug
851 *
852 * @return string
853 * @since 3.0.1
854 */
855 public function ui_slug() {
856 $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
857 $docs = get_posts( ['post_type' => 'docs', 'post_status' => 'any', 'numberposts' => 2] );
858
859 if ( $last_visited === 'modern_ui' || count( $docs ) == 0 ) {
860 $slug = 'betterdocs-admin';
861 } else {
862 $slug = admin_url( 'edit.php?post_type=docs&bdocs_view=classic' );
863 }
864
865 return $slug;
866 }
867
868 /**
869 * Resets a duplicate submenu in WordPress if the parent main menu and the first submenu permalink are not the same.
870 *
871 * @return string
872 * @since 3.0.1
873 */
874 public function reset_submenu() {
875 global $submenu;
876
877 $docs = get_posts( ['post_type' => 'docs'] );
878 if ( count( $docs ) == 0 ) {
879 return;
880 }
881
882 $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
883
884 if ( $last_visited === 'classic_ui' && isset( $submenu['betterdocs-admin'] ) && in_array( "betterdocs-admin", $submenu['betterdocs-admin'][0] ) ) {
885 unset( $submenu['betterdocs-admin'][0] );
886 $submenu['betterdocs-admin'] = array_values( $submenu['betterdocs-admin'] );
887 }
888 }
889 }
890