作者选择了电子前哨基金会基金会接受捐赠作为写作捐赠计划的一部分。

引言

Wordpress 是一个流行的内容管理系统,根据 W3Techs (网络技术调查) ,超过33% 的网站在互联网上运行。 它如此受欢迎的一个原因是它很容易用清晰、直接的文档进行设置。 此外,还有大量支持 WordPress 开发者的社区资源。 Wordpress 可以用一个便宜的甚至是免费的开箱即用的解决方案来解决许多用例。 最后,WordPress 提供了一个定义良好的插件系统,允许开发人员编写自定义代码来添加自己的功能。 这个插件系统有很好的文档记录,工作良好,正如您将在本教程后面看到的,很容易使用。

那些希望提供最丰富、最具交互性体验的开发人员可以使用 JavaScript,并得到 React 等框架的支持。 React 是一个 JavaScript 库,旨在使开发人员更容易地创建动态的、交互式的 ui,这些 ui 超越了典型的静态页面或表单。 由 Facebook 创建,因此在安全性、稳定性和易用性方面得到了很好的维护。 React 之所以受欢迎,是因为它拥有良好的文档和一个完善的、由社区驱动的文档和插件生态系统。

本教程将向您介绍在 WordPress 站点中嵌入 React 应用程序的最佳实践。 例如,它将使用一个常见的用例: 创建一个小部件,用于嵌入多个页面,有时在一个页面上嵌入多次。 在服务器端,它将实现为 WordPress 短代码。 短代码类似于 HTML 标记,但它使用方括号([ ... ])而不是尖括号(...)。 它不直接呈现 HTML 元素,而是调用一个 PHP 函数,这个函数再呈现来自数据库的数据内插的 HTML。

在本教程结束时,您将创建自己的短代码,将其插入到 WP Admin 的一个页面中,并发布该页面。 在这个页面上,你可以看到浏览器显示的 React 小部件。

先决条件

为了遵循这个教程,你必须:

  • 一个 Ubuntu 18.04服务器使用 Ubuntu 18.04教程初始服务器安装程序为你的服务器配置一个防火墙以及一个拥有 root 权限的新用户。
  • 一个完全注册的域名。 本教程将使用您的域作为一个例子贯穿始终。 你可以在 Namecheap 上购买一个域名,在 Freenom 上免费获得一个域名,或者使用你选择的域名注册商。
  • 为服务器设置的下列 DNS 记录。 你可以通过这篇 DigitalOcean DNS 的介绍来了解如何添加它们。 指向服务器公共 IP 地址的域的记录。 一个带 www 的记录。 你的域名指向服务器的公共 IP 地址。
  • 在服务器上安装 Apache、 MySQL 和 PHP。 你可以通过下面的如何在 Ubuntu 18.04上安装 Linux,Apache,MySQL,PHP (LAMP)堆栈来获得。
  • 通过遵循如何在 Ubuntu 18.04上使用 Let’ s Encrypt 保护 Apache 以生成一个免费的 SSL 证书来保护 Apache。
  • 一个 WordPress 安装,你可以按照如何在 Ubuntu 18.04及其先决条件下使用 LAMP 安装 WordPress。
  • 通过在如何在 Ubuntu 18.04上安装 Node.js 中的“使用 PPA 安装”选项来安装 Node.js。 本教程将使用11.15.0版本,因此在使用 curl 下载安装脚本时,请按照本教程中的步骤将10.x 替换为11.x。

步骤1ー更新和配置访问许可权

在 Ubuntu 18.04先决条件初始服务器安装程序中创建的非根用户登录后,您将无权查看或编辑 WordPress 目录中的任何文件。 这是一个问题,因为稍后您将添加和修改文件以创建您的 WordPress 插件和 React 应用程序。 为了解决这个问题,在这个步骤中你需要更新你的 WordPress 配置,这样你就可以编辑你的 WordPress 文件了。

运行以下命令,用 sammy 替换非 root 用户的名称,用 / var / www / WordPress 替换到 WordPress 目录的路径(这是您在先决条件中创建的 Apache 文档 root 文件夹) :

  • sudo chown -R sammy:www-data /var/www/wordpress

让我们分解一下这个命令:

  • Sudo ー这允许你以 root 身份执行这个命令,因为你正在修改 sammy 无法访问的文件。
  • Chown ー此命令更改文件所有权。
  • - r ー此标志递归更改所有权,包括所有子文件夹和文件。
  • Www-data ー这将所有者设置为非 root 用户(sammy) ,并将组保持为 www-data,这样 Apache 仍然可以访问这些文件以便为它们服务。
  • / var / www / WordPress ー这指定了到 WordPress 目录的路径。 这是所有权将发生变化的目录。

为了验证这个命令是否成功,列出 WordPress 目录的内容:

  • ls -la /var/www/wordpress

您将看到目录内容的列表:

