Adding React to a WordPress Theme Tutorial
React Ships with WordPress
Ever since WordPress 5.0, React (or an abstraction of it), now ships with WordPress.
WordPress takes the entire React and ReactDOM libraries and exports them onto a global window object named wp.element
.
This is a little different from how most React apps work.
In a Normal React App We Import React, in WordPress We Don’t
Normally, with a React app or project, you import React at the top of each file that uses React. On your main index page you would likely import ReactDOM as well.
// A Normal React App
import React from "react";
import ReactDOM from "react-dom";
import MyComponent from "./components/MyComponent";
ReactDOM.render(<MyComponent />, document.getElementById("root"));
In WordPress we do not import React or React DOM because they are made available in the global wp.element
object.
So one important difference when you go to include React in your WordPress project is you do not import it into your files.
Another difference between using React normally and in a WordPress theme or plugin has to do with tooling.
Using WP Scripts Instead of Create React App
If you have built React apps before you probably use Create React App or a similar bundle of tools to run your development server and build your production code.
This tooling does not work as well for WordPress because React is loaded in the global window object wp.element
rather than bundled with the code. Create React App does not officially support loading React from an external source without ejecting so that is not necessarily the best option for tooling.
Luckily, the WordPress team built a wp-scripts
package based off of the react-scripts
package used with Create React App.
WP Scripts includes develop, lint, test and build commands by default. You can also extend it with your own custom webpack config if you want to do something special, like compile SASS for instance.
We will look at how to setup WP Scripts below, but first let’s get our basic theme setup with React loaded on the front end.
Enqueuing React in Your Theme
To make sure React is loaded, you will simply add wp-element
as a dependency of your own JavaScript file.
The following would go in your functions.php
file.
// Enqueue Theme JS w React Dependency
add_action( 'wp_enqueue_scripts', 'my_enqueue_theme_js' );
function my_enqueue_theme_js() {
wp_enqueue_script(
'my-theme-frontend',
get_stylesheet_directory_uri() . '/build/index.js',
['wp-element'],
time(), // Change this to null for production
true
);
}
For this to work you will need a file located at /build/index.js
. WP Scripts will create this for us when we run the build
command
Now wp.element
will load on the front end of your theme.
How to Setup WP Scripts
Setting Up WP Scripts involves two steps: 1) install wp-scripts
; 2) add the scripts to your package.json file.
If you have not setup a package.json file yet run the following command from the root of your WordPress theme:
npm init
You can either press return
for each of the prompts or add in your own custom information.
Once your package.json file is created, run the following command:
npm install @wordpress/scripts --save-dev
This will download WP Scripts to your node_modules and make it available to use in the command line.
We can now do something like this:
wp-scripts start
However, to make this more universal and easy to use, we will map the WordPress Scripts to NPM scripts.
Open up your package.json file and replace the current "scripts"
settings with the following:
{
"name": "myreacttheme",
"version": "1.0.0",
"description": "My WordPress theme with React",
"main": "src/index.js",
"dependencies": {},
"devDependencies": {
"@wordpress/scripts": "^5.1.0"
},
"scripts": {
"build": "wp-scripts build",
"check-engines": "wp-scripts check-engines",
"check-licenses": "wp-scripts check-licenses",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"lint:pkg-json": "wp-scripts lint-pkg-json",
"start": "wp-scripts start",
"test:e2e": "wp-scripts test-e2e",
"test:unit": "wp-scripts test-unit-js"
},
"author": "",
"license": "1 GNU V2+, MIT"
}
If you do not need all of these, you can shorten it to just the start
and build
commands. However, the others can be useful to have as well.
Now we are able to run the following:
npm start
And it will call off the WP Scripts start
command. This will look for any file imported from src/index.js
and build it out to build/index.js
any time a file is changed.
The build
command does the same thing, but only once and does not watch for changes.
Adding React to a Custom Page Template
More and more of the display of content is controlled in WordPress through blocks. Blocks in WordPress are also based on React, but they are a little ecosystem in and of themselves and outside the scope of this particular blog post.
Here we are going to focus on adding some React to a custom page template. While everything we do could be built into a block, there are still going to be times when building a custom page template React serves as useful.
For this purpose I am going to make a Child Theme of the 2020 Default WordPress Theme. My basic theme structure looks like this:
/build
/src
/-- index.js
functions.php
package.json
page-react.php
style.css
These are about the minimum requirements we will need.
Without too much explanation, here is the code for the functions.php file and the style.css file.
Here is the functions.php
file:
<?php
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_styles' );
function my_theme_enqueue_styles() {
$parent_style = 'twentytwenty-style';
wp_enqueue_style( $parent_style, get_template_directory_uri() . '/style.css' );
wp_enqueue_style( 'child-style',
get_stylesheet_directory_uri() . '/style.css',
[ $parent_style ],
time() //For production use wp_get_theme()->get('Version')
);
wp_enqueue_script(
'my-theme-frontend',
get_stylesheet_directory_uri() . '/build/index.js',
['wp-element'],
time() //For production use wp_get_theme()->get('Version')
);
}
And then the style.css
:
/*
Theme Name: Twenty Twenty Child
Description: Twenty Twenty Child Theme
Author: Zac Gordon
Author URI: https://javascriptforwp.com/
Template: twentytwenty
Version: 0.9.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: twentytwentychild
*/
We also have a very simple custom page template page-react.php
that looks like this:
<? php
/**
* Template Name: React Template
*/
get_header();
?>
<main id="site-content" role="main">
<article class="post-2 page type-page status-publish hentry">
<?php get_template_part( 'template-parts/entry-header' ); ?>
<div class="post-inner thin">
<div class="entry-content">
<div id="react-app"></div><!-- #react-app -->
</div><!-- .entry-content -->
</div><!-- .post-inner -->
</article><!-- .post -->
</main><!-- #site-content -->
<?php get_template_part( 'template-parts/footer-menus-widgets' ); ?>
<?php get_footer(); ?>
This is basically a simplified page.php
template from the parent theme with a div containing the id react-app
added for us to load our React code into.
It is possible to build larger sections of a theme with React, but we are going to just focus on loading it on a single template here.
To complete this setup process, create a new page and select the “React Template” as the page template.
Writing Our React
Inside of our src/index.js
file we can start writing our React code and adding it to the page.
We will build on this over the course of this series, but for now we will add a simple component that lets you click a button to increase the number of votes for something.
const { render, useState } = wp.element;
const Votes = () => {
const [votes, setVotes] = useState(0);
const addVote = () => {
setVotes(votes + 1);
};
return (
<div>
<h2>{votes} Votes</h2>
<p>
<button onClick={addVote}>Vote!</button>
</p>
</div>
);
};
render(<Votes />, document.getElementById(`react-app`));
A few important things of note here:
- We are not importing React or ReactDOM on the page, but rather getting what we need from
wp.element
, which is already loaded for us. ReactDOM.render()
is also included inwp.element
- Currently the state is not being saved in WordPress, but we will change that in future articles
From here you can start writing whatever React you want, as well as breaking code out into separate files and importing them as needed.
This is hopefully enough to get you up and running with adding React to your WordPress themes.
Setting Up Webpack Externals to Use Libraries Importing React
Most React packages that you use will be used to having React bundled with the final code and will include import React from "react"
and things like that in their own code.
This will not work with WP Scripts by default. To get this to work we have to extend WP Scripts with our own webpack.config.js
file and define React and ReactDOMs as external resources that will be available outside of the bundled code.
To do this, create a new webpack.config.js
file in the root of your theme and add the following:
const defaults = require("@wordpress/scripts/config/webpack.config");
module.exports = {
...defaults,
externals: {
"react": "React",
"react-dom": "ReactDOM"
}
};
This will get the default configurations from WP Scripts and add them as the fallback configurations for Webpack. Then we can add in our customization of defining “react” and “react-dom” as being available as externals.
This will prevent errors from occurring when using third party React libraries that expect React to be imported.
Next Steps
From here can hopefully start building all the React you need for your themes. You may need to load your React in different places, like the header, sidebars or footer but the process is pretty similar.
In future articles we will go into more things you can do with React in WordPress Themes! You can find the main repo for this series here.
Please share how you’re using React in your WordPress themes and projects!
Have you seen create-react-wptheme? it creates the react ready theme for you and it uses your WordPress server as the development server instead of the Webpack Dev Server.
Only just started looking at it but it seems good so far
Seen it, haven’t tried it
So on trying the Create-React-wptheme, your solution feels like a better solution especially if you want to be able to make changes to your Functions.php.
If i wanted to do the above as a standalone theme would i just omit the parent style enquing. for example if i have a underscores theme template
How cool Zac, very good the tutorial, helped me a lot on a project recently.
In the first snippet where you say: “The following would go in your functions.php file”, in the line where you say: “// Change this to null for production”, I am using it like this:
“`php
$ _SERVER [‘SERVER_NAME’] === ‘localhost’? time (): null
“`
I believe it can help to make the snippet more complete 🙂
I hope to read more of your tutorials between React and WP soon.
Alex.
I had to add true to the end of the enqueue script for this to work (as shown in the top code snippet but not the second later in the guide).
wp_enqueue_script( 'my-theme-frontend', get_stylesheet_directory_uri() . '/build/index.js', ['wp-element'], time(), true );
Awesome tutorial, just what I was looking for. The last piece of the puzzle for me is how to development locally. Do you have any recommendations on the best way to develop the react app locally – even though it is going to be run within a WP environment? Not sure if there is a trick to just loading up the app piece without requiring all the Wordpress components. Thanks again!
I was receiving a “Target container is not a DOM element.” error until I appended the wp_enqueue_script function with in_footer: true, which forced the javascript to wait until the DOM element #react-app had rendered. Otherwise great tutorial!
I am following along and find my experiments using the React code in a custom plugin (ACF Engine) works fine. But I skipped the steps involving NPM. I don’t really understand why I need to do the npm init or the following setup of mapping, it seems like this is some added tooling. And the tutorial doesn’t seem to explain why this is needed. React and ReactDOM is already loaded, what are we actually gaining from involving npm and setting up this “package” format? As a PHP dev this is the part of modern JS dev where I can’t follow sometimes, why is there always this reliance on these packages and tools, I wish there was more explanations about specifically how these things work and why they are necessary.
Follow up to my earlier reply, I have now done the npm init and package changes and understand better why those are needed. I think it’s mainly because without this setup you can’t use the JSX. I thought I was already seeing everything working, but that’s because I was just console.log( wp.element ). When I actually used JSX it threw parsing errors, after the npm setup the output in /build/ is parsed usable JS which I then can enqueue. Thanks for a great introduction to the topic it’s helped me get this integrated into ACF Engine where we are mostly relying on ACF to register Gutenberg blocks, but want to also get into more custom rendering with React.
How Can I use this workflow with a blunder like parcel ?
I have tried it but when importing another component and using it as , it does not work..it does not show the content of that component..instead it prints in browser html…
Hello Zac,
First of all, I would like to say that it is a great article !
I managed to plug my react app to my wordpress theme and it looks pretty neat. So thank you very much !
I just would like to add one comment because it took me a lot of time to find the solution.
I had a problem with my react rendering. I kept having the same message : “target container is not a DOM element” ; even though I rendered my react in a real DOM element => document.getElementById(“react-app”) (exactly like you did in your “page-react” file and the index.js)
After a lot of investigation, the thing that was causing the problem was that my script was enqueued in my and not at the end of my . The solution was to set the $in_footer parameter to “true” in my wp_enqueue_script function injecting my script.
I hope it can help some people facing the same issue as I did.
Thanks again for this great and clear article.
Cheers
Nicolas
Some words got cut out :
“After a lot of investigation, the thing that was causing the problem was that my script was enqueued in my head and not at the end of my body . The solution was to set the $in_footer parameter to “true” in my wp_enqueue_script function injecting my script.”
Hello Zac,
First of all, I would like to say that it is a great article !
I managed to plug my react app to my wordpress theme and it looks pretty neat. So thank you very much !
I just would like to add one comment because it took me a lot of time to find the solution.
I had a problem with my react rendering. I kept having the same message : “target container is not a DOM element” ; even though I rendered my react in a real DOM element => document.getElementById(“react-app”) (exactly like you did in your “page-react” file and the index.js)
After a lot of investigation, the thing that was causing the problem was that my script was enqueued in my head and not at the end of my body . The solution was to set the $in_footer parameter to “true” in my wp_enqueue_script function injecting my script.
I hope it can help some people facing the same issue as I did.
Thanks again for this great and clear article.
Cheers
Nicolas
where I can create the css file in react theme
If anyone else is following along and get the error Target container is not a DOM element it is because the index.js script declaration is in the head and no just before the closing body tag.
In the wp_enqueue_script make sure in footer parameter is set to true.
wp_enqueue_script(
‘my-theme-frontend’,
get_stylesheet_directory_uri() . ‘/build/index.js’,
[‘wp-element’],
get_versioning(), //For production use wp_get_theme()->get(‘Version’)
true
);
Of course it had to be Zac! I stumbled upon this article and helped me a lot. Very well written. I remember watching your courses from Tree House. Thanks again.
Spent hours and didn’t know about that part where WordPress actually already included React and ReactDOM.
Thanks a lot for saving my times.
Thanks Zac this is the best starter guide to setting up with React that I’ve found. I used the process you detailed in a plugin and it works great. Nice to get past the tooling hurdles and focus on writing components.
Hi Zack is a wonderfull tutorial. I have a question, How are translations added using wp.element?
I have to agree that is is an excellent explainer post which should help plenty of readers who want to include React.
How would one go about making this a block? Could that block be inserted on any existing page then? Awesome tutorial btw
You might want to checkout the block courses then you’d be able to drop this right in as a block!