WP React Plugin
A starter framework for WordPress plugins powered by React + Vite.
by chadcharlesdigital · github.com/chadcharlesdigital/wordpress-react-plugin
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/chadcharlesdigital/wordpress-react-plugin/archive/refs/heads/main.zipA starter framework for building WordPress plugins with a React + Vite frontend.
Clone it, rename it, and start building — the plumbing is already done.
What's included
- PHP plugin scaffold with activation/uninstall hooks
- React + Vite frontend with hot module replacement in development
- Production build pipeline that generates hashed assets and a manifest WordPress reads at runtime
- REST API stub wired to your plugin's namespace
- A
wp_localize_scriptbridge that passes your API URL and nonce to React automatically - Build script that produces a ready-to-install
.zip
Quick start
1. Clone and rename
git clone https://github.com/chadcharlesdigital/wordpress-react-plugin.git my-plugin
cd my-plugin
Rename the directory and main plugin file to your slug:
mv wp-react-plugin.php my-plugin.php
The directory name, main PHP filename, and
WP_RP_SLUGinincludes/constants.phpmust all match.
2. Configure your plugin identity
Open includes/constants.php and update these five values:
define( 'WP_RP_SLUG', 'my-plugin' ); // kebab-case — matches directory + filename
define( 'WP_RP_NAME', 'My Plugin' ); // human-readable
define( 'WP_RP_PREFIX', 'myplugin' ); // short prefix, letters only, no hyphens
define( 'WP_RP_VERSION', '1.0.0' );
define( 'WP_RP_ROOT_ID', 'myplugin-root' ); // id of the <div> React mounts into
Everything else — REST namespace, shortcode tag, script handles, JS global name — is derived from these automatically.
3. Update the plugin header
In my-plugin.php, update the WordPress plugin header to match:
/**
* Plugin Name: My Plugin
* Description: What your plugin does.
* Version: 1.0.0
* Text Domain: my-plugin
*/
4. Install frontend dependencies
cd frontend
npm install
5. Start developing
# Terminal 1 — Vite dev server
cd frontend
npm run dev
# In includes/constants.php — enable dev mode
define( 'WP_RP_DEV_MODE', true );
Activate your plugin in WordPress, add the shortcode to any page or post:
[my_plugin]
The shortcode tag is your slug with hyphens replaced by underscores:
my-plugin→[my_plugin]
Your React app will load with hot module replacement. Edit frontend/src/App.jsx and changes appear instantly.
Project structure
my-plugin/
├── my-plugin.php # Main plugin file — shortcode, asset loading, WP hooks
├── uninstall.php # Cleanup when plugin is deleted
├── includes/
│ ├── constants.php # START HERE — all plugin configuration
│ ├── activate.php # Runs once on plugin activation
│ └── api.php # REST API endpoints
├── scripts/
│ └── build-plugin.js # Builds and zips the plugin for distribution
└── frontend/
├── src/
│ ├── main.jsx # React entry point
│ └── App.jsx # Root component — start building here
├── public/ # Static assets copied to dist/ on build
├── dist/ # Built output (gitignored — generated by npm run build)
├── vite.config.js
└── package.json
How dev mode and production mode work
The framework has two asset loading modes, controlled by WP_RP_DEV_MODE in includes/constants.php.
Dev mode (true) — WordPress loads scripts directly from the Vite dev server (http://localhost:5173). You get hot module replacement. Requires npm run dev to be running.
Production mode (false) — WordPress reads frontend/dist/.vite/manifest.json to find the hashed filenames generated by npm run build, then enqueues those assets. No dev server needed.
Always set WP_RP_DEV_MODE to false before building for distribution.
Calling the REST API from React
PHP passes two values to your React app via window.{prefix}Data (e.g. window.mypluginData):
| Key | Value |
|---|---|
apiUrl |
Full URL to your plugin's REST namespace, e.g. https://yoursite.com/wp-json/my-plugin/v1/ |
nonce |
WordPress REST nonce for authenticated requests |
Use them in React:
const { apiUrl, nonce } = window.mypluginData ?? {}
const res = await fetch( apiUrl + 'hello', {
headers: { 'X-WP-Nonce': nonce }
})
const data = await res.json()
The fallback ?? {} ensures this works gracefully when running npm run dev outside WordPress.
Adding REST API endpoints
Open includes/api.php. Add new routes inside register_routes() following the hello example:
public function register_routes() {
register_rest_route( $this->namespace(), '/hello', [
'methods' => 'GET',
'callback' => [ $this, 'hello' ],
'permission_callback' => '__return_true',
] );
// Your endpoint:
register_rest_route( $this->namespace(), '/items', [
'methods' => 'GET',
'callback' => [ $this, 'get_items' ],
'permission_callback' => '__return_true',
] );
}
public function get_items( WP_REST_Request $request ) {
return new WP_REST_Response( [ 'items' => [] ], 200 );
}
The namespace (my-plugin/v1) is derived from WP_RP_SLUG automatically — no hardcoding needed.
One-time setup on activation
Open includes/activate.php to run code when the plugin is first activated:
function wprp_activate() {
add_option( WP_RP_SLUG . '_settings', [
'option_one' => 'default_value',
]);
}
Building for distribution
# From the plugin root directory:
npm run build-plugin
This will:
- Run
npm installandnpm run buildinsidefrontend/ - Remove dev-only files (
src/,node_modules/, config files) - Create a
.zipnamed after your plugin directory, ready to upload to WordPress
Make sure WP_RP_DEV_MODE is set to false before running this.
Renaming checklist
When customizing this framework, update these locations:
| File | What to change |
|---|---|
| Directory name | Rename wp-react-plugin/ to your-slug/ |
includes/constants.php |
WP_RP_SLUG, WP_RP_NAME, WP_RP_PREFIX, WP_RP_ROOT_ID |
wp-react-plugin.php filename |
Rename to your-slug.php |
Plugin header in your-slug.php |
Plugin Name, Description, Text Domain |
frontend/index.html |
<title> and <div id="..."> to match WP_RP_ROOT_ID |
frontend/src/main.jsx |
getElementById(...) to match WP_RP_ROOT_ID |
frontend/src/App.jsx |
window.wprpData → window.{yourPrefix}Data |
frontend/package.json |
name field (cosmetic) |
Requirements
- PHP 7.4+
- WordPress 5.8+
- Node.js 18+