Скрытие постов от незарегистрированных пользователей

Вопрос или проблема

Я хочу скрыть определенные посты от всех, кто не авторизован. Я пробовал плагин Restrict Content (RC), но он лишь скрывал содержимое постов, я хочу полностью исключить пост.

Используя RC как основу, я пробовал следующее:

function hideFromUnknownUsers($postObject) {
    $rcUserLevel = get_post_meta ( $postObject->ID, 'rcUserLevel', true );

    if(have_posts())
    {
        if (!(
                !current_user_can ( 'read' ) &&
                (
                    $rcUserLevel == 'Administrator' ||
                    $rcUserLevel == 'Editor' ||
                    $rcUserLevel == 'Author' ||
                    $rcUserLevel == 'Contributor' ||
                    $rcUserLevel == 'Subscriber'
                )
            )) {
            the_post();
        }
    }
}

add_action ( 'the_post', 'hideFromUnknownUsers' );

У этого подхода есть системный недостаток. Последний пост нельзя игнорировать. Однако я могу с этим смириться на данный момент. Еще одна проблема в том, что это вызывает бесконечный цикл, повторяя одни и те же посты снова и снова. Я обнаружил, что это происходит из-за того, что have_posts() не только сообщает нам о том, что достигнут конец последнего поста, но и имеет побочный эффект, что счетчик постов также сбрасывается, что мешает моему основному циклу достигнуть конца. Создание have_posts(), которое было бы ненавязчивым, оказалось сложным, поскольку я не смог понять, как получить доступ к $wp_query->current_post и $wp_query->post_count из плагина.

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

Есть ли другой способ скрыть определенные посты от неизвестных пользователей?

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

Следующее ограничит все посты, запрашиваемые для незарегистрированных посетителей, теми, которые либо не имеют связанных метаданных hide_from_guests, либо имеют эти метаданные, установленные на 'false':

function wpse225120_hide_posts_from_guests( $query ) {
  // Если пользователь авторизован, выходите из функции сейчас.
  if( is_user_logged_in() )
    return;

  // Получите текущий мета-запрос, чтобы мы могли его изменить, а не перезаписать
  $meta_query = $query->get( 'meta_query' );

  // Создайте мета-запрос, фильтрующий скрытые посты
  $hidden_meta_query = array(
    'relation' => 'OR',
    array(
      'key'     => 'hide_from_guests',
      'value'   => 'false'
    ),
    array(
      'key'     => 'hide_from_guests',
      'compare' => 'NOT_EXISTS'
    ) 
  );

  // Если мета-запроса еще нет, предоставьте один для скрытых постов и выходите
  if( ! is_array( $meta_query ) || empty( $meta_query ) ) {
    $query->set( 'meta_query', $hidden_meta_query );
    return;
  }

  // Если существует существующий мета-запрос, измените его, чтобы поддерживать наш новый мета-запрос скрытых постов
  // как основное условие 'AND', если это необходимо
  if( isset( $meta_query[ 'relation' ] ) && 'OR' === $meta_query[ 'relation' ] )
    $meta_query = array(
      'relation'  => 'AND',
      $meta_query
    );
  }

  // Добавьте мета-запрос скрытых постов и перезапишите старый мета-запрос $query
  $meta_query[] = $hidden_meta_query;
  $query->set( 'meta_query', $meta_query );
}
add_action( 'pre_get_posts', 'wpse225120_hide_posts_from_guests' );

Примечание о том, что глобальное изменение каждого запроса таким образом обычно считается плохой практикой. Если возможно, используйте is_main_query() и другие условные теги, чтобы ограничить изменения запросов только релевантными запросами, чтобы предотвратить неожиданные поведения и влияние на производительность.

Метаданные постов 'hide_from_guests' могут быть установлены на индивидульные посты с помощью интерфейса пользовательских полей, функций метаданных постов или реализуя пользовательский метабокс и прикрепляя его к соответствующим типам постов, среди прочих способов.

Используйте этот код в файле functions.php вашей дочерней темы.

