Как сделать черновик записи доступным для всех пользователей?

18 июл. 2013 г., 23:14:37
Просмотры: 16.8K
Голосов: 14

У меня есть несколько неопубликованных записей на моем сайте WordPress, и я пытаюсь сделать их доступными для обычных пользователей (не авторизованных) через стандартные ЧПУ-ссылки (site.com/post-here). Я понимаю, что это не лучшая практика, но для моих особых целей это необходимо.

Я пробовал добавить следующий код в файл functions.php:

// Включаем возможность просмотра черновиков
function enable_view_drafts() {
$role = get_role( 'subscriber' ); 
$role->add_cap( 'read_private_posts' ); 
$role->add_cap( 'edit_posts' );
}
add_action( 'after_setup_theme', 'enable_view_drafts');

Также пробовал использовать хук init вместо after_setup_theme. Безрезультатно.

Насколько я понимаю, изменения ролей сохраняются в базе данных и должны выполняться только один раз. Поэтому я использую хук after_setup_theme для вызова функции.

Но когда я пытаюсь открыть страницу как обычный пользователь, вместо содержимого записи отображается ошибка 404. Я также пробовал использовать URL превью (site.com/?p=212&preview=true), но это тоже не сработало.

Мои предположения:

  • обычный пользователь не имеет достаточных прав (caps) для чтения черновиков
  • просмотр черновиков на фронтэнде невозможен для любых пользователей (включая администраторов)

Какие изменения мне нужно внести, чтобы достичь желаемого? Если это невозможно, какие альтернативные решения вы можете предложить?

Примечание: Меня интересуют решения без использования плагинов.

5
Комментарии

Кажется, тут есть небольшая путаница. Если кто-то не авторизован, он не является пользователем, а значит у него нет никаких прав. Подписчики — это пользователи, поэтому они должны быть зарегистрированы и войти в систему, чтобы их распознали как подписчиков. Вы не можете дать права тому, кто не авторизован. Если вы хотите, чтобы незалогиненные пользователи видели ваши записи, они ничем не отличаются от опубликованных. Так почему бы просто не опубликовать их? Или вы хотите показывать черновики подписчикам (авторизованным как подписчики)?

gmazzap gmazzap
3 сент. 2013 г. 03:13:14

@G.M.: Я пытаюсь сделать неопубликованные записи доступными для всех, кто знает прямой пермалинк к записи. Это может показаться странным требованием, но оно нужно для проекта. Как я уже упоминал в вопросе, если это невозможно — можете предложить альтернативные решения (если знаете, конечно)?

Amal Amal
4 нояб. 2013 г. 16:14:09

@G.M.: Знаете ли вы плагин, который это делает?

Amal Amal
4 нояб. 2013 г. 16:26:37

Вы прочитали ответ чуть ниже с 3 голосами? Там объясняется, как это сделать, и в конце ответа вы найдете ссылку для скачивания полностью рабочего плагина с GitHub.

gmazzap gmazzap
4 нояб. 2013 г. 17:04:05

Для тех, кто заглянет позже: есть этот плагин от Dominik Schilling, доступный на GitHub.

kaiser kaiser
27 нояб. 2013 г. 14:32:58
Все ответы на вопрос 5
1
13

Нельзя назначать права неизвестным пользователям. Если вы хотите сделать запись видимой для всех, создайте отдельный URL для таких записей и добавьте элемент управления в редактор записи, чтобы включить предпросмотр только для выбранных записей.
При обращении к такому URL проверяйте, разрешен ли предпросмотр для записи и не была ли запись уже опубликована. Также убедитесь, что поисковые системы игнорируют этот URL.

Для URL я бы использовал эндпоинт:

add_rewrite_endpoint( 'post-preview', EP_ROOT );

Теперь можно создавать URL вида …

http://example.com/post-preview/123

… где 123 — это ID записи.

Затем используйте обработчик обратного вызова для проверки ID записи, его валидности и переопределения основного запроса. Это, вероятно, единственный допустимый случай использования query_posts(). :)

Допустим, эндпоинт — это класс T5_Endpoint (модель), а обработчик вывода — класс T5_Render_Endpoint (представление), которому ранее передавалась модель. Тогда, вероятно, есть метод render(), вызываемый на template_redirect:

