@wordpress/build 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,252 @@
1
+ <?php
2
+ /**
3
+ * Page: {{PAGE_SLUG}} (wp-admin integrated)
4
+ * Auto-generated by build process.
5
+ * Do not edit this file manually.
6
+ *
7
+ * This version integrates with the standard WordPress admin interface,
8
+ * keeping the wp-admin sidebar and scripts/styles intact.
9
+ *
10
+ * @package {{PREFIX}}
11
+ */
12
+
13
+ // Global storage for {{PAGE_SLUG}} routes and menu items
14
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes, ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items;
15
+ ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes = array();
16
+ ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items = array();
17
+
18
+ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_route' ) ) {
19
+ /**
20
+ * Register a route for the {{PAGE_SLUG}}-wp-admin page.
21
+ *
22
+ * @param string $path Route path (e.g., '/types/$type/edit/$id').
23
+ * @param string|null $content_module Script module ID for content (stage/inspector).
24
+ * @param string|null $route_module Script module ID for route lifecycle hooks.
25
+ */
26
+ function register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_route( $path, $content_module = null, $route_module = null ) {
27
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes;
28
+
29
+ $route = array( 'path' => $path );
30
+ if ( ! empty( $content_module ) ) {
31
+ $route['content_module'] = $content_module;
32
+ }
33
+ if ( ! empty( $route_module ) ) {
34
+ $route['route_module'] = $route_module;
35
+ }
36
+
37
+ ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes[] = $route;
38
+ }
39
+ }
40
+
41
+ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_item' ) ) {
42
+ /**
43
+ * Register a menu item for the {{PAGE_SLUG}}-wp-admin page.
44
+ * Note: Menu items are registered but not displayed in single-page mode.
45
+ *
46
+ * @param string $id Menu item ID.
47
+ * @param string $label Display label.
48
+ * @param string $to Route path to navigate to.
49
+ * @param string $parent_id Optional. Parent menu item ID.
50
+ */
51
+ function register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_item( $id, $label, $to, $parent_id = '' ) {
52
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items;
53
+
54
+ $menu_item = array(
55
+ 'id' => $id,
56
+ 'label' => $label,
57
+ 'to' => $to,
58
+ );
59
+
60
+ if ( ! empty( $parent_id ) ) {
61
+ $menu_item['parent'] = $parent_id;
62
+ }
63
+
64
+ ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items[] = $menu_item;
65
+ }
66
+ }
67
+
68
+ if ( ! function_exists( 'get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes' ) ) {
69
+ /**
70
+ * Get all registered routes for the {{PAGE_SLUG}}-wp-admin page.
71
+ *
72
+ * @return array Array of route objects.
73
+ */
74
+ function get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes() {
75
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes;
76
+ return ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes ?? array();
77
+ }
78
+ }
79
+
80
+ if ( ! function_exists( 'get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items' ) ) {
81
+ /**
82
+ * Get all registered menu items for the {{PAGE_SLUG}}-wp-admin page.
83
+ *
84
+ * @return array Array of menu item objects.
85
+ */
86
+ function get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items() {
87
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items;
88
+ return ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items ?? array();
89
+ }
90
+ }
91
+
92
+ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data' ) ) {
93
+ /**
94
+ * Preload REST API data for the {{PAGE_SLUG}}-wp-admin page.
95
+ * Automatically called during page rendering.
96
+ */
97
+ function {{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data() {
98
+ // Define paths to preload - same for all pages
99
+ $preload_paths = array(
100
+ '/?_fields=description,gmt_offset,home,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front',
101
+ array( '/wp/v2/settings', 'OPTIONS' ),
102
+ );
103
+
104
+ // Use rest_preload_api_request to gather the preloaded data
105
+ $preload_data = array_reduce(
106
+ $preload_paths,
107
+ 'rest_preload_api_request',
108
+ array()
109
+ );
110
+
111
+ // Register the preloading middleware with wp-api-fetch
112
+ wp_add_inline_script(
113
+ 'wp-api-fetch',
114
+ sprintf(
115
+ 'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );',
116
+ wp_json_encode( $preload_data )
117
+ ),
118
+ 'after'
119
+ );
120
+ }
121
+ }
122
+
123
+ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts' ) ) {
124
+ /**
125
+ * Enqueue scripts and styles for the {{PAGE_SLUG}}-wp-admin page.
126
+ * Hooked to admin_enqueue_scripts.
127
+ *
128
+ * @param string $hook_suffix The current admin page.
129
+ */
130
+ function {{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts( $hook_suffix ) {
131
+ // Only enqueue on our page
132
+ if ( ! isset( $_GET['page'] ) || '{{PAGE_SLUG}}-wp-admin' !== $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
133
+ return;
134
+ }
135
+
136
+ // Fire init action for extensions to register routes and menu items
137
+ do_action( '{{PAGE_SLUG}}-wp-admin_init' );
138
+
139
+ // Preload REST API data
140
+ {{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data();
141
+
142
+ // Get all registered routes
143
+ $routes = get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes();
144
+
145
+ // Get boot module asset file for dependencies
146
+ $asset_file = plugin_dir_path( __FILE__ ) . '../../modules/boot/index.min.asset.php';
147
+ if ( file_exists( $asset_file ) ) {
148
+ $asset = require $asset_file;
149
+
150
+ // This script serves two purposes:
151
+ // 1. It ensures all the globals that are made available to the modules are loaded.
152
+ // 2. It initializes the boot module as an inline script.
153
+ wp_register_script( '{{PAGE_SLUG}}-wp-admin-prerequisites', '', $asset['dependencies'], $asset['version'], true );
154
+
155
+ // Add inline script to initialize the app using initSinglePage (no menuItems)
156
+ wp_add_inline_script(
157
+ '{{PAGE_SLUG}}-wp-admin-prerequisites',
158
+ sprintf(
159
+ 'import("@wordpress/boot").then(mod => mod.initSinglePage({mountId: "%s", routes: %s}));',
160
+ '{{PAGE_SLUG}}-wp-admin-app',
161
+ wp_json_encode( $routes, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES )
162
+ )
163
+ );
164
+
165
+ // Register prerequisites style by filtering script dependencies to find registered styles
166
+ $style_dependencies = array_filter(
167
+ $asset['dependencies'],
168
+ function ( $handle ) {
169
+ return wp_style_is( $handle, 'registered' );
170
+ }
171
+ );
172
+ wp_register_style( '{{PAGE_SLUG}}-wp-admin-prerequisites', false, $style_dependencies, $asset['version'] );
173
+
174
+ // Build dependencies for {{PAGE_SLUG}}-wp-admin module
175
+ $boot_dependencies = array(
176
+ array(
177
+ 'import' => 'static',
178
+ 'id' => '@wordpress/boot',
179
+ ),
180
+ );
181
+
182
+ // Add all registered routes as dependencies
183
+ foreach ( $routes as $route ) {
184
+ if ( isset( $route['route_module'] ) ) {
185
+ $boot_dependencies[] = array(
186
+ 'import' => 'static',
187
+ 'id' => $route['route_module'],
188
+ );
189
+ }
190
+ if ( isset( $route['content_module'] ) ) {
191
+ $boot_dependencies[] = array(
192
+ 'import' => 'dynamic',
193
+ 'id' => $route['content_module'],
194
+ );
195
+ }
196
+ }
197
+
198
+ // Dummy script module to ensure dependencies are loaded
199
+ wp_register_script_module(
200
+ '{{PAGE_SLUG}}-wp-admin',
201
+ plugin_dir_url( __FILE__ ) . 'loader.js',
202
+ $boot_dependencies
203
+ );
204
+
205
+ // Enqueue the boot scripts and styles
206
+ wp_enqueue_script( '{{PAGE_SLUG}}-wp-admin-prerequisites' );
207
+ wp_enqueue_script_module( '{{PAGE_SLUG}}-wp-admin' );
208
+ wp_enqueue_style( '{{PAGE_SLUG}}-wp-admin-prerequisites' );
209
+ }
210
+ }
211
+ }
212
+
213
+ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_render_page' ) ) {
214
+ /**
215
+ * Render the {{PAGE_SLUG}}-wp-admin page.
216
+ * Call this function from add_menu_page or add_submenu_page.
217
+ * This renders within the normal WordPress admin interface.
218
+ */
219
+ function {{PAGE_SLUG_UNDERSCORE}}_wp_admin_render_page() {
220
+ ?>
221
+ <div id="{{PAGE_SLUG}}-wp-admin-app" class="boot-layout-container"></div>
222
+ <?php
223
+ }
224
+ }
225
+
226
+ // Hook the enqueue function to admin_enqueue_scripts
227
+ add_action( 'admin_enqueue_scripts', '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts' );
228
+
229
+ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_register_page' ) ) {
230
+ /**
231
+ * Register the {{PAGE_SLUG}}-wp-admin base page handler.
232
+ * This is hidden from the menu but provides the page callback for URL routing.
233
+ * Visible menu items should use the full URL pattern with query parameters.
234
+ *
235
+ * Example:
236
+ * $url = admin_url( 'admin.php?page={{PAGE_SLUG}}-wp-admin&p=' . urlencode( '/your/route' ) );
237
+ * add_menu_page( 'Title', 'Menu', 'capability', $url, '', 'icon', 10 );
238
+ */
239
+ function {{PAGE_SLUG_UNDERSCORE}}_wp_admin_register_page() {
240
+ add_submenu_page(
241
+ 'nothing-{{PAGE_SLUG}}', // Hidden page (no parent)
242
+ __( '{{PAGE_SLUG}} (WP Admin)', '{{PREFIX}}' ), // Page title
243
+ __( '{{PAGE_SLUG}} (WP Admin)', '{{PREFIX}}' ), // Menu title (not visible)
244
+ 'read', // Minimum capability
245
+ '{{PAGE_SLUG}}-wp-admin', // Menu slug for URL routing
246
+ '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_render_page' // Callback function
247
+ );
248
+ }
249
+ }
250
+
251
+ // Hook the registration to admin_menu
252
+ add_action( 'admin_menu', '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_register_page' );
@@ -0,0 +1,311 @@
1
+ <?php
2
+ /**
3
+ * Page: {{PAGE_SLUG}}
4
+ * Auto-generated by build process.
5
+ * Do not edit this file manually.
6
+ *
7
+ * @package {{PREFIX}}
8
+ */
9
+
10
+ // Global storage for {{PAGE_SLUG}} routes and menu items
11
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes, ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items;
12
+ ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes = array();
13
+ ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items = array();
14
+
15
+ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_route' ) ) {
16
+ /**
17
+ * Register a route for the {{PAGE_SLUG}} page.
18
+ *
19
+ * @param string $path Route path (e.g., '/types/$type/edit/$id').
20
+ * @param string|null $content_module Script module ID for content (stage/inspector).
21
+ * @param string|null $route_module Script module ID for route lifecycle hooks.
22
+ */
23
+ function register_{{PAGE_SLUG_UNDERSCORE}}_route( $path, $content_module = null, $route_module = null ) {
24
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes;
25
+
26
+ $route = array( 'path' => $path );
27
+ if ( ! empty( $content_module ) ) {
28
+ $route['content_module'] = $content_module;
29
+ }
30
+ if ( ! empty( $route_module ) ) {
31
+ $route['route_module'] = $route_module;
32
+ }
33
+
34
+ ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes[] = $route;
35
+ }
36
+ }
37
+
38
+ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_menu_item' ) ) {
39
+ /**
40
+ * Register a menu item for the {{PAGE_SLUG}} page.
41
+ *
42
+ * @param string $id Menu item ID.
43
+ * @param string $label Display label.
44
+ * @param string $to Route path to navigate to.
45
+ * @param string $parent_id Optional. Parent menu item ID.
46
+ */
47
+ function register_{{PAGE_SLUG_UNDERSCORE}}_menu_item( $id, $label, $to, $parent_id = '' ) {
48
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items;
49
+
50
+ $menu_item = array(
51
+ 'id' => $id,
52
+ 'label' => $label,
53
+ 'to' => $to,
54
+ );
55
+
56
+ if ( ! empty( $parent_id ) ) {
57
+ $menu_item['parent'] = $parent_id;
58
+ }
59
+
60
+ ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items[] = $menu_item;
61
+ }
62
+ }
63
+
64
+ if ( ! function_exists( 'get_{{PAGE_SLUG_UNDERSCORE}}_routes' ) ) {
65
+ /**
66
+ * Get all registered routes for the {{PAGE_SLUG}} page.
67
+ *
68
+ * @return array Array of route objects.
69
+ */
70
+ function get_{{PAGE_SLUG_UNDERSCORE}}_routes() {
71
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes;
72
+ return ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes ?? array();
73
+ }
74
+ }
75
+
76
+ if ( ! function_exists( 'get_{{PAGE_SLUG_UNDERSCORE}}_menu_items' ) ) {
77
+ /**
78
+ * Get all registered menu items for the {{PAGE_SLUG}} page.
79
+ *
80
+ * @return array Array of menu item objects.
81
+ */
82
+ function get_{{PAGE_SLUG_UNDERSCORE}}_menu_items() {
83
+ global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items;
84
+ return ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items ?? array();
85
+ }
86
+ }
87
+
88
+ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_preload_data' ) ) {
89
+ /**
90
+ * Preload REST API data for the {{PAGE_SLUG}} page.
91
+ * Automatically called during page rendering.
92
+ */
93
+ function {{PAGE_SLUG_UNDERSCORE}}_preload_data() {
94
+ // Define paths to preload - same for all pages
95
+ $preload_paths = array(
96
+ '/?_fields=description,gmt_offset,home,name,site_icon,site_icon_url,site_logo,timezone_string,url,page_for_posts,page_on_front,show_on_front',
97
+ array( '/wp/v2/settings', 'OPTIONS' ),
98
+ );
99
+
100
+ // Use rest_preload_api_request to gather the preloaded data
101
+ $preload_data = array_reduce(
102
+ $preload_paths,
103
+ 'rest_preload_api_request',
104
+ array()
105
+ );
106
+
107
+ // Register the preloading middleware with wp-api-fetch
108
+ wp_add_inline_script(
109
+ 'wp-api-fetch',
110
+ sprintf(
111
+ 'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );',
112
+ wp_json_encode( $preload_data )
113
+ ),
114
+ 'after'
115
+ );
116
+ }
117
+ }
118
+
119
+ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_render_page' ) ) {
120
+ /**
121
+ * Render the {{PAGE_SLUG}} page.
122
+ * Call this function from add_menu_page or add_submenu_page.
123
+ */
124
+ function {{PAGE_SLUG_UNDERSCORE}}_render_page() {
125
+ // Set current screen
126
+ set_current_screen();
127
+
128
+ // Remove unwanted deprecated handler
129
+ remove_action( 'admin_head', 'wp_admin_bar_header' );
130
+
131
+ // Remove unwanted scripts and styles that were enqueued during `admin_init`
132
+ foreach ( wp_scripts()->queue as $script ) {
133
+ wp_dequeue_script( $script );
134
+ }
135
+ foreach ( wp_styles()->queue as $style ) {
136
+ wp_dequeue_style( $style );
137
+ }
138
+
139
+ // Fire init action for extensions to register routes and menu items
140
+ do_action( '{{PAGE_SLUG}}_init' );
141
+
142
+ // Preload REST API data
143
+ {{PAGE_SLUG_UNDERSCORE}}_preload_data();
144
+
145
+ // Get all registered routes and menu items
146
+ $menu_items = get_{{PAGE_SLUG_UNDERSCORE}}_menu_items();
147
+ $routes = get_{{PAGE_SLUG_UNDERSCORE}}_routes();
148
+
149
+ // Get boot module asset file for dependencies
150
+ $asset_file = plugin_dir_path( __FILE__ ) . '../../modules/boot/index.min.asset.php';
151
+ if ( file_exists( $asset_file ) ) {
152
+ $asset = require $asset_file;
153
+
154
+ // This script serves two purposes:
155
+ // 1. It ensures all the globals that are made available to the modules are loaded.
156
+ // 2. It initializes the boot module as an inline script.
157
+ wp_register_script( '{{PAGE_SLUG}}-prerequisites', '', $asset['dependencies'], $asset['version'], true );
158
+
159
+ // Add inline script to initialize the app
160
+ wp_add_inline_script(
161
+ '{{PAGE_SLUG}}-prerequisites',
162
+ sprintf(
163
+ 'import("@wordpress/boot").then(mod => mod.init({mountId: "%s", menuItems: %s, routes: %s}));',
164
+ '{{PAGE_SLUG}}-app',
165
+ wp_json_encode( $menu_items, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ),
166
+ wp_json_encode( $routes, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES )
167
+ )
168
+ );
169
+
170
+ // Register prerequisites style by filtering script dependencies to find registered styles
171
+ $style_dependencies = array_filter(
172
+ $asset['dependencies'],
173
+ function ( $handle ) {
174
+ return wp_style_is( $handle, 'registered' );
175
+ }
176
+ );
177
+ wp_register_style( '{{PAGE_SLUG}}-prerequisites', false, $style_dependencies, $asset['version'] );
178
+
179
+ // Build dependencies for {{PAGE_SLUG}} module
180
+ $boot_dependencies = array(
181
+ array(
182
+ 'import' => 'static',
183
+ 'id' => '@wordpress/boot',
184
+ ),
185
+ );
186
+
187
+ // Add all registered routes as dependencies
188
+ foreach ( $routes as $route ) {
189
+ if ( isset( $route['route_module'] ) ) {
190
+ $boot_dependencies[] = array(
191
+ 'import' => 'static',
192
+ 'id' => $route['route_module'],
193
+ );
194
+ }
195
+ if ( isset( $route['content_module'] ) ) {
196
+ $boot_dependencies[] = array(
197
+ 'import' => 'dynamic',
198
+ 'id' => $route['content_module'],
199
+ );
200
+ }
201
+ }
202
+
203
+ // Dummy script module to ensure dependencies are loaded
204
+ wp_register_script_module(
205
+ '{{PAGE_SLUG}}',
206
+ plugin_dir_url( __FILE__ ) . 'loader.js',
207
+ $boot_dependencies
208
+ );
209
+
210
+ // Enqueue the boot scripts and styles
211
+ wp_enqueue_script( '{{PAGE_SLUG}}-prerequisites' );
212
+ wp_enqueue_script_module( '{{PAGE_SLUG}}' );
213
+ wp_enqueue_style( '{{PAGE_SLUG}}-prerequisites' );
214
+ }
215
+
216
+ // Output the HTML
217
+ ?>
218
+ <!DOCTYPE html>
219
+ <html <?php language_attributes(); ?>>
220
+ <head>
221
+ <meta charset="<?php bloginfo( 'charset' ); ?>">
222
+ <meta name="viewport" content="width=device-width, initial-scale=1">
223
+ <title><?php echo esc_html( get_admin_page_title() ); ?></title>
224
+ <style>
225
+ html {
226
+ background: #f1f1f1;
227
+ color: #444;
228
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
229
+ font-size: 13px;
230
+ line-height: 1.4em;
231
+ }
232
+ body {
233
+ margin: 0;
234
+ }
235
+ #wpadminbar { display: none; }
236
+ </style>
237
+ <?php
238
+ global $hook_suffix;
239
+ // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
240
+ $hook_suffix = '{{PAGE_SLUG}}';
241
+
242
+ // BEGIN see wp-admin/admin-header.php
243
+ print_admin_styles();
244
+ print_head_scripts();
245
+
246
+ /**
247
+ * Fires in head section for a specific admin page.
248
+ *
249
+ * @since 2.1.0
250
+ */
251
+ do_action( "admin_head-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
252
+
253
+ /**
254
+ * Fires in head section for all admin pages.
255
+ *
256
+ * @since 2.1.0
257
+ */
258
+ do_action( 'admin_head' );
259
+ // END see wp-admin/admin-header.php
260
+ ?>
261
+ </head>
262
+ <body class="{{PAGE_SLUG}}">
263
+ <div id="{{PAGE_SLUG}}-app" style="height: 100vh; box-sizing: border-box;"></div>
264
+ <?php
265
+ // BEGIN see wp-admin/admin-footer.php
266
+
267
+ /**
268
+ * Prints scripts or data before the default footer scripts.
269
+ *
270
+ * @since 1.2.0
271
+ */
272
+ do_action( 'admin_footer', '' );
273
+
274
+ // Print import map first so it's available for inline scripts
275
+ wp_script_modules()->print_import_map();
276
+ print_footer_scripts();
277
+ wp_script_modules()->print_enqueued_script_modules();
278
+ wp_script_modules()->print_script_module_preloads();
279
+ wp_script_modules()->print_script_module_data();
280
+
281
+ /**
282
+ * Prints scripts or data after the default footer scripts.
283
+ *
284
+ * @since 2.8.0
285
+ */
286
+ do_action( "admin_footer-{$hook_suffix}" ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
287
+ // END see wp-admin/admin-footer.php
288
+ ?>
289
+ </body>
290
+ </html>
291
+ <?php
292
+ exit;
293
+ }
294
+ }
295
+
296
+ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_intercept_render' ) ) {
297
+ /**
298
+ * Intercept admin_init to render the page early.
299
+ * This bypasses the default WordPress admin template.
300
+ */
301
+ function {{PAGE_SLUG_UNDERSCORE}}_intercept_render() {
302
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
303
+ if ( isset( $_GET['page'] ) && '{{PAGE_SLUG}}' === $_GET['page'] ) {
304
+ {{PAGE_SLUG_UNDERSCORE}}_render_page();
305
+ exit;
306
+ }
307
+ }
308
+ }
309
+
310
+ // Hook the interceptor to admin_init
311
+ add_action( 'admin_init', '{{PAGE_SLUG_UNDERSCORE}}_intercept_render' );
@@ -0,0 +1,9 @@
1
+ <?php
2
+ /**
3
+ * Pages loader - Auto-generated by build process.
4
+ * Do not edit this file manually.
5
+ *
6
+ * @package {{PREFIX}}
7
+ */
8
+
9
+ {{PAGE_INCLUDES}}
@@ -0,0 +1,11 @@
1
+ <?php
2
+ /**
3
+ * Route registry - Auto-generated by build process.
4
+ * Do not edit this file manually.
5
+ *
6
+ * @package {{PREFIX}}
7
+ */
8
+
9
+ return array(
10
+ {{ROUTES}}
11
+ );
@@ -0,0 +1,90 @@
1
+ <?php
2
+ /**
3
+ * Routes registration - Auto-generated by build process.
4
+ * Registers all routes on their respective page init hooks.
5
+ * Do not edit this file manually.
6
+ *
7
+ * @package {{PREFIX}}
8
+ */
9
+
10
+ // Load routes registry
11
+ $routes_file = __DIR__ . '/routes/index.php';
12
+ if ( ! file_exists( $routes_file ) ) {
13
+ return;
14
+ }
15
+
16
+ $routes = require $routes_file;
17
+
18
+ // Group routes by page
19
+ $routes_by_page = array();
20
+ foreach ( $routes as $route ) {
21
+ $page_slug = $route['page'];
22
+ if ( ! isset( $routes_by_page[ $page_slug ] ) ) {
23
+ $routes_by_page[ $page_slug ] = array();
24
+ }
25
+ $routes_by_page[ $page_slug ][] = $route;
26
+ }
27
+
28
+ // Helper function to register routes for a page
29
+ $register_routes_callback = function ( $page_routes, $page_slug_underscore, $register_function_name ) {
30
+ return function () use ( $page_routes, $page_slug_underscore, $register_function_name ) {
31
+ foreach ( $page_routes as $route ) {
32
+ $content_handle = null;
33
+ $route_handle = null;
34
+
35
+ // Register content module if exists
36
+ if ( $route['has_content'] ) {
37
+ $content_asset_path = __DIR__ . "/routes/{$route['name']}/content.min.asset.php";
38
+ if ( file_exists( $content_asset_path ) ) {
39
+ $content_asset = require $content_asset_path;
40
+ $content_handle = '{{HANDLE_PREFIX}}/routes/' . $route['name'] . '/content';
41
+ $extension = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.js' : '.min.js';
42
+ wp_register_script_module(
43
+ $content_handle,
44
+ plugins_url( 'build/routes/' . $route['name'] . '/content' . $extension, dirname( __FILE__ ) ),
45
+ $content_asset['module_dependencies'] ?? array(),
46
+ $content_asset['version'] ?? false
47
+ );
48
+ }
49
+ }
50
+
51
+ // Register route module if exists
52
+ if ( $route['has_route'] ) {
53
+ $route_asset_path = __DIR__ . "/routes/{$route['name']}/route.min.asset.php";
54
+ if ( file_exists( $route_asset_path ) ) {
55
+ $route_asset = require $route_asset_path;
56
+ $route_handle = '{{HANDLE_PREFIX}}/routes/' . $route['name'] . '/route';
57
+ $extension = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.js' : '.min.js';
58
+ wp_register_script_module(
59
+ $route_handle,
60
+ plugins_url( 'build/routes/' . $route['name'] . '/route' . $extension, dirname( __FILE__ ) ),
61
+ $route_asset['module_dependencies'] ?? array(),
62
+ $route_asset['version'] ?? false
63
+ );
64
+ }
65
+ }
66
+
67
+ // Register route with page
68
+ if ( function_exists( $register_function_name ) ) {
69
+ call_user_func( $register_function_name, $route['path'], $content_handle, $route_handle );
70
+ }
71
+ }
72
+ };
73
+ };
74
+
75
+ // Register hooks for both full-page and wp-admin modes
76
+ foreach ( $routes_by_page as $page_slug => $page_routes ) {
77
+ $page_slug_underscore = str_replace( '-', '_', $page_slug );
78
+
79
+ // Register all routes for full-page mode (page.php)
80
+ add_action(
81
+ "{$page_slug}_init",
82
+ $register_routes_callback( $page_routes, $page_slug_underscore, "register_{$page_slug_underscore}_route" )
83
+ );
84
+
85
+ // Register all routes for wp-admin mode (page-wp-admin.php)
86
+ add_action(
87
+ "{$page_slug}-wp-admin_init",
88
+ $register_routes_callback( $page_routes, $page_slug_underscore, "register_{$page_slug_underscore}_wp_admin_route" )
89
+ );
90
+ }