EP106. “程序化创建文章与动态教授 ID 传递”
🔒 登录后可标记已读用 wp_insert_post() 在 createLike() 端点里真正创建一篇 like 文章,并把自定义字段 liked_professor_id 设成当前点赞的教授 ID。分三步验证:先写死标题/正文确认 wp_insert_post() 能建文章;再写死 meta_input 里的字段值确认自定义字段能正确赋值;最后把「写死的教授 ID」换成「点击的具体教授的真实 ID」——做法是先把教授 ID 写进 .like-box 的 data-professor 属性,前端读出这个属性、通过 AJAX 的 data 参数带给后端,后端再从请求数据里读出来使用。
涉及文件
wp-content/themes/fictional-university-theme/inc/like-route.php(修改)wp-content/themes/fictional-university-theme/single-professor.php(修改)wp-content/themes/fictional-university-theme/src/modules/Like.js(修改)
代码实现
inc/like-route.php:createLike() 改为真正创建文章:
// wp-content/themes/fictional-university-theme/inc/like-route.php
function createLike($data) {
$professor = sanitize_text_field($data['professorId']);
wp_insert_post(array(
'post_type' => 'like',
'post_status' => 'publish',
'post_title' => '2nd PHP Test',
'meta_input' => array(
'liked_professor_id' => $professor
)
));
}
single-professor.php:给 .like-box 加上教授 ID 的 data 属性:
<span class="like-box" data-professor="<?php the_ID(); ?>" data-exists="<?php echo $existStatus; ?>">
src/modules/Like.js:把 currentLikeBox 传给 createLike(),AJAX 请求带上教授 ID:
// wp-content/themes/fictional-university-theme/src/modules/Like.js
ourClickDispatcher(e) {
var currentLikeBox = $(e.target).closest(".like-box")
if (currentLikeBox.data("exists") == "yes") {
this.deleteLike(currentLikeBox)
} else {
this.createLike(currentLikeBox) // 修改:把点击到的 like-box 传进去
}
}
createLike(currentLikeBox) {
$.ajax({
url: universityData.root_url + "/wp-json/university/v1/manageLike",
type: "POST",
data: { "professorId": currentLikeBox.data("professor") }, // 新增
success: response => {
console.log(response)
},
error: response => {
console.log(response)
}
})
}
关键改动点:
wp_insert_post($args)是程序化创建文章的核心函数,接收一个描述文章的关联数组:post_type、post_status(不指定默认是draft,这里显式设为publish)、post_title、post_content等标准字段都可以直接指定meta_input是一个特殊参数,允许在创建文章的同一步顺带设置自定义字段(WordPress 原生叫「meta field」,ACF 插件本质上只是给这套原生机制包了一层友好的编辑界面)——关键点是这里的 key 必须精确匹配 ACF 字段的内部变量名(liked_professor_id,全小写下划线),跟后台显示的标签文字「Liked Professor ID」是两回事- 自定义 REST 路由的
callback函数会自动接收到一个包含全部请求数据的参数(这里命名为$data),不管数据是通过 URL 查询字符串还是请求体传来的,WordPress 都会统一合并到这个数组里,用$data['professorId']就能取到前端传来的值——字段名professorId要跟前端 JS 里data: { "professorId": ... }的 key 完全一致 - 服务端拿到
professorId之后先过sanitize_text_field()净化一遍才使用,这是又一次「不信任任何外部输入」的具体实践——即使这个值原本预期是数字,也统一走一遍净化以防万一 - 前端定位教授 ID 的方式:
the_ID()在 PHP 模板里直接输出当前教授文章的 ID 到data-professor属性上,JS 侧用currentLikeBox.data("professor")读出(jQuery 的.data()自动去掉data-前缀)——这条链路能保证「无论点的是哪个教授的赞按钮,传给后端的都是那个教授真实的 ID」,而不是写死的测试值
[截图:wp-admin 后台 Likes 列表,显示程序化创建出来的 like 文章记录]
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
wp_insert_post($args) | WP 内建 function | 程序化创建/更新文章,$args 里的 meta_input 可以在创建同时设置自定义字段 |
the_ID() | WP 内建 function | 直接输出(echo)当前循环文章的 ID |
常见坑
meta_input里的 key 跟 ACF 字段的显示标签混淆——一定要用 ACF 生成的内部变量名(通常全小写、下划线分隔),不是后台看到的那行文字标题- 前后端字段名对不上(比如前端传
professorId,后端读$data['professor_id'])——REST 端点的自定义参数名完全靠人工约定一致,没有框架帮你自动纠错,拼错或大小写不一致会导致读到null - 忘记把
professorId经过sanitize_text_field()才存入数据库——即使这一讲的攻击面还不算严重,也应该养成「凡是外部输入,先净化再使用」的习惯
延伸 / 后续讲座会用到
createLike() 现在还没有任何权限校验——任何人(哪怕没登录)都能调用它无限次创建赞。下一讲(part 2)要加上「必须登录」「每人对每位教授只能点一次」这些自定义限制,deleteLike() 也还完全没实现。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 20, EP106