public function render()
{
    $post_id = $this->endpoint->get_value();

    if ( ! $post_id )
        return;

    if ( 1 !== $this->meta->get_value( $post_id )
        or 'publish' === get_post_status( $post_id )
        )
    {
        wp_redirect( get_permalink( $post_id ) );
        exit;
    }

    $query = array (
        'suppress_filters' => TRUE,
        'p'                => $post_id,
        'post_type'        => 'any'
    );

    query_posts( $query );

    add_action( 'wp_head', 'wp_no_robots' );
}

$this->meta — это еще одна модель (класс T5_Post_Meta) для мета-значения записи, которое контролирует разрешение предпросмотра. Элемент управления размещается в блоке Publish (действие post_submitbox_misc_actions), отображаемом другим представлением, которое получает тот же мета-класс.

скриншот

Таким образом, T5_Post_Meta знает, где и когда сохранять мета-значение, а представления делают с ним что-то.
Также подключите хук transition_post_status, чтобы удалить мета-поле записи при публикации. Мы же не хотим тратить ресурсы впустую, верно?

Это лишь общий план. Есть множество деталей, которые нужно учесть… Я написал небольшой плагин, демонстрирующий реализацию: T5 Public Preview.

3 окт. 2013 г. 20:05:44
Комментарии

Огромное спасибо. В итоге я достиг своей цели с небольшими доработками. Отлично. :D

Amal Amal
6 нояб. 2013 г. 21:07:45
7

Я решил эту проблему, как мне кажется, более простым способом, чем ответ @toscho выше.

Мой случай использования: я использую одну и ту же базу данных для внутренней интранет-стадии и публичного сайта. Рабочий процесс заключается в том, что авторы пишут черновики и делятся ими с другими пользователями, которые просматривают эти черновики на интранет-сайте, перед публикацией. Я специально не хотел требовать от рецензентов входа в систему для просмотра черновиков, поэтому я просто завишу от константы ENV_PRODUCTION, которая устанавливается в файле wp-config на основе имени хоста в $_SERVER['SERVER_NAME']. Именно для этого здесь нужны проверки на ENV_PRODUCTION — просто отключаем все эти фильтры, если просматривается рабочий сайт.

Это немного странно, потому что приходится подключаться после того, как WP_Query удаляет все записи из массива $wp_query->posts, но мне это кажется стабильным и безопасным.

/*
 * На стадии домашней страницы и архивов черновики должны быть видны.
 */
function show_drafts_in_staging_archives( $query ) {
    if ( ENV_PRODUCTION )
        return;

    if ( is_admin() || is_feed() )
        return;

    $query->set( 'post_status', array( 'publish', 'draft' ) );
}

add_action( 'pre_get_posts', 'show_drafts_in_staging_archives' );


/*
 * Сделать черновики видимыми на стадии при одиночном просмотре.
 *
 * (Потому что при одиночном просмотре WP_Query проверяет, 
 * может ли текущий пользователь редактировать запись, прежде чем показать черновик.)
 */
function show_single_drafts_on_staging( $posts, $wp_query ) {
    if ( ENV_PRODUCTION )
        return $posts;

    // Убеждаемся, что это предпросмотр, чтобы не показывать опубликованные приватные записи
    if ( ! is_preview() )        
        return $posts;

    if ( count( $posts ) )
        return $posts;

    if ( !empty( $wp_query->query['p'] ) ) {
        return array ( get_post( $wp_query->query['p'] ) );
    }
}

add_filter( 'the_posts', 'show_single_drafts_on_staging', 10, 2 );

Здесь два отдельных фильтра:

  • Фильтр на хуке "pre_get_posts" устанавливает post_status по умолчанию в 'publish,draft' для стадии. Это позволит показывать черновики в архивах.
  • Отдельный фильтр нужен для одиночных просмотров, потому что в классе WP_Query есть сложная логика, удаляющая черновики из результатов запроса, если текущий пользователь не может их редактировать. Я обошел это, фильтруя 'the_posts' и добавляя нужную запись обратно в результаты.
10 окт. 2014 г. 23:38:01
Комментарии

Это невероятно, огромное спасибо за то, что поделились этим. Абсолютно идеально и именно то, что мне было нужно.

Christian Christian
4 февр. 2015 г. 08:30:23

Куда вставить этот код? (в какой файл(ы)?)