Output
total 216 drwxr-x--- 5 sammy www-data 4096 Apr 13 15:42 . drwxr-xr-x 4 root root 4096 Apr 13 15:39 .. -rw-r----- 1 sammy www-data 235 Apr 13 15:54 .htaccess -rw-r----- 1 sammy www-data 420 Nov 30 2017 index.php -rw-r----- 1 sammy www-data 19935 Jan 1 20:37 license.txt -rw-r----- 1 sammy www-data 7425 Jan 9 02:56 readme.html -rw-r----- 1 sammy www-data 6919 Jan 12 06:41 wp-activate.php drwxr-x--- 9 sammy www-data 4096 Mar 13 00:18 wp-admin -rw-r----- 1 sammy www-data 369 Nov 30 2017 wp-blog-header.php -rw-r----- 1 sammy www-data 2283 Jan 21 01:34 wp-comments-post.php -rw-r----- 1 sammy www-data 2898 Jan 8 04:30 wp-config-sample.php -rw-r----- 1 sammy www-data 3214 Apr 13 15:42 wp-config.php drwxr-x--- 6 sammy www-data 4096 Apr 13 15:54 wp-content -rw-r----- 1 sammy www-data 3847 Jan 9 08:37 wp-cron.php drwxr-x--- 19 sammy www-data 12288 Mar 13 00:18 wp-includes -rw-r----- 1 sammy www-data 2502 Jan 16 05:29 wp-links-opml.php -rw-r----- 1 sammy www-data 3306 Nov 30 2017 wp-load.php -rw-r----- 1 sammy www-data 38883 Jan 12 06:41 wp-login.php -rw-r----- 1 sammy www-data 8403 Nov 30 2017 wp-mail.php -rw-r----- 1 sammy www-data 17947 Jan 30 11:01 wp-settings.php -rw-r----- 1 sammy www-data 31085 Jan 16 16:51 wp-signup.php -rw-r----- 1 sammy www-data 4764 Nov 30 2017 wp-trackback.php -rw-r----- 1 sammy www-data 3068 Aug 17 2018 xmlrpc.php

这些文件包含在 WordPress 核心中的 latest.tar.gz 文件中,你可以从 WordPress 官网下载,这是在 Ubuntu 18.04的前提下如何用 LAMP 安装 WordPress 的。 如果权限出现在前面的输出中,这意味着您的文件和目录已经正确更新。

在这个步骤中,你更新了你的 WordPress 安装,让你自己可以编辑它的文件。 在下一步,你将使用这个访问权限创建文件,组成一个 WordPress 插件。

第二步ー创建一个基本的 WordPress 插件

现在你可以修改 WordPress 目录中的文件了,你可以创建一个基本的 WordPress 插件并将其添加到安装中。 这将允许 React 在教程的后面与 WordPress 进行交互。

一个 WordPress 插件可以简单如下:

  1. Wp-content / plugins 中的目录。
  2. 该目录中具有相同名称和.php 文件扩展名的文件。
  3. 在文件顶部有一个特别的注释,它为 WordPress 提供了重要的插件元数据。

要为稍后编写的 React 代码创建一个插件,首先要为 WordPress 插件创建一个目录。 为了简单起见,本教程将把这个插件命名为 react-wordpress。 运行以下命令,用 Apache 文档根目录替换 wordpress:

  • mkdir /var/www/wordpress/wp-content/plugins/react-wordpress

然后,导航到新创建的目录。后续命令将从这里执行。

  • cd /var/www/wordpress/wp-content/plugins/react-wordpress

现在让我们创建插件文件。 本教程将使用 nano 作为所有文件的命令行文本编辑器,它与 nano 命令一起调用。 您还可以自由选择使用任何其他文本编辑器,如 Pico、 Vim 或 Emacs。

打开 react-wordpress.php 进行编辑:

  • nano react-wordpress.php

添加以下行到你的文件中创建插件的开始:

/var/www/wordpress/wp-content/plugins/react-wordpress/react-wordpress.php
<?php
/**
 * @wordpress-plugin
 * Plugin Name:       Embedding React In Wordpress
 */

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

顶部的注释部分为插件提供了元数据,检查 ABSPATH 常量的行防止坏参与者通过其 URL 直接访问该脚本。 Abspath 是 WordPress 根目录的绝对路径,因此如果定义了 ABSPATH,那么可以确定文件是通过 WordPress 环境加载的。

注意: 许多字段可用于插件元数据注释,但只需要 Plugin Name。 更多细节请参见 WordPress 文档中的 Header Requirements 页面。

接下来,打开一个网页浏览器并导航到您的域的插件页面(https: / / your domain / wp-admin / Plugins.php)。 你会看到你的插件和 WordPress 的默认插件一起被列出来:

点击激活来启用你的插件。

一旦你激活了你的插件,包含你的插件的行将被高亮显示为蓝色,左边有一个蓝色边框,下面的链接不是激活,而是一个写着停用:

接下来,您将建立您的插件的结构。

返回到你的终端打开 react-wordpress.php:

  • nano react-wordpress.php

然后更新它,添加以下突出显示的行,这些行定义了有用的常量:

/var/www/wordpress/wp-content/plugins/react-wordpress/react-wordpress.php
<?php
/**
 * @wordpress-plugin
 * Plugin Name:       Embedding React In Wordpress
 */

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

define( 'ERW_WIDGET_PATH', plugin_dir_path( __FILE__ ) . '/widget' );
define( 'ERW_ASSET_MANIFEST', ERW_WIDGET_PATH . '/build/asset-manifest.json' );
define( 'ERW_INCLUDES', plugin_dir_path( __FILE__ ) . '/includes' );

在新添加的行中,您定义了三个常量:

  1. Erw 小部件路径ー这将是通往 React 应用程序的路径。
  2. Erw asset manifest ——这是 React asset manifest 的路径,这个文件包含了 JavaScript 和 CSS 文件的列表,这些文件需要包含在页面中,以便您的应用程序能够正常工作。
  3. Erw includes ー这个子目录将包含所有 PHP 文件。

