如何让React开发的WordPress插件内容被Google识别?
解决React开发WordPress短代码插件的SEO抓取问题
针对你用React开发WordPress短代码插件、内容无法被Google抓取的问题,结合你使用wp-scripts的情况,提供以下几种实用方案:
方案一:服务端渲染(SSR)适配WordPress
核心思路是在PHP短代码执行时,先通过Node环境或PHP扩展渲染React组件为静态HTML输出,再加载客户端JS做交互激活(hydrate),确保源码可见且可被抓取。
步骤1:扩展wp-scripts配置支持SSR打包
在项目根目录创建webpack.config.js,添加SSR打包规则:
const defaultConfig = require('@wordpress/scripts/config/webpack.config'); module.exports = [ // 保留原客户端打包配置 defaultConfig, // 添加SSR打包配置 { ...defaultConfig, entry: { ssr: './src/ssr.js', }, output: { ...defaultConfig.output, filename: '[name].js', libraryTarget: 'commonjs2', }, target: 'node', externals: { react: 'commonjs react', 'react-dom': 'commonjs react-dom', }, }, ];
步骤2:编写SSR渲染脚本
创建src/ssr.js,负责渲染组件为HTML字符串:
import React from 'react'; import { renderToString } from 'react-dom/server'; import MyPluginComponent from './components/MyPluginComponent'; // 接收外部传入的短代码参数,输出渲染后的HTML module.exports = (props) => renderToString(<MyPluginComponent {...props} />);
步骤3:PHP短代码中调用SSR渲染
方式A:使用Node环境执行SSR脚本(需服务器允许exec)
function my_plugin_shortcode($atts) { // 处理短代码参数 $props = json_encode(shortcode_atts([ 'post_id' => '', 'limit' => 5, ], $atts)); // 执行SSR脚本获取静态HTML $ssr_script_path = plugin_dir_path(__FILE__) . 'build/ssr.js'; $html = exec('node -e "const render = require(\''.$ssr_script_path.'\'); console.log(render('.$props.'))"'); // 加载客户端JS/CSS wp_enqueue_script( 'my-plugin-script', plugin_dir_url(__FILE__) . 'build/index.js', [], filemtime(plugin_dir_path(__FILE__) . 'build/index.asset.php'), true ); wp_enqueue_style( 'my-plugin-style', plugin_dir_url(__FILE__) . 'build/index.css', [], filemtime(plugin_dir_path(__FILE__) . 'build/index.css') ); // 传递参数到客户端用于hydrate wp_localize_script('my-plugin-script', 'myPluginProps', $atts); // 输出带根节点的静态HTML return '<div id="my-plugin-root">' . $html . '</div>'; } add_shortcode('my_react_plugin', 'my_plugin_shortcode');
方式B:使用PHP V8JS扩展(更安全,无需exec)
如果服务器安装了V8JS扩展,可直接在PHP中执行SSR脚本:
use V8Js; function my_plugin_render_ssr($props) { $v8 = new V8Js(); $ssr_script = file_get_contents(plugin_dir_path(__FILE__) . 'build/ssr.js'); $props_json = json_encode($props); // 执行SSR渲染 return $v8->executeString(' global.props = JSON.parse(\''.$props_json.'\'); const render = require(\''.plugin_dir_path(__FILE__).'build/ssr.js\'); render(global.props); ', 'ssr-render'); } // 短代码函数中调用上述方法即可
步骤4:客户端代码改为hydrate激活
修改src/index.js,用hydrateRoot替代createRoot,复用服务器渲染的DOM:
import React from 'react'; import { hydrateRoot } from 'react-dom/client'; import MyPluginComponent from './components/MyPluginComponent'; const root = document.getElementById('my-plugin-root'); hydrateRoot(root, <MyPluginComponent {...window.myPluginProps} />);
方案二:静态预渲染(适合内容固定的组件)
如果你的React组件内容不随短代码参数变化,可预渲染静态HTML,直接在短代码中输出。
步骤1:配置react-snap预渲染
安装依赖:
npm install react-snap --save-dev
修改package.json的脚本:
"scripts": { "build": "wp-scripts build && npm run prerender", "prerender": "react-snap" }, "reactSnap": { "source": "public", "target": "build/prerendered", "inlineCss": true }
创建public/index.html作为预渲染模板:
<!DOCTYPE html> <html> <body> <div id="my-plugin-root"></div> <script src="../build/index.js"></script> </body> </html>
步骤2:PHP短代码中加载预渲染HTML
function my_plugin_shortcode($atts) { // 加载客户端JS/CSS wp_enqueue_script( 'my-plugin-script', plugin_dir_url(__FILE__) . 'build/index.js', [], filemtime(plugin_dir_path(__FILE__) . 'build/index.asset.php'), true ); wp_enqueue_style( 'my-plugin-style', plugin_dir_url(__FILE__) . 'build/index.css', [], filemtime(plugin_dir_path(__FILE__) . 'build/index.css') ); // 读取预渲染的HTML内容 $prerendered_html = file_get_contents(plugin_dir_path(__FILE__) . 'build/prerendered/index.html'); // 提取根节点内的内容 preg_match('/<div id="my-plugin-root">(.*?)<\/div>/s', $prerendered_html, $matches); $static_html = $matches[1] ?? ''; return '<div id="my-plugin-root">' . $static_html . '</div>'; } add_shortcode('my_react_plugin', 'my_plugin_shortcode');
方案三:PHP静态输出+React交互(极简方案)
如果组件数据来自WordPress,可直接用PHP查询数据并输出静态HTML,React仅负责添加交互逻辑:
function my_plugin_shortcode($atts) { // PHP查询数据(比如自定义帖子类型) $posts = get_posts([ 'post_type' => 'custom_post', 'posts_per_page' => $atts['limit'] ?? 5, ]); // 输出静态HTML $static_html = '<div id="my-plugin-root"><ul>'; foreach ($posts as $post) { $static_html .= '<li class="post-item" data-id="'.$post->ID.'">'.$post->post_title.'</li>'; } $static_html .= '</ul></div>'; // 加载React交互脚本 wp_enqueue_script( 'my-plugin-script', plugin_dir_url(__FILE__) . 'build/index.js', [], filemtime(plugin_dir_path(__FILE__) . 'build/index.asset.php'), true ); return $static_html; } add_shortcode('my_react_plugin', 'my_plugin_shortcode');
客户端React只需挂载到已有的DOM上,添加点击事件等交互:
import React from 'react'; import { hydrateRoot } from 'react-dom/client'; const MyPluginComponent = () => { const handleClick = (e) => { const postId = e.currentTarget.dataset.id; // 交互逻辑,比如弹窗显示内容 }; return ( <ul> {Array.from(document.querySelectorAll('.post-item')).map(item => ( <li key={item.dataset.id} onClick={handleClick}>{item.textContent}</li> ))} </ul> ); }; const root = document.getElementById('my-plugin-root'); hydrateRoot(root, <MyPluginComponent />);
内容的提问来源于stack exchange,提问作者Sau Thapa
相关产品推荐
相关产品推荐

