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

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