注意,每个 define ()引用插件目录路径(FILE)。 它表示该文件的目录路径。

添加常量定义后,保存文件并退出编辑器。

注意: 命名空间对常量很重要。 在这种情况下,我们使用的名称空间 ERW,代表嵌入在 WordPress 中的 React。 在这个名称空间中加上前缀可以确保变量是唯一的,这样它们就不会与其他插件中定义的常量发生冲突。

要创建包含其他 PHP 文件的 include / 文件夹,从插件目录的顶层开始,/ var / www / your domain / wp-content / plugins / react-wordpress。 然后,创建文件夹:

  • mkdir includes

现在您已经搭建了制作 WordPress 插件所需的与 php 相关的文件和文件夹,您将为 React 创建初始文件和文件夹。

步骤3ー初始化 React 应用程序

在这一步中,您将使用 Create React App 来初始化 React 应用程序。

本教程使用 Create React App version 3.0.1进行测试。 版本3.0.0对资产清单的结构进行了突变更改。 所以这个早期版本不兼容这个教程没有修改。 为了确保你使用的是预期的版本,运行这个命令来安装 Create React App:

此命令将安装 Create React App 的3.0.1版本。 全局标志将在系统范围内安装它。 安装系统范围可以确保在没有指定任何路径的情况下运行 create-react-app (或 npx create-react-app)时,您将使用刚刚安装的版本。

安装 Create React App 后,使用它来创建 React 应用程序。 本教程将把应用部件命名为:

  • sudo create-react-app widget

这个命令使用 npx,它是 NPM 附带的二进制文件。 它的设计目的是简化 CLI 工具和 NPM 上托管的其他可执行文件的使用。 如果在本地找不到这些工具,它将安装这些工具。

Create-React-app 命令将为基本 React app 生成一个项目文件夹和所有必要的文件。 这包括一个索引 html 文件,启动 JavaScript、 CSS 和测试文件,以及用于定义项目和依赖关系的 package.json。 它预先包含了依赖项和脚本,使您可以为生产环境构建应用程序,而无需安装和配置任何其他构建工具。

一旦你设置好小部件应用程序,终端中的输出结果如下所示:

Output
... Success! Created widget at /var/www/wordpress/wp-content/plugins/react-wordpress/widget Inside that directory, you can run several commands: npm start Starts the development server. npm run build Bundles the app into static files for production. npm test Starts the test runner. npm run eject Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back! We suggest that you begin by typing: cd widget npm start Happy hacking!

接下来,导航到新创建的目录:

  • cd widget

