Когда WordPress очищает столбец post_content_filtered в базе данных?
Некоторые плагины WordPress (хотя и очень немногие) используют столбец post_content_filtered
в базе данных для хранения информации, связанной с записью.
Например, плагин Markdown on Save сохраняет версию записи в формате Markdown в столбце post_content_formatted
, а разобранный HTML - в столбце post_content
, чтобы при деактивации плагина записи не отображали Markdown (поскольку HTML хранится в post_content
).
Я обнаружил, что post_content_filtered
используется в основном для временного хранения данных, то есть содержимое столбца теряется (или очищается) в следующих случаях:
при внесении изменений в запись (заголовок, теги, категории и т.д.) с помощью опции "Быстрое редактирование"
при автоматической публикации отложенной записи
при массовом редактировании записей
при переключении между ревизиями записи
при сохранении записи из внешнего редактора (не через редактор WordPress)
Вопросы:
В каких ещё ситуациях очищаются данные в столбце
post_content_filtered
?Можно ли как-то полностью предотвратить эту очистку? (То есть, можно ли сделать так, чтобы данные хранились постоянно, как в столбце
post_content
?)

Каждое обновление записи в WordPress обрабатывается функцией wp_update_post
.
Эта функция имеет некоторые значения по умолчанию, и для post_content_filtered
значение по умолчанию — '' (пустая строка).
После того как значения по умолчанию объединяются с аргументами, переданными в функцию через wp_parse_args
, это означает, что каждый раз, когда запись обновляется и post_content_filtered
не передается явно, он устанавливается в пустую строку.
Теперь мы можем задать вопрос: когда post_content_filtered
явно передается в wp_update_post
? Ответ: никогда в WordPress.
Итак, для вашего первого вопроса:
В каких других ситуациях данные в столбце post_content_filtered очищаются?
Короткий ответ: каждый раз, когда запись обновляется, по любой причине.
Обратите внимание, что изменение только одного поля является обновлением, в частности, каждое изменение статуса — это обновление, например, черновик в опубликованный, ожидающий в опубликованный, запланированный в опубликованный, опубликованный в корзину (удаление записи) и так далее...
Если что-то меняется в записи, то post_content_filtered
очищается; единственное исключение — когда post_content_filtered
явно передается в wp_update_post
, и, как уже было сказано, WordPress этого никогда не делает.
Есть ли способ полностью предотвратить это? (То есть, есть ли способ гарантировать, что данные хранятся постоянно?)
Если вы создали это поле своим кодом и хотите его сохранить, вам нужно отслеживать каждое обновление, выполняемое 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 ( ! isset($postarr['ID']) || ! $postarr['ID'] ) return $data;
/*
* Хотите ли вы фильтровать по post_type?
* Вам стоит это делать, чтобы избежать проблем с типами записей, такими как пункты меню.
*/
if ( ! in_array( $data['post_type'], array( 'post', 'page' ) ) return $data;
/* Как запись выглядит сейчас, до обновления */
$before = get_post( $postarr['ID'] );
/* Если content_filtered уже пуст, нам нечего сохранять */
if ( empty( $before->post_content_filtered ) ) return $data;
if ( empty( $data['post_content_filtered'] ) ) {
/*
* Ой! WordPress хочет очистить наш ценный post_content_filtered...
* Давайте предотвратим это!
*/
$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
, вы можете вызвать эту функцию.
Вы также можете создать метабокс с кнопкой «Очистить content filtered», и при нажатии на эту кнопку просто вызывать вашу функцию reset_post_content_filtered
, например, через Ajax.
