Как отключить страницу одиночного просмотра для произвольного типа записи?

5 янв. 2014 г., 16:05:33
Просмотры: 126K
Голосов: 75

Допустим, у нас есть такой произвольный тип записи:

register_post_type(
    'sample_post_type',
    [
        'labels' => [
            'name' => _x('Примеры записей', 'общее название типа записи'),
            'singular_name' => _x('Пример записи', 'единичное название типа записи'),
        ],
        'public' => true,
        'show_in_nav_menus' => false,
        'exclude_from_search' => true,
    ]
);

Как можно отключить просмотр одиночной записи для этого конкретного типа записи? Показ простой 404 ошибки подойдет, или редирект на главную страницу. Поскольку это плагин, я не могу создать файл single-sample_post_type.php для настройки пустой страницы.

0
Все ответы на вопрос 9
4
107

Просто установите аргумент

'publicly_queryable'  => false

при вызове register_post_type()

27 дек. 2014 г. 23:38:13
Комментарии

Это похоже на решение, которое предотвращает создание реальных веб-страниц для вашего CPT, сохраняя при этом все ссылки в базе данных.

Ben Racicot Ben Racicot
17 сент. 2015 г. 21:11:49

Это также скрывает архив.

spaceman spaceman
11 окт. 2016 г. 19:12:19

Это должно быть принятым ответом.

SinisterBeard SinisterBeard
16 мар. 2018 г. 12:26:45

У меня это вызывает перенаправление на главную страницу вместо ошибки 404. Есть идеи, почему так происходит? Я регистрирую post_type с помощью Piklist, если это имеет значение.

emersonthis emersonthis
10 сент. 2018 г. 00:27:17
6
86

Чтобы отключить одиночное отображение (single view) для пользовательского типа записи (CPT), вы можете либо перенаправить пользователей на определенный URL, либо отключить эту возможность при регистрации самого CPT.

МЕТОД 1:

Перенаправление одиночного просмотра CPT на пользовательский URL, при этом архивная страница остается доступной.

Вы можете использовать хук template_redirect для перенаправления пользователя. Вместо home_url() можно указать любой нужный URL, а в качестве второго аргумента — желаемый код ошибки.

<?php
add_action( 'template_redirect', 'wpse_128636_redirect_post' );

function wpse_128636_redirect_post() {
  if ( is_singular( 'sample_post_type' ) ) :
    wp_redirect( home_url(), 301 );
    exit;
  endif;
}
?>

МЕТОД 2:

Полное отключение одиночных и архивных страниц на фронтенде; Работает только для пользовательских типов записей.

Альтернативный подход — установить параметр publicly_queryable в значение false при регистрации пользовательского типа записи.

'publicly_queryable'  => false

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

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

5 янв. 2014 г. 16:12:14
Комментарии

Хорошее решение. Я обнаружил, что полезно выполнять этот редирект только для неаутентифицированных пользователей, проверяя, возвращает ли get_current_user_id() значение 0.

RevNoah RevNoah
29 июн. 2015 г. 16:25:32

Пожалуйста, проверьте ответ от @Gustavo

Richard Richard
18 нояб. 2016 г. 11:17:44

почему бы не использовать просто is_singular('post-type-slug') в условии if() вместо двух условий?

Akash K. Akash K.
22 окт. 2018 г. 23:36:19

@AkashK. Да, это тоже может сработать, не знал об этой функции.

Kumar Kumar
23 окт. 2018 г. 09:26:50

предложение использовать remove_rewrite_tag( '%post-type-slug%' ) - хорошее решение

Pbearne Pbearne
5 мая 2020 г. 01:20:44

Пропущена закрывающая скобка в коде - должно быть...

if ( is_singular( 'sample_post_type' ) )

neilgee neilgee
18 авг. 2020 г. 07:31:26
Показать остальные 1 комментариев
6
17

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

Чтобы архив был доступен и отображал записи, а отдельная запись не была доступна и автоматически перенаправляла на 404, установите

'query_var' => false

при регистрации вашего CPT. Если вы установите publicly_queryable в false, ваши архивы будут перенаправлены на главную страницу, никакие другие комбинации не сработают. Просто установите query_var в false, и всё.

Вот полный код CPT: https://gist.github.com/danyj/bfd038d3c8d578548c4d700bd0a7942a

см. строку 50: https://gist.github.com/danyj/bfd038d3c8d578548c4d700bd0a7942a#file-thz_cpt_items_single_view_redirect-php-L50

Как указано здесь:

https://codex.wordpress.org/Function_Reference/register_post_type

Примечание: Если query_var пуст, null или имеет значение FALSE, WordPress всё равно попытается его интерпретировать (4.2.2), и предпросмотры/просмотры вашего пользовательского типа записи будут возвращать 404 ошибки.

17 нояб. 2018 г. 00:22:57
Комментарии

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

powerbuoy powerbuoy
31 янв. 2019 г. 15:40:15