现在您可以使用默认的 build 命令 npm run build 构建应用程序了。 这个 build 命令查看名为 build 的脚本的 key scripts 下面的 package.json 文件:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/package.json
{
  "name": "widget",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-scripts": "3.1.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

这就调用了反应脚本。 由 react-scripts 节点模块提供的 js 可执行文件,它是 create-react-app 提供的核心组件之一。 这反过来调用构建脚本,它使用 webpack 将您的项目文件编译成您的浏览器可以理解的静态资产文件。 它是通过以下方式实现的:

  • 解决依赖关系。
  • 将 SASS 文件编译成 CSS 和 JSX,或者将打字稿编译成 JavaScript。
  • 将 ES6语法转换为具有更好的跨浏览器兼容性的 ES5语法。

现在你已经对 build 有了一些了解,在你的终端中运行命令:

  • sudo npm run build

一旦命令完成,您将收到类似于下面的输出:

Output
> widget@0.1.0 build /var/www/wordpress/wp-content/plugins/react-wordpress/widget > react-scripts build Creating an optimized production build... Compiled successfully. File sizes after gzip: 36.83 KB (+43 B) build/static/js/2.6efc73d3.chunk.js 762 B (+44 B) build/static/js/runtime~main.a8a9905a.js 710 B (+38 B) build/static/js/main.2d1d08c1.chunk.js 539 B (+44 B) build/static/css/main.30ddb8d4.chunk.css The project was built assuming it is hosted at the server root. You can control this with the homepage field in your package.json. For example, add this to build it for GitHub Pages: "homepage" : "http://myname.github.io/myapp", The build folder is ready to be deployed. You may serve it with a static server: npm install -g serve serve -s build Find out more about deployment here: https://bit.ly/CRA-deploy

现在已经构建了项目,但在进入下一步之前,最好确保应用程序只在存在时加载。

React 在其中呈现应用程序的 DOM 中使用一个 HTML 元素。 这被称为目标元素。 默认情况下,此元素具有 ID 根。 要确保这个根节点是您正在创建的应用程序,可以更改 src / index。 Js 来检查名称空间 erw-root 的目标 ID。 要做到这一点,首先打开 src / index。 我不知道该怎么办:

  • sudo nano src/index.js

修改并添加突出显示的行:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

const target = document.getElementById('erw-root');
if (target) { ReactDOM.render(<App />, target); }

serviceWorker.unregister();

最后,保存文件并在完成编辑后退出。

在这个文件中,你对默认的 index.js 文件做了两个重要的修改:

  1. 你把目标元素从 div id"root"/ div 改成 div"erw-root"/ div 这样它就可以为你的应用程序定义名称了。
  2. 在 if (...)语句中附加对 ReactDOM.render ()的调用,这样只有当应用程序存在时才会加载它。

注意: 如果您希望小部件出现在每个页面上,那么您可能还希望添加一行错误处理,如果没有找到具有 ID-erw-root 的元素,它将向控制台输出一条消息。 但是,本教程将省略此步骤。 像这样的行会在每个没有元素的页面上产生一个控制台错误,包括那些您不打算包含元素的页面。 这些多重的 JavaScript 控制台错误可能会降低你网站的搜索引擎排名。

在更改 src / 目录中的任何 JavaScript 或 CSS 文件之后,重新编译应用程序以便将更改合并起来是非常重要的。 要重新构建应用程序,请运行:

  • sudo npm run build

现在构建 / 目录中包含了一个工作的 React 应用程序,它以 JavaScript 和 CSS 文件的形式出现。 下一步涉及到设置一些 PHP 文件,这些文件将在页面中为您的 JavaScript 和 CSS 排队。

第四步ー查询 JavaScript 和 CSS 文件

在这个步骤中,你将使用 WordPress 的动作和过滤器:

  1. 在 WordPress 页面加载周期的适当时间输出脚本排队代码。
  2. 以一种对页面加载速度影响最小的方式对 JavaScript 和 CSS 文件进行排队。

使用动作和过滤器作为它的主要钩子。 操作使得在页面加载周期的指定时间执行代码成为可能,并且过滤器通过更改不属于您的函数的返回值来修改特定的行为。

要使用这些钩子,您将创建一个 PHP 文件,该文件将包含解析资产清单的代码。 稍后您将使用这个文件对所有资产进行排队,以便将脚本写入 head 标记中。

在创建文件之前,使用以下命令导航出包含 React app 的目录,进入顶级 React-wordpress 插件目录:

  • cd /var/www/wordpress/wp-content/plugins/react-wordpress

在 include / 文件夹中创建 enqueue.php 文件:

  • nano includes/enqueue.php

从放置开口开始? 在文件顶部的 php 标签。 同时添加检查 ABSPATH 的行,正如前面所讨论的,这是每个 PHP 文件中的最佳实践:

/var/www/wordpress/wp-content/plugins/react-wordpress/includes/enqueue.php
<?php
// This file enqueues scripts and styles

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

保存并退出此文件。

然后,更新 react-wordpress.php,从项目中调用 enqueue.php,首先打开文件进行编辑:

  • nano react-wordpress.php

添加以下突出显示的行:

/var/www/wordpress/wp-content/plugins/react-wordpress/react-wordpress.php
<?php
/**
 * @wordpress-plugin
 * Plugin Name:       Embedding React In Wordpress
 */

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

define( 'ERW_WIDGET_PATH', plugin_dir_path( __FILE__ ) . '/widget' );
define( 'ERW_ASSET_MANIFEST', ERW_WIDGET_PATH . '/build/asset-manifest.json' );
define( 'ERW_INCLUDES', plugin_dir_path( __FILE__ ) . '/includes' );

require_once( ERW_INCLUDES . '/enqueue.php' );

在 WordPress 插件中,一个常见的模式是要求 include / 目录中的其他 PHP 文件将重要的任务分割成块。 Require once ()函数解析作为参数传递的文件的内容,仿佛该文件的 PHP 代码就是在那里内联编写的。 与类似的命令 include 不同,require 将在试图要求的文件找不到时引发异常。 使用 require once ()(而不是 just require ())可以确保如果指令要求一次(ERW includes) ,enqueue.php 不会被解析多次 / enqueue.php’) ; 被赋予多次。

保存并退出文件。

现在重新打开 includes / enqueue.php:

  • nano includes/enqueue.php

然后,添加以下突出显示的代码:

/var/www/wordpress/wp-content/plugins/react-wordpress/includes/enqueue.php
<?php
// This file enqueues scripts and styles

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

add_action( 'init', function() {

  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 );

  add_action( 'wp_enqueue_scripts', function() {

  });
});

向 init 操作添加一个函数意味着这段代码将在加载过程的 init 阶段运行,这个阶段是在您的主题和其他插件加载之后。

使用脚本加载程序标记过滤器设置脚本标记上的 async 和 defer 属性告诉浏览器异步加载脚本,而不是阻塞 DOM 构造和页面呈现。

可湿性粉剂加入脚本行动,然后排队前端项目。

确保写入文件并退出。

现在你已经告诉 WordPress 编写脚本和样式表标签到页面。 在下一步中,您将解析一个名为资产清单的文件。 这将为您提供加入队列所需的所有文件的路径。

第五步: 解析资产清单

在这一步中,您将把 React 构建生成的资产清单解析为一个 JavaScript 和 CSS 文件列表。

当您构建应用程序时,React 构建脚本将把您的项目构建成多个 JavaScript 和 CSS 文件。 每次构建的文件数量和名称都不同,因为每次构建都包含文件内容的哈希。 资产清单提供上次生成中生成的每个文件的名称以及该文件的路径。 通过编程解析它,可以保证您写入页面的脚本和样式表标记将始终指向正确的文件,即使名称发生了更改。

首先,使用 cat 命令检查 asset-manifest. json:

  • cat widget/build/asset-manifest.json

它看起来是这样的:

