Skip to content
🔒 4 способа программно снять пост с публикации в WordPress

🔒 4 способа программно снять пост с публикации в WordPress

Сайт упал после обновления плагина, нужно срочно скрыть проблемный пост, пока не поздно. А через неделю, вернуть обратно, когда баг починят. Или клиент просит убрать устаревшую статью из выдачи, но не удалять навсегда.

Ручное переключение статуса через админку работает для одного-двух постов. Но когда таких десятки или логика должна срабатывать автоматически, нужен программный подход. WordPress даёт четыре способа снять пост с публикации через PHP: от безопасного черновика до полного удаления.

Ниже, каждый метод с готовым кодом, объяснением и подсказкой, когда какой применять.

💡 Быстрый обзор:

  • Перевели пост в черновик через wp_update_post со статусом draft, самый безопасный и обратимый способ
  • Сделали пост приватным (private), виден только администраторам и редакторам
  • Отправили пост в будущее через post_date, пост исчезает из выдачи до наступления заданной даты
  • Удалили пост навсегда через wp_delete_post, крайняя мера с предупреждениями и бэкапом

Шаг 1. Черновик: снимаем пост с публикации без потери данных

Самый частый сценарий: нужно временно скрыть пост, но сохранить весь контент, URL и возможность вернуть обратно одним кликом. Перевод в черновик, идеальный вариант.

Меняется только поле post_status в таблице wp_posts. Сам пост, его мета-поля, вложения и URL остаются нетронутыми. Когда решите вернуть, меняете статус обратно на publish.

Код для смены статуса на draft. Добавьте в functions.php дочерней темы или через плагин Code Snippets:

1/**
2 * Переводит пост в черновик по ID.
3 *
4 * @param int $post_id ID поста, который нужно снять с публикации.
5 */
6function sd_unpublish_to_draft( $post_id ) {
7 wp_update_post( array(
8 'ID' => $post_id,
9 'post_status' => 'draft',
10 ) );
11}
12
13// Пример вызова: снимаем пост с ID = 42
14sd_unpublish_to_draft( 42 );

wp_update_post() обновляет запись в БД. Мы передаём только ID и новое значение post_status, всё остальное WordPress подхватывает сам. Никакие другие поля не меняются.

Когда применять: временное скрытие поста на доработку, автоматическая деактивация постов с истёкшим сроком актуальности (например, акции), программная модерация пользовательского контента.

Шаг 2. Приватный пост: скрываем от посетителей, оставляем редакторам

Приватный статус — это середина между публичным и скрытым. Пост не виден обычным посетителям, но доступен администраторам и редакторам в админке. Удобно для внутренних материалов: инструкций для команды, черновиков клиентского контента, закрытых страниц.

Отличие от черновика: приватный пост технически «опубликован» и может иметь свой URL, но WordPress проверяет права пользователя перед показом. Посетитель без роли read_private_posts увидит 404.

Код аналогичен предыдущему, меняется только статус:

1/**
2 * Делает пост приватным — видимым только админам и редакторам.
3 *
4 * @param int $post_id ID поста.
5 */
6function sd_unpublish_to_private( $post_id ) {
7 wp_update_post( array(
8 'ID' => $post_id,
9 'post_status' => 'private',
10 ) );
11}
12
13// Пример вызова
14sd_unpublish_to_private( 42 );

Обратите внимание: если на сайте есть пользовательские роли с кастомными правами, проверьте capabilities перед массовым использованием. По умолчанию приватные посты видят роли editor и administrator.

Когда применять: премиум-контент по подписке (в связке с membership-плагинами), внутренняя документация команды, скрытие постов для пересогласования с клиентом перед повторной публикацией.

Шаг 3. Будущая дата: отложенное снятие с публикации

Интересный приём: вместо смены статуса можно «отправить пост в будущее», задать дату публикации на 2050 год. Пост мгновенно исчезает из выдачи, потому что WordPress показывает только посты с датой ≤ текущему моменту.

Этот метод не меняет post_status: пост остаётся publish. Он просто «ещё не наступил» с точки зрения WordPress. Плюс, при необходимости можно вернуть реальную дату, и пост снова появится.

Код использует поля post_date и post_date_gmt:

1/**
2 * Скрывает пост, устанавливая дату публикации в далёкое будущее.
3 *
4 * @param int $post_id ID поста.
5 */
6function sd_unpublish_to_future( $post_id ) {
7 $future_date = '2050-12-31 23:59:59';
8
9 wp_update_post( array(
10 'ID' => $post_id,
11 'post_date' => $future_date,
12 'post_date_gmt' => get_gmt_from_date( $future_date ),
13 ) );
14}
15
16// Пример вызова
17sd_unpublish_to_future( 42 );

get_gmt_from_date() конвертирует локальное время в GMT, WordPress хранит обе версии даты. Не пренебрегайте GMT-полем: без него поведение при смене часового пояса сайта станет непредсказуемым.

Когда применять: «отложенная» публикация контента по расписанию, временное скрытие новостей без изменения статуса, сценарии где post_status должен остаться publish для обратной совместимости с другими плагинами.

Шаг 4. Удаление: когда пост не нужен совсем

