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