Как получить slug текущей страницы?
Я пытаюсь получить slug текущей страницы WordPress вне цикла. Заголовок страницы возвращается с помощью wp_title()
, но как получить slug?
<li>
<a href="/slug-текущей-страницы/">
<?php wp_title('', true); ?>
</a>
</li>

Используйте глобальную переменную $post
:
<?php
global $post;
$post_slug = $post->post_name;
?>

Спасибо. Ваше решение отлично работает. Просто нужно вывести slug: <?php
global $post;
$post_slug=$post->post_name; echo $post_slug;
?>

Как сказал sarytash, вам нужно использовать echo
. Таким образом, идеальный вариант будет: <?php global $post; echo $post->post_name; ?>

А как насчет $WP_Post
?

Не будет работать, если вы, скажем, находитесь на yourpage.com/search, если это не существующая страница, а результат преобразования из ?s=

разве post_name это не читаемый человеком заголовок (включая пробелы), а не слаг?

Как указано в других ответах, слаг хранится в свойстве post_name
. Хотя к нему можно получить прямой доступ, я предпочитаю (редко используемую) функцию get_post_field()
для доступа к свойствам поста, для которых нет специального API.
Она требует явного указания поста и не использует текущий пост по умолчанию, поэтому для получения слага текущего поста полный код будет таким:
$slug = get_post_field( 'post_name', get_post() );
// Получаем значение поля post_name (слаг) для текущего поста

Стоит отметить, что если вы находитесь внутри цикла, вы можете использовать get_post_field
без второго аргумента (документация)

Небольшое примечание: Я использовал этот метод примерно на 8 разных сайтах с моим плагином, но на последнем сайте, где я установил плагин, не удалось получить правильный slug страницы. Вероятно, темы или другие плагины нарушили правильную ссылку на объект $post, что привело к получению неправильного slug'а записи. В любом случае, ответ @Pieter Goosen решил эту проблему для меня: https://wordpress.stackexchange.com/a/188945/150100

Вероятно, это очевидно, но также хочу добавить, что вторым аргументом может быть ID записи.

да, этот ответ или ответ Pieter ниже должен быть принят как правильный! почему? ... если вы глобализируете $post в функции и затем случайно присваиваете ему значение... вы только что перезаписали глобальный $post, что может нарушить последующий код... лучше использовать этот пример или get_queried_object()->post_name

ПРАВКА 5 АПРЕЛЯ 2016
После поиска более надежного решения, я пришел к этому ответу в следующей публикации, что привело к этой правке: (Обязательно ознакомьтесь)
Самый надежный метод на сегодняшний день, который я смог найти:
// Получаем объект запроса и очищаем его
$current_page = sanitize_post( $GLOBALS['wp_the_query']->get_queried_object() );
// Получаем ярлык страницы
$slug = $current_page->post_name;
Таким образом, вы можете быть уверены на 99.9999%, что получите правильные данные каждый раз.
ИСХОДНЫЙ ОТВЕТ
Другой более безопасной альтернативой для этой задачи является использование get_queried_object()
, который содержит текущий запрашиваемый объект, чтобы получить ярлык страницы, который хранится в свойстве post_name
. Это можно использовать в любом месте вашего шаблона.
Можно использовать $post
, но это может быть ненадежно, так как любой пользовательский запрос или пользовательский код может изменить значение $post
, поэтому этого следует избегать за пределами цикла.
Использование get_queried_object()
для получения объекта текущей страницы гораздо надежнее и с меньшей вероятностью будет изменено, если только вы не используете вредоносный query_posts
, который нарушает основной объект запроса, но это уже зависит от вас.
Вы можете использовать вышеуказанное следующим образом
if ( is_page() )
$slug = get_queried_object()->post_name;

это зависит от настроек постоянных ссылок. Если вы используете "простые" настройки, ссылки будут выглядеть как http://domain/?p=123
, оставляя вам ?p=123
.

@Mene верно, но вопрос в том, как получить ЧПУ (slug), что обычно означает его наличие в URL (GET параметр p
не является ЧПУ).

Судя по примеру кода, то, что вам действительно нужно - это ссылка. В этом случае вы можете использовать get_permalink(), который можно использовать вне цикла. Это должно сделать то, что вам нужно, более надежным способом, чем использование ярлыка записи.

Возможно, это старый вопрос, но я создал функции get_the_slug() и the_slug() на основе ваших ответов.
if ( !function_exists("get_the_slug") ) {
/**
* Возвращает ЧПУ (slug) страницы или записи.
*
* @param int|WP_Post|null $id (Опционально) ID записи или объект записи. По умолчанию глобальная переменная $post.
* @return string
*/
function get_the_slug( $id = null ){
$post = get_post($id);
if( !empty($post) ) return $post->post_name;
return ''; // Глобальная переменная $post или соответствующий ID недоступны.
}
/**
* Отображает ЧПУ (slug) страницы или записи
*
* Использует get_the_slug() и применяет фильтр 'the_slug'.
*
* @param int|WP_Post|null $id (Опционально) ID записи или объект записи. По умолчанию глобальная переменная $post.
*/
function the_slug( $id=null ){
echo apply_filters( 'the_slug', get_the_slug($id) );
}
}

Вы можете просто разделить слаг из запроса.
global $wp;
// Поскольку сами слаги не могут содержать слэши,
// давайте разделим по слэшам и возьмем только последнюю часть.
$request_args = explode('/', $wp->request);
$current_slug = end($request_args);
// При URL вида https://example.com/foo/bar/foo-bar
if ($current_slug === 'foo-bar') {
// условие будет выполнено.
}
Это работает для всех записей, страниц и пользовательских маршрутов.