Output
{ "files": { "main.css": "/static/css/main.2cce8147.chunk.css", "main.js": "/static/js/main.a284ff71.chunk.js", "main.js.map": "/static/js/main.a284ff71.chunk.js.map", "runtime~main.js": "/static/js/runtime~main.fa565546.js", "runtime~main.js.map": "/static/js/runtime~main.fa565546.js.map", "static/js/2.9ca06fd6.chunk.js": "/static/js/2.9ca06fd6.chunk.js", "static/js/2.9ca06fd6.chunk.js.map": "/static/js/2.9ca06fd6.chunk.js.map", "index.html": "/index.html", "precache-manifest.e40c3c7a647ca45e36eb20f8e1a654ee.js": "/precache-manifest.e40c3c7a647ca45e36eb20f8e1a654ee.js", "service-worker.js": "/service-worker.js", "static/css/main.2cce8147.chunk.css.map": "/static/css/main.2cce8147.chunk.css.map", "static/media/logo.svg": "/static/media/logo.5d5d9eef.svg" } }

要解析它,您的代码将查找以. js 和. css 结尾的对象键。

打开 enqueue.php 文件:

  • nano includes/enqueue.php

添加突出显示的片段:

/var/www/wordpress/wp-content/plugins/react-wordpress/includes/enqueue.php
<?php
// This file enqueues scripts and styles

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

add_action( 'init', function() {

  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 );

  add_action( 'wp_enqueue_scripts', function() {

    $asset_manifest = json_decode( file_get_contents( ERW_ASSET_MANIFEST ), true )['files'];

    if ( isset( $asset_manifest[ 'main.css' ] ) ) {
      wp_enqueue_style( 'erw', get_site_url() . $asset_manifest[ 'main.css' ] );
    }

    wp_enqueue_script( 'erw-runtime', get_site_url() . $asset_manifest[ 'runtime~main.js' ], array(), null, true );

    wp_enqueue_script( 'erw-main', get_site_url() . $asset_manifest[ 'main.js' ], array('erw-runtime'), null, true );

    foreach ( $asset_manifest as $key => $value ) {
      if ( preg_match( '@static/js/(.*)\.chunk\[email protected]', $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\[email protected]', $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 );
        }
      }
    }

  });
});

完成后,写入并退出文件。

突出显示的代码执行以下操作:

  1. 读取资产清单文件并将其解析为 JSON 文件。 它访问存储在键“ files”上的内容,并将其存储到 $asset manifest 变量中。
  2. 询问主 CSS 文件是否存在。
  3. 首先排队 React runtime,然后是主 JavaScript 文件,将运行时设置为依赖项,以确保首先在页面中加载。
  4. 解析任何名为 static / js / hash 的 JavaScript 文件的资产清单文件列表。 然后把它们放在主文件后面的页面中。
  5. 解析任何名为 static / CSS / hash 的 CSS 文件的资产清单文件列表。 在主 CSS 文件之后将它们放到页面中的 chunk.CSS 和 enquireues 中。

注意: 使用 wp enqueue script ()和 wp enqueue 样式将导致排队文件的 script 和 link 标记出现在每个页面中。 最后一个参数 true 告诉 WordPress 将文件放在页面内容页脚的下面,而不是 head 元素的底部。 这一点非常重要,因此加载 JavaScript 文件不会减慢页面其余部分的速度。

在这个步骤中,您隔离了应用程序使用的脚本和样式的文件路径。 在下一步中,您将确保这些文件路径指向 React 应用程序的构建目录,并确保您的源文件无法从浏览器中访问。

第六步ー伺服及保护静态档案

现在,你已经告诉 WordPress 要加载哪些 JavaScript 和 CSS 文件,以及在哪里可以找到它们。 但是,如果您在浏览器中访问 https: / / your domain 并查看 JavaScript 控制台,您将看到 HTTP 404错误。 (查看这篇文章获得更多关于如何使用 JavaScript 控制台的信息。)

这是因为文件的 URL 路由(例如 / static / js / main. 2 d1d08c1.chunk.js)与文件的实际路径(例如 / wp-content / plugins / react-wordpress / widget / build / static / js / main. 2 d1d08c1.chunk.js)不匹配。

在这个步骤中,您将通过告诉 React 构建目录的位置来纠正这个问题。 对象中添加 Apache 重写规则。 使用 htaccess 文件来保护你的源文件不被浏览器查看。

为了给 React 提供应用程序的正确路径,在 React 应用程序的目录中打开 package.json:

  • sudo nano widget/package.json

