Включить комментирование страницы предварительного просмотра для ожидающих сообщений

Мы находимся в процессе предоставления авторам совместной работы в составе редакционного процесса. Они будут иметь доступ ко всем страницам предварительного просмотра ожидающих сообщений (а не после редактирования страниц).

Я хочу разрешить этим пользователям публиковать обычный комментарий, когда сообщение находится в ожидании post_status .

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

Предисловие

Когда post preview является интерфейсом, форма комментария зависит от того, как тема обрабатывает его. В этом ответе я предполагаю, что форма комментария показана с использованием стандартной функции comment_form() .

Предыдущее предположение недостаточно, на самом деле comment_form , вероятно, является функцией в ядре WordPress с большим количеством перехватов. Для каждой линии есть почти крючок. Так что показано на странице, многое зависит от плагинов или темы, которые могут ее изменить.

После этого использование comment_form для сохранения комментария POST в wp-comment-post.php которое также содержит много перехватов, так что даже если мое решение работает на ванильной установке WP с использованием темы 20 *, я не могу заверить, что это работает также с некоторыми плагинами или настраиваемой темой.

Workflow

Итак, как только мы предполагаем, что вы находитесь в стандартном случае, то, что вы просите, проще, чем связанный Q / A, потому что форма комментария не использует ajax и потому, что есть много крючков, которые могут помочь нам получить желаемый результат (об отрицательной стороне этого пункта в предисловии).

По существу мы должны:

  1. Добавляя поле в форме комментария, когда мы находимся в ожидании предварительного просмотра, таким образом, мы можем распознать комментарий, исходящий из этой формы.
  2. Как только нам нужно сломать проверку безопасности WordPress, чтобы дать комментарий к ожидающему сообщению, хорошая идея заменить эту проверку другим: использование nonce для скрытого поля в точке 1. может быть хорошей идеей.
  3. В качестве дополнительной проверки безопасности, я думаю, это хорошая идея, позволяющая оставлять комментарии только для зарегистрированных пользователей (но, похоже, вы уже разрешаете доступ к просмотру только зарегистрированным пользователям). Вероятно, также ограничить роли – хорошая идея.
  4. Основная часть этого рабочего процесса – это перерыв в проверке, которую делает WordPress для предотвращения комментариев в ожидающих сообщениях и проектах сообщений. Моя идея состоит в том, чтобы просто дразнить WordPress, оставив его в надежде опубликовать наш пост. То, как я это сделаю, можно принять за пример того, почему глобальные переменные следует избегать, чтобы не допустить, чтобы наш код дразнил кого-то.
  5. Последнее, что нам нужно сделать, – перехватить редирект после создания комментария, поскольку стандартная точка перенаправления на стандартную постоянную ссылку, нам нужно указать, что postmink

Код

Прежде всего, давайте создадим функцию, которая добавляет поле nonce в форме комментария, только для разрешенных пользователей и только в post preview. Я также напишу функцию, чтобы проверить, является ли текущий пользователь одним из разрешенных, таким образом я могу использовать его для других областей. В этой функции я помещаю специальный крючок фильтра, таким образом, роли alloewd могут быть изменены.

 /** * Return true if user can comment on post preview */ function is_a_preview_commenter() { // change this roles according to your needs $roles = array('administrator', 'editor', 'author', 'contributor'); $allowed_roles = apply_filters('preview_comment_allowed_roles', $roles); $user = wp_get_current_user(); $inrole = array_intersect($user->roles, $allowed_roles); return ! empty( $inrole ); } /** * Add a nonce field for comment form in post preview for allowed users */ function additional_comment_fields() { if ( is_preview() && is_a_preview_commenter() ) { $nonce = wp_create_nonce('comment_preview'); echo '<input type="hidden" name="check_the_preview" value="' . $nonce . '" />'; } } add_action( 'comment_form_logged_in_after', 'additional_comment_fields'); 

Теперь давайте дразнить WordPress. Способ WP, используемый для проверки того, хорошо ли комментируется статус сообщения, заключается в вызове $status_obj = get_post_status_object($status) (где $status – это поле post_status комментария, которое будет прокомментировано), затем проверьте, является ли $status_obj private или public wp_die . Но единственное, что делает get_post_status_object , это вернуть значение из глобального массива $wp_post_statuses (тот, который $wp_post_statuses с запрошенным статусом сообщения). Подделка глобальной переменной означает фальсификацию get_post_status_object а также фальсификацию проверки WordPress.

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

 /** * On 'wp_loaded', when the current page is wp-comments-post.php, check if the request * comes from post preview, if so and also the current user is allowed replace * $GLOBALS['wp_post_statuses']['pending'] with $GLOBALS['wp_post_statuses']['publish'] */ function fake_public_pending() { global $pagenow; if ( $pagenow === 'wp-comments-post.php' && is_a_preview_commenter() ) { $nonce = filter_input(INPUT_POST, 'check_the_preview', FILTER_SANITIZE_STRING); if ( empty($nonce) || ! wp_verify_nonce($nonce, 'comment_preview') ) return; global $wp_post_statuses; // let WordPress believe all pending posts are published post $wp_post_statuses['pending'] = $wp_post_statuses['publish']; } } add_action('wp_loaded', 'fake_public_pending'); 

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

 /** * After a comment is inserted, redirect page to post preview when request come from * post preview. Also check if current user role is one of the allowed */ function redirect_to_preview( $comment, $user ) { if ( ! is_a_preview_commenter() ) return; $nonce = filter_input(INPUT_POST, 'check_the_preview', FILTER_SANITIZE_STRING); if ( empty($nonce) || ! wp_verify_nonce($nonce, 'comment_preview') ) return; $link = get_permalink($comment->comment_post_ID); $url = add_query_arg( array('preview' => 'true'), $link ); wp_safe_redirect("{$url}#comment-{$comment->comment_ID}", 302); exit(); } add_action('set_comment_cookies', 'redirect_to_preview', 9999, 2 );