EP148. “把 attributes 数据从 PHP 传给前台 React”
🔒 登录后可标记已读解决「PHP 端的 attributes 数据怎么传给前台 JS」这个问题——作者坦言这不是 WordPress 官方文档提供标准答案的地方,不同开发者会有不同做法,这里介绍作者自己惯用的技巧:PHP 用 wp_json_encode() 把 attributes 转成 JSON 字符串,藏进一个 display:none 的隐藏 <pre> 标签里(不用真的展示给用户看,只是让 JS 能在 DOM 里读到这份数据);前台 JS 用 JSON.parse() 把它解析回真正的对象,再用 JS 的展开语法({...data})一次性把所有属性都当 props 传给 React 组件,避免一个个手动列举。
涉及文件
wp-content/plugins/are-you-paying-attention/index.php(修改)wp-content/plugins/are-you-paying-attention/src/frontend.js(修改)wp-content/plugins/are-you-paying-attention/src/frontend.scss(修改,追加一行背景色,内容从略)
代码实现
index.php:把 attributes 编码成 JSON,藏进隐藏的 <pre> 标签:
ob_start(); ?>
<div class="paying-attention-update-me"><pre style="display: none;"><?php echo wp_json_encode($attributes) ?></pre></div>
<?php return ob_get_clean();
src/frontend.js:解析隐藏数据、用展开语法一次性传入所有 props:
import React from 'react'
import ReactDOM from 'react-dom'
import "./frontend.scss"
const divsToUpdate = document.querySelectorAll(".paying-attention-update-me")
divsToUpdate.forEach(function(div) {
const data = JSON.parse(div.querySelector("pre").innerHTML)
ReactDOM.render(<Quiz {...data} />, div)
div.classList.remove("paying-attention-update-me")
})
function Quiz(props) {
return (
<div className="paying-attention-frontend">
<p>{props.question}</p>
<ul>
{props.answers.map(function(answer) {
return <li>{answer}</li>
})}
</ul>
</div>
)
}
关键改动点:
wp_json_encode($attributes):WordPress 对 PHP 内建json_encode()的包装函数,把 attributes 关联数组转成 JSON 字符串——用wp_json_encode()而不是直接用json_encode(),是 WordPress 项目里的通用惯例(能兼容一些字符编码上的细节处理)- 直接把 JSON 字符串输出到 HTML 里会有问题:HTML 会把字符串里的普通引号自动转成「弯引号/智能引号」,破坏 JSON 格式,导致 JS 那边解析失败——用
<pre>标签包裹能保留字符串的原始格式(<pre>语义就是「保留原始格式,不做二次处理」),配合style="display: none;"让它在视觉上不可见,但依然存在于 DOM 结构里,JS 完全能访问到 div.querySelector("pre").innerHTML:从当前占位 div 里找到那个隐藏的<pre>标签,取出它的原始文本内容(也就是 JSON 字符串)JSON.parse(字符串):浏览器原生方法,把符合 JSON 格式的字符串解析成真正可用的 JS 对象/数组<Quiz {...data} />:ES6 的展开语法(spread syntax),等价于把data对象里的每一个属性都逐一列成question={data.question} answers={data.answers} correctAnswer={data.correctAnswer}这种写法——用展开语法能一次性把所有属性都传给组件,不用逐个手写,也不用在组件内部多一层props.data.question这样的嵌套访问Quiz(props)组件内部因此可以直接用props.question、props.answers访问,跟在编辑器里用props.attributes.question相比少了一层嵌套,读取更直接props.answers.map(function(answer) { return <li>{answer}</li> }):跟编辑器端EditComponent里遍历渲染答案输入框是同样的思路,只是前台这里只需要单纯展示成列表项,不需要输入框和事件绑定- CSS 上给前台的答案列表项加了一层半透明白色背景色,让它们视觉上看起来像可点击的按钮(虽然此时还没有接上真正的点击交互)
[截图:前台页面里 Quiz Block 已显示真实的问题文字和答案列表(不再是"Hello from React"占位文字)]
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
wp_json_encode($data) | WP 内建 function | 把 PHP 数据编码成 JSON 字符串(json_encode() 的 WordPress 包装版) |
JSON.parse($string) | JS 内建方法(浏览器原生) | 把 JSON 格式的字符串解析成 JS 对象/数组 |
展开语法 {...obj} | ES6 语法 | 把一个对象的所有属性平铺展开,常用于合并对象或批量传递 props |
常见坑
- JSON 字符串直接输出到普通 HTML 标签里(不用
<pre>包裹)——浏览器会把英文直引号自动转换成弯引号(智能引号),破坏 JSON 格式,导致JSON.parse()解析失败并报错 - 忘记把承载 JSON 数据的元素隐藏(
display: none)——虽然不影响功能,但会让访客在页面上看到一大段不该出现的原始文本 - 一个个手动列举 props 而不用展开语法——属性一多容易漏写、也让代码显得啰嗦,尤其是 attributes 后续还可能继续增加字段的情况下
延伸 / 后续讲座会用到
数据已经打通、答案列表也已经能展示,下一讲要给每个答案接上真正的点击事件——点了之后判断对错、显示提示信息、并在答错/答对后给出对应的视觉反馈。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 25, EP148