然后,添加突出显示的主页行:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/package.json
{
  "name": "widget",
  "version": "0.1.0",
  "private": true,
  "homepage": "/wp-content/plugins/react-wordpress/widget/build",
  "dependencies": {
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-scripts": "3.1.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

写入并退出文件。然后重新构建 React 应用程序。移动到 widget / 的顶层:

  • cd widget

然后运行 build 命令:

  • sudo npm run build

在 build 命令完成后,通过向终端输出资产清单的内容来检查资产清单:

  • cat build/asset-manifest.json

你会看到所有的文件路径都改变了:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/build/asset-manifest.json
{
  "files": {
    "main.css": "/wp-content/plugins/react-wordpress/widget/build/static/css/main.2cce8147.chunk.css",
    "main.js": "/wp-content/plugins/react-wordpress/widget/build/static/js/main.a28d856a.chunk.js",
    "main.js.map": "/wp-content/plugins/react-wordpress/widget/build/static/js/main.a28d856a.chunk.js.map",
    "runtime~main.js": "/wp-content/plugins/react-wordpress/widget/build/static/js/runtime~main.2df87c4b.js",
    "runtime~main.js.map": "/wp-content/plugins/react-wordpress/widget/build/static/js/runtime~main.2df87c4b.js.map",
    "static/js/2.9ca06fd6.chunk.js": "/wp-content/plugins/react-wordpress/widget/build/static/js/2.9ca06fd6.chunk.js",
    "static/js/2.9ca06fd6.chunk.js.map": "/wp-content/plugins/react-wordpress/widget/build/static/js/2.9ca06fd6.chunk.js.map",
    "index.html": "/wp-content/plugins/react-wordpress/widget/build/index.html",
    "precache-manifest.233e0a9875cf4d2df27d6280d12b780d.js": "/wp-content/plugins/react-wordpress/widget/build/precache-manifest.233e0a9875cf4d2df27d6280d12b780d.js",
    "service-worker.js": "/wp-content/plugins/react-wordpress/widget/build/service-worker.js",
    "static/css/main.2cce8147.chunk.css.map": "/wp-content/plugins/react-wordpress/widget/build/static/css/main.2cce8147.chunk.css.map",
    "static/media/logo.svg": "/wp-content/plugins/react-wordpress/widget/build/static/media/logo.5d5d9eef.svg"
  }
}

这会告诉你的应用程序在哪里可以找到正确的文件,但同时也提出了一个问题: 它暴露了应用程序 src 目录的路径,熟悉 create-react-app 的人可以访问 https: / / your domain / wp-content / plugins / react-wordpress / widget / src / index。 开始探索你的应用程序的源文件。 你自己试试吧!

为了保护你不希望用户访问的路径,在你的 WordPress 中添加一个 Apache 重写规则。 Htaccess 文件。

  • nano /var/www/wordpress/.htaccess

添加四条高亮线:

/var/www/wordpress/.htaccess
<IfModule mod_rewrite.c>
RewriteRule ^wp-content/plugins/react-wordpress/widget/(build|public)/(.*) - [L]
RewriteRule ^wp-content/plugins/react-wordpress/widget/* totally-bogus-erw.php [L]
</IfModule>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

这告诉 Apache 允许浏览器对 wp-content / plugins / react-wordpress / widget / build / 或 wp-content / react-wordpress / widget / public / 的任何请求。 其他任何信息都将重定向到 totally-bogus-erw.php。 除非您在顶层有一个名为 totally-bogus-erw.php 的文件,否则这个请求将由 WordPress 处理,它将显示一个404错误。

有一些 WordPress 插件,比如 Stream,可以监控请求活动并记录404s。 在日志中,请求将显示 IP 地址和当用户收到404时请求的页面。 观察 totally-bogus-erw.php 会告诉您是否有一个特定的 IP 地址正试图爬行 React 应用程序的 src 目录。

确保写入并退出文件。

现在你已经建立了将 JavaScript 和 CSS 文件加载到页面上所需的路由,是时候使用简短代码将 HTML 元素添加到页面上,这样 JavaScript 就可以与页面进行交互来呈现你的应用程序。

步骤7ー创建一个 Shortcode

短代码使插入由服务器端数据插入的复杂 HTML 块成为可能,具有非常简单的页内语法。 在这个步骤中,您将创建并注册一个 WordPress 短代码,并使用它将您的应用程序嵌入到页面中。

导航到你的插件的顶层:

  • cd /var/www/wordpress/wp-content/plugins/react-wordpress/

创建一个包含 shortcode 的新 PHP 文件:

  • touch includes/shortcode.php

然后,编辑您的主 PHP 文件,以便在加载插件时需要包含 / shortcode.PHP。 首先打开 react-wordpress.php:

  • nano react-wordpress.php

然后添加以下突出显示的行:

/var/www/wordpress/wp-content/plugins/react-wordpress/react-wordpress.php
<?php
/**
 * @wordpress-plugin
 * Plugin Name:       Embedding React In Wordpress
 */

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

define( 'ERW_WIDGET_PATH', plugin_dir_path( __FILE__ ) . '/widget' );
define( 'ERW_ASSET_MANIFEST', ERW_WIDGET_PATH . '/build/asset-manifest.json' );
define( 'ERW_INCLUDES', plugin_dir_path( __FILE__ ) . '/includes' );

require_once( ERW_INCLUDES . '/enqueue.php' );
require_once( ERW_INCLUDES . '/shortcode.php' );

写入并退出文件。

现在,打开新创建的 shortcode 文件:

  • nano includes/shortcode.php

添加以下代码:

/var/www/wordpress/wp-content/plugins/react-wordpress/includes/shortcode.php
<?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 );

  return "<div id='erw-root'></div>";
});

这段代码大部分是样板文件。 它注册了一个名为 erw 的短代码小部件,当调用该小部件时,会在页面上输出 div id"erw-root"/ div,即 React 应用程序的根元素。

保存并退出 shortcode.php。

要查看 React 应用程序的运行情况,您需要创建一个新的 WordPress 页面,并添加短代码到其中。

在 web 浏览器中导航到 https: / / your domain / wp-admin。 在页面的顶部,你会看到一个黑色的栏,左边有 WordPress 的 logo,后面是一个房屋图标,你网站的名称,一个评论泡泡图标和数字,还有一个链接写着 + New。 将鼠标悬停在 + New 按钮上,菜单就会下拉。 单击显示“页”的菜单项。

