WP DEVELOP

EP148. “把 attributes 数据从 PHP 传给前台 React”

首页 WordPress 开发课程 GUTENBERG BLOCK 入门(block.json) · EP148
约 10 分钟· #EP148#GUTENBERG BLOCK 入门(block.json)
🔒 登录后可标记已读

解决「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.questionprops.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