问题描述

一些 WordPress 插件 (尽管很少) 使用数据库中的 post_content_filtered 列来保存一些与文章相关的数据。

例如,Markdown on Save 分别将 post_content_formatted 列中的解析后的 HTML 和 post_content 列中的 HTML 分开存储在一起,这样当插件被禁用时,这些帖子不会显示出 Markdown(因为 HTML 存储在 post_content 中) 。

现在,我意识到 post_content_filtered 几乎用于临时存储,即:列中的内容丢失 (或清除):

  • 您使用’Quick Edit’ 选项更改帖子 (标题,标签,类别等)

  • (自动) 发布预定的帖子

  • 您可以批量修改帖子

  • 你在一个帖子的修订之间切换

  • 一个帖子从外部编辑器 (即不是 WordPress 的帖子编辑器) 保存起来

问题:

  1. 在其他情况下,post_content_filtered 列中的数据是否已清除?

  2. 有办法防止这种情况发生吗? (我的意思是,有没有办法确保数据被永久存储,post_content 列的处理方式?)

最佳解决方案

WordPress 中的每个帖子更新都由 wp_update_post 函数处理。

此功能有一些默认值,而对于 post_content_filtered,默认值为”(空字符串) 。

一旦默认值与通过 wp_parse_args 传递给函数的 args 合并,这意味着每次更新一个帖子并且没有明确传递 post_content_filtered 时,它被设置为一个空字符串。

现在我们可以问:post_content_filtered 是什么时候显式传递给 wp_update_post?答案是:永远不要用 WordPress 。

所以对于你的第一个问题:

In what other situations is the data in the post_content_filtered column cleared?

简短的回答是:每次更新一个帖子,都是因为任何原因。

请注意,仅更改一个字段是更新,特别是每个状态更改都是更新。草稿发布,等待发布,未来发布,发布到垃圾 (一个帖子删除) 等等…

如果帖子发生变化,则 post_content_filtered 被清除; 只有当 post_content_filtered 被明确传递给 wp_update_post 时才是异常,而且如上所述,这是从来没有由 WordPress 完成的。

Is there a way to prevent this from happening at all? (I mean, is there a way to make sure that the data is stored permanently?

如果您使用代码创建该字段,并且要保留它,则必须查看 WordPress 执行的每个更新,并阻止更改。

听起来好像很努力,但是如果你阅读了这个答案的第一句话,「WordPress 中的每一篇文章更新都是由 wp_update_post 函数来处理的」,你明白唯一需要看的是这个功能,幸运的是,挂钩。

我建议的钩子是 wp_insert_post_data 有两个原因:

  • 它在更新之前运行,所以您不必恢复,但可以防止

  • 它传递 2 个参数:功能将要更新的数据,以及传递的参数的数组 (在更新的情况下) 包含该帖子的 ID

所以使用一个简单的 get_post,你可以比较现在的帖子,以及这个帖子如何:如果你不喜欢的话,你可以改变它。

我们的代码:

add_filter( 'wp_insert_post_data', 'preserve_content_filtered', 999, 2 );

function preserve_content_filtered ( $data, $postarr ) {

    /* If this is not an update, we have nothing to do */
    if ( ! isset($postarr['ID']) || ! $postarr['ID'] ) return $data;

    /*
     * Do you want you filter per post_type?
     * You should, to prevent issues on post type like menu items.
     */
    if ( ! in_array( $data['post_type'], array( 'post', 'page' ) ) ) return $data;

    /* How post is now, before the update */
    $before = get_post( $postarr['ID'] );

    /* If content_filtered is already empty we have nothing to preserve */
    if ( empty( $before->post_content_filtered ) ) return $data;

    if ( empty( $data['post_content_filtered'] ) ) {
        /*
         * Hey! WordPress wants to clear our valuable post_content_filtered...
         * Let's prevent it!
         */
        $data['post_content_filtered'] = $before->post_content_filtered;
    }

    return $data;

}

有一个可能的问题,其中以前的功能防止每个 post_content_filtered 清洁。如果你因为任何理由想清除它?

我已经说过每个 WP 的帖子更改都是由 wp_update_post 处理的,但是你不是 WordPress 。

你可以写一个函数,如:

function reset_post_content_filtered( $postid ) {
    global $wpdb;
    $wpdb->query( $wpdb->prepare(
        "UPDATE $wpdb->posts SET `post_content_filtered` = '' WHERE `ID` = %d", $postid
    ) );
}

作为 $wpdb 查询,它不会触发我们的过滤器,所以重置完成没有问题,并且您的代码中的任何地方都需要重置 post_content_filtered,您可以调用此功能。

您还可以使用 「清除内容过滤」 按钮创建一个 metabox,当此按钮被点击时,只需调用您的 reset_post_content_filtered 功能,例如。通过 Ajax 。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。