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

897 lines 38.9 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 ] );
310 }
311
312 /**
313 * Opt-In Notice
314 */
315 $allow_tracking = get_option( 'wpins_allow_tracking' );
316 if ( $this->insights != null && ! isset( $allow_tracking[ 'betterdocs' ] ) ) {
317 $notices->add( 'opt_in', [$this->insights, 'notice'], [
318 'classes' => 'updated put-dismiss-notice',
319 // 'start' => $notices->time(),
320 'start' => strtotime('12:00:00pm December 6, 2024'),
321 'refresh' => BETTERDOCS_VERSION,
322 'dismissible' => true,
323 'do_action' => 'wpdeveloper_notice_clicked_for_betterdocs',
324 'display_if' => ! function_exists( 'betterdocs_pro' ),
325 'screens' => ['dashboard']
326 ] );
327 }
328
329 $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">
330 <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"/>
331 <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"/>
332 </svg> Upgrade To PRO</a></div>';
333 $_blackfriday_notice = [
334 'thumbnail' => $this->assets->icon( 'betterdocs-logo.svg', true ),
335 'html' => $blackfriday_message
336 ];
337
338 $notices->add( 'blackfriday24', $_blackfriday_notice, [
339 'start' => $notices->time(),
340 'recurrence' => false,
341 'dismissible' => true,
342 'refresh' => BETTERDOCS_VERSION,
343 "expire" => strtotime('11:59:59pm December 5, 2024'),
344 'display_if' => ! is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' )
345 ] );
346
347 self::$cache_bank->create_account( $notices );
348 self::$cache_bank->calculate_deposits( $notices );
349 if ( method_exists( self::$cache_bank, 'clear_notices_in_' ) ) {
350 self::$cache_bank->clear_notices_in_( [
351 'toplevel_page_betterdocs-admin',
352 'betterdocs_page_betterdocs-admin',
353 'betterdocs_page_betterdocs-settings',
354 'betterdocs_page_betterdocs-faq',
355 'betterdocs_page_betterdocs-analytics',
356 'betterdocs_page_betterdocs-glossaries',
357 'edit-doc_category',
358 'edit-doc_tag'
359 ], $notices, true );
360 }
361 }
362
363 public function body_classes( $classes ) {
364 $saved_settings = get_option( 'betterdocs_settings', false );
365 $dark_mode = isset( $saved_settings['dark_mode'] ) ? $saved_settings['dark_mode'] : false;
366 $dark_mode = ! empty( $dark_mode ) ? boolval( $dark_mode ) : false;
367 $current_screen_id = get_current_screen() != null ? str_replace( 'toplevel_page_', '', get_current_screen()->id ) : '';
368 $registered_screens = [
369 'betterdocs-settings',
370 'betterdocs-admin',
371 'betterdocs-analytics',
372 'betterdocs-glossaries'
373 ];
374 $classes .= ' betterdocs-admin ';
375
376 if ( $dark_mode === true && in_array( $current_screen_id, $registered_screens ) ) {
377 $classes .= ' betterdocs-dark-mode ';
378 }
379
380 return $classes;
381 }
382
383 /**
384 * Remove Comments Column From List Table
385 *
386 * @param array $columns
387 *
388 * @return array
389 * @since 1.0.0
390 */
391 public function set_custom_edit_action_columns( $columns ) {
392 unset( $columns['comments'] );
393 $new_columns = [];
394 foreach ( $columns as $key => $value ) {
395 if ( $key == 'date' ) {
396 $new_columns['betterdocs_word_count'] = __( 'Word Count', 'betterdocs' ); // put the tags column before it
397 $new_columns['betterdocs_reaction'] = __( 'Reactions', 'betterdocs' );
398 }
399 $new_columns[$key] = $value;
400 }
401
402 return $new_columns;
403 }
404
405 public function manage_custom_columns( $column, $post_id ) {
406 global $wpdb;
407 switch ( $column ) {
408 case 'betterdocs_word_count':
409 $content_without_html_tags = trim( strip_tags( get_post_field( 'post_content', $post_id ) ) );
410 preg_match_all( '/<[^>]*>|[\p{L}\p{M}]+/u', $content_without_html_tags, $matches );
411 $total_words = ! empty( $matches[0] ) ? count( $matches[0] ) : count( [] );
412 $word_count = $total_words;
413 echo '<span>' . $word_count . '</span>';
414 break;
415 case 'betterdocs_reaction':
416 $where = "WHERE post_id='" . esc_sql( $post_id ) . "'";
417 $analytics = $wpdb->get_results( "SELECT
418 sum(impressions) as totalViews,
419 sum(unique_visit) as totalUniqueViews,
420 sum(happy + sad + normal) as totalReactions,
421 sum(happy) as totalHappy,
422 sum(normal) as totalNormal,
423 sum(sad) as totalSad
424 FROM {$wpdb->prefix}betterdocs_analytics
425 $where" );
426
427 echo '<ul class="reactions-count">
428 <li>
429 <a title="happy" class="betterdocs-feelings happy" data-feelings="happy" href="#">
430 <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">
431 <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
432 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
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.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
434 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" />
435 <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
436 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
437 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
438 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" />
439 </svg>
440 <span>' . ( $analytics[0]->totalHappy != null ? $analytics[0]->totalHappy : 0 ) . '</span>
441 </a>
442 </li>
443 <li>
444 <a title="normal" class="betterdocs-feelings normal" data-feelings="normal" href="#">
445 <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">
446 <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
447 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
448 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
449 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" />
450 </svg>
451 <span>' . ( $analytics[0]->totalNormal != null ? $analytics[0]->totalNormal : 0 ) . '</span>
452 </a>
453 </li>
454 <li>
455 <a title="sad" class="betterdocs-feelings sad" data-feelings="sad" href="#">
456 <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">
457 <circle class="st0" cx="27.5" cy="0.6" r="1.9" />
458 <circle class="st0" cx="36" cy="0.6" r="1.9" />
459 <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
460 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
461 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
462 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
463 c1.8,0,3.5,0.8,4.6,2.1C15,14.3,14.7,15,14.1,15z" />
464 </svg>
465 <span>' . ( $analytics[0]->totalSad != null ? $analytics[0]->totalSad : 0 ) . '</span>
466 </a>
467 </li>
468 </ul>';
469 break;
470 }
471 }
472
473 /**
474 * Enqueue Assets for Admin ( Styles )
475 *
476 * @param string $hook
477 *
478 * @return void
479 * @since 1.0.0
480 */
481 public function styles( $hook ) {
482 $this->assets->enqueue( 'betterdocs-global', 'admin/css/global.css', [], 'all' );
483
484 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
485 return;
486 }
487
488 $this->assets->enqueue( 'betterdocs-select2', 'vendor/css/select2.min.css', [], 'all' );
489 $this->assets->enqueue( 'betterdocs-daterangepicker', 'vendor/css/daterangepicker.css', [], 'all' );
490 $this->assets->enqueue( 'betterdocs-old', 'admin/css/betterdocs.css', [], 'all' );
491
492 /**
493 * This scripts enqueued for Dashboard App.
494 */
495 $this->assets->enqueue( 'betterdocs', 'admin/css/dashboard.css', ['betterdocs-old'] );
496 $this->assets->enqueue( 'betterdocs-icons', 'admin/btd-icon/style.css' );
497 }
498
499 /**
500 * Enqueue Assets for Admin ( Scripts )
501 *
502 * @param string $hook
503 *
504 * @return void
505 * @since 1.0.0
506 */
507 public function scripts( $hook ) {
508 if ( ( $hook === 'edit.php' ) && get_post_type() == 'docs' ) {
509 $this->assets->enqueue( 'betterdocs-switcher', 'admin/js/switcher.js', [
510 'jquery'
511 ] );
512
513 $this->assets->localize( 'betterdocs-switcher', 'betterdocsSwitcher', [
514 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
515 'site_address' => get_bloginfo( 'url' ),
516 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
517 'betterdocs_pro_version' => betterdocs()->pro_version()
518 ] );
519
520 return;
521 }
522
523 wp_enqueue_script('wp-editor'); // enqueue this for yoast related issue
524
525 if ( ! betterdocs()->is_betterdocs_screen( $hook ) ) {
526 return;
527 }
528
529 $this->assets->register( 'betterdocs-admin', 'admin/js/dashboard.js' );
530
531 $saved_settings = get_option( 'betterdocs_settings', false );
532 $dark_mode = $saved_settings['dark_mode'] ?? false;
533 $dark_mode = ! empty( $dark_mode ) && boolval( $dark_mode );
534 $this->assets->localize( 'betterdocs-admin', 'betterdocs_admin', [
535 'ajaxurl' => admin_url( 'admin-ajax.php' ),
536 'doc_cat_order_nonce' => wp_create_nonce( 'doc_cat_order_nonce' ),
537 'knowledge_base_order_nonce' => wp_create_nonce( 'knowledge_base_order_nonce' ),
538 'paged' => isset( $_GET['paged'] ) ? absint( wp_unslash( $_GET['paged'] ) ) : 0,
539 'per_page_id' => "edit_doc_category_per_page",
540 'menu_title' => __( 'Switch to BetterDocs UI', 'betterdocs' ),
541 'dark_mode' => $dark_mode,
542 'text' => __( 'Copied!', 'betterdocs' ),
543 'test_report' => __( 'Test Report!', 'betterdocs' ),
544 'sending' => __( 'Sending...', 'betterdocs' ),
545 'dir_url' => BETTERDOCS_ABSURL,
546 'rest_url' => esc_url_raw( rest_url() ),
547 'free_version' => betterdocs()->version,
548 'generate_data_url' => get_rest_url( null, '/betterdocs/v1/create-sample-docs' ),
549 'nonce' => wp_create_nonce( 'wp_rest' ),
550 'admin_url' => admin_url(),
551 'ia_preview' => betterdocs()->settings->get( 'ia_enable_preview', false ),
552 'multiple_kb' => betterdocs()->settings->get( 'multiple_kb' ),
553 'previewMode' => betterdocs()->settings->get( 'ia_enable_preview', false ),
554 'dashboard_mode' => get_option( 'dashboard_mode' ),
555 'betterdocs_pro_plugin' => betterdocs()->is_pro_active(),
556 'betterdocs_pro_version' => betterdocs()->pro_version(),
557 'analytics_older' => version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
558 ] );
559
560 $this->assets->enqueue( 'moment', 'vendor/js/moment.min.js', [] );
561 wp_enqueue_script( 'betterdocs-admin' );
562
563 /**
564 * Duplicate Codes Need to Be Removed From Here Onwards
565 */
566
567 //FAQ Builder Related Localization
568 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/css/faq.css' );
569 betterdocs()->assets->enqueue( 'betterdocs-admin-faq', 'admin/js/faq.js' );
570
571 // removing emoji support
572 remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
573 remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
574
575 betterdocs()->assets->localize( 'betterdocs-admin-faq', 'betterdocsFaq', [
576 'dir_url' => BETTERDOCS_ABSURL,
577 'rest_url' => esc_url_raw( rest_url() ),
578 'free_version' => betterdocs()->version,
579 'nonce' => wp_create_nonce( 'wp_rest' ),
580 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
581 ] );
582
583 //Glossaries Related Localization
584 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/css/faq.css' );
585
586 betterdocs()->assets->enqueue( 'betterdocs-admin-glossaries', 'admin/js/glossaries.js' );
587
588 betterdocs()->assets->localize( 'betterdocs-admin-glossaries', 'betterdocsGlossary', [
589 'dir_url' => BETTERDOCS_ABSURL,
590 'rest_url' => esc_url_raw( rest_url() ),
591 'free_version' => betterdocs()->version,
592 'nonce' => wp_create_nonce( 'wp_rest' ),
593 'betterdocs_settings' => get_option( 'betterdocs_settings', false )
594 ] );
595 }
596
597 /**
598 * All admin pages header
599 *
600 * @return void
601 * @since 1.0.0
602 */
603 public function header( $admin_tab_name ) {
604 $quick_links = [
605 'switch_view' => sprintf( '<a href="%s" class="betterdocs-button betterdocs-button-secondary">%s</a>', add_query_arg( [
606 'post_type' => 'docs',
607 'bdocs_view' => 'classic'
608 ], 'edit.php' ), __( 'Switch to Classic UI', 'betterdocs' ) ),
609 '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' ) )
610 ];
611
612 $quick_links = apply_filters( 'betterdocs_quick_links', $quick_links );
613
614 betterdocs()->views->get( 'admin/header', [
615 'quick_links' => $quick_links,
616 'active_tab' => $admin_tab_name
617 ] );
618 }
619
620 /**
621 * Register all the menus for BetterDocs
622 *
623 * @return void
624 * @since 1.0.0
625 */
626
627 public function menus() {
628 $default_args = [
629 'page_title' => 'BetterDocs',
630 'menu_title' => 'BetterDocs',
631 'capability' => 'edit_posts',
632 'menu_slug' => $this->slug,
633 'callback' => [$this, 'output'],
634 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
635 'position' => 5
636 ];
637
638 $_menu_position = 5;
639
640 foreach ( $this->menu_list() as $key => $value ) {
641 if ( $key === 'betterdocs' ) {
642 $callable = 'add_menu_page';
643 $value = wp_parse_args( $value, $default_args );
644 } else {
645 $callable = 'add_submenu_page';
646 $default_args['callback'] = '';
647 $default_args['position'] = $_menu_position;
648 unset( $default_args['icon_url'] );
649 $value = wp_parse_args( $value, array_merge( ['parent_slug' => $this->slug], $default_args ) );
650 }
651
652 $_menu_position++;
653
654 call_user_func_array( $callable, $value );
655 }
656 }
657
658 /**
659 * BetterDocs Admin Page Output
660 *
661 * @return void
662 * @since 1.0.0
663 */
664 public function output() {
665 if ( betterdocs()->is_pro_active()
666 && version_compare( betterdocs()->pro_version(), '3.3.4', '<=' )
667 && get_current_screen()->id == 'betterdocs_page_betterdocs-analytics' ) {
668 betterdocs_pro()->views->get( 'admin/analytics-pro' );
669 } else {
670 betterdocs()->views->get( 'admin/main', [
671 'admin_ui' => 'dnd'
672 ] );
673 }
674 }
675
676 /**
677 * Menu creator helper
678 *
679 * @param string $title
680 * @param string $slug
681 * @param string $cap
682 * @param array $callback
683 *
684 * @return array
685 * @since 2.5.0
686 *
687 */
688 private function normalize_menu( $title, $slug, $cap = 'edit_docs', $callback = null, $optional = [] ) {
689 return Helper::normalize_menu( $title, $slug, $cap, $callback, $optional );
690 }
691
692 /**
693 * BetterDocs Menu List
694 *
695 * @return array
696 * @since 1.0.0
697 */
698 private function menu_list() {
699 $parent_slug = [];
700
701 $betterdocs_admin_pages = [
702 'betterdocs' => [
703 'menu_slug' => $this->slug,
704 'page_title' => 'BetterDocs',
705 'menu_title' => 'BetterDocs',
706 'capability' => 'edit_docs',
707 'callback' => [$this, 'output'],
708 'icon_url' => betterdocs()->assets->icon( 'betterdocs-icon-white.svg', true ),
709 'position' => 5
710 ],
711 'all_docs' => $this->normalize_menu( __( 'All Docs', 'betterdocs' ), $this->ui_slug() ),
712 'add_new' => $this->normalize_menu( __( 'Add New', 'betterdocs' ), 'post-new.php?post_type=docs' ),
713 'categories' => $this->normalize_menu( __( 'Categories', 'betterdocs' ), 'edit-tags.php?taxonomy=doc_category&post_type=docs', 'manage_doc_terms' ),
714 'tags' => $this->normalize_menu( __( 'Tags', 'betterdocs' ), 'edit-tags.php?taxonomy=doc_tag&post_type=docs', 'manage_doc_terms' ),
715 'settings' => $this->normalize_menu( __( 'Settings', 'betterdocs' ), 'betterdocs-settings', 'edit_docs_settings', [
716 $this,
717 'output'
718 ], $parent_slug ),
719 'analytics' => $this->normalize_menu( __( 'Analytics', 'betterdocs' ), 'betterdocs-analytics', 'read_docs_analytics', [
720 $this,
721 'output'
722 ], $parent_slug ),
723 'faq' => $this->normalize_menu( __( 'FAQ Builder', 'betterdocs' ), 'betterdocs-faq', 'read_docs_analytics', [
724 $this,
725 'output'
726 ], $parent_slug )
727 ];
728
729 if ( betterdocs()->is_pro_active() && betterdocs()->settings->get( 'enable_glossaries' ) == true ) {
730 $betterdocs_admin_pages['glossaries'] = $this->normalize_menu( __( 'Glossaries', 'betterdocs' ), 'betterdocs-glossaries', 'read_docs_analytics', [
731 $this,
732 'output'
733 ], $parent_slug );
734 }
735
736 return apply_filters( 'betterdocs_admin_menu', $betterdocs_admin_pages );
737 }
738
739 public function add_custom_classes_to_menu_items() {
740 global $menu, $submenu;
741
742 $menu_items = [
743 'betterdocs' => 'betterdocs',
744 'betterdocs_page_all_docs' => 'betterdocs-all-docs',
745 'betterdocs_page_add_new' => 'betterdocs-add-new',
746 'edit-tags.php?taxonomy=doc_category&post_type=docs' => 'betterdocs-categories',
747 'edit-tags.php?taxonomy=doc_tag&post_type=docs' => 'betterdocs-tags',
748 'betterdocs-settings' => 'betterdocs-settings',
749 'betterdocs-analytics' => 'betterdocs-analytics',
750 'betterdocs-faq' => 'betterdocs-faq',
751 'betterdocs-glossaries' => 'betterdocs-glossaries',
752 'edit-tags.php?taxonomy=knowledge_base&post_type=docs' => 'betterdocs-multiplekb'
753 ];
754
755 foreach ( $menu as &$item ) {
756 if ( isset( $menu_items[$item[2]] ) ) {
757 if ( ! isset( $item[4] ) ) {
758 $item[4] = '';
759 }
760 $item[4] .= '' . $menu_items[$item[2]];
761 }
762 }
763
764 foreach ( $submenu as &$submenu_items ) {
765 foreach ( $submenu_items as &$sub_item ) {
766 if ( isset( $menu_items[$sub_item[2]] ) ) {
767 if ( ! isset( $sub_item[4] ) ) {
768 $sub_item[4] = '';
769 }
770 $sub_item[4] .= '' . $menu_items[$sub_item[2]];
771 }
772 }
773 }
774 }
775
776 public function quick_setup_menu( $menus ) {
777 $betterdocs_settings = get_option( 'betterdocs_settings' );
778 if ( $betterdocs_settings ) {
779 return $menus;
780 } else {
781 $menus['quick_setup'] = $this->normalize_menu( __( 'Quick Setup', 'betterdocs' ), 'betterdocs-setup', 'delete_users', [
782 $this->container->get( SetupWizard::class ),
783 'views'
784 ] );
785 }
786
787 return $menus;
788 }
789
790 public function insert_plugin_links( $links ) {
791 $links[] = '<a href="admin.php?page=betterdocs-settings">' . __( 'Settings', 'betterdocs' ) . '</a>';
792
793 return $links;
794 }
795
796 public function toolbar_menu( $admin_bar ) {
797 if ( ! is_admin() || ! is_admin_bar_showing() ) {
798 return;
799 }
800
801 // Show only when the user is a member of this site, or they're a super admin.
802 if ( ! is_user_member_of_blog() && ! is_super_admin() ) {
803 return;
804 }
805
806 $docs_url = '';
807 $encyclopedia_url = '';
808
809 if ( $this->settings->get( 'builtin_doc_page' ) ) {
810 $docs_url = get_post_type_archive_link( 'docs' );
811 } elseif ( intval( $docs_page = $this->settings->get( 'docs_page' ) ) ) {
812 $docs_url = ! empty( $docs_page ) ? get_page_link( $docs_page ) : false;
813 }
814
815 if ( ! $docs_url ) {
816 return;
817 }
818
819 $slug = $this->settings->get( 'encyclopedia_root_slug' );
820
821 $encyclopedia_url = home_url( $slug );
822
823 $admin_bar->add_node( [
824 'parent' => 'site-name',
825 'id' => 'view-docs',
826 'title' => __( 'Visit Documentation', 'betterdocs' ),
827 'href' => $docs_url
828 ] );
829
830 $is_enable_encyclopedia = betterdocs()->settings->get( 'enable_encyclopedia' );
831
832 if ( $is_enable_encyclopedia && betterdocs()->is_pro_active() ) {
833 $admin_bar->add_node( [
834 'parent' => 'site-name',
835 'id' => 'view-encyclopedia',
836 'title' => __( 'Visit Encyclopedia', 'betterdocs' ),
837 'href' => $encyclopedia_url
838 ] );
839 }
840 }
841
842 /**
843 * Save last visited admin ui
844 *
845 * @since 3.0.1
846 *
847 */
848 public function save_admin_page() {
849 if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'docs' && isset( $_GET['bdocs_view'] ) && $_GET['bdocs_view'] === 'classic' ) {
850 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'classic_ui' );
851 } elseif ( isset( $_GET['page'] ) && $_GET['page'] === 'betterdocs-admin' ) {
852 update_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', 'modern_ui' );
853 }
854 }
855
856 /**
857 * Return last visited admin ui slug
858 *
859 * @return string
860 * @since 3.0.1
861 */
862 public function ui_slug() {
863 $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
864 $docs = get_posts( ['post_type' => 'docs', 'post_status' => 'any', 'numberposts' => 2] );
865
866 if ( $last_visited === 'modern_ui' || count( $docs ) == 0 ) {
867 $slug = 'betterdocs-admin';
868 } else {
869 $slug = admin_url( 'edit.php?post_type=docs&bdocs_view=classic' );
870 }
871
872 return $slug;
873 }
874
875 /**
876 * Resets a duplicate submenu in WordPress if the parent main menu and the first submenu permalink are not the same.
877 *
878 * @return string
879 * @since 3.0.1
880 */
881 public function reset_submenu() {
882 global $submenu;
883
884 $docs = get_posts( ['post_type' => 'docs'] );
885 if ( count( $docs ) == 0 ) {
886 return;
887 }
888
889 $last_visited = get_user_meta( get_current_user_id(), 'last_visited_docs_admin_page', true );
890
891 if ( $last_visited === 'classic_ui' && isset( $submenu['betterdocs-admin'] ) && in_array( "betterdocs-admin", $submenu['betterdocs-admin'][0] ) ) {
892 unset( $submenu['betterdocs-admin'][0] );
893 $submenu['betterdocs-admin'] = array_values( $submenu['betterdocs-admin'] );
894 }
895 }
896 }
897