Это функция, которая используется для получения ярлыка (slug) вне цикла.
get_post_field( 'post_name');
Ответ найден здесь: Как получить ярлык текущей страницы в WordPress?

Если вам нужен более детальный ответ, вы можете использовать следующий SQL-запрос для получения всех записей, которые являются либо постами, страницами или пользовательскими таксономиями в любое время, даже если никакие хуки еще не сработали.
Чистый SQL:
SELECT `id`, `post_type` AS `type`, `post_author` AS `author`, `post_name` AS
`slug`, `post_status` AS `status`
FROM wp_posts
WHERE `post_type` NOT IN ('attachment', 'nav_menu_item', 'revision')
AND `post_status` NOT IN ('draft', 'trash')
ORDER BY `id`;
Это работает даже в самой первой строке вашего файла functions.php, еще до срабатывания хуков mu_plugins_loaded
или init
.
@примечание
Это предполагает, что у вас стандартный префикс базы данных wp_posts
. Если вам нужно учитывать переменные префиксы, вы можете легко получить правильную таблицу постов через PHP следующим образом:
<?php
global $wpdb;
$table = $wpdb->posts;
$query = "SELECT `id`, `post_type` AS `type`, `post_author` AS `author`, `post_name` AS
`slug`, `post_status` AS `status`
FROM " . $table . "
WHERE `post_type` NOT IN ('attachment', 'nav_menu_item', 'revision')
AND `post_status` NOT IN ('draft', 'trash')
ORDER BY `id`;"
Затем выполните запрос с помощью $wpdb
, mysqli
или экземпляра PDO
. Поскольку в этом запросе нет пользовательского ввода, его безопасно выполнять без подготовленного выражения, если вы не внедряете в него какие-либо переменные.
Я бы предложил сохранить это как приватное статическое значение класса, чтобы к нему можно было получить доступ без необходимости повторного выполнения запроса более одного раза на страницу для лучшей производительности, примерно так:
class Post_Cache
{
private static $post_cache;
public function __construct()
{
//Таким образом он пропускает операцию, если она уже установлена
$this->initCache();
}
public function get($id, $type = null)
{
if ( !(is_int( $id ) && array_key_exists( $id, self::$post_cache ) ) )
return false;
}
if ( !is_null( $type ) )
{
//возвращает определенное значение столбца для id
return self::$post_cache[$id][$type];
}
//возвращает всю строку
return self::$post_cache[$id];
}
private function initCache()
{
if ( is_null(self::$post_cache) )
{
$query = "...";
$result = some_query_method($query); //Здесь выполняется логика вашего запроса
self::$post_cache = $result;
{
}
}
Использование
$cache = new \Post_Cache();
//Получить слаг страницы
$slug = $cache->get( get_the_ID(), 'slug');
if ($cache->get( get_the_ID() ))
{
//запись существует
} else {
//нет, показать 404
}
if ( $cache->get( get_the_ID(), 'status') === 'publish' )
{
//она опубликована
} else {
//либо проверить current_user_can('whatever_permission'), либо просто показать 404,
//в зависимости от того, хотите ли вы, чтобы она была видна текущему пользователю или нет
}
if ( $cache->get( get_the_ID(), 'type') === 'post' )
{
//Это запись
}
if ( $cache->get( get_the_ID(), 'type') === 'page' )
{
//Это страница
}
Вы поняли суть. Если вам нужны дополнительные детали, вы можете получить их как обычно с помощью new \WP_Post( get_the_ID() );
Это позволит вам проверять записи в любое время, даже если цикл WordPress еще не достиг точки, где он находит ваш запрос приемлемым. Это немного более оптимизированная версия того же запроса, выполняемого ядром WordPress. Этот запрос отфильтровывает весь ненужный материал, который вы не хотели бы получить, и просто дает вам аккуратно организованный список с соответствующим ID автора, типом записи, слагом и видимостью. Если вам нужны дополнительные детали, вы можете получить их как обычно с помощью new \WP_Post($id);
или использовать любые другие нативные функции WordPress с любыми соответствующими строками таблицы, даже вне цикла.
Я использую подобную настройку в нескольких своих собственных темах и плагинах, и это работает отлично. Это также безопасно и не оставляет внутренние данные плавающими в глобальной области видимости, где они могут быть переопределены, как это делает большинство вещей в WordPress.

Если вы находитесь внутри цикла WordPress, то другие ответы вам помогут.
Если нет (например, вы используете хуки init
или plugins_loaded
), вы можете прибегнуть к стандартной функции PHP parse_url()
.
Вот функция, которая работает в обоих случаях:
function get_the_slug() {
global $post;
$slug = $post->post_name ?? '';
if ( ! $slug ) {
$slug = basename( parse_url( $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH ) );
}
return $slug;
}
Обратите внимание, что этот подход работает только для записей/страниц корневого уровня из-за особенностей работы функции basename()
.

В дополнение к ответу @Matthew Boynes, если вы также хотите получить родительский slug (при наличии), я нашел эту полезную функцию:
function mytheme_get_slugs() {
if ( $link = get_permalink() ) {
$link = str_replace( home_url( '/' ), '', $link );
if ( ( $len = strlen( $link ) ) > 0 && $link[$len - 1] == '/' ) {
$link = substr( $link, 0, -1 );
}
return explode( '/', $link );
}
return false;
}
Например, чтобы добавить slug(и) к классу body:
function mytheme_body_class( $classes ) {
if ( $slugs = mytheme_get_slugs() ) {
$classes = array_merge( $classes, $slugs );
}
return $classes;
}
add_filter( 'body_class', 'mytheme_body_class' );