wp_delete_post(), необратимая операция. Пост удаляется из базы, а вместе с ним, все мета-поля, связи с таксономиями и (опционально) вложения.

Это не «снятие с публикации» в строгом смысле. Но в контексте программного управления контентом удаление, четвёртый, самый жёсткий инструмент. И он требует предохранителей.

Перед запуском сделайте полный бэкап базы данных. Скрипт ниже сначала выводит список того, что будет удалено, и только потом, боевой вариант.

1/**
2 * Удаляет пост. Сначала — dry-run с выводом информации, затем — боевое удаление.
3 *
4 * ВНИМАНИЕ: необратимая операция. Сделайте бэкап перед запуском.
5 *
6 * @param int $post_id ID поста.
7 * @param bool $force_delete true — удалить навсегда (минуя корзину), false — в корзину.
8 */
9function sd_delete_post_safe( $post_id, $force_delete = false ) {
10 $post = get_post( $post_id );
11
12 if ( ! $post ) {
13 error_log( "Post with ID {$post_id} not found." );
14 return;
15 }
16
17 // Dry-run: выводим информацию без удаления
18 error_log( sprintf(
19 'READY TO DELETE: ID=%d, title="%s", status=%s, attachments=%d',
20 $post->ID,
21 $post->post_title,
22 $post->post_status,
23 count( get_attached_media( '', $post_id ) )
24 ) );
25
26 // Раскомментируйте следующую строку для реального удаления:
27 // wp_delete_post( $post_id, $force_delete );
28}
29
30// Dry-run: только выводит информацию
31sd_delete_post_safe( 12341, false );

Флаг $force_delete:

  • false, пост попадает в корзину (Trash), его можно восстановить в течение 30 дней.
  • true, удаление навсегда, восстановить нельзя даже через базу (без бэкапа).

Функция логирует через error_log(), сообщения появятся в wp-content/debug.log при включённом WP_DEBUG. В продакшене замените на свой механизм оповещений.

Когда применять: автоматическая очистка спам-постов, удаление просроченного контента (вакансии, мероприятия), программная ротация контента с полным удалением старых записей.

Сравнение четырёх методов

Метод

Статус поста

Обратимость

Видимость для читателей

Видимость в админке

Когда применять

Черновик

draft

Полная

Скрыт

Всем ролям с доступом к постам

Временное скрытие, доработка

Приватный

private

Полная

Скрыт

Админам и редакторам

Внутренний контент, премиум

Будущая дата

publish

Полная

Скрыт до даты

Всем

Отложенная публикация, расписание

Удаление

-

Только из корзины (30 дней)

-

Только админам

Полное удаление, очистка

⁉️🤔 Частые вопросы

Чем отличается снятие с публикации от удаления?

Снятие с публикации (draft/private/future) сохраняет пост в базе: контент, URL, вложения и SEO-история остаются. Удаление (wp_delete_post) стирает запись полностью. Для временного скрытия всегда используйте черновик — это безопасно и обратимо за секунду.

Какой метод не требует смены post_status?

Отправка в будущее через post_date. Пост остаётся publish, но WordPress считает его «ещё не наступившим» и не показывает посетителям. Это может быть важно, если другие плагины или сниппеты завязаны на статус publish.

Можно ли снять с публикации сразу несколько постов?

Да, оберните вызов функции в цикл по массиву ID. Добавьте wp_die() или ограничение на количество постов за раз, чтобы не положить сайт при массовой операции: array_slice($post_ids, 0, 50) для батча по 50.

Нужно ли очищать кэш после программной смены статуса?

Обязательно. WordPress сбрасывает внутренний кэш поста при вызове wp_update_post(), но внешний кэш (плагины вроде WP Rocket, серверный кэш, CDN) нужно сбрасывать отдельно. Добавьте вызов wp_cache_flush() или хук clean_post_cache после смены статуса.

Безопасно ли запускать wp_delete_post в продакшене?

Только с предохранителями. Перед вызовом: (1) проверьте current_user_can('delete_posts'), (2) запросите подтверждение через отдельный nonce-токен, (3) логируйте ID и заголовок удаляемого поста. И главное, бэкап. Даже в корзине пост живёт 30 дней, после чего WordPress удаляет его автоматически.

Что использовать в вашем случае: итоговый расклад

Четыре метода закрывают почти любой сценарий программного управления публикациями. Выбор сводится к одному вопросу: нужно ли сохранить пост?

  • Если пост временно скрыть на доработку, берите черновик (draft). Пара строк, ноль риска.
  • Если контент для ограниченного круга лиц, приватный статус (private). Редакторы видят, посетители, нет.
  • Если нужно скрыть пост без смены статуса, будущая дата (post_date в 2050 год). Хитрый, но рабочий приём.
  • Если пост точно не пригодится, удаление (wp_delete_post). Но сначала dry-run и полный бэкап.

Начните с обёртки в functions.php для одного метода, например, черновика. Когда поймёте логику wp_update_post(), остальные три способа соберутся за пять минут.

А каким методом вы пользуетесь для программного управления постами? Напишите в комментариях, интересно сравнить подходы.