¿Cuándo limpia WordPress la columna 'post_content_filtered' en la base de datos?

8 sept 2013, 13:08:28
Vistas: 13.9K
Votos: 34

Algunos plugins de WordPress (aunque muy pocos) utilizan la columna post_content_filtered en la base de datos para guardar información relacionada con un post.

Por ejemplo, Markdown on Save almacena la versión en markdown de un post en la columna post_content_formatted y el HTML parseado en la columna post_content, para que cuando el plugin se desactive los posts no muestren Markdown (porque el HTML está almacenado en post_content).

Ahora, me he dado cuenta de que post_content_filtered se usa principalmente para almacenamiento temporal, es decir, el contenido de la columna se pierde (o se borra) cuando:

  • Haces cambios en un post (título, etiquetas, categorías, etc.) usando la opción 'Edición rápida'

  • Un post programado se publica (automáticamente)

  • Haces ediciones masivas a posts

  • Cambias entre revisiones de un post

  • Un post se guarda desde un editor externo (es decir, no desde el editor de posts de WordPress)

Preguntas:

  1. ¿En qué otras situaciones se borran los datos de la columna post_content_filtered?

  2. ¿Hay alguna manera de evitar que esto suceda? (¿Existe alguna forma de asegurar que los datos se almacenen permanentemente, como ocurre con la columna post_content?)

0
Todas las respuestas a la pregunta 1
0
37

Cada actualización de una entrada en WordPress es manejada por la función wp_update_post.

Esta función tiene algunos valores predeterminados, y para post_content_filtered el valor predeterminado es '' (cadena vacía).

Una vez que los valores predeterminados se combinan con los argumentos pasados a la función mediante wp_parse_args, significa que cada vez que se actualiza una entrada y post_content_filtered no se pasa explícitamente, se establece como una cadena vacía.

Ahora podemos preguntar: ¿cuándo se pasa explícitamente post_content_filtered a wp_update_post? La respuesta es: nunca por parte de WordPress.

Entonces, para tu primera pregunta:

¿En qué otras situaciones se borran los datos en la columna post_content_filtered?

La respuesta corta es: cada vez que se actualiza una entrada, por cualquier motivo.

Ten en cuenta que cambiar solo un campo es una actualización, en particular, cada cambio de estado es una actualización, por ejemplo, de borrador a publicado, de pendiente a publicado, de programado a publicado, de publicado a papelera (un borrado de entrada), y así sucesivamente...

Si algo cambia en una entrada, entonces post_content_filtered se borra; la única excepción es cuando post_content_filtered se pasa explícitamente a wp_update_post, y como ya se dijo, esto nunca lo hace WordPress.

¿Hay alguna manera de evitar que esto suceda en absoluto? (Quiero decir, ¿hay alguna manera de asegurarse de que los datos se almacenen permanentemente?

Si creas ese campo con tu código y quieres preservarlo, debes estar atento a cada actualización realizada por WordPress y evitar el cambio.

Esto puede parecer un trabajo arduo, pero si lees la primera frase de esta respuesta, "Cada actualización de una entrada en WordPress es manejada por la función wp_update_post", entenderás que lo único necesario es mirar esa función, que afortunadamente tiene diferentes hooks.

El hook que sugiero es wp_insert_post_data por 2 razones:

  • Se ejecuta antes de la actualización, por lo que no tienes que recuperar sino que puedes prevenir
  • Pasa 2 parámetros: los datos que la función va a actualizar y un arreglo de los parámetros pasados, que (en caso de actualización) contienen el ID de la entrada

Así que usando un simple get_post puedes comparar cómo está la entrada ahora y cómo será después: si no te gusta algo, puedes cambiarlo.

Vamos al código:

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

function preserve_content_filtered ( $data, $postarr ) {

    /* Si no es una actualización, no tenemos nada que hacer */
    if ( ! isset($postarr['ID']) || ! $postarr['ID'] ) return $data;

    /*
     * ¿Quieres filtrar por post_type?
     * Deberías, para evitar problemas en tipos de entrada como elementos de menú.
     */
    if ( ! in_array( $data['post_type'], array( 'post', 'page' ) ) return $data;

    /* Cómo está la entrada ahora, antes de la actualización */
    $before = get_post( $postarr['ID'] ); 

    /* Si content_filtered ya está vacío, no tenemos nada que preservar */
    if ( empty( $before->post_content_filtered ) ) return $data;

    if ( empty( $data['post_content_filtered'] ) {
        /*
         * ¡Oye! WordPress quiere borrar nuestro valioso post_content_filtered...
         * ¡Evitémoslo!
         */
        $data['post_content_filtered'] = $before->post_content_filtered;
    }

    return $data;

}

Hay un posible problema, donde la función anterior evita cualquier borrado de post_content_filtered. ¿Y si , por alguna razón, quieres borrarlo?

He dicho que cada cambio de entrada de WP es manejado por wp_update_post, pero tú no eres WordPress.

Puedes escribir una función como:

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

Al ser una consulta $wpdb, no activa nuestro filtro, por lo que el reinicio se realiza sin problemas, y en cualquier parte de tu código donde necesites reiniciar post_content_filtered, puedes llamar a esta función.

También puedes crear un metabox con un botón 'Limpiar contenido filtrado' y cuando se haga clic en este botón, simplemente llamar a tu función reset_post_content_filtered, por ejemplo, mediante Ajax.

11 sept 2013 06:04:50