post_excerpt变空是因为该字段未被显式设置,并非数据损坏;常见于导入、迁移或插件清空操作,修复需批量生成并写回摘要。
为什么 post_excerpt 会变空?常见触发场景
WordPress 的 post_excerpt 字段不是自动生成的,它只在手动填写摘要、或调用 wp_insert_post() 时显式传入 'post_excerpt' 参数才会被写入。很多主题和插件在导入、迁移、批量更新时跳过这个字段;REST API 或 WP-CLI 导入文章默认也不填充;甚至某些“一键优化”插件会清空它来“节省空间”。
常见错误现象:get_the_excerpt() 返回空字符串,后台编辑页摘要框为空,但文章内容(post_content)完整存在。
关键判断:如果 post_excerpt 为空但 post_content 有内容,且你没主动删过摘要,那大概率是字段从未被设值,而非损坏——这不是数据库损坏,是数据缺失,修复 = 批量生成 + 写回。
用 SQL 直接批量填充 post_excerpt(最稳最快)
直接操作数据库绕过 WordPress 钩子和权限校验,适合已确认数据安全、需一次性修复的场景。注意:必须先备份 wp_posts 表。
核心逻辑是取 post_content 前 N 个字符(去掉 HTML 标签),截断到第一个句号/换行/空格边界,并补省略号。MySQL 本身不支持正则替换 HTML,所以用 SUBSTRING_INDEX() 和 TRIM() 组合控制长度更可靠。
UPDATE wp_posts
SET post_excerpt = TRIM(
CONCAT(
LEFT(
REPLACE(
REPLACE(
REPLACE(wp_posts.post_content, '<p>', ' '),
'</p>', ' '
),
'<br>', ' '
),
200
),
'…'
)
)
WHERE post_excerpt = ''
AND post_content != ''
AND post_status = 'publish'
AND post_type = 'post';
- 200 是纯文本截取长度,不是字节数,中文也按 1 算;超过可能被截断在标签中间,所以先粗暴替换常见 HTML 换行标签
-
post_status = 'publish'和post_type = 'post'必须加,避免误触草稿、页面、附件 - 执行前务必确认表前缀是
wp_,否则替换成你的实际前缀(如mydb_posts) - 如果服务器禁用
REPLACE()多层嵌套,改用 PHP 脚本分批处理(见下一条)
用 WP-CLI 分批生成并保存(兼容性更好,适合生产环境)
比裸 SQL 更安全,能触发 save_post 钩子,兼容 SEO 插件、缓存清理等逻辑。但速度慢,需确保 WP-CLI 可访问且内存足够。
命令本质是查出符合条件的文章 ID,对每个 ID 调用 wp_update_post() 并设置 post_excerpt 字段。
wp post list \
--post_status=publish \
--post_type=post \
--post_excerpt__empty \
--format=ids \
| xargs -r -n 50 wp post update --post_excerpt='{{post_content|excerpt:200}}'
-
--post_excerpt__empty是 WP-CLI 4.2+ 支持的条件,精准筛选空摘要 -
-n 50控制每批 50 篇,防超时;若提示 “argument list too long”,改小到 20 -
{{post_content|excerpt:200}}是 WP-CLI 内置过滤器,自动去 HTML、截断、加省略号 - 如果报错
PHP Fatal error: Allowed memory size exhausted,在命令前加WP_MEMORY_LIMIT=512M
PHP 脚本手动补全(可控最强,适合复杂逻辑)
当你要按分类、标签、自定义字段差异化生成摘要(比如产品文章取 _price + 简介,博客文章取首段),SQL 和 CLI 都不够用,就得写脚本。
把脚本放 WordPress 根目录下(如 fix-excerpt.php),用浏览器或 CLI 执行,核心是遍历 + wp_update_post()。
<?php require_once 'wp-load.php';
$args = [
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => 100,
'fields' => 'ids',
'meta_query' => [['key' => '_yoast_wpseo_metadesc', 'compare' => 'NOT EXISTS']],
];
$posts = get_posts($args);
foreach ($posts as $id) {
$content = get_post_field('post_content', $id);
$excerpt = wp_trim_words($content, 30, '…'); // 自动去标签、按词截断
wp_update_post(['ID' => $id, 'post_excerpt' => $excerpt]);
}
echo "Done: " . count($posts) . " posts updated.\n";
-
wp_trim_words()比substr()安全,不会切开 UTF-8 字符或 HTML 实体 - 加
meta_query排除已用 Yoast 设置了_yoast_wpseo_metadesc的文章,避免覆盖人工摘要 - 每次最多处理 100 篇,防止超时;如需继续,修改
offset参数分页重跑 - 别漏掉
require_once 'wp-load.php',否则wp_update_post()找不到
post_excerpt 不是“丢失”,是压根没被写进去;修复的关键不是恢复旧数据,而是按当前内容合理生成新摘要。最容易被忽略的是:不同文章类型(page、product)是否要一并处理,以及已有 SEO 插件元字段是否该优先保留——这些不提前判断,脚本一跑,人工写的摘要就没了。











