@wordpress/build 0.5.1-next.v.0 → 0.6.2-next.v.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.
- package/CHANGELOG.md +20 -0
- package/README.md +24 -9
- package/lib/build.mjs +43 -23
- package/package.json +2 -2
- package/templates/module-registration.php.template +2 -2
- package/templates/page-wp-admin.php.template +18 -18
- package/templates/page.php.template +20 -20
- package/templates/routes-page-functions.php.template +22 -0
- package/templates/routes-registration.php.template +22 -23
- package/templates/script-registration.php.template +1 -1
- package/templates/style-registration.php.template +1 -1
- /package/templates/{index.php.template → build.php.template} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.6.1-next.0 (2026-01-23)
|
|
6
|
+
|
|
7
|
+
- Update documentation to describe `wpPlugin.name`
|
|
8
|
+
|
|
9
|
+
## 0.6.0 (2026-01-16)
|
|
10
|
+
|
|
11
|
+
### Breaking Changes
|
|
12
|
+
|
|
13
|
+
- Renamed generated PHP files to avoid `index.php` naming conflicts:
|
|
14
|
+
- `build/index.php` → `build/build.php`
|
|
15
|
+
- `build/modules/index.php` → `build/modules/registry.php`
|
|
16
|
+
- `build/scripts/index.php` → `build/scripts/registry.php`
|
|
17
|
+
- `build/styles/index.php` → `build/styles/registry.php`
|
|
18
|
+
- `build/routes/index.php` → `build/routes/registry.php`
|
|
19
|
+
- All generated page functions now include the `{{PREFIX}}` (from `wpPlugin.name`) at the beginning:
|
|
20
|
+
- `register_my_page_route()` → `my_plugin_register_my_page_route()`
|
|
21
|
+
- `my_page_render_page()` → `my_plugin_my_page_render_page()`
|
|
22
|
+
- And similarly for all other page functions
|
|
23
|
+
- Route registration now uses named functions instead of anonymous closures, allowing third-party developers to unhook them
|
|
24
|
+
|
|
5
25
|
## 0.4.0 (2025-11-26)
|
|
6
26
|
|
|
7
27
|
## 0.3.0 (2025-11-12)
|
package/README.md
CHANGED
|
@@ -136,6 +136,18 @@ Files to copy with optional PHP transformations:
|
|
|
136
136
|
|
|
137
137
|
Configure your root `package.json` with a `wpPlugin` object to control global namespace and externalization behavior:
|
|
138
138
|
|
|
139
|
+
### `wpPlugin.name`
|
|
140
|
+
|
|
141
|
+
Name used to prefix genereated PHP functions. Must follow function name rules in PHP, i.e. valid name starts with a letter or underscore, followed by any number of letters, numbers, or underscores.
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"wpPlugin": {
|
|
146
|
+
"name": "myPlugin"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
139
151
|
### `wpPlugin.scriptGlobal`
|
|
140
152
|
|
|
141
153
|
The global variable name for your packages (e.g., `"wp"`, `"myPlugin"`). Set to `false` to disable global exposure:
|
|
@@ -248,15 +260,17 @@ WP-Admin mode integrates within the standard WordPress admin interface (keeping
|
|
|
248
260
|
|
|
249
261
|
```php
|
|
250
262
|
add_submenu_page(
|
|
251
|
-
'themes.php',
|
|
252
|
-
__( 'My Page', 'my-plugin' ),
|
|
253
|
-
__( 'My Page', 'my-plugin' ),
|
|
254
|
-
'edit_theme_options',
|
|
255
|
-
'my-admin-page-wp-admin',
|
|
256
|
-
'
|
|
263
|
+
'themes.php', // Parent menu
|
|
264
|
+
__( 'My Page', 'my-plugin' ), // Page title
|
|
265
|
+
__( 'My Page', 'my-plugin' ), // Menu title
|
|
266
|
+
'edit_theme_options', // Capability
|
|
267
|
+
'my-admin-page-wp-admin', // Menu slug (simple)
|
|
268
|
+
'my_plugin_my_admin_page_wp_admin_render_page' // Callback from generated PHP (prefixed)
|
|
257
269
|
);
|
|
258
270
|
```
|
|
259
271
|
|
|
272
|
+
Note: The callback function name is prefixed with your plugin name (from `wpPlugin.name` in root `package.json`). For example, if your plugin name is `my-plugin`, the function will be `my_plugin_my_admin_page_wp_admin_render_page`.
|
|
273
|
+
|
|
260
274
|
The page slug is `my-admin-page-wp-admin` (your page ID + `-wp-admin`). WordPress routes all requests to this callback, and the JavaScript router handles internal navigation.
|
|
261
275
|
|
|
262
276
|
**Deep linking with the `p` query parameter:**
|
|
@@ -274,7 +288,7 @@ When the page loads, the JavaScript boot system reads the `p` parameter and navi
|
|
|
274
288
|
Full-page mode takes over the entire admin screen with a custom sidebar:
|
|
275
289
|
|
|
276
290
|
```php
|
|
277
|
-
add_menu_page( 'Title', 'Menu', 'capability', 'my-admin-page', '
|
|
291
|
+
add_menu_page( 'Title', 'Menu', 'capability', 'my-admin-page', 'my_plugin_my_admin_page_render_page', 'icon', 20 );
|
|
278
292
|
```
|
|
279
293
|
|
|
280
294
|
**Init Modules:**
|
|
@@ -337,6 +351,7 @@ This configuration:
|
|
|
337
351
|
```json
|
|
338
352
|
{
|
|
339
353
|
"wpPlugin": {
|
|
354
|
+
"name": "acme",
|
|
340
355
|
"scriptGlobal": "acme",
|
|
341
356
|
"packageNamespace": "acme"
|
|
342
357
|
}
|
|
@@ -364,7 +379,7 @@ The built tool generates several files in the `build/` directory, but the primar
|
|
|
364
379
|
Make sure to include the generated PHP file in your plugin file.
|
|
365
380
|
|
|
366
381
|
```php
|
|
367
|
-
require_once plugin_dir_path( __FILE__ ) . 'build/
|
|
382
|
+
require_once plugin_dir_path( __FILE__ ) . 'build/build.php';
|
|
368
383
|
```
|
|
369
384
|
|
|
370
385
|
## Routes (Experimental)
|
|
@@ -470,7 +485,7 @@ The `canvas()` function controls which canvas is rendered:
|
|
|
470
485
|
The build system generates:
|
|
471
486
|
- `build/routes/{route-name}/content.js` - Bundled stage/inspector/canvas components
|
|
472
487
|
- `build/routes/{route-name}/route.js` - Bundled lifecycle hooks (if present)
|
|
473
|
-
- `build/routes/
|
|
488
|
+
- `build/routes/registry.php` - Route registry data
|
|
474
489
|
- `build/routes.php` - Route registration logic
|
|
475
490
|
|
|
476
491
|
The boot package in Gutenberg will automatically use these routes and make them available.
|
package/lib/build.mjs
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
import {
|
|
31
31
|
generatePhpFromTemplate,
|
|
32
32
|
getPhpReplacements,
|
|
33
|
+
renderTemplateToString,
|
|
33
34
|
} from './php-generator.mjs';
|
|
34
35
|
import { getPackageInfo, getPackageInfoFromFile } from './package-utils.mjs';
|
|
35
36
|
import { createWordpressExternalsPlugin } from './wordpress-externals-plugin.mjs';
|
|
@@ -743,7 +744,7 @@ async function generateModuleRegistrationPhp( modules, replacements ) {
|
|
|
743
744
|
await Promise.all( [
|
|
744
745
|
generatePhpFromTemplate(
|
|
745
746
|
'module-registry.php.template',
|
|
746
|
-
path.join( BUILD_DIR, 'modules', '
|
|
747
|
+
path.join( BUILD_DIR, 'modules', 'registry.php' ),
|
|
747
748
|
{ ...replacements, '{{MODULES}}': modulesArray }
|
|
748
749
|
),
|
|
749
750
|
generatePhpFromTemplate(
|
|
@@ -776,7 +777,7 @@ async function generateScriptRegistrationPhp( scripts, replacements ) {
|
|
|
776
777
|
await Promise.all( [
|
|
777
778
|
generatePhpFromTemplate(
|
|
778
779
|
'script-registry.php.template',
|
|
779
|
-
path.join( BUILD_DIR, 'scripts', '
|
|
780
|
+
path.join( BUILD_DIR, 'scripts', 'registry.php' ),
|
|
780
781
|
{ ...replacements, '{{SCRIPTS}}': scriptsArray }
|
|
781
782
|
),
|
|
782
783
|
generatePhpFromTemplate(
|
|
@@ -824,7 +825,7 @@ async function generateStyleRegistrationPhp( styles, replacements ) {
|
|
|
824
825
|
await Promise.all( [
|
|
825
826
|
generatePhpFromTemplate(
|
|
826
827
|
'style-registry.php.template',
|
|
827
|
-
path.join( BUILD_DIR, 'styles', '
|
|
828
|
+
path.join( BUILD_DIR, 'styles', 'registry.php' ),
|
|
828
829
|
{ ...replacements, '{{STYLES}}': stylesArray }
|
|
829
830
|
),
|
|
830
831
|
generatePhpFromTemplate(
|
|
@@ -836,14 +837,14 @@ async function generateStyleRegistrationPhp( styles, replacements ) {
|
|
|
836
837
|
}
|
|
837
838
|
|
|
838
839
|
/**
|
|
839
|
-
* Generate main
|
|
840
|
+
* Generate main build.php that loads both modules and scripts.
|
|
840
841
|
*
|
|
841
842
|
* @param {Record<string, string>} replacements PHP template replacements.
|
|
842
843
|
*/
|
|
843
|
-
async function
|
|
844
|
+
async function generateMainBuildPhp( replacements ) {
|
|
844
845
|
await generatePhpFromTemplate(
|
|
845
|
-
'
|
|
846
|
-
path.join( BUILD_DIR, '
|
|
846
|
+
'build.php.template',
|
|
847
|
+
path.join( BUILD_DIR, 'build.php' ),
|
|
847
848
|
replacements
|
|
848
849
|
);
|
|
849
850
|
}
|
|
@@ -876,10 +877,10 @@ async function generateRoutesRegistry( routes, replacements ) {
|
|
|
876
877
|
} )
|
|
877
878
|
.join( ',\n' );
|
|
878
879
|
|
|
879
|
-
// Generate single global registry at build/routes/
|
|
880
|
+
// Generate single global registry at build/routes/registry.php
|
|
880
881
|
await generatePhpFromTemplate(
|
|
881
882
|
'route-registry.php.template',
|
|
882
|
-
path.join( BUILD_DIR, 'routes', '
|
|
883
|
+
path.join( BUILD_DIR, 'routes', 'registry.php' ),
|
|
883
884
|
{ ...replacements, '{{ROUTES}}': routeEntries }
|
|
884
885
|
);
|
|
885
886
|
}
|
|
@@ -897,11 +898,35 @@ async function generateRoutesPhp( routes, replacements ) {
|
|
|
897
898
|
return;
|
|
898
899
|
}
|
|
899
900
|
|
|
900
|
-
//
|
|
901
|
+
// Get unique pages from routes
|
|
902
|
+
const pages = [ ...new Set( routes.map( ( route ) => route.page ) ) ];
|
|
903
|
+
|
|
904
|
+
// Generate page-specific functions for each page
|
|
905
|
+
const pageFunctionsPromises = pages.map( async ( pageSlug ) => {
|
|
906
|
+
const pageSlugUnderscore = pageSlug.replace( /-/g, '_' );
|
|
907
|
+
const pageReplacements = {
|
|
908
|
+
...replacements,
|
|
909
|
+
'{{PAGE_SLUG}}': pageSlug,
|
|
910
|
+
'{{PAGE_SLUG_UNDERSCORE}}': pageSlugUnderscore,
|
|
911
|
+
};
|
|
912
|
+
return renderTemplateToString(
|
|
913
|
+
'routes-page-functions.php.template',
|
|
914
|
+
pageReplacements
|
|
915
|
+
);
|
|
916
|
+
} );
|
|
917
|
+
|
|
918
|
+
const pageFunctions = await Promise.all( pageFunctionsPromises );
|
|
919
|
+
const pageRouteFunctionsCode = pageFunctions.join( '\n' );
|
|
920
|
+
|
|
921
|
+
// Generate routes.php from template with injected page functions
|
|
901
922
|
await generatePhpFromTemplate(
|
|
902
923
|
'routes-registration.php.template',
|
|
903
924
|
path.join( BUILD_DIR, 'routes.php' ),
|
|
904
|
-
{
|
|
925
|
+
{
|
|
926
|
+
...replacements,
|
|
927
|
+
'{{HANDLE_PREFIX}}': HANDLE_PREFIX,
|
|
928
|
+
'{{PAGE_ROUTE_FUNCTIONS}}': pageRouteFunctionsCode,
|
|
929
|
+
}
|
|
905
930
|
);
|
|
906
931
|
}
|
|
907
932
|
|
|
@@ -1343,12 +1368,6 @@ async function buildRoute( routeName ) {
|
|
|
1343
1368
|
// Ensure output directory exists
|
|
1344
1369
|
await mkdir( outputDir, { recursive: true } );
|
|
1345
1370
|
|
|
1346
|
-
// Copy package.json
|
|
1347
|
-
await copyFile(
|
|
1348
|
-
path.join( routeDir, 'package.json' ),
|
|
1349
|
-
path.join( outputDir, 'package.json' )
|
|
1350
|
-
);
|
|
1351
|
-
|
|
1352
1371
|
const files = getRouteFiles( routeDir );
|
|
1353
1372
|
|
|
1354
1373
|
// Build route.js if it exists
|
|
@@ -1646,7 +1665,7 @@ async function buildAll( baseUrlExpression ) {
|
|
|
1646
1665
|
baseUrlExpression
|
|
1647
1666
|
);
|
|
1648
1667
|
await Promise.all( [
|
|
1649
|
-
|
|
1668
|
+
generateMainBuildPhp( phpReplacements ),
|
|
1650
1669
|
generateModuleRegistrationPhp( modules, phpReplacements ),
|
|
1651
1670
|
generateScriptRegistrationPhp( scripts, phpReplacements ),
|
|
1652
1671
|
generateStyleRegistrationPhp( styles, phpReplacements ),
|
|
@@ -1655,13 +1674,14 @@ async function buildAll( baseUrlExpression ) {
|
|
|
1655
1674
|
generateRoutesPhp( routes, phpReplacements ),
|
|
1656
1675
|
generatePagesPhp( pageData, phpReplacements ),
|
|
1657
1676
|
] );
|
|
1677
|
+
console.log( ' ✔ Generated build/build.php' );
|
|
1658
1678
|
console.log( ' ✔ Generated build/modules.php' );
|
|
1659
|
-
console.log( ' ✔ Generated build/modules/
|
|
1679
|
+
console.log( ' ✔ Generated build/modules/registry.php' );
|
|
1660
1680
|
console.log( ' ✔ Generated build/scripts.php' );
|
|
1661
|
-
console.log( ' ✔ Generated build/scripts/
|
|
1681
|
+
console.log( ' ✔ Generated build/scripts/registry.php' );
|
|
1662
1682
|
console.log( ' ✔ Generated build/styles.php' );
|
|
1663
|
-
console.log( ' ✔ Generated build/styles/
|
|
1664
|
-
console.log( ' ✔ Generated build/
|
|
1683
|
+
console.log( ' ✔ Generated build/styles/registry.php' );
|
|
1684
|
+
console.log( ' ✔ Generated build/constants.php' );
|
|
1665
1685
|
console.log( ' ✔ Generated build/routes.php' );
|
|
1666
1686
|
if ( pageData.length > 0 ) {
|
|
1667
1687
|
console.log( ' ✔ Generated build/pages.php' );
|
|
@@ -1674,7 +1694,6 @@ async function buildAll( baseUrlExpression ) {
|
|
|
1674
1694
|
);
|
|
1675
1695
|
}
|
|
1676
1696
|
}
|
|
1677
|
-
console.log( ' ✔ Generated build/index.php' );
|
|
1678
1697
|
|
|
1679
1698
|
const totalTime = Date.now() - startTime;
|
|
1680
1699
|
console.log(
|
|
@@ -1944,6 +1963,7 @@ async function main() {
|
|
|
1944
1963
|
default: 'plugin_dir_url( __FILE__ )',
|
|
1945
1964
|
},
|
|
1946
1965
|
},
|
|
1966
|
+
strict: false,
|
|
1947
1967
|
} );
|
|
1948
1968
|
|
|
1949
1969
|
const baseUrlExpression = values[ 'base-url' ];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/build",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.2-next.v.0+b8934fcf9",
|
|
4
4
|
"description": "Build tool for WordPress plugins.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -77,5 +77,5 @@
|
|
|
77
77
|
"publishConfig": {
|
|
78
78
|
"access": "public"
|
|
79
79
|
},
|
|
80
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "17529010285784fd2e735348a28391c79de87c88"
|
|
81
81
|
}
|
|
@@ -13,8 +13,8 @@ if ( ! function_exists( '{{PREFIX}}_register_script_modules' ) ) {
|
|
|
13
13
|
function {{PREFIX}}_register_script_modules() {
|
|
14
14
|
// Load build constants
|
|
15
15
|
$build_constants = require __DIR__ . '/constants.php';
|
|
16
|
-
$modules_dir
|
|
17
|
-
$modules_file
|
|
16
|
+
$modules_dir = __DIR__ . '/modules';
|
|
17
|
+
$modules_file = $modules_dir . '/registry.php';
|
|
18
18
|
|
|
19
19
|
if ( ! file_exists( $modules_file ) ) {
|
|
20
20
|
return;
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
|
|
13
13
|
// Global storage for {{PAGE_SLUG}} routes and menu items
|
|
14
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
|
|
15
|
+
${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes = array();
|
|
16
16
|
${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items = array();
|
|
17
17
|
|
|
18
|
-
if ( ! function_exists( '
|
|
18
|
+
if ( ! function_exists( '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_route' ) ) {
|
|
19
19
|
/**
|
|
20
20
|
* Register a route for the {{PAGE_SLUG}}-wp-admin page.
|
|
21
21
|
*
|
|
@@ -23,7 +23,7 @@ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_route' ) ) {
|
|
|
23
23
|
* @param string|null $content_module Script module ID for content (stage/inspector).
|
|
24
24
|
* @param string|null $route_module Script module ID for route lifecycle hooks.
|
|
25
25
|
*/
|
|
26
|
-
function
|
|
26
|
+
function {{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_route( $path, $content_module = null, $route_module = null ) {
|
|
27
27
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes;
|
|
28
28
|
|
|
29
29
|
$route = array( 'path' => $path );
|
|
@@ -38,7 +38,7 @@ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_route' ) ) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
if ( ! function_exists( '
|
|
41
|
+
if ( ! function_exists( '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_item' ) ) {
|
|
42
42
|
/**
|
|
43
43
|
* Register a menu item for the {{PAGE_SLUG}}-wp-admin page.
|
|
44
44
|
* Note: Menu items are registered but not displayed in single-page mode.
|
|
@@ -48,7 +48,7 @@ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_item' )
|
|
|
48
48
|
* @param string $to Route path to navigate to.
|
|
49
49
|
* @param string $parent_id Optional. Parent menu item ID.
|
|
50
50
|
*/
|
|
51
|
-
function
|
|
51
|
+
function {{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_item( $id, $label, $to, $parent_id = '' ) {
|
|
52
52
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items;
|
|
53
53
|
|
|
54
54
|
$menu_item = array(
|
|
@@ -65,36 +65,36 @@ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_item' )
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
if ( ! function_exists( '
|
|
68
|
+
if ( ! function_exists( '{{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes' ) ) {
|
|
69
69
|
/**
|
|
70
70
|
* Get all registered routes for the {{PAGE_SLUG}}-wp-admin page.
|
|
71
71
|
*
|
|
72
72
|
* @return array Array of route objects.
|
|
73
73
|
*/
|
|
74
|
-
function
|
|
74
|
+
function {{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes() {
|
|
75
75
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes;
|
|
76
76
|
return ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes ?? array();
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
if ( ! function_exists( '
|
|
80
|
+
if ( ! function_exists( '{{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items' ) ) {
|
|
81
81
|
/**
|
|
82
82
|
* Get all registered menu items for the {{PAGE_SLUG}}-wp-admin page.
|
|
83
83
|
*
|
|
84
84
|
* @return array Array of menu item objects.
|
|
85
85
|
*/
|
|
86
|
-
function
|
|
86
|
+
function {{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items() {
|
|
87
87
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items;
|
|
88
88
|
return ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_menu_items ?? array();
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data' ) ) {
|
|
92
|
+
if ( ! function_exists( '{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data' ) ) {
|
|
93
93
|
/**
|
|
94
94
|
* Preload REST API data for the {{PAGE_SLUG}}-wp-admin page.
|
|
95
95
|
* Automatically called during page rendering.
|
|
96
96
|
*/
|
|
97
|
-
function {{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data() {
|
|
97
|
+
function {{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data() {
|
|
98
98
|
// Define paths to preload - same for all pages
|
|
99
99
|
$preload_paths = array(
|
|
100
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',
|
|
@@ -120,14 +120,14 @@ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data' ) ) {
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts' ) ) {
|
|
123
|
+
if ( ! function_exists( '{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts' ) ) {
|
|
124
124
|
/**
|
|
125
125
|
* Enqueue scripts and styles for the {{PAGE_SLUG}}-wp-admin page.
|
|
126
126
|
* Hooked to admin_enqueue_scripts.
|
|
127
127
|
*
|
|
128
128
|
* @param string $hook_suffix The current admin page.
|
|
129
129
|
*/
|
|
130
|
-
function {{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts( $hook_suffix ) {
|
|
130
|
+
function {{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts( $hook_suffix ) {
|
|
131
131
|
// Check all possible ways this page can be accessed:
|
|
132
132
|
// 1. Menu page via admin.php?page={{PAGE_SLUG}}-wp-admin (plugin)
|
|
133
133
|
// 2. Direct file via {{PAGE_SLUG}}.php (Core) - screen ID will be '{{PAGE_SLUG}}'
|
|
@@ -148,10 +148,10 @@ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts' ) )
|
|
|
148
148
|
do_action( '{{PAGE_SLUG}}-wp-admin_init' );
|
|
149
149
|
|
|
150
150
|
// Preload REST API data
|
|
151
|
-
{{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data();
|
|
151
|
+
{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data();
|
|
152
152
|
|
|
153
153
|
// Get all registered routes
|
|
154
|
-
$routes =
|
|
154
|
+
$routes = {{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_routes();
|
|
155
155
|
|
|
156
156
|
// Get boot module asset file for dependencies
|
|
157
157
|
$asset_file = __DIR__ . '/../../modules/boot/index.min.asset.php';
|
|
@@ -221,13 +221,13 @@ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts' ) )
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_render_page' ) ) {
|
|
224
|
+
if ( ! function_exists( '{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_render_page' ) ) {
|
|
225
225
|
/**
|
|
226
226
|
* Render the {{PAGE_SLUG}}-wp-admin page.
|
|
227
227
|
* Call this function from add_menu_page or add_submenu_page.
|
|
228
228
|
* This renders within the normal WordPress admin interface.
|
|
229
229
|
*/
|
|
230
|
-
function {{PAGE_SLUG_UNDERSCORE}}_wp_admin_render_page() {
|
|
230
|
+
function {{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_render_page() {
|
|
231
231
|
?>
|
|
232
232
|
<style>
|
|
233
233
|
/* Critical styles to prevent layout shifts - inlined for immediate application */
|
|
@@ -288,5 +288,5 @@ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_render_page' ) ) {
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
// Hook the enqueue function to admin_enqueue_scripts
|
|
291
|
-
add_action( 'admin_enqueue_scripts', '{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts' );
|
|
291
|
+
add_action( 'admin_enqueue_scripts', '{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_enqueue_scripts' );
|
|
292
292
|
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
// Global storage for {{PAGE_SLUG}} routes and menu items
|
|
11
11
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes, ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items;
|
|
12
|
-
${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes
|
|
12
|
+
${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes = array();
|
|
13
13
|
${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items = array();
|
|
14
14
|
|
|
15
|
-
if ( ! function_exists( '
|
|
15
|
+
if ( ! function_exists( '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_route' ) ) {
|
|
16
16
|
/**
|
|
17
17
|
* Register a route for the {{PAGE_SLUG}} page.
|
|
18
18
|
*
|
|
@@ -20,7 +20,7 @@ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_route' ) ) {
|
|
|
20
20
|
* @param string|null $content_module Script module ID for content (stage/inspector).
|
|
21
21
|
* @param string|null $route_module Script module ID for route lifecycle hooks.
|
|
22
22
|
*/
|
|
23
|
-
function
|
|
23
|
+
function {{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_route( $path, $content_module = null, $route_module = null ) {
|
|
24
24
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes;
|
|
25
25
|
|
|
26
26
|
$route = array( 'path' => $path );
|
|
@@ -35,7 +35,7 @@ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_route' ) ) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
if ( ! function_exists( '
|
|
38
|
+
if ( ! function_exists( '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_menu_item' ) ) {
|
|
39
39
|
/**
|
|
40
40
|
* Register a menu item for the {{PAGE_SLUG}} page.
|
|
41
41
|
*
|
|
@@ -45,7 +45,7 @@ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_menu_item' ) ) {
|
|
|
45
45
|
* @param string $parent_id Optional. Parent menu item ID.
|
|
46
46
|
* @param string $parent_type Optional. Parent type: 'drilldown' or 'dropdown'.
|
|
47
47
|
*/
|
|
48
|
-
function
|
|
48
|
+
function {{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_menu_item( $id, $label, $to, $parent_id = '', $parent_type = '' ) {
|
|
49
49
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items;
|
|
50
50
|
|
|
51
51
|
$menu_item = array(
|
|
@@ -66,36 +66,36 @@ if ( ! function_exists( 'register_{{PAGE_SLUG_UNDERSCORE}}_menu_item' ) ) {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
if ( ! function_exists( '
|
|
69
|
+
if ( ! function_exists( '{{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_routes' ) ) {
|
|
70
70
|
/**
|
|
71
71
|
* Get all registered routes for the {{PAGE_SLUG}} page.
|
|
72
72
|
*
|
|
73
73
|
* @return array Array of route objects.
|
|
74
74
|
*/
|
|
75
|
-
function
|
|
75
|
+
function {{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_routes() {
|
|
76
76
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes;
|
|
77
77
|
return ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes ?? array();
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
if ( ! function_exists( '
|
|
81
|
+
if ( ! function_exists( '{{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_menu_items' ) ) {
|
|
82
82
|
/**
|
|
83
83
|
* Get all registered menu items for the {{PAGE_SLUG}} page.
|
|
84
84
|
*
|
|
85
85
|
* @return array Array of menu item objects.
|
|
86
86
|
*/
|
|
87
|
-
function
|
|
87
|
+
function {{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_menu_items() {
|
|
88
88
|
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items;
|
|
89
89
|
return ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_menu_items ?? array();
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_preload_data' ) ) {
|
|
93
|
+
if ( ! function_exists( '{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_preload_data' ) ) {
|
|
94
94
|
/**
|
|
95
95
|
* Preload REST API data for the {{PAGE_SLUG}} page.
|
|
96
96
|
* Automatically called during page rendering.
|
|
97
97
|
*/
|
|
98
|
-
function {{PAGE_SLUG_UNDERSCORE}}_preload_data() {
|
|
98
|
+
function {{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_preload_data() {
|
|
99
99
|
// Define paths to preload - same for all pages
|
|
100
100
|
$preload_paths = array(
|
|
101
101
|
'/?_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',
|
|
@@ -121,12 +121,12 @@ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_preload_data' ) ) {
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_render_page' ) ) {
|
|
124
|
+
if ( ! function_exists( '{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_render_page' ) ) {
|
|
125
125
|
/**
|
|
126
126
|
* Render the {{PAGE_SLUG}} page.
|
|
127
127
|
* Call this function from add_menu_page or add_submenu_page.
|
|
128
128
|
*/
|
|
129
|
-
function {{PAGE_SLUG_UNDERSCORE}}_render_page() {
|
|
129
|
+
function {{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_render_page() {
|
|
130
130
|
// Load build constants
|
|
131
131
|
$build_constants = require __DIR__ . '/../../constants.php';
|
|
132
132
|
|
|
@@ -153,11 +153,11 @@ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_render_page' ) ) {
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// Preload REST API data
|
|
156
|
-
{{PAGE_SLUG_UNDERSCORE}}_preload_data();
|
|
156
|
+
{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_preload_data();
|
|
157
157
|
|
|
158
158
|
// Get all registered routes and menu items
|
|
159
|
-
$menu_items =
|
|
160
|
-
$routes =
|
|
159
|
+
$menu_items = {{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_menu_items();
|
|
160
|
+
$routes = {{PREFIX}}_get_{{PAGE_SLUG_UNDERSCORE}}_routes();
|
|
161
161
|
|
|
162
162
|
// Get boot module asset file for dependencies
|
|
163
163
|
$asset_file = __DIR__ . '/../../modules/boot/index.min.asset.php';
|
|
@@ -312,19 +312,19 @@ if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_render_page' ) ) {
|
|
|
312
312
|
}
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
if ( ! function_exists( '{{PAGE_SLUG_UNDERSCORE}}_intercept_render' ) ) {
|
|
315
|
+
if ( ! function_exists( '{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_intercept_render' ) ) {
|
|
316
316
|
/**
|
|
317
317
|
* Intercept admin_init to render the page early.
|
|
318
318
|
* This bypasses the default WordPress admin template.
|
|
319
319
|
*/
|
|
320
|
-
function {{PAGE_SLUG_UNDERSCORE}}_intercept_render() {
|
|
320
|
+
function {{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_intercept_render() {
|
|
321
321
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
322
322
|
if ( isset( $_GET['page'] ) && '{{PAGE_SLUG}}' === $_GET['page'] ) {
|
|
323
|
-
{{PAGE_SLUG_UNDERSCORE}}_render_page();
|
|
323
|
+
{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_render_page();
|
|
324
324
|
exit;
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
// Hook the interceptor to admin_init
|
|
330
|
-
add_action( 'admin_init', '{{PAGE_SLUG_UNDERSCORE}}_intercept_render' );
|
|
330
|
+
add_action( 'admin_init', '{{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_intercept_render' );
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Page-specific route registration functions for {{PAGE_SLUG}}
|
|
2
|
+
if ( ! function_exists( '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_page_routes' ) ) {
|
|
3
|
+
/**
|
|
4
|
+
* Register routes for {{PAGE_SLUG}} page (full-page mode).
|
|
5
|
+
*/
|
|
6
|
+
function {{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_page_routes() {
|
|
7
|
+
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes_data;
|
|
8
|
+
{{PREFIX}}_register_page_routes( ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes_data, '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_route' );
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
add_action( '{{PAGE_SLUG}}_init', '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_page_routes' );
|
|
12
|
+
|
|
13
|
+
if ( ! function_exists( '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_page_routes' ) ) {
|
|
14
|
+
/**
|
|
15
|
+
* Register routes for {{PAGE_SLUG}} page (wp-admin mode).
|
|
16
|
+
*/
|
|
17
|
+
function {{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_page_routes() {
|
|
18
|
+
global ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes_data;
|
|
19
|
+
{{PREFIX}}_register_page_routes( ${{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_routes_data, '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_route' );
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
add_action( '{{PAGE_SLUG}}-wp-admin_init', '{{PREFIX}}_register_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_page_routes' );
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
// Load routes registry
|
|
11
|
-
$routes_file = __DIR__ . '/routes/
|
|
11
|
+
$routes_file = __DIR__ . '/routes/registry.php';
|
|
12
12
|
if ( ! file_exists( $routes_file ) ) {
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
$routes = require $routes_file;
|
|
17
17
|
|
|
18
|
-
// Group routes by page
|
|
18
|
+
// Group routes by page and store in globals for page-specific functions
|
|
19
19
|
$routes_by_page = array();
|
|
20
20
|
foreach ( $routes as $route ) {
|
|
21
21
|
$page_slug = $route['page'];
|
|
@@ -25,11 +25,24 @@ foreach ( $routes as $route ) {
|
|
|
25
25
|
$routes_by_page[ $page_slug ][] = $route;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
// Store routes data in globals for each page
|
|
29
|
+
foreach ( $routes_by_page as $page_slug => $page_routes ) {
|
|
30
|
+
$page_slug_underscore = str_replace( '-', '_', $page_slug );
|
|
31
|
+
$global_name = '{{PREFIX}}_' . $page_slug_underscore . '_routes_data';
|
|
32
|
+
$GLOBALS[ $global_name ] = $page_routes;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if ( ! function_exists( '{{PREFIX}}_register_page_routes' ) ) {
|
|
36
|
+
/**
|
|
37
|
+
* Generic helper function to register routes for a page.
|
|
38
|
+
*
|
|
39
|
+
* @param array $page_routes Array of route data for the page.
|
|
40
|
+
* @param string $register_function_name Name of the function to call for registering each route.
|
|
41
|
+
*/
|
|
42
|
+
function {{PREFIX}}_register_page_routes( $page_routes, $register_function_name ) {
|
|
31
43
|
// Load build constants
|
|
32
44
|
$build_constants = require __DIR__ . '/constants.php';
|
|
45
|
+
|
|
33
46
|
foreach ( $page_routes as $route ) {
|
|
34
47
|
$content_handle = null;
|
|
35
48
|
$route_handle = null;
|
|
@@ -71,22 +84,8 @@ $register_routes_callback = function ( $page_routes, $page_slug_underscore, $reg
|
|
|
71
84
|
call_user_func( $register_function_name, $route['path'], $content_handle, $route_handle );
|
|
72
85
|
}
|
|
73
86
|
}
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// Register hooks for both full-page and wp-admin modes
|
|
78
|
-
foreach ( $routes_by_page as $page_slug => $page_routes ) {
|
|
79
|
-
$page_slug_underscore = str_replace( '-', '_', $page_slug );
|
|
80
|
-
|
|
81
|
-
// Register all routes for full-page mode (page.php)
|
|
82
|
-
add_action(
|
|
83
|
-
"{$page_slug}_init",
|
|
84
|
-
$register_routes_callback( $page_routes, $page_slug_underscore, "register_{$page_slug_underscore}_route" )
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
// Register all routes for wp-admin mode (page-wp-admin.php)
|
|
88
|
-
add_action(
|
|
89
|
-
"{$page_slug}-wp-admin_init",
|
|
90
|
-
$register_routes_callback( $page_routes, $page_slug_underscore, "register_{$page_slug_underscore}_wp_admin_route" )
|
|
91
|
-
);
|
|
87
|
+
}
|
|
92
88
|
}
|
|
89
|
+
|
|
90
|
+
// Page-specific route registration functions
|
|
91
|
+
{{PAGE_ROUTE_FUNCTIONS}}
|
|
@@ -59,7 +59,7 @@ if ( ! function_exists( '{{PREFIX}}_register_package_scripts' ) ) {
|
|
|
59
59
|
$extension = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.js' : '.min.js';
|
|
60
60
|
|
|
61
61
|
$scripts_dir = __DIR__ . '/scripts';
|
|
62
|
-
$scripts_file = $scripts_dir . '/
|
|
62
|
+
$scripts_file = $scripts_dir . '/registry.php';
|
|
63
63
|
|
|
64
64
|
if ( ! file_exists( $scripts_file ) ) {
|
|
65
65
|
return;
|
|
@@ -49,7 +49,7 @@ if ( ! function_exists( '{{PREFIX}}_register_package_styles' ) ) {
|
|
|
49
49
|
$suffix = SCRIPT_DEBUG ? '' : '.min';
|
|
50
50
|
|
|
51
51
|
$styles_dir = __DIR__ . '/styles';
|
|
52
|
-
$styles_file = $styles_dir . '/
|
|
52
|
+
$styles_file = $styles_dir . '/registry.php';
|
|
53
53
|
|
|
54
54
|
if ( ! file_exists( $styles_file ) ) {
|
|
55
55
|
return;
|
|
File without changes
|