When is the 'post_content_filtered' column in database cleared by WordPress?

Some WordPress plugins (although very few) use the post_content_filtered column in database to save some data related to a post.

For example, Markdown on Save stores the markdown version of a post separately in the post_content_formatted column and the parsed HTML in the post_content column, so that when the plugin is deactivated the posts won’t spew out Markdown (because HTML is stored in post_content).

Now, I came to realize that post_content_filtered is pretty much used for temporary storage i.e. the content in the column is lost (or cleared) when:

  • you make changes to a post (title, tags, categories, etc.) using the ‘Quick Edit’ option

  • a scheduled post is (automatically) published

  • you do bulk edits to posts

  • you switch between revisions of a post

  • a post is saved from an external editor (i.e. not the WordPress post editor)

Questions:

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

  2. 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, the way the post_content column is treated?)

Solutions Collecting From Web of "When is the 'post_content_filtered' column in database cleared by WordPress?"

Every post update in WordPress is handled by the wp_update_post function.

This function has some defaults, and for post_content_filtered the default value is ” (empty string).

Once the defaults are merged with args passed to function via wp_parse_args it means that every time a post is updated and post_content_filtered is not explicitly passed, it is set to a empty string.

Now we can ask: when is the post_content_filtered explicitly passed to wp_update_post? Answer is: never by WordPress.

So for your first question:

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

Short answer is: every time a post is updated, for any reason.

Note that changing only one field is an update, in particular, every status change is an update, e.g. draft to publish, pending to publish, future to publish, publish to trash (a post delete), and so on…

If something changes in a post, then post_content_filtered is cleared; only exception is when post_content_filtered is explicitly passed to wp_update_post, and as already said, this is never done by 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?

If you create that field with your code, and you want to preserve it, you have to look at every update performed by WordPress, and prevent the change.

This can sound like hard work, but if you read the first sentence in this answer, “Every post update in WordPress is handled by the wp_update_post function“, you understand that the only thing needed is to look at that function, which luckily has different hooks.

The hook that I suggest is the wp_insert_post_data for 2 reasons:

  • It runs before the update, so you don’t have to recover but you
    can prevent
  • It passes 2 parameters: the data that function is going to update, and an
    array of the passed parameters, that (in case of update) contain the ID of the post

So using a simple get_post you are able to compare how the post is now, and how the post will be: if you don’t like something, you can change it.

Let’s code:

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;

}

There is a possible issue, where the previous function prevents every post_content_filtered cleaning. And if you, for any reason, want to clear it?

I’ve said that every WP post change is handled by wp_update_post, but you are not WordPress.

You can write a function like:

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

Being a $wpdb query, it doesn’t trigger our filter, so resetting is done with no problem, and everywhere in your code you need to reset post_content_filtered, you can call this function.

You can also create a metabox with a button ‘Clear content filtered’ and when this button is clicked just call your reset_post_content_filtered function, e.g. via Ajax.