Привет, я попробовал сделать то же самое, но это не сработало. Несмотря на добавление query_var в false, я всё ещё могу переходить по ссылкам на одиночные страницы. Можешь помочь?

iSaumya iSaumya
13 окт. 2020 г. 15:08:30

@iSaumya попробуй сбросить постоянные ссылки (перейди на страницу постоянных ссылок и сохрани снова) или используй команду wp-cli wp rewrite flush && wp cache flush

thetwopct thetwopct
28 мая 2021 г. 19:23:36

Больше не работает (август 2022). Заметка о том, что одиночные просмотры удалены, также больше не существует в документации.

Blorf Blorf
30 авг. 2022 г. 18:02:34

@blorf заметка всё ещё в документации - она указана в разделе publicly_queryable

rtpHarry rtpHarry
11 сент. 2022 г. 15:54:33

У меня это работает, у меня установлены Elementor с JetEngine, и я настраиваю тип записи с параметрами public, publicly_queryable и has_archive установленными в true, а query_var установлен в false. Мои архивы работают, а одиночные записи перенаправляются (301) на главную страницу.

rtpHarry rtpHarry
11 сент. 2022 г. 15:59:56
Показать остальные 1 комментариев
3
10

Более простой способ сделать это — передать следующие аргументы при регистрации пользовательского типа записи:

register_post_type('sample_post_type',array(
'labels' => array(
    'name' => _x('Пример записей', 'общее название типа записи'),
    'singular_name' => _x('Пример записи', 'название типа записи в единственном числе')
),
'public' => true,
'exclude_from_search' => true,
'show_in_admin_bar'   => false,
'show_in_nav_menus'   => false,
'publicly_queryable'  => false,
'query_var'           => false
));
24 мая 2014 г. 22:01:04
Комментарии

Для работы архивов типа записи необходимо, чтобы параметр publically_querable был установлен в true.

Howdy_McGee Howdy_McGee
12 нояб. 2014 г. 21:42:28

У меня это не работает. При попытке перейти в архив происходит перенаправление на главную страницу.

Yahya Uddin Yahya Uddin
15 июл. 2015 г. 18:51:10

Установка query_var в false отключает только использование query vars в URL, например /?sample_post_type=sample_slug, но не блокирует доступ через /sample_post_type/sample_slug/.

Enchiridion Enchiridion
5 янв. 2021 г. 07:57:12
3

Первый способ. Добавьте в файл functions.php:

add_action( 'template_redirect', 'redirect_cpt_singular_posts' );
    function redirect_cpt_singular_posts() {
      if ( is_singular('your-cpt-slug') ) { // Замените 'your-cpt-slug' на ярлык вашего типа записи
        wp_redirect( home_url(), 302 ); // Перенаправление на главную страницу с кодом 302
        exit;
      }
    }

Второй способ. Добавьте в файл single-cpt.php (замените cpt на ваш тип записи):

<?php wp_redirect( home_url() ); exit; // Перенаправление на главную страницу ?>
24 мая 2014 г. 22:10:43
Комментарии

Мне понравился второй вариант. Но мне нужно знать, есть ли какие-то недостатки у этого второго варианта.

user2584538 user2584538
10 окт. 2017 г. 09:27:08

@user2584538 Если у вас нет кастомного файла single-cpt_name.php, вы не сможете этого сделать. Если поместите функцию в простой файл плагина, вы сможете активировать/деактивировать его без редактирования каких-либо файлов.

Elías Gómez Elías Gómez
5 февр. 2018 г. 12:12:42

Недостаток, вероятно, будет связан с SEO. Для любого из этих ответов я бы рекомендовал добавить следующий мета-тег <meta name="robots" content="none, nosnippet, noarchive" /> на каждой странице, которую вы решили перенаправлять.

amarinediary amarinediary
2 янв. 2021 г. 04:12:57
3

Основываясь на отличном ответе Свена, я переписал его функцию, чтобы упростить добавление нескольких типов записей с использованием in_array() в условии if, а затем перенаправлять на страницу архива вместо главной страницы.

(кстати, я думаю, что установка query_var и/или publically_queryable в false отключит не только одиночные просмотры, но и нативное представление архива, переопределяя 'has_archive' => true. В таком случае вы всё ещё можете настроить custom WP_query и создать свою собственную страницу архива в шаблоне, но основной запрос уже не будет этого делать, верно?)

function fq_disable_single_cpt_views() {
  $queried_post_type = get_query_var('post_type');
  $cpts_without_single_views = array( 'my-post-type', 'my-other-post-type' );
  if ( is_single() && in_array( $queried_post_type, $cpts_without_single_views )  ) {
    wp_redirect( home_url( '/' . $queried_post_type . '/' ), 301 );
    exit;
  }
}

add_action( 'template_redirect', 'fq_disable_single_cpt_views' );
9 июл. 2016 г. 19:27:21
Комментарии

это была хорошая идея, но не работает, если изменить редирект для CPT (пользовательских типов записей)

