Получить ярлык (slug) произвольного типа записи для страницы архива
Как мне определить ярлык (slug) произвольного типа записи, когда я нахожусь на странице архива?
Например, если /products/
вызывает шаблон archive-products.php
, как (программно) получить ярлык типа записи?
Спасибо

Чтобы получить текущий тип записи, используйте get_post_type()
. Затем запросите get_post_type_object()
для всех необходимых данных, например, для получения ярлыка (slug):
$post_type = get_post_type();
if ( $post_type )
{
$post_type_data = get_post_type_object( $post_type );
$post_type_slug = $post_type_data->rewrite['slug'];
echo $post_type_slug;
}

Думаю (не проверял), что get_queried_object()
получит ту же информацию за меньшее количество действий.

@Rarst Возможно, но мне кажется, что предложенный мной код проще для понимания.

Решение Toscho неверно, потому что get_post_type возвращает тип записи текущей страницы, и, когда вы находитесь на странице архива, эта функция всегда возвращает "page". Я ищу решение для той же проблемы: когда я нахожусь на странице архива 'books' (например), я хочу получить: 'books'. Когда найду решение - опубликую.

к сожалению, это не так просто, хотя вам будет лучше использовать просто $posttype = get_query_var('post_type');
... я добавил более комплексную альтернативу.

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

Я использую этот код вне цикла в шаблоне archive.php, чтобы определить, в каком архиве пользовательских записей я нахожусь.
Это комбинация методов, которые рекомендовали и @toscho, и @Rarst:
$post_type = get_queried_object();
echo $post_type->rewrite['slug'];
Обновление: @majick указал, что это работает только если вы установили rewrite slug для вашего CPT. Rewrite slug является необязательным параметром при регистрации CPT и по умолчанию использует post_type, если не задан.

когда я попробовал это, я получил Notice: Undefined property: stdClass::$rewrite in ***\wp-content\themes\marks-remarks\archive.php on line 4

это будет работать только если rewrite slug установлен для зарегистрированного CPT, так как он является необязательным и по умолчанию использует post_type

Спасибо, что заметили это @majick! Я обновил пост с учётом вашей информации.

Ответы становятся запутанными. И, возможно, я тоже, но главный вопрос:
Получить слаг пользовательского типа записи для архивной страницы
Если вы имеете в виду лендинг-страницу архива типа записи, и когда is_post_type_archive()
возвращает true
, вам нужен слаг, соответствующий текущему просматриваемому архиву:
/* возвращает /products/ */
$responding_name = str_replace(get_home_url(), '', get_post_type_archive_link(get_query_var('post_type')));
/* продолжаем получать 'products' без слэшей */
$responding_name = str_replace('/', '', $responding_name);
-- КОНЕЦ ОТВЕТА НА ВОПРОС --
Объяснение:
Вы не можете полагаться на зарегистрированный слаг. WordPress тоже не может. Например, при вызове get_post_type_archive_link()
WordPress проверяет текущие правила перезаписи для вашей установки.
Где бы вы ни находились — внутри или вне цикла, в текущем архиве или отдельной записи, обратите механизм get_post_type_archive_link()
. (ЧПУ включены.)
Рекомендации:
Как упоминалось здесь, тип(ы) записей в текущем запросе могут быть массивом
. Вы можете пойти дальше в своих намерениях, отфильтровав нужный тип записи, например:
$post_type = get_query_var('post_type');
if(is_array($post_type)) $post_type = reset($post_type);
или
if(isset($post_types[0])) $post_type = $post_types[0];
Другой взгляд:
Пример WooCommerce: зарегистрирован с типом записи 'products', но на самом деле использует переписанное имя правила (shop):
/* возвращает shop */
$responding_name = str_replace('/', '', str_replace(get_home_url(), '', get_post_type_archive_link('product')));
Марк, я использую
$responding_name
, потому что цели могут различаться. Архива записей не существует, это просто URL.

Это очень прояснило ситуацию, спасибо. Как раз искал такое решение. Если бы вопрос не касался только "названия типа записи", этот ответ заслуживал бы голоса.