// Скрыть для незарегистрированных пользователей (публичные посетители)
function bp_logged_out_page_template_redirect() {
    if( ! is_user_logged_in() && 
        is_page( 'members' )|| 
        is_page( 'activity' ) || 
        bp_is_user() 
    ) { 
        wp_redirect( home_url( '/register/' ) ); exit();
    }
} 
add_action( 'template_redirect', 'bp_logged_out_page_template_redirect' );

Вышеуказанный фрагмент сделает следующее:

ЕСЛИ пользователь не авторизован..
И имя страницы — ‘members’ ИЛИ ‘activity’ ИЛИ bp-profile-page..
ТОГДА он будет перенаправлен на страницу РЕГИСТРАЦИИ.

Ответ или решение

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

Подходы к решению задачи

  1. Использование плагина Restrict Content (RC):
    Вы уже использовали плагин RC, однако его возможности ограничиваются лишь скрытием содержимого постов, но не полной их омиссией. Это может быть недостаточно для ваших требований, так как посты продолжат отображаться в списках, просто не будут видны незарегистрированным пользователям.

  2. Метаданные постов и использование pre_get_posts:
    Оптимальным решением будет использование метаданных для пометки постов, которые необходимо скрыть. Для этого можно применить хук pre_get_posts, чтобы изменять запросы на выборку постов в зависимости от статуса пользователя.

    Пример кода, который скрывает посты с метаданными hide_from_guests, устанавливаемым на ‘true’:

    function wpse225120_hide_posts_from_guests( $query ) {
       if( is_user_logged_in() ) {
           return; // Если пользователь залогинен, ничего не меняем
       }
    
       // Получаем текущие метаданные
       $meta_query = $query->get( 'meta_query' );
    
       // Создаем новый мета-запрос для фильтрации скрытых постов
       $hidden_meta_query = array(
           'relation' => 'OR',
           array(
               'key'     => 'hide_from_guests',
               'value'   => 'false'
           ),
           array(
               'key'     => 'hide_from_guests',
               'compare' => 'NOT EXISTS'
           ) 
       );
    
       if( ! is_array( $meta_query ) || empty( $meta_query ) ) {
           $query->set( 'meta_query', $hidden_meta_query );
           return;
       }
    
       // Модификация существующего мета-запроса
       if( isset( $meta_query['relation'] ) && 'OR' === $meta_query['relation'] ) {
           $meta_query = array(
               'relation'  => 'AND',
               $meta_query
           );
       }
    
       $meta_query[] = $hidden_meta_query;
       $query->set( 'meta_query', $meta_query );
    }
    add_action( 'pre_get_posts', 'wpse225120_hide_posts_from_guests' );

    Данная реализация работает таким образом, что если пользователь не авторизован, то выполняется запрос метаданных, отбирающий только те посты, которые не помечены как скрытые.

  3. Изменение тем и адаптация кода:
    Если вы хотите изменить видимость на уровне вывода постов в отдельных шаблонах, вам также следует учитывать изменения в темах, чтобы обеспечить четкость и последовательность. Использование функции is_main_query() позволит вам избежать непреднамеренного изменения всех запросов.

  4. Редиректы для незарегистрированных пользователей:
    Также может иметь смысл сделать редирект для незарегистрированных пользователей на страницу регистрации или другую целевую страницу, если они попытаются получить доступ к защищенному контенту. Пример кода:

    function bp_logged_out_page_template_redirect() {
       if( ! is_user_logged_in() && ( is_page( 'members' ) || is_page( 'activity' ) || bp_is_user() ) ) { 
           wp_redirect( home_url( '/register/' ) ); 
           exit();
       }
    } 
    add_action( 'template_redirect', 'bp_logged_out_page_template_redirect' );

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

Рекомендации по реализации

  • Тестирование: После внесения изменений важно протестировать их на предмет корректной работы как для зарегистрированных, так и для незарегистрированных пользователей.

  • Производительность: Старайтесь минимизировать изменения в глобальных запросах, чтобы не влиять на производительность вашего сайта.

  • Документация: Не забывайте документировать ваши изменения, чтобы в будущем подобные задачи можно было выполнять легче и быстрее.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...