PluginProbe ʕ •ᴥ•ʔ
Admin Help Docs / 2.0.3
Admin Help Docs v2.0.3
2.0.3 2.0.2 2.0.1.1 trunk 1.4.3.2 2.0.0 2.0.0.1 2.0.0.2 2.0.1
admin-help-docs / inc / menu.php
admin-help-docs / inc Last commit date
css 19 hours ago docs 19 hours ago img 19 hours ago js 19 hours ago tabs 19 hours ago api.php 19 hours ago cleanup.php 19 hours ago colors.php 19 hours ago deprecated.php 19 hours ago header.php 19 hours ago helpers.php 19 hours ago index.php 19 hours ago menu.php 19 hours ago plugins-page.php 19 hours ago post-type-help-doc-imports.php 19 hours ago post-type-help-docs.php 19 hours ago shortcodes.php 19 hours ago taxonomy-folders.php 19 hours ago
menu.php
602 lines
1 <?php
2 /**
3 * Menu Loader
4 */
5
6 namespace PluginRx\AdminHelpDocs;
7
8 if ( ! defined( 'ABSPATH' ) ) exit;
9
10 class Menu {
11
12 /**
13 * Defaults
14 */
15 public static $default_menu_position = 2;
16
17
18 /**
19 * Tab slugs and labels
20 *
21 * @param string $tab The current tab slug.
22 * @return array
23 */
24 public static function tabs( $tab = null ) : array {
25 $post_new_link = Bootstrap::admin_url( 'post-new.php' );
26 $author_uri = Bootstrap::author_uri();
27 $text_domain = Bootstrap::textdomain();
28
29 $import_header = isset( $_GET[ 'id' ] ) ? __( 'Edit Import', 'admin-help-docs' ) : __( 'Add New Import', 'admin-help-docs' ); // phpcs:ignore
30
31 $tabs = [
32 'documentation' => [
33 'label' => __( 'Documentation', 'admin-help-docs' ),
34 'buttons' => [
35 [
36 'link' => add_query_arg( 'post_type', HelpDocs::$post_type, $post_new_link ),
37 'text' => '<span class="dashicons dashicons-plus"></span> ' . __( 'Add New', 'admin-help-docs' ),
38 ],
39 ],
40 'class' => Documentation::class,
41 ],
42 'manage' => [
43 'label' => __( 'Manage Docs', 'admin-help-docs' ),
44 'title' => __( 'Manage Help Docs', 'admin-help-docs' ),
45 'buttons' => [
46 [
47 'link' => add_query_arg( 'post_type', HelpDocs::$post_type, $post_new_link ),
48 'text' => '<span class="dashicons dashicons-plus"></span> ' . __( 'Add New', 'admin-help-docs' ),
49 ],
50 ],
51 'link' => Bootstrap::tab_url( 'manage' ),
52 ],
53 'folders' => [
54 'label' => __( 'Folders', 'admin-help-docs' ),
55 'title' => __( 'Folders', 'admin-help-docs' ),
56 'link' => Bootstrap::tab_url( 'folders' ),
57 ],
58 'imports' => [
59 'label' => __( 'Imports', 'admin-help-docs' ),
60 'title' => __( 'Imported Docs', 'admin-help-docs' ),
61 'buttons' => [
62 [
63 'link' => Bootstrap::tab_url( 'import' ),
64 'text' => '<span class="dashicons dashicons-plus"></span> ' . __( 'Add New', 'admin-help-docs' ),
65 ],
66 ],
67 'link' => Bootstrap::tab_url( 'imports' ),
68 ],
69 'import' => [
70 'label' => $import_header,
71 'buttons' => [
72 [
73 'id' => 'save_import_settings',
74 'link' => '#',
75 'text' => __( 'Save Import Settings', 'admin-help-docs' ),
76 'form' => 'helpdocs_import_form',
77 'disabled' => true,
78 ],
79 ],
80 'class' => ImportEditor::class,
81 'hidden' => true,
82 ],
83 'migrate' => [
84 'label' => __( 'Migrate', 'admin-help-docs' ),
85 'title' => __( 'Migrate Docs', 'admin-help-docs' ),
86 'class' => Migrate::class,
87 ],
88 'admin-menu' => [
89 'label' => __( 'Admin Menu', 'admin-help-docs' ),
90 'buttons' => [
91 [
92 'link' => '#',
93 'text' => __( 'Save', 'admin-help-docs' ),
94 ],
95 ],
96 'class' => AdminMenu::class,
97 ],
98 'settings' => [
99 'label' => __( 'Settings', 'admin-help-docs' ),
100 'buttons' => [
101 [
102 'link' => '#',
103 'text' => __( 'Save', 'admin-help-docs' ),
104 ],
105 ],
106 'class' => Settings::class,
107 ],
108 'faq' => [
109 'label' => __( 'FAQ', 'admin-help-docs' ),
110 'title' => __( 'Frequently Asked Questions', 'admin-help-docs' ),
111 'buttons' => [
112 [
113 'link' => $author_uri . 'guide/plugin/' . $text_domain,
114 'text' => __( 'Help Guides', 'admin-help-docs' ),
115 'target' => '_blank',
116 ],
117 [
118 'link' => $author_uri . 'docs/plugin/' . $text_domain,
119 'text' => __( 'Developer Docs', 'admin-help-docs' ),
120 'target' => '_blank',
121 ],
122 [
123 'link' => $author_uri . 'support/plugin/' . $text_domain,
124 'text' => __( 'Support', 'admin-help-docs' ),
125 'target' => '_blank',
126 ],
127 ],
128 'class' => FAQ::class,
129 ],
130 'support' => [
131 'label' => __( 'Contact Support', 'admin-help-docs' ),
132 'title' => __( 'Contact Support', 'admin-help-docs' ),
133 'class' => Support::class,
134 ],
135 ];
136
137 if ( $tab ) {
138 return $tabs[ $tab ] ?? [];
139 }
140 return $tabs;
141 } // End tabs()
142
143
144 /**
145 * The single instance of the class
146 *
147 * @var self|null
148 */
149 private static ?Menu $instance = null;
150
151
152 /**
153 * Get the singleton instance
154 *
155 * @return self
156 */
157 public static function instance() : self {
158 return self::$instance ??= new self();
159 } // End instance()
160
161
162 /**
163 * Constructor
164 */
165 private function __construct() {
166 add_action( is_network_admin() ? 'network_admin_menu' : 'admin_menu', [ $this, 'register_menu' ] );
167 add_filter( 'parent_file', [ $this, 'submenus' ], 999 );
168 add_action( 'admin_body_class', [ $this, 'admin_body_class' ] );
169 add_filter( 'admin_title', [ $this, 'admin_title' ], 10, 2 );
170 add_action( 'in_admin_header', [ $this, 'admin_header' ] );
171 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
172 } // End __construct()
173
174
175 /**
176 * Register admin menu
177 *
178 * @return void
179 */
180 public function register_menu() : void {
181 // Register the hidden dashboard replacement page
182 add_submenu_page(
183 'index.php',
184 __( 'Dashboard', 'admin-help-docs' ),
185 __( 'Dashboard', 'admin-help-docs' ),
186 'read',
187 'admin-help-dashboard',
188 [ WPDashboard::class, 'render_replacement_page' ]
189 );
190
191 // Register the help docs main menu
192 $title = sanitize_text_field( get_option( 'helpdocs_menu_title', Helpers::get_menu_title() ) );
193
194 $icon = Helpers::get_icon();
195 $position = absint( get_option( 'helpdocs_menu_position', self::$default_menu_position ) );
196
197 $parent_slug = Bootstrap::textdomain();
198
199 add_menu_page(
200 Bootstrap::name(),
201 $title,
202 'read',
203 $parent_slug,
204 [ $this, 'render_tab' ],
205 $icon,
206 $position
207 );
208
209 if ( ! Helpers::user_can_view() ) {
210 remove_menu_page( $parent_slug );
211 return;
212 }
213
214 // Add submenu items for each tab
215 $user_can_edit = Helpers::user_can_edit();
216
217 global $submenu;
218
219 foreach ( self::tabs() as $slug => $tab ) {
220
221 if ( isset( $tab[ 'hidden' ] ) && $tab[ 'hidden' ] ) {
222 continue;
223 }
224
225 // Documentation tab is always added for users with view access, even if they don't have edit access.
226 // Other tabs are only added if the user has edit access.
227 if ( $slug === 'documentation' ) {
228 $link = Bootstrap::tab_url( $slug );
229 $submenu[ $parent_slug ][] = [ $tab[ 'label' ] ?? '', 'read', $link ];
230 continue;
231 }
232
233 if ( ! $user_can_edit ) {
234 continue;
235 }
236
237 if ( $slug === 'support' && ! get_option( 'helpdocs_contact_form' ) ) {
238 continue;
239 }
240
241 if ( isset( $tab[ 'link' ] ) && $tab[ 'link' ] ) {
242 $link = $tab[ 'link' ];
243 } else {
244 $link = Bootstrap::tab_url( $slug );
245 }
246
247 $submenu[ $parent_slug ][] = [ $tab[ 'label' ] ?? '', 'read', $link ];
248 }
249 } // End register_menu()
250
251
252 /**
253 * Set the correct submenu file for our pages
254 *
255 * @param string $parent_file The current parent file slug.
256 * @return string The modified parent file slug.
257 */
258 public function submenus( $parent_file ) {
259 global $submenu_file, $current_screen;
260
261 if ( ( 'admin_page_admin-help-dashboard' ) === $current_screen->id ) {
262 $parent_file = 'index.php';
263 $submenu_file = 'index.php';
264 return $parent_file;
265 }
266
267 $textdomain = Bootstrap::textdomain();
268 $options_page = 'toplevel_page_' . $textdomain;
269
270 if ( is_network_admin() ) {
271 $options_page .= '-network';
272 }
273
274 // Help Docs Tabs
275 if ( $current_screen->id === $options_page ) {
276 $tab = self::get_current_tab();
277 if ( ! $tab ) {
278 return $parent_file;
279 }
280
281 if ( $tab === 'import' ) {
282 $parent_file = $textdomain;
283 $submenu_file = Bootstrap::tab_url( 'imports' );
284 return $parent_file;
285 }
286
287 $submenu_file = Bootstrap::tab_url( $tab );
288
289 // Folder taxonomy
290 } elseif ( $current_screen->id === 'edit-' . Folders::$taxonomy ) {
291 $parent_file = $textdomain;
292 $submenu_file = Bootstrap::tab_url( 'folders' );
293
294 // Post Type Submenus
295 } elseif ( isset( $current_screen->post_type ) && $current_screen->post_type === HelpDocs::$post_type ) {
296 $parent_file = $textdomain;
297 $submenu_file = Bootstrap::tab_url( 'manage' );
298
299 } elseif ( isset( $current_screen->post_type ) && $current_screen->post_type === Imports::$post_type ) {
300 $parent_file = $textdomain;
301 $submenu_file = Bootstrap::tab_url( 'imports' );
302 }
303
304 return $parent_file;
305 } // End submenus()
306
307
308 /**
309 * Add custom body class on our plugin pages
310 *
311 * @param string $classes Existing body classes.
312 * @return string Modified body classes.
313 */
314 public function admin_body_class( $classes ) {
315 $current_screen = get_current_screen();
316
317 $helpdocs_screen_ids = [
318 'toplevel_page_' . Bootstrap::textdomain(),
319 'toplevel_page_' . Bootstrap::textdomain() . '-network',
320 'edit-' . HelpDocs::$post_type,
321 'edit-' . Imports::$post_type,
322 'edit-' . Folders::$taxonomy,
323 ];
324
325 if ( in_array( $current_screen->id, $helpdocs_screen_ids, true ) ) {
326 $classes .= ' helpdocs-admin-screen';
327 }
328
329 return $classes;
330 } // End admin_body_class()
331
332
333 /**
334 * Admin title filter
335 *
336 * @param string $title Current admin title.
337 * @param string $page Current page slug.
338 *
339 * @return string
340 */
341 public function admin_title( $title, $page ) {
342 if ( $page === 'toplevel_page_' . Bootstrap::textdomain() || $page === 'toplevel_page_' . Bootstrap::textdomain() . '-network' ) {
343 $current_tab = self::get_current_tab();
344 $tab = self::tabs( $current_tab );
345 if ( ! empty( $tab ) ) {
346 return $tab[ 'label' ] . '' . Bootstrap::name();
347 }
348 return Bootstrap::name();
349 }
350
351 return $title;
352 } // End admin_title()
353
354
355 /**
356 * Admin header action
357 *
358 * @return void
359 */
360 public function admin_header() {
361 $current_screen = get_current_screen();
362 if ( $current_screen->id === 'toplevel_page_' . Bootstrap::textdomain() || $current_screen->id === 'toplevel_page_' . Bootstrap::textdomain() . '-network' ) {
363 include Bootstrap::path( 'inc/header.php' );
364 }
365 } // End admin_header()
366
367
368 public static function is_our_tab( $tab ) : bool {
369 // Check if it's one of our pages first
370 $is_current_page = self::get_current_page() === Bootstrap::textdomain();
371 if ( ! $is_current_page ) {
372 return false;
373 }
374
375 // Then check if the tab matches
376 $is_current_tab = self::get_current_tab() === $tab;
377 if ( ! $is_current_tab ) {
378 return false;
379 }
380
381 // Finally, check if the tab exists in our tabs array
382 $tabs = self::tabs();
383 return isset( $tabs[ $tab ] );
384 } // End is_our_tab()
385
386
387 /**
388 * Get the current page slug
389 *
390 * @return string
391 */
392 public static function get_current_page() : string {
393 return isset( $_GET[ 'page' ] ) ? sanitize_text_field( wp_unslash( $_GET[ 'page' ] ) ) : ''; // phpcs:ignore
394 } // End get_current_page()
395
396
397 /**
398 * Get the current tab slug
399 *
400 * @return string
401 */
402 public static function get_current_tab() : string {
403 return isset( $_GET[ 'tab' ] ) ? sanitize_key( wp_unslash( $_GET[ 'tab' ] ) ) : ''; // phpcs:ignore
404 } // End get_current_tab()
405
406
407 /**
408 * Render tab content
409 *
410 * @return void
411 */
412 public function render_tab() : void {
413 $tabs = self::tabs();
414 $current_tab_slug = self::get_current_tab();
415 if ( ! $current_tab_slug || ! isset( $tabs[ $current_tab_slug ] ) || ( $current_tab_slug === 'support' && ! get_option( 'helpdocs_contact_form' ) ) ) {
416 wp_safe_redirect( Bootstrap::tab_url( 'documentation' ) );
417 exit;
418 }
419 ?>
420 <div id="<?php echo esc_attr( Bootstrap::textdomain() ); ?>">
421
422 <div class="tab-content">
423 <?php
424 foreach ( $tabs as $key => $tab ) {
425 if ( $current_tab_slug === $key ) {
426
427 if ( isset( $tab[ 'class' ] ) && class_exists( $tab[ 'class' ] ) ) {
428 ?>
429 <div id="<?php echo esc_attr( $key ); ?>">
430 <?php
431 $class_name = $tab[ 'class' ];
432 $instance = $class_name::instance();
433 $instance->render_tab();
434 ?>
435 </div>
436 <?php
437 } else {
438 echo 'Tab content not available.';
439 }
440 }
441 }
442 ?>
443 </div>
444
445 </div>
446 <?php
447 } // End render_tab()
448
449
450 /**
451 * Enqueue admin assets
452 *
453 * @return void
454 */
455 public function enqueue_assets() : void {
456 $text_domain = Bootstrap::textdomain();
457 $script_version = Bootstrap::script_version();
458
459 // All pages in admin area
460 wp_enqueue_style( $text_domain . '-docs', Bootstrap::url( 'inc/css/docs.css' ), [], $script_version );
461
462 $colors = Colors::get();
463 if ( ! empty( $colors ) ) {
464 $inline_css = ':root {';
465 foreach ( $colors as $key => $color ) {
466 $key = str_replace( '_', '-', $key );
467 $inline_css .= "--helpdocs-color-{$key}: {$color};";
468 }
469 $inline_css .= '}';
470 wp_add_inline_style( $text_domain . '-docs', $inline_css );
471 }
472
473 // Click to copy script
474 wp_enqueue_script( $text_domain . '-click-to-copy', Bootstrap::url( 'inc/js/click-to-copy.js' ), [ 'jquery' ], $script_version, true );
475 wp_localize_script( $text_domain . "-click-to-copy", "helpdocs_click_to_copy", [
476 'copied_text' => __( 'Copied!', 'admin-help-docs' ),
477 ] );
478
479 // Limited pages in admin area
480 $current_screen = get_current_screen();
481 $is_helpdocs_screen = $current_screen->id === 'toplevel_page_' . $text_domain || $current_screen->id === 'toplevel_page_' . $text_domain . '-network';
482 $is_post_type_list_screen = $current_screen->id === 'edit-' . HelpDocs::$post_type || $current_screen->id === 'edit-' . Imports::$post_type;
483 $is_taxonomy_list_screen = $current_screen->id === 'edit-' . Folders::$taxonomy;
484 $is_our_dashboard = $current_screen->id === 'dashboard_page_admin-help-dashboard';
485
486 // Only on our dashboard
487 if ( $is_our_dashboard ) {
488 wp_enqueue_style( $text_domain . '-our-dashboard', Bootstrap::url( 'inc/css/our-dashboard.css' ), [], $script_version );
489 }
490
491 // Only on our plugin pages and related post type list screens
492 if ( $is_helpdocs_screen || $is_post_type_list_screen || $is_taxonomy_list_screen ) {
493 wp_enqueue_style( $text_domain . '-header', Bootstrap::url( 'inc/css/header.css' ), [], $script_version );
494 }
495
496 // Only on our tab pages
497 if ( $is_helpdocs_screen ) {
498 wp_enqueue_style( $text_domain . '-content', Bootstrap::url( 'inc/css/content.css' ), [], $script_version );
499 }
500
501 // Only on our post types and taxonomies list screens
502 if ( $is_post_type_list_screen || $is_taxonomy_list_screen ) {
503 wp_enqueue_style( $text_domain . '-pt-tax', Bootstrap::url( 'inc/css/pt-tax.css' ), [], $script_version );
504 }
505
506 // Only on our post types list screens
507 if ( $is_post_type_list_screen ) {
508 wp_enqueue_style( $text_domain . '-post-types', Bootstrap::url( 'inc/css/post-types.css' ), [], $script_version );
509 }
510
511 // Only on our taxonomy list screens
512 if ( $is_taxonomy_list_screen ) {
513 wp_enqueue_style( $text_domain . '-taxonomies', Bootstrap::url( 'inc/css/taxonomies.css' ), [], $script_version );
514 }
515
516 // Load tab-specific assets
517 $current_tab = self::get_current_tab();
518 if ( $is_helpdocs_screen && $current_tab ) {
519 if ( file_exists( Bootstrap::path( "inc/tabs/js/{$current_tab}.js" ) ) ) {
520 wp_enqueue_script( $text_domain . "-tab-{$current_tab}", Bootstrap::url( "inc/tabs/js/{$current_tab}.js" ), [ 'jquery' ], $script_version, true );
521 }
522 if ( file_exists( Bootstrap::path( "inc/tabs/css/{$current_tab}.css" ) ) ) {
523 wp_enqueue_style( $text_domain . "-tab-{$current_tab}", Bootstrap::url( "inc/tabs/css/{$current_tab}.css" ), [], $script_version );
524 }
525
526 // Settings tab
527 if ( $current_tab === 'settings' ) {
528 $editor_settings = wp_enqueue_code_editor( [ 'type' => 'text/css' ] );
529 wp_localize_script( $text_domain . "-tab-{$current_tab}", "helpdocs_{$current_tab}", [
530 'nonce' => wp_create_nonce( "helpdocs_{$current_tab}_nonce" ),
531 'settings' => Settings::setting_fields( true ),
532 'wp_version' => get_bloginfo( 'version' ),
533 'themes' => Colors::themes(),
534 'default_logo' => Helpers::get_default_logo_url(),
535 'editor_settings' => $editor_settings,
536 'saving_text' => __( 'Saving', 'admin-help-docs' ),
537 'saved_text' => __( 'Settings saved successfully.', 'admin-help-docs' ),
538 'error_text' => __( 'Error saving settings. Please try again.', 'admin-help-docs' ),
539 'flushing_text' => __( 'Clearing Cache', 'admin-help-docs' ),
540 ] );
541 }
542
543 // Admin Menu tab
544 if ( $current_tab === 'admin-menu' ) {
545 $current__tab = str_replace( '-', '_', $current_tab );
546 wp_localize_script( $text_domain . "-tab-{$current_tab}", "helpdocs_{$current__tab}", [
547 'nonce' => wp_create_nonce( "helpdocs_{$current__tab}_nonce" ),
548 'settings' => AdminMenu::setting_fields( true ),
549 ] );
550 }
551
552 // Documentation tab
553 if ( $current_tab === 'documentation' ) {
554
555 $main_docs_css = get_option( 'helpdocs_main_docs_css' );
556 if ( ! empty( $main_docs_css ) ) {
557 wp_add_inline_style( $text_domain . "-tab-{$current_tab}", wp_strip_all_tags( $main_docs_css ) );
558 }
559
560 wp_localize_script( $text_domain . "-tab-{$current_tab}", "helpdocs_{$current_tab}", [
561 'nonce' => wp_create_nonce( "helpdocs_{$current_tab}_nonce" ),
562 ] );
563 }
564
565 // Support tab
566 if ( $current_tab === 'support' ) {
567 wp_localize_script( $text_domain . "-tab-{$current_tab}", "helpdocs_{$current_tab}", [
568 'nonce' => wp_create_nonce( "helpdocs_{$current_tab}_nonce" ),
569 'clear_logs_confirm' => __( 'Are you sure you want to delete all support logs?', 'admin-help-docs' ),
570 'max_attachment_mb' => Support::$max_attachment_mb,
571 'files_too_large' => sprintf( __( 'Total uploads exceed the maximum size of %dMB.', 'admin-help-docs' ), Support::$max_attachment_mb ),
572 'log_date_format' => Support::$log_date_format,
573 'required_fields' => __( 'Please fill in all required fields.', 'admin-help-docs' ),
574 ] );
575 }
576
577 // Import tab
578 if ( $current_tab === 'import' ) {
579 wp_localize_script( $text_domain . "-tab-{$current_tab}", "helpdocs_{$current_tab}", [
580 'fetch_nonce' => wp_create_nonce( "helpdocs_{$current_tab}_fetch_nonce" ),
581 'clone_nonce' => wp_create_nonce( "helpdocs_{$current_tab}_clone_nonce" ),
582 'fetching_text' => __( 'Fetching', 'admin-help-docs' ),
583 'importing_text' => __( 'Cloning', 'admin-help-docs' ),
584 'imported_text' => __( 'Copy Complete!', 'admin-help-docs' ),
585 'error_text' => __( 'An error occurred during cloning.', 'admin-help-docs' ),
586 'saving_text' => __( 'Saving', 'admin-help-docs' ),
587 ] );
588 }
589 }
590 } // End enqueue_assets()
591
592
593 /**
594 * Prevent cloning and unserializing
595 */
596 public function __clone() {}
597 public function __wakeup() {}
598
599 }
600
601
602 Menu::instance();