PluginProbe
Code Snippets / trunk
Code Snippets vtrunk
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
← All changes | php/Admin/Menus/Edit_Menu.php +103 -20 4.0.0-beta.1 → trunk View file →
@@ -3,9 +3,8 @@
3 3 namespace Code_Snippets\Admin\Menus;
4 4
5 5 use Code_Snippets\Admin\Contextual_Help;
6 6 use Code_Snippets\Model\Snippet;
7 -use WP_Screen;
8 7 use function Code_Snippets\code_snippets;
9 8 use function Code_Snippets\get_all_snippet_tags;
10 9 use function Code_Snippets\get_snippet;
11 10 use function Code_Snippets\Settings\get_setting;
@@ -21,14 +20,14 @@
21 20
22 21 /**
23 22 * Handle for JavaScript asset file.
24 23 */
25 - public const JS_HANDLE = 'code-snippets-edit-menu';
24 + private const JS_HANDLE = 'code-snippets-edit-menu';
26 25
27 26 /**
28 27 * Handle for CSS asset file.
29 28 */
30 - public const CSS_HANDLE = 'code-snippets-edit';
29 + private const CSS_HANDLE = 'code-snippets-edit';
31 30
32 31 /**
33 32 * The snippet object currently being edited
34 33 *
@@ -48,10 +47,8 @@
48 47 _x( 'Edit Snippet', 'menu label', 'code-snippets' ),
49 48 __( 'Edit Snippet', 'code-snippets' )
50 49 );
51 50
52 - add_action( 'current_screen', array( $this, 'maybe_hide_menu_item' ) );
53 -
54 51 $this->remove_debug_bar_codemirror();
55 52 }
56 53
57 54 /**
@@ -59,10 +56,21 @@
59 56 *
60 57 * @return void
61 58 */
62 59 public function register() {
63 - parent::register();
60 + // The page itself is always registered outside the menu, so nothing that
61 + // reads the menu during `admin_menu` — menu editors and role managers
62 + // among them — ever sees it. Registering it in the menu and removing it
63 + // afterward is why a page that never renders in the menu could still end
64 + // up in someone's saved menu.
65 + $this->register_without_menu_item();
64 66
67 + $snippet_id = $this->get_requested_snippet_id();
68 +
69 + if ( $snippet_id ) {
70 + $this->add_current_snippet_menu_item( $snippet_id );
71 + }
72 +
65 73 // Create New Snippet menu.
66 74 $this->add_menu(
67 75 code_snippets()->get_menu_slug( 'add' ),
68 76 _x( 'Add New', 'menu label', 'code-snippets' ),
@@ -70,28 +78,104 @@
70 78 );
71 79 }
72 80
73 81 /**
74 - * Hide the static Edit Snippet menu item unless a specific snippet is being edited.
82 + * The snippet this request is editing, if any.
75 83 *
76 - * @param WP_Screen $screen Current admin screen.
84 + * Read from the request rather than the current screen, because this runs
85 + * during `admin_menu`, before the screen is known.
77 86 *
87 + * @return int Snippet ID, or 0 when not editing a specific snippet.
88 + */
89 + private function get_requested_snippet_id(): int {
90 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only routing parameter.
91 + $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
92 +
93 + if ( $page !== $this->slug ) {
94 + return 0;
95 + }
96 +
97 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only routing parameter.
98 + return isset( $_GET['id'] ) ? absint( $_GET['id'] ) : 0;
99 + }
100 +
101 + /**
102 + * Register the edit page without placing it in the admin menu.
103 + *
78 104 * @return void
79 105 */
80 - public function maybe_hide_menu_item( WP_Screen $screen ) {
81 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin menu context.
82 - $current_id = isset( $_GET['id'] ) ? absint( $_GET['id'] ) : 0;
83 - $edit_hook = get_plugin_page_hookname( $this->slug, $this->base_slug );
84 - $edit_hook .= $screen->in_admin( 'network' ) ? '-network' : '';
106 + private function register_without_menu_item(): void {
107 + $hook = add_submenu_page(
108 + '',
109 + $this->title,
110 + $this->label,
111 + code_snippets()->get_cap(),
112 + $this->slug,
113 + array( $this, 'render' )
114 + );
85 115
86 - if ( ( $screen->id === $edit_hook || $screen->base === $edit_hook ) && 0 < $current_id ) {
87 - return;
116 + if ( $hook ) {
117 + add_action( 'load-' . $hook, array( $this, 'load' ) );
88 118 }
119 + }
89 120
90 - remove_submenu_page( $this->base_slug, $this->slug );
121 + /**
122 + * Mark the snippet being edited in the menu.
123 + *
124 + * Added as a plain link rather than a second registration of the page: a
125 + * submenu slug doubles as the identifier WordPress checks permissions
126 + * against, so carrying the ID in the slug would make `page=edit-snippet`
127 + * match nothing and the screen would refuse to load.
128 + *
129 + * @param int $snippet_id Snippet being edited.
130 + *
131 + * @return void
132 + */
133 + private function add_current_snippet_menu_item( int $snippet_id ): void {
134 + add_submenu_page(
135 + $this->base_slug,
136 + $this->title,
137 + $this->label,
138 + code_snippets()->get_cap(),
139 + add_query_arg(
140 + [
141 + 'page' => $this->slug,
142 + 'id' => $snippet_id,
143 + ],
144 + 'admin.php'
145 + ),
146 + '',
147 + 1
148 + );
91 149 }
92 150
93 151 /**
152 + * Retrieve the hookname of the edit page.
153 + *
154 + * The page is registered without a parent, so WordPress files it under
155 + * "admin_page_" rather than under the Snippets menu; deriving it from the
156 + * menu slug would name a screen that does not exist.
157 + *
158 + * @return string
159 + */
160 + public function get_hookname(): string {
161 + return get_plugin_page_hookname( $this->slug, '' );
162 + }
163 +
164 + /**
165 + * Retrieve every hookname registered by this menu, including the separate
166 + * "Add New" page, so screen-based checks recognize both editor views.
167 + *
168 + * @return string[]
169 + */
170 + public function get_hooknames(): array {
171 + return [
172 + $this->get_hookname(),
173 + get_plugin_page_hookname( code_snippets()->get_menu_slug( 'add' ), $this->base_slug ),
174 + ];
175 + }
176 +
177 + /**
94 178 * Executed when the menu is loaded.
95 179 *
96 180 * @return void
97 181 */
@@ -110,11 +194,10 @@
110 194 *
111 195 * @return void
112 196 */
113 197 protected function ensure_correct_page() {
114 - $screen = get_current_screen();
115 - $edit_hook = get_plugin_page_hookname( $this->slug, $this->base_slug );
116 - $edit_hook .= $screen->in_admin( 'network' ) ? '-network' : '';
198 + $screen = get_current_screen();
199 + $edit_hook = $this->get_hookname() . ( $screen->in_admin( 'network' ) ? '-network' : '' );
117 200
118 201 // Disallow visiting the edit snippet page without a valid ID.
119 202 if (
120 203 $screen->base === $edit_hook
@@ -191,9 +274,9 @@
191 274
192 275 wp_enqueue_script(
193 276 self::JS_HANDLE,
194 277 plugins_url( 'dist/edit.js', PLUGIN_FILE ),
195 - [ 'code-snippets-code-editor' ] + self::$script_deps,
278 + array_merge( [ 'code-snippets-code-editor' ], self::$script_deps ),
196 279 PLUGIN_VERSION,
197 280 [ 'in_footer' => true ]
198 281 );
199 282