This guide explains how the WeLabs Plugin admin menu is built with PHP and React, how settings are saved via the WordPress REST API, and how you can extend it.
Overview
- PHP registers a top-level admin menu and submenus, and renders root containers for React.
- React mounts on those containers to render Dashboard, Settings, Analytics, Tools, and Help.
- REST API endpoints handle plugin settings and analytics.
- Security relies on nonces and capability checks.
Key files
-
includes/Admin/AdminMenu.php
– menu registration, enqueue assets, print HTML roots -
includes/Admin/Settings.php
– settings page and script localization -
includes/Admin/REST/*Controller.php
– REST endpoints -
src/admin.js
– bootstraps React -
src/Components/*
– React components
Highlights for Reliability
- Menu Registration & Enqueue – Only enqueue scripts/styles on plugin pages; localize REST URL, nonce, and current page slug for consistent JS context.
- React Bootstrapping – Check that DOM IDs printed in PHP match IDs queried in JS to avoid silent mount failures.
-
REST API Usage – Always sanitize (
sanitize_text_field
,absint
) and check capabilities (manage_options
) in controllers. -
Build Process – Run
npm run build
before pushing; ensure PHP paths point toassets/build/admin/*
. -
Testing – Log REST responses, verify nonces with
apiFetch.createNonceMiddleware
, and test on a fresh WP install or local environment.
📄 Full Guide (.md)
`
Plugin Admin Menu – Developer Guide
This guide walks you through how the WeLabs Plugin admin menu is built with PHP and powered by React, how settings are saved via the WordPress REST API, and how to extend it.
Overview
- PHP registers a top-level admin menu with multiple submenus and renders "root" containers for React.
- React mounts on those root containers and renders pages (Dashboard, Settings, Analytics, Tools, Help).
- REST API endpoints handle read/write of plugin settings and other data.
- Security uses nonces and capability checks.
Folder highlights:
-
includes/Admin/AdminMenu.php
– menu registration, enqueue assets, HTML containers -
includes/Admin/Settings.php
– classic settings page and script localization -
includes/Admin/REST/SettingsController.php
– settings REST routes (read/update) -
includes/Admin/REST/AnalyticsController.php
– analytics REST routes (demo data) -
src/admin.js
– React bootstrapping for each page -
src/Components/*
– React components
1) Register the Admin Menu in PHP
Key file: includes/Admin/AdminMenu.php
What it does:
- Registers a top-level menu
WeLabs Plugin
and submenusDashboard
,Settings
,Analytics
,Tools
,Help & Support
. - Enqueues the compiled script/style only on these pages.
- Localizes data (REST URL, nonce, current page) to JS.
Important parts to look at:
-
register_admin_menu()
– adds menu and submenus -
enqueue_admin_scripts( $hook )
– enqueuesassets/build/admin/script.js
andadmin.css
-
render_*_page()
– prints a wrapper with a unique root div (e.g.,#welabs-plugin-dashboard
) -
get_current_page_slug()
– helps JS know which submenu is active
Extending:
- Add another submenu with
add_submenu_page( 'welabs-plugin', 'Title', 'Menu', 'manage_options', 'welabs-plugin-new', [ $this, 'render_new_page' ] );
- Add a matching
render_new_page()
method that outputs a unique root container div for React.
2) Enqueue and Localize Admin Assets
Key files:
-
includes/Admin/AdminMenu.php
(WeLabs menu pages) -
includes/Admin/Settings.php
(classic settings page)
Both enqueue the admin script built to assets/build/admin/script.js
and localize:
-
apiUrl
orapiRoot
– REST base URL -
nonce
– used to authenticate REST requests -
currentPage
– helps JS know which page it's on
Security note:
- Nonce is created with
wp_create_nonce( 'wp_rest' )
and used in JS via@wordpress/api-fetch
nonce middleware.
3) React Bootstrapping
Key file: src/admin.js
What it does:
- Configures
apiFetch
to use the localized REST nonce and root URL:
`js
import apiFetch from '@wordpress/api-fetch';
if ( window.welabsSettings ) {
apiFetch.use( apiFetch.createNonceMiddleware( window.welabsSettings.nonce ) );
apiFetch.use( apiFetch.createRootURLMiddleware( window.welabsSettings.apiRoot ) );
}
`
- Mounts React apps to DOM nodes printed by PHP:
`js
const dashboardContainer = document.getElementById( 'welabs-plugin-dashboard' );
if ( dashboardContainer ) { /* render */ }
const settingsContainer = document.getElementById( 'CustomizedPluginWithReactSettings' );
if ( settingsContainer ) { /* render with routes */ }
`
Extending:
- Create a new component under
src/Components/
and mount it to a new root div you print in PHP.
4) Settings REST API (Read/Write)
Key file: includes/Admin/REST/SettingsController.php
Routes:
-
GET /customized-plugin-with-react/v1/settings
– fetch current settings -
POST /customized-plugin-with-react/v1/settings
– update settings
Security:
- Capability check via
current_user_can( 'manage_options' )
- Input sanitized with
sanitize_text_field()
Example React usage (simplified):
`js
import apiFetch from '@wordpress/api-fetch';
// Read settings
const settings = await apiFetch( { path: '/customized-plugin-with-react/v1/settings' } );
// Write settings
await apiFetch( {
path: '/customized-plugin-with-react/v1/settings',
method: 'POST',
data: {
customized_plugin_with_react_page_title: 'My Title',
customized_plugin_with_react_product_per_page: '12',
},
} );
`
5) Additional REST (Analytics)
Key file: includes/Admin/REST/AnalyticsController.php
Demo route:
GET /customized-plugin-with-react/v1/analytics?time_range=7|30|90|365
How to add your own:
- Create a new controller in
includes/Admin/REST/
following theWP_REST_Controller
pattern. - Register endpoints in
register_routes()
. - Initialize the controller in
includes/CustomizedPluginWithReact.php
→init_classes()
and register inregister_rest_route()
.
6) Security Checklist
- Always check capabilities (
current_user_can( 'manage_options' )
) for admin actions. - Use nonces for REST (
wp_create_nonce( 'wp_rest' )
+apiFetch.createNonceMiddleware
). - Sanitize all incoming data (
sanitize_text_field()
,absint()
, etc.). - Escape output in PHP (
esc_html__
,esc_attr
,esc_url
).
7) Build & Assets
Build command (runs @wordpress/scripts
):
bash
npm run build
What it produces:
- JS:
assets/build/admin/script.js
- CSS:
assets/build/admin.css
- Asset manifest:
assets/build/admin/script.asset.php
Ensure PHP points to these files when enqueuing.
8) Common Pitfalls & Fixes
- "Class not found" – Confirm PSR-4 autoload and namespaces match
composer.json
and file paths. - React not mounting – Verify the root div IDs printed in PHP match
document.getElementById(...)
insrc/admin.js
. - 401/403 on REST – Ensure nonce is localized and
apiFetch
nonce middleware is configured; confirm you are logged in and havemanage_options
capability. - Assets not loading – Run
npm run build
and confirmassets/build/*
exists; verify enqueue paths.
9) How to Add a New Submenu + React Page (Quick Recipe)
1) PHP – Add submenu and render method in AdminMenu.php
:
`php
add_submenu_page(
'welabs-plugin',
_( 'My Page', 'customized-plugin-with-react' ),
_( 'My Page', 'customized-plugin-with-react' ),
'manage_options',
'welabs-plugin-my-page',
[ $this, 'render_my_page' ]
);
public function render_my_page() {
?>
<?php esc_html_e( 'My Page', 'customized-plugin-with-react' ); ?>
<?php
}
`
2) React – Create src/Components/MyPage.js
and mount it in src/admin.js
:
`js
import MyPage from './Components/MyPage';
const myPageContainer = document.getElementById( 'welabs-plugin-my-page' );
if ( myPageContainer ) {
const root = createRoot( myPageContainer );
root.render( );
}
`
3) Build assets and test:
bash
npm run build
That's it! You now have a new submenu powered by React with REST-ready plumbing.
`
Top comments (0)