Joelio Joelio
27 апр. 2015 г. 23:21:51

@Joelio Можете конкретнее описать проблему, которую решаете? В простом варианте я просто добавил этот код в свой functions.php и простое определение в wp-config.php, которое устанавливает константу ENV_PRODUCTION в true или false в зависимости от домена запроса.

goldenapples goldenapples
29 апр. 2015 г. 01:59:09

@goldenapples Я добавил этот кусок кода в свой function.php, что мне нужно добавить в wp-config? Спасибо за помощь

Graham Slick Graham Slick
26 сент. 2015 г. 13:04:04

@MatthiasGrahamSlick - Тебе просто нужно что-то, что будет устанавливать константу ENV_PRODUCTION, если ты на продакшене. Я использовал domain.com для прода и staging.domain.com для стейджинга, так что моя строка была define( 'ENV_PRODUCTION', false === stripos( $_SERVER['HTTP_HOST'], 'staging' ) ); Помогает?

goldenapples goldenapples
28 сент. 2015 г. 15:58:37

@goldenapples где в твоей функции show_single_drafts_on_staging ты контролируешь показ только постов с post_status=draft? Насколько я протестировал твой код, он будет отображать любые посты (даже удаленные) на страницах записей. Или я что-то делаю не так?

Sebastian Sebastian
17 февр. 2016 г. 01:36:25

Это именно то, что мне было нужно для сайта, где незарегистрированные пользователи могут добавлять контент; вторая функция позволила им просматривать превью (убрал проверку на ENV_PRODUCTION)

cogdog cogdog
16 окт. 2019 г. 03:37:37
Показать остальные 2 комментариев
3

Я думаю, плагин "User Role Editor", доступный на сайте WordPress.org, может быть тем, что вам нужно. Кстати, зачем вам открывать доступ к черновикам для всех пользователей? Лично я не могу представить ситуацию, где это было бы необходимо.

19 июл. 2013 г. 04:27:03
Комментарии

Нет, как уже упоминалось в вопросе, я не ищу решения на основе плагинов. Этот случай использования немного сложный, но я уверен, что это лучшее решение для конкретной задачи, которую я пытаюсь выполнить. :-)

Amal Amal
19 июл. 2013 г. 04:32:53

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

KenB KenB
26 июл. 2013 г. 03:11:28

Я разрешаю пользователям видеть контент, но по некоторым особым причинам не хочу, чтобы записи были опубликованы.

Amal Amal
26 июл. 2013 г. 10:20:52
0

Я считаю, что комментарий G.M. здесь лучший. Предполагаю, вы пытаетесь сделать следующее:

  1. Написать пост
  2. Сохранить как черновик
  3. Разрешить внешнему (не авторизованному) пользователю просмотреть черновик для согласования
  4. Опубликовать

Так ли это?

К сожалению, я не могу придумать простого способа сделать это. Вы можете опубликовать его как приватный пост, тогда для просмотра потребуется ввести пароль, но для этого нужно быть авторизованным. Вы также можете защитить его паролем, но тогда он всё равно будет отображаться в вашей ленте и списке последних постов и т.д. Не могли бы вы создать гостевую учётную запись и передать им логин/пароль, когда даёте им URL?

Подробнее читайте здесь: http://codex.wordpress.org/Content_Visibility

Альтернативно, есть плагин, который может подойти для ваших нужд: http://wordpress.org/extend/plugins/shareadraft/ Я бегло просмотрел код, и кажется, разработчик изменяет значение, возвращаемое get_post_status, так что вы можете поэкспериментировать с этим:

http://codex.wordpress.org/Function_Reference/get_post_status

Надеюсь, это поможет.

24 сент. 2013 г. 09:01:57
1
-1

Вы можете просто изменить видимость страницы/записи на "Приватная", что сделает её видимой только для редакторов и администраторов, но не для публичных посетителей, поисковых систем, RSS-лент и т.д.

3 сент. 2013 г. 01:09:25
Комментарии

Это не является жизнеспособным решением для уже опубликованной страницы. Вы можете редактировать текущую живую страницу и сохранять изменения как черновик. Если вы решите использовать этот подход на живой странице, это со временем удалит её из результатов поиска и потенциально может вызвать другие проблемы.

Hunter Nelson Hunter Nelson
13 дек. 2021 г. 17:39:01