当屏幕加载时,您的光标将集中在添加标题的文本框中。 点击那里并开始输入给新的页面一个相关的标题。 本教程将使用 My React App:

假设您正在使用 WordPress Gutenberg 编辑器,您将在页面顶部的标题下面看到一行文本,上面写着开始写作或者键入 / 选择一个块。 当你把鼠标悬停在文本上时,右边会出现三个符号。 选择最接近的一个类似[ / ]来添加一个短代码块:

在新添加的文本区域中键入 shortcode [ erw widget ]。 然后,单击窗口右上角的蓝色 Publish... 按钮,然后按 Publish 确认。

你会看到一个绿色的条,确认页面已经发布。点击查看页面链接:

在屏幕上,你会看到你的应用程序:

现在页面中已经有了基本的 React 应用程序呈现,可以使用管理员提供的服务器端选项自定义该应用程序。

步骤8ー注入伺服器产生的设定

在此步骤中,您将使用服务器生成的数据和用户提供的数据将设置注入到应用程序中。 这将使您能够在应用程序中显示动态数据,并在一个页面中多次使用小部件。

首先,打开 index.js 文件:

  • sudo nano widget/src/index.js

然后,从中删除导入应用程序。 使用以下突出显示的行来更新 index.js 的内容:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';

const App = () => (
  <div className="App">
    <span className="App__Message">Hello,<br />World!</span>
  </div>
);

const target = document.getElementById('erw-root');
if (target) { ReactDOM.render(<App />, target); }

serviceWorker.unregister();

这将修改您的 React 应用程序,以便不返回默认的 Create React App 屏幕,而是返回一个读取 Hello,World! .

保存并退出文件,然后打开 index.css 进行编辑:

  • nano widget/src/index.css

用下面的代码替换 index.css 的内容:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/src/index.css
.App {
  width: 100px;
  height: 100px;
  border: 1px solid;
  display: inline-block;
  margin-right: 20px;
  position: relative;
}

.App .App__Message {
  font-size: 15px;
  line-height: 15px;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  text-align: center;
  width: 100%;
}

的风格。 应用程序将呈现一个100像素的正方形,与坚实的边界,和样式为。 应用程序消息将呈现文本是中心内的广场,无论是垂直和水平。

写入并退出文件,然后重新生成应用程序:

  • cd widget
  • sudo npm run build

一旦构建成功,在浏览器中刷新 https: / / your domain / index.php / my-react-app / 。 现在您将看到您用 CSS 设计的框,以及文本 Hello,World! :

接下来,您将添加自定义设置,包括用户提供的边框颜色和大小。 您还将从服务器传递当前用户的显示名称。

更新 Shortcode 以接受参数

要传递用户提供的参数,必须首先向用户提供传递参数的方法。 返回到终端,导航回到你的插件的顶层:

  • cd ..

接下来,打开 shortcode.php 文件进行编辑:

  • nano includes/shortcode.php

更新您的 shortcode 文件,使其包含以下突出显示的行:

/var/www/wordpress/wp-content/plugins/react-wordpress/includes/shortcode.php
<?php
// This file enqueues your shortcode.

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

add_shortcode( 'erw_widget', function( $atts ) {
  $default_atts = array( 'color' => 'black' );
  $args = shortcode_atts( $default_atts, $atts );

  return "<div class='erw-root'></div>";
});

写入并退出文件。 注意代码是如何将‘ color’‘ black’添加到 $default atts 数组中的。 数组键颜色指示 WordPress 期望颜色属性可以传递给[ erw widget ]短代码。 数组值,黑色,设置默认值。 所有的 shortcode 属性都作为字符串传递给 shortcode 函数,因此如果不想设置默认值,可以使用空字符串(”)。 最后一行更改为使用类而不是 ID,因为预计页面中将有多个元素。