rudtek rudtek
23 мар. 2020 г. 19:57:53

Я изменил вашу строку wp_redirect на wp_redirect( get_post_type_archive_link( $queried_post_type ), 301 ); работает отлично!

rudtek rudtek
23 мар. 2020 г. 20:06:25

Отлично. Хорошее улучшение.

slashbob slashbob
24 мар. 2020 г. 23:18:25
2

Если вы хотите полностью отключить одиночное представление (single view) пользовательского типа записи на фронтенде, но при этом сохранить возможность отображения архивной страницы, ситуация становится немного сложнее.

Установка параметра publicly_queryable в false или rewrite в false предотвратит отображение как одиночного, так и архивного представления. В аргументах функции register_post_type нет флага, который бы предотвращал создание правил перезаписи только для одиночного представления.

https://github.com/WordPress/WordPress/blob/5.2.3/wp-includes/class-wp-post-type.php#L540

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

/**
 * Регистрация типа записи "Событие"
 */
function wpse_128636_register_event_post_type() {

    $labels = array(
        'name' => __( 'События' ),
        'singular_name' => __( 'Событие' ),
        'add_new' => __( 'Добавить новое' ),
        'add_new_item' => __( 'Добавить новое' ),
        'edit_item' => __( 'Редактировать' ),
        'new_item' => __( 'Новое' ),
        'view_item' => __( 'Просмотр' ),
        'search_items' => __( 'Поиск' ),
        'not_found' => __( 'Не найдено' ),
        'not_found_in_trash' => __( 'События не найдены в корзине' ),
        'parent_item_colon' => __( 'Родительский' ),
        'menu_name' => __( 'События' ),

    );

    $args = array(
        'labels' => $labels,
        'hierarchical' => false,
        'supports' => array( 'title', 'page-attributes' ),
        'public' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'show_in_nav_menus' => true,
        'publicly_queryable' => true,
        'exclude_from_search' => true,
        'has_archive' => true,
        'rewrite' => array('slug' => 'event'),
        'capability_type' => 'post',
    );

    register_post_type( 'event', $args );
    remove_rewrite_tag( '%event%' ); // Эта строка удалит правила перезаписи для одиночного представления событий
}

add_action( 'init', 'wpse_128636_register_event_post_type' );

Дополнительным бонусом является то, что теперь вы можете создавать простые страницы WordPress, используя структуру постоянных ссылок типа записи event (event/prostaya-stranica), что может быть полезно в сложных веб-сайтах.

Не забудьте сбросить правила перезаписи после изменения кода.

25 сент. 2019 г. 12:50:03
Комментарии

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

artist learning to code artist learning to code
12 июн. 2020 г. 23:17:22

У меня это превращает отдельные страницы в 404, но YOAST SEO всё равно добавляет ссылки в свою XML-карту сайта.

Jordan Carter Jordan Carter
23 апр. 2021 г. 20:13:26
0

В WordPress 5.9.0 был добавлен новый фильтр, который позволяет не только отключать одиночную запись (single), но и удалять все ссылки на неё в административной панели.

add_filter( 'is_post_type_viewable', function( $is_viewable, $post_type ) {
    if ( 'sample_post_type' === $post_type->name ) {
        return false;
    }
    return $is_viewable;
}, 10, 2 );

Одиночная запись не будет загружаться, но если ввести URL вручную, вместо 404 ошибки будет загружаться главная страница. Чтобы вместо главной страницы отображалась 404 ошибка, вы можете удалить правило перезаписи после регистрации типа записи.

remove_rewrite_tag( '%sample_post_type%' );

После внесения этих изменений необходимо сбросить правила перезаписи.

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

21 мар. 2022 г. 16:43:57
0

Моё текущее решение (в основном "решение с редиректом") с небольшим отличием в реализации.

Это позволит оставить архивные страницы включенными (has_archive = TRUE)

Но даст возможность включать или отключать одиночные страницы при использовании register_post_type() с параметром x_has_single = TRUE (параметр передается вместе со свойствами объекта типа записи).

add_action( 'init', function() {
    $args = [
        ... // другие переменные
        'public'             => FALSE,
        'publicly_queryable' => TRUE,
        'show_ui'            => TRUE,
        'has_archive'        => 'customers',
        'rewrite'            => [ 'slug' => 'customers', 'with_front' => FALSE ],
        'x_has_single'       => FALSE,
    ];
    register_post_type( 'customers', $args );
} );

add_action( 'template_redirect', function() {
    $post_type = get_post_type() ?: FALSE;
    $post_type_obj = get_post_type_object( $post_type );
    $has_single = $post_type_obj->x_has_single ?? TRUE;
    if ( FALSE === $has_single && $post_type && is_singular( $post_type ) ) {
        wp_redirect( get_post_type_archive_link( $post_type ) ?: '/', 301 );
        exit;
    }
} );
27 сент. 2022 г. 03:57:30