- Jun 10, 2010
- 2,400
- 1,676
I previously wrote about how you can create websites using headless wordpress with react, and in this post I will show you how you can harness the power of WordPress and React again to build beautiful wordpress plugins that function like a true application. For some plugins this might be a bit overkill but if you are building a WordPress plugin that is expected to behave more like a web app then this guide is for you.
Enter JavaScript. We can use JavaScript to make our application more dynamic by making asynchronous calls to our WordPress backend and dynamically updating the frontend based on our results.
The directory structure to start from is:
The root "wordpress-react-plugin" directory is arbitrary, but it's the main folder where we develop and commit our project.
The "frontend" directory is where all of the react and frontend development goes. If you have modules to install using npm or yarn, you would install them in this directory because this is where everything that goes into your UI will live. Code inside the frontend directory does not get included with your plugin. Instead, we will bundle our application into a single app.js that will be consumed by our plugin.
The "plugin" directory is where our PHP code will live. You will want to change "plugin" to the name of your WordPress plugin, the same goes for the plugin.php file because the combination of plugin/plugin.php will become the slug. The "plugin/assets" folder will contain a JavaScript build from our frontend directory.
You can find the source code for this project here:
Source Code
Clone the wordpress-react-plugin to get started:
Next, we need to install our frontend dependencies:
While still inside the frontend folder, run the following command to setup your project.
About the setup prompts:
You should now have a folder called "wordpress-react-plugin/hello-world" which was automatically created for you based on the Plugin Name prompt.
(Optional) Install composer dependencies. This will help you manage and load PHP dependencies.
NOTE: If you are not using composer then make sure to remove require_once 'vendor/autoload.php'; from your plugin.php file.
Your plugin should now be all set and ready to go!
This will monitor code in your frontend folder for changes and automatically compile it into an app.js file which is in plugin/assets/app.js file. This will allow your plugin to load the latest frontend changes.
This generates a nicely minified version of your frontend using only the files your required.
The "plugin.php" file is the main entry into your plugin. I typically use this as the plugin loader that includes all of my plugin logic.
The "includes/" directory is where I place all of my plugin modules and it helps me organize my plugin by features. This is where you will create your plugin functionality and be sure to include them in your plugin/plugin.php file.
App.php - This file is used to build our plugin's menu and load our app.js code and CSS styles.
Registers.php - This file used to run code when your plugin is activated, deactivated, and uninstalled.
Ajax.php - This is the file that will process all requests from our frontend code. All of the endpoints your frontend needs to call will be defined in this file and then calls the necessary php code. See example below:
Example: Some file inside frontend/.../.js
Now inside your hello-world/includes/Ajax.php I would create an action that waits for ajax requests...
This is meant to be a starter, allowing you to expand and change to fit your development flow to how you see fit.
Why mix WordPress and React?
Why would you want to mix WordPress and React? The short answer, separation of concerns (more on this to follow). WordPress, more specifically PHP, is a great server side language that anyone with low coding skills can use but the "WordPress way" of creating PHP templates and plugins is archaic and begins to show its age when compared to more modern ways of developing web applications. With PHP, all of your code has to render on the server and then gets pushed to the browser, any interactions with your plugin such as form submits, have to get submitted back to the server to be processed and the result return backed to the screen. When this happens, the WordPress core and your backend plugin has to all load again which is quite unnecessary just to submit data.Enter JavaScript. We can use JavaScript to make our application more dynamic by making asynchronous calls to our WordPress backend and dynamically updating the frontend based on our results.
Why React and not use jQuery?
You're probably thinking WordPress already includes jQuery so why not use that? jQuery serves its purpose for easy DOM manipulations and is suitable for enhancing/modifying the HTML currently being displayed but if you are building a web application then React will be much more performant and easier to work with on a larger scale application. React has a plethora of UI kits, Material UI, tailwind UI, Ant design, react bootstrap, and countless more that will help you build beautiful UIs quickly.Putting it all together.
As I said above, I like this approach because of the separation of concerns. In my mind I see WordPress as the data source and platform for which my plugin will use and the visual piece of the plugin you see is the frontend. The frontend is my consumer of my data and the frontend shouldn't really care where it's being used and how as long it receives the data it requires. I think of a frontend component as a template that knows what to render based on the data it requires. It doesn't care where the data comes from as long as it receives the data it needs. In our case, WordPress will be providing the data so our react app will be wired to make calls to the WP backend to fetch its data.Use wordpress-react-plugin
I created wordpress-react-plugin as a starter template to help scaffold a workspace for building a wordpress plugin using react.The directory structure to start from is:
Code:
wordpress-react-plugin/
└───frontend/
└───src/
| │ App.js
| │ index.js
| │ style.css
│ package.json
└───plugin/
└───assets/
└───includes/
│ | Ajax.php
│ | App.php
│ | Registers.php
| plugin.php
| composer.json
The root "wordpress-react-plugin" directory is arbitrary, but it's the main folder where we develop and commit our project.
The "frontend" directory is where all of the react and frontend development goes. If you have modules to install using npm or yarn, you would install them in this directory because this is where everything that goes into your UI will live. Code inside the frontend directory does not get included with your plugin. Instead, we will bundle our application into a single app.js that will be consumed by our plugin.
The "plugin" directory is where our PHP code will live. You will want to change "plugin" to the name of your WordPress plugin, the same goes for the plugin.php file because the combination of plugin/plugin.php will become the slug. The "plugin/assets" folder will contain a JavaScript build from our frontend directory.
You can find the source code for this project here:
Source Code
Getting Started
We are going to create a plugin called "Hello World".Clone the wordpress-react-plugin to get started:
Code:
git clone https://github.com/undeprecated/wordpress-react-plugin.git
Next, we need to install our frontend dependencies:
Code:
cd wordpress-react-plugin/frontend && npm install
While still inside the frontend folder, run the following command to setup your project.
Code:
npm run setup
> [email protected] setup
> node ../bin/setup.js
Plugin Name: Hello World
Plugin Author: NulledCode
Plugin URI: https://www.blackhatworld.com
Plugin Description: Hello world plugin using react
Plugin Slug: hello-world
Plugin Version: 1.0.0
Namespace: HelloWorld
DEFINE_BASE: HELLOWORLD
About the setup prompts:
- Plugin Name - Name of your plugin. Used for the WordPress Plugin Name heading of your plugin.php file.
- Plugin Author - Author of your plugin.
- Plugin URI - URI of your plugin.
- Plugin Description - Plugin description.
- Plugin Slug - Plugin slug. Automatically derived from plugin name. Setting this value will move plugin\plugin.php to slug\slug.php.
- Plugin Version - Version number. Defaults to 1.0.0.
- Namespace - namespace to use in your PHP files. Defaults to plugin name without spaces.
- DEFINE_BASE - Used to prefix define() constants in your plugin. Defaults to value of namespace uppercased.
You should now have a folder called "wordpress-react-plugin/hello-world" which was automatically created for you based on the Plugin Name prompt.
(Optional) Install composer dependencies. This will help you manage and load PHP dependencies.
Code:
cd hello-world && composer install
NOTE: If you are not using composer then make sure to remove require_once 'vendor/autoload.php'; from your plugin.php file.
Your plugin should now be all set and ready to go!
Frontend
Developing
When working on your frontend code you want to run run
Code:
cd frontend && npm run watch
This will monitor code in your frontend folder for changes and automatically compile it into an app.js file which is in plugin/assets/app.js file. This will allow your plugin to load the latest frontend changes.
Ajax Requests to WordPress
Your frontend code needs a way to query your backend wordpress to fetch data. You can use any module or method you prefer, but I chose to use jQuery since WordPress already has a way to use jQuery to fetch requests. I included a React hook frontend/src/hooks/useWordPressAjax that does this for you.Production
When you are ready for production and need to deploy your plugin, you want to build frontend app:
Code:
npm run build
This generates a nicely minified version of your frontend using only the files your required.
Backend
All of your plugin's php code will live here. This is the folder that you want to compress and ship.The "plugin.php" file is the main entry into your plugin. I typically use this as the plugin loader that includes all of my plugin logic.
The "includes/" directory is where I place all of my plugin modules and it helps me organize my plugin by features. This is where you will create your plugin functionality and be sure to include them in your plugin/plugin.php file.
App.php - This file is used to build our plugin's menu and load our app.js code and CSS styles.
Registers.php - This file used to run code when your plugin is activated, deactivated, and uninstalled.
Ajax.php - This is the file that will process all requests from our frontend code. All of the endpoints your frontend needs to call will be defined in this file and then calls the necessary php code. See example below:
Making frontend requests to backend
This example shows how you would make a request from your frontend app to wordPress.Example: Some file inside frontend/.../.js
JSX:
import useWordPressAjax from '../hooks/useWordPressAjax';
// ----------------------------------------------------------------------
export default function Example() {
const {fetch} = useWordPressAjax();
const handleClick = async () => {
const request = {
action: 'my_plugin_save_config',
data: "data"
}
const response = await fetch(request);
}
return (<button onClick={handleClick}>Save Config</button>);
}
Now inside your hello-world/includes/Ajax.php I would create an action that waits for ajax requests...
PHP:
<?php
/**
* Class file used to for handling ajax requests sent from app.js.
*/
namespace HelloWorld;
class Ajax
{
public static function init()
{
// @NOTE: rename this to whatever ajax name you need.
add_action('wp_ajax_my_plugin_save_config', [__CLASS__, 'save_config']);
}
public static function save_config()
{
echo 'Save completed.';
wp_die();
}
}
Build and Deploy
You want to run 'npm run build' inside your frontend folder to generate a compressed app.js file. After you do this, you simple zip your "plugin" folder (in our case, hello-world/) and now you have a new version for your plugin.Conclusion
I really enjoy developing plugins in this matter because it nicely separates my frontend and backend code. I don't like having to write PHP templates or have PHP return html in my plugins and then have to use jQuery to make things more dynamic and reactive, it feels so clunky. If unit testing is your thing, this approach allows you to write separate tests for your frontend and backend without having to rely much on each other.This is meant to be a starter, allowing you to expand and change to fit your development flow to how you see fit.