React Application as WordPress shortcode

Vasundhara Mehta
4 min readFeb 14, 2023

--

While WordPress is an extremely popular and well-known CRM, it does tend to lack the versatility of a React App. It is, however, possible to build and package your react apps as easy-to-use shortcodes using a custom plugin so that you can pick and choose these elements and publish pages.

Creating your plugin

Creating a custom WordPress plugin has very simple requirements. We need to create a directory with a PHP file of the same name and a special commented section at the top of that file providing plugin metadata.

Directory structure of plugin
The directory structure of plugin

For the purpose of this post, we will call the plugin react-wordpress, and the following file would be react-wordpress.php.

<?php
/**
* @wordpress-plugin
* Plugin Name: Embedding React In Wordpress
*/

// checks that file is loaded through wordpress environment only
defined( 'ABSPATH' ) or die( 'Direct script access disallowed.' );
// This will be the path to the React application.
define( 'ERW_WIDGET_PATH', plugin_dir_path( __FILE__ ) . '/widget' );
// path to the React asset manifest
define( 'ERW_ASSET_MANIFEST', ERW_WIDGET_PATH . '/build/asset-manifest.json' );
// subdirectory will contain all of the PHP files
define( 'ERW_INCLUDES', plugin_dir_path( __FILE__ ) . '/includes' );

// this enqueues javascript and css files with least impact on page load
require_once( ERW_INCLUDES . '/enqueue.php' );
require_once( ERW_INCLUDES . '/shortcode.php' );

enqueue.php uses WordPress actions and filters to load the scripts and styles for the react app at the appropriate time in the load cycle.

<?php
// This file enqueues scripts and styles

defined( 'ABSPATH' ) or die( 'Direct script access disallowed.' );

// this init action code will be run during the init phase of the load process,
// which is after your theme and other plugins have loaded.
add_action( 'init', function() {

// add async and defer to all scripts outside of the main scripts loaded below
// the erw preface is added to identify them
add_filter( 'script_loader_tag', function( $tag, $handle ) {
if ( ! preg_match( '/^erw-/', $handle ) ) { return $tag; }
return str_replace( ' src', ' async defer src', $tag );
}, 10, 2 );

// enqueues frontend items
add_action( 'wp_enqueue_scripts', function() {
// parse asset manifest generated by react build
$asset_manifest = json_decode( file_get_contents( ERW_ASSET_MANIFEST ), true )['files'];
// load main.css files first if exists adding erw preface
if ( isset( $asset_manifest[ 'main.css' ] ) ) {
wp_enqueue_style( 'erw', get_site_url() . $asset_manifest[ 'main.css' ] );
}
// load react runtime adding erw preface
wp_enqueue_script( 'erw-runtime', get_site_url() . $asset_manifest[ 'runtime-main.js' ], array(), null, true );
// load main js file adding erw preface
wp_enqueue_script( 'erw-main', get_site_url() . $asset_manifest[ 'main.js' ], array('erw-runtime'), null, true );
// check for other .js and .css files and load them
foreach ( $asset_manifest as $key => $value ) {
if ( preg_match( '@static/js/(.*)\.chunk\.js@', $key, $matches ) ) {
if ( $matches && is_array( $matches ) && count( $matches ) === 2 ) {
$name = "erw-" . preg_replace( '/[^A-Za-z0-9_]/', '-', $matches[1] );
wp_enqueue_script( $name, get_site_url() . $value, array( 'erw-main' ), null, true );
}
}

if ( preg_match( '@static/css/(.*)\.chunk\.css@', $key, $matches ) ) {
if ( $matches && is_array( $matches ) && count( $matches ) == 2 ) {
$name = "erw-" . preg_replace( '/[^A-Za-z0-9_]/', '-', $matches[1] );
wp_enqueue_style( $name, get_site_url() . $value, array( 'erw' ), null );
}
}
}

});
});

shortcode.php is used to create and register a shortcode

<?php
// This file enqueues a shortcode.

defined('ABSPATH') or die('Direct script access disallowed.');

add_shortcode('erw_widget', function ($atts) {
$default_atts = array();
$args = shortcode_atts($default_atts, $atts);
// erw-root is defined as the lement in which react app is supposed to load
return "<style>.erw-root {width: 100%;height: 90rem;position: relative; overflow: scroll}@media screen and (min-device-width: 1200px)@media screen and (min-width: 48em) {.erw-root {overflow: inherit !important;}} {.erw-root {width: 1020px;height: 70rem;position: relative;}}</style><div id='erw-root' class='erw-root'></div>";
});

Modifying React App

The only change that needs to occur on the React app, is that we check that the root element is present before loading it to ensure the plugin doesn't load the app files unnecessarily.

src/index.js

Building and activating the plugin

To build the plugin, we will modify the build scripts in package.json. We have a separate build-mac script to allow building the app on a mac environment. We have defined the build path, to generate files under our widget directory in the plugin folder.

Additionally, the homepage for the app is modified to be the WordPress plugin directory so that file paths generated at build time are accurate

package.json

After building react app using our custom build scripts, check that the build files show up under react-wordpress/widget/build. Copy over the directory to wp-content/plugins on the WordPress Server.

Go to the plugin page of the WordPress dashboard via a web browser (https://your_domain/wp-admin/plugins.php) and activate the react-wordpress plugin.

--

--

Vasundhara Mehta
Vasundhara Mehta

Written by Vasundhara Mehta

Software Architect | Fullstack, DevOps, AR, Blockchain

No responses yet