现在,回到你的浏览器,点击你的 Hello,World 下面的编辑按钮! 盒子。 在浏览器中更新 WordPress 页面,添加第二个 shortcode 实例,并为这两个实例添加颜色属性。 本教程将使用[ erw widget color” # cf6f1a”]和[ erw widget color” # 11757e”] :

单击蓝色更新按钮保存。

注意: 第二个小部件还不会显示。 您需要更新 React 应用程序,以期待由类标识的多个实例,而不是由 ID 标识的单个实例。

接下来,打开 index.js 进行编辑:

  • sudo nano widget/src/index.js

更新如下:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';

const App = () => (
  <div className="App">
    <span className="App__Message">Hello,<br />World!</span>
  </div>
);

const targets = document.querySelectorAll('.erw-root');
Array.prototype.forEach.call(targets, target => ReactDOM.render(<App />, target));

serviceWorker.unregister();

写入并退出文件。 更新的代码行将在每个实例上调用 erw-root 类的 React 应用程序。 因此,如果使用短代码两次,页面中将出现两个方块。

最后,打开 index.css 进行编辑:

  • sudo nano widget/src/index.css

更新文件以包含以下突出显示的行:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/src/index.css
.erw-root { display: inline-block; }

.App {
  width: 100px;
  height: 100px;
  border: 1px solid;
  display: inline-block;
  margin-right: 20px;
  position: relative;
}

.App .App__Message {
  font-size: 15px;
  line-height: 15px;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  text-align: center;
  width: 100%;
}

使用这个添加的行,多个相邻的小部件将并排显示,而不是一个上一个。

保存并退出文件。

现在,重新编译 React 应用程序:

  • cd widget
  • sudo npm run build

现在,如果你在浏览器中刷新页面,你会看到两个小工具:

注意小部件仍然不显示边框颜色。

唯一标识每个小部件实例

为了唯一地标识每个小部件,必须从服务器传递一个 ID。 这可以通过根元素的 data-id 属性来完成。 这很重要,因为页面上的每个小部件可能有不同的设置。

要做到这一点,返回到顶级插件目录,打开 shortcode.php 进行编辑:

  • cd ..
  • nano includes/shortcode.php

更新为以下突出显示的行:

/var/www/wordpress/wp-content/plugins/react-wordpress/includes/shortcode.php
<?php
// This file enqueues your shortcode.

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

add_shortcode( 'erw_widget', function( $atts ) {
  $default_atts = array( 'color' => 'black' );
  $args = shortcode_atts( $default_atts, $atts );
  $uniqid = uniqid('id');

  return "<div class='erw-root' data-id='{$uniqid}'></div>";
});

第一个新行生成具有前缀 ID 的唯一 ID。 更新的行使用 data-ID 属性将 ID 附加到 React 根。 这将使 ID 可以在 React 中访问。

保存文件,但是不要退出。

将设置写入 JavaScript 窗口对象

在 shortcode 文件中,您将在一个 window-global JavaScript 对象中将设置写入页面。 使用 window 对象确保可以从 React 内部访问它。

如果 shortcode.php 仍然打开,则更新它,使其包含以下内容:

/var/www/wordpress/wp-content/plugins/react-wordpress/includes/shortcode.php
<?php
// This file enqueues your shortcode.

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

add_shortcode( 'erw_widget', function( $atts ) {
  $default_atts = array( 'color' => 'black' );
  $args = shortcode_atts( $default_atts, $atts );
  $uniqid = uniqid('id');

  global $current_user;
  $display_name = $current_user ? $current_user->display_name : 'World';

  ob_start(); ?>
  <script>
  window.erwSettings = window.erwSettings || {};
  window.erwSettings["<?= $uniqid ?>"] = {
    'color': '<?= $args["color"] ?>',
    'name': '<?= $display_name ?>',
  }
  </script>
  <div class="erw-root" data-id="<?= $uniqid ?>"></div>

  <?php
  return ob_get_clean();
});

这些更新在每个元素之前写一个脚本块,初始化窗口全局设置对象,并用 WP Admin 中提供的数据填充它。

注意: 语法? 是? php echo 的简写形式

保存并退出文件。

现在,检查你网页浏览器中的 WordPress 页面。 这将显示你的网页的 HTML。 如果你 ctrl + f 并搜索 windows.erwsettings,你会看到如下设置被写入你的页面的 HTML:

...
  window.erwSettings = window.erwSettings || {};
  window.erwSettings["id5d5f1958aa5ae"] = {
    'color': '#cf6f1a',
    'name': 'sammy',
  }
...

从反应中检索设置

在 React App 中,您将检索基于 ID 的设置,并将边框颜色值作为属性(prop)传递给 App 组件。 这使得 App 组件可以使用这个值,而不需要知道它从哪里来。

打开 index.js 进行编辑:

  • sudo nano widget/src/index.js

更新它,使其包含以下突出显示的行:

/var/www/wordpress/wp-content/plugins/react-wordpress/widget/src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';

const App = ({ settings }) => (
  <div className="App" style={{borderColor: settings.color}}>
    <span className="App__Message">Hello,<br />{settings.name}!</span>
  </div>
);

const targets = document.querySelectorAll('.erw-root');
Array.prototype.forEach.call(targets, target => {
  const id = target.dataset.id;
  const settings = window.erwSettings[id];
  ReactDOM.render(<App settings={settings} />, target)
});

serviceWorker.unregister();

保存文件并从文本编辑器退出。

您的 React 应用程序现在将使用来自 window-global window.erwSettings 对象的唯一 ID 来检索设置并将它们传递给 App 组件。 要实现这一点,请重新编译您的应用程序:

  • cd widget
  • sudo npm run build

完成最后一步后,在浏览器中刷新 WordPress 页面。 你会看到用户提供的边框颜色和服务器提供的显示名称出现在小部件中:

总结

在本教程中,您创建了自己的 WordPress 插件,其中包含一个 React 应用程序。 然后您构建了一个短代码作为桥接,使您的应用程序可嵌入到 WP Admin 页面构建器中,最后,您在页面上定制了小部件。

现在,您可以放心地扩展 React 应用程序,因为您的交付机制已经到位。 Wordpress 的这个基础确保你可以专注于客户端的体验,并且随着你的应用程序的扩展和增长,你可以很容易地添加更多的面向生产的工具和技术,这些工具和技术可以用于任何 WordPress 安装。

为了进一步了解你可以用你坚实的 React 基础做什么,试着探索这些教程中的一个:

  • 如何使用 React 显示来自 DigitalOcean API 的数据为 React 提供了一个有趣而实用的用例。
  • 如何使用 React 和 TypeScript 构建客户列表管理应用程序提供了更高级的 React 和 TypeScript 应用。