Следует отметить, что если при регистрации пользовательского типа записи has_archive
установлен в true, архив типа записи /cptslug/
будет внутренне переписан в ?post_type=cptslug
. Это также означает, что is_post_type_archive()
вернет true.
К сожалению, если зарегистрированный слаг перезаписи отличается от типа записи, вы не сможете надежно получить post_type
. Например, если ваш тип записи — myplugin_cars
, а слаг перезаписи — cars
, и вам нужно получить именно myplugin_cars
, то даже этот код (чтобы избежать ошибок, если текущий запрашиваемый объект не является пользовательским типом записи) всё равно не сработает:
$queryobject = get_queried_object();
if (has_property('rewrite',$queryobject)) {
if (isset($queryobject->rewrite['slug'])) {
$posttype = $queryobject->rewrite['slug'];
}
}
Но поскольку is_post_type_archive
возвращает true, этот способ более надежен:
if (is_post_type_archive()) {
$posttype = get_query_var('post_type');
// что по сути то же самое, что:
// global $wp_query;
// $posttype = $wp_query->query_vars['post_type'];
}
else ($posttype = 'post';}
Но подождите, есть ещё кое-что... Оказывается, после небольшого тестирования всё не так просто... Что, если вы находитесь на странице архива таксономии с несколькими типами записей? Или присвоили метки записи пользовательскому типу, отличному от post
? Или находитесь на странице архива автора? Архива по дате? ...или даже используете сложный tax_query
или meta_query
для WP_Query
?
Единственный надежный способ (без проверки всех возможных случаев архива) — это перебрать фактические записи в запросе... Вот полная функция, которую я разработал, чтобы она работала как на отдельных страницах, так и на архивах, позволяя при необходимости передавать пользовательский объект запроса (или объект записи/ID записи для отдельных записей):
function get_current_post_types($object=null) {
// если передано числовое значение, считаем его ID записи
if ( ($object) && (is_numeric($object)) ) {$object = get_post($object);}
// если передан объект, считаем его объектом записи
if ( ($object) && (is_object($object)) ) {return get_post_type($object);}
// стандартные проверки типа записи для отдельных страниц
if (is_404()) {return '';}
// обновление: убрал эту проверку, обрабатывается is_singular
// if (is_single()) {return 'post';}
if (is_page()) {return 'page';}
if (is_attachment()) {return 'attachment';}
if (is_singular()) {return get_post_type();}
// если пользовательский объект запроса не передан, используем глобальный $wp_query
if ( (!$object) || (!is_object($object)) ) {
global $wp_query; $object = $wp_query;
}
if (!is_object($object)) {return '';} // на всякий случай
// если переменная запроса post_type была явно установлена
// (или неявно установлена для CPT через редирект has_archive)
// то есть это верно как минимум для is_post_type_archive
// $vqueriedposttype = get_query_var('post_type'); // только для $wp_query
if (property_exists($object,'query_vars')) {
$posttype = $object->query_vars['post_type'];
if ($posttype) {return $posttype;}
}
// обработка всех остальных случаев путем перебора записей в объекте запроса
$posttypes = array();
if (method_exists($object,'found_posts')) {
if ($object->found_posts > 0) {
$queriedposts = $object->posts;
foreach ($queriedposts as $queriedpost) {
$posttype = $queriedpost->post_type;
if (!in_array($posttype,$posttypes)) {$posttypes[] = $posttype;}
}
if (count($posttypes == 1)) {return $posttypes[0];}
else {return $posttypes;}
}
}
return ''; // ничего не найдено
}
Эта функция надежно (я уже говорил это?) вернет массив типов записей, если их несколько, или строку с одним типом записи, если он единственный. Всё, что вам нужно сделать:
$posttypes = get_current_post_types();
// или передать ID записи
$posttypes = get_current_post_types($postid);
// или передать объект записи
$posttypes = get_current_post_types($post);
// или передать пользовательский запрос, который уже выполнен
$posttypes = get_current_post_types($query);
Пример использования (просто для развлечения):
add_filter('the_posts','myplugin_fading_thumbnails',10,2);
function myplugin_fading_thumbnails($posts,$query) {
if (!is_archive()) {return $posts;}
$cptslug = 'myplugin_slug'; $dosomethingcool = false;
$posttypes = get_current_post_types($query);
if ( (is_array($posttypes)) && (in_array($cptslug,$posttypes)) ) {$dosomethingcool = true;}
elseif ($cptslug == $posttypes) {$dosomethingcool = true;}
if ($dosomethingcool) {
global $fadingthumbnails; $fadingthumbnails = $cptslug;
if (!has_action('wp_footer','myplugin_cpt_script')) {
add_action('wp_footer','myplugin_cpt_script');
}
}
function myplugin_cpt_script() {
global $fadingthumbnails;
echo "<script>var thumbnailclass = 'img.thumbtype-".$fadingthumbnails."';
function fadeoutthumbnails() {jQuery(thumbnailclass).fadeOut(3000,fadeinthumbnails);}
function fadeinthumbnails() {jQuery(thumbnailclass).fadeIn(3000,fadeoutthumbnails);}
jQuery(document).ready(function() {fadeoutthumbnails();});
</script>";
}
return $posts;
}
Чтобы увидеть эффект, измените пользовательский тип записи в коде на post
и добавьте атрибут класса thumbtype-post
к вашим миниатюрам записей...

для этого нужно $queried_object->query_var['post_type'];
, чтобы работало...

Нет. $queried_object->query_var содержит только строку типа записи. Это не объект и не массив. Посмотрите на это изображение: http://prntscr.com/bd58e1

ок, но только если запрошенный объект точно является объектом произвольного типа записи, вы получите другой соответствующий объект и, следовательно, пустое значение для архивных страниц категорий/таксономий/меток/авторов, например. Даже для ?post_type=post
я получаю пустое значение. Сравните с get_query_var('post_type');
