今天给 Blog 加上了最后更新时间的显示,但发现加上后很多文章的最后更新日期都是 2023年4月2日,似乎是那天笔者批量地给文章加上了文章名(因为那天把 URL 格式改成了包含 slug 的形式),让 WordPress 更新了文章的 post_modified 字段。但我们希望最后一次更新显示的是文章内容实质更新的时间,因此需要将 wp_posts 表中的修订版本条目作为参照,修正这些文章的时间。

因此,笔者写了简短的 SQL 来修复这些文章,开一帖仅供记录。如果您要采用这些命令,请自行替换其中硬编码的表名、条件与日期。

# 先查看出问题的文章列表并预览修改结果(对比post_modified与post_modified_new)
SELECT parent.ID, parent.post_title, parent.post_date, parent.post_modified, revision.post_modified as post_modified_new
FROM cwp_posts AS parent
JOIN cwp_posts AS revision ON
    revision.ID = (
        SELECT r1.ID
        FROM cwp_posts AS r1
        WHERE parent.ID = r1.post_parent AND NOT (r1.post_modified BETWEEN '2023-04-02 00:00:00' AND '2023-04-02 23:59:59') # 注意:这里假设这天没有对文章做实质性的更新!
        ORDER BY r1.post_modified DESC LIMIT 1
    )
WHERE parent.post_type = 'post' AND parent.post_modified BETWEEN '2023-04-02 00:00:00' AND '2023-04-02 23:59:59'
;

# 开始一个事务以免意外
START TRANSACTION;

# 执行操作,注意比对 Affected rows 与上一条查询出来的行数是否对得上
UPDATE cwp_posts as parent
JOIN cwp_posts AS revision ON
    revision.ID = (
        SELECT r1.ID
        FROM cwp_posts AS r1
        WHERE parent.ID = r1.post_parent AND NOT (r1.post_modified BETWEEN '2023-04-02 00:00:00' AND '2023-04-02 23:59:59')
        ORDER BY r1.post_modified DESC LIMIT 1
    )
SET parent.post_modified = revision.post_modified, parent.post_modified_gmt = revision.post_modified_gmt
WHERE parent.post_type = 'post' AND parent.post_modified BETWEEN '2023-04-02 00:00:00' AND '2023-04-02 23:59:59';

# 手动检查执行结果
SELECT ID, post_title, post_date, post_modified FROM cwp_posts WHERE post_type = 'post';

# 如果正常,则提交,否则需要用 ROLLBACK; 回滚
COMMIT;

幸好笔者当时是在同一天内改完所有帖子的文章名,因此可以用相对简单的查询条件完成筛选,但一个并不小的插曲是,笔者第一次提交时忘了仔细查看,结果漏掉了 ORDER BY 子句的 DESC 选项就提交了事务,结果只能冒一些风险用时间差作更新条件(把对 parent.post_modified 的过滤换成 ABS(UNIX_TIMESTAMP(parent.post_modified) - UNIX_TIMESTAMP(revision.post_modified)) > 7200)。

修改完后,可以看到文章的更新时间正常显示了。


不想被自己的惰性打败。