¿Cómo obtengo el slug de la página actual?
Estoy intentando obtener el slug de la página actual de WordPress fuera del loop. El título de la página se obtiene con wp_title()
, pero ¿cómo puedo obtener el slug?
<li>
<a href="/slug-de-pagina-actual/">
<?php wp_title('', true); ?>
</a>
</li>

Utiliza la variable global $post
:
<?php
global $post;
$post_slug = $post->post_name;
?>

Gracias. Tu solución funciona muy bien. Solo necesitas hacer echo del slug: <?php
global $post;
$post_slug=$post->post_name; echo $post_slug;
?>

Como dijo sarytash, necesitas usar echo
. Entonces, esto sería lo ideal: <?php global $post; echo $post->post_name; ?>

¿Qué hay de $WP_Post
?

No funcionará si estás, por ejemplo, en yourpage.com/search si esta no es una página existente sino una reescritura desde ?s=

¿no es post_name el título legible por humanos (incluyendo espacios en blanco) en lugar del slug?

Como se indica en otras respuestas, el slug se almacena en la propiedad post_name
. Si bien se podría acceder directamente, prefiero la función (poco utilizada) get_post_field()
para acceder a las propiedades de la entrada que no tienen una API específica para ellas.
Requiere que la entrada se proporcione explícitamente y no toma por defecto la entrada actual, así que para la entrada actual sería así:
$slug = get_post_field( 'post_name', get_post() );

Vale la pena señalar que si estás dentro del loop puedes usar get_post_field
sin el segundo argumento (documentación)

Pequeña nota: He estado usando este método en aproximadamente 8 sitios web diferentes con mi plugin, pero falló al recuperar el slug de página correcto en el último sitio web donde instalé el plugin. Los temas u otros plugins probablemente alteraron la referencia correcta al objeto $post, resultando en el slug incorrecto del post. De todos modos, la respuesta de @Pieter Goosen solucionó este problema para mí: https://wordpress.stackexchange.com/a/188945/150100

Es probablemente obvio, pero también quiero agregar que el segundo argumento puede ser un ID de entrada también.

¡sí, esta o la respuesta de Pieter debajo debería ser la respuesta aceptada! ¿por qué? ... si globalizas $post en una función y luego inadvertidamente le asignas un valor... acabas de sobrescribir el $post global que podría romper el código subsiguiente... es mejor usar este ejemplo o get_queried_object()->post_name

EDICIÓN 5 ABRIL 2016
Después de investigar más sobre la fiabilidad, terminé haciendo esta respuesta a la siguiente publicación que lleva a esta edición: (Asegúrate de revisarla)
El método más fiable hasta la fecha que pude encontrar es el siguiente:
// Obtener el objeto consultado y limpiarlo
$current_page = sanitize_post( $GLOBALS['wp_the_query']->get_queried_object() );
// Obtener el slug de la página
$slug = $current_page->post_name;
De esta manera, tienes un 99.9999% de seguridad de obtener los datos correctos cada vez.
RESPUESTA ORIGINAL
Otra alternativa más segura para este problema es usar get_queried_object()
que contiene el objeto consultado actual para obtener el slug de la página que está contenido en la propiedad post_name
. Esto se puede usar en cualquier parte de tu plantilla.
Se puede usar $post
, pero puede no ser fiable ya que cualquier consulta personalizada o código personalizado puede cambiar el valor de $post
, por lo que debe evitarse fuera del loop.
Usar get_queried_object()
para obtener el objeto de la página actual es mucho más fiable y es menos probable que se modifique, a menos que estés usando el malvado query_posts
que rompe el objeto de consulta principal, pero eso ya depende de ti.
Puedes usar lo anterior de la siguiente manera
if ( is_page() )
$slug = get_queried_object()->post_name;

esto depende de la configuración de los enlaces permanentes. Si usas la configuración "simple", los enlaces se verán como http://domain/?p=123
, dejándote con ?p=123
.

@Mene es cierto, pero la pregunta es cómo obtener el slug que, usualmente, significa que hay uno en la url (el argumento GET p
no es un slug).

Dado el ejemplo de código, parece que lo que realmente necesitas es un enlace. En ese caso, puedes usar get_permalink(), que se puede utilizar fuera del bucle. Esto debería hacer lo que necesitas de manera más confiable que usar el slug del post.

Puede que sea una pregunta antigua, pero creé las funciones get_the_slug() y the_slug() basadas en sus respuestas.
if ( !function_exists("get_the_slug") ) {
/**
* Devuelve el slug de la página o entrada.
*
* @param int|WP_Post|null $id (Opcional) ID de la entrada o objeto post. Por defecto usa la variable global $post.
* @return string
*/
function get_the_slug( $id = null ){
$post = get_post($id);
if( !empty($post) ) return $post->post_name;
return ''; // No hay variable global $post o ID correspondiente disponible.
}
/**
* Muestra el slug de la página o entrada
*
* Utiliza get_the_slug() y aplica el filtro 'the_slug'.
*
* @param int|WP_Post|null $id (Opcional) ID de la entrada o objeto post. Por defecto usa la variable global $post.
*/
function the_slug( $id=null ){
echo apply_filters( 'the_slug', get_the_slug($id) );
}
}

Puedes simplemente separar el slug de la solicitud.
global $wp;
// Como los slugs por sí mismos no pueden contener barras diagonales,
// vamos a separar por barras y obtener solo la última parte.
$request_args = explode('/', $wp->request);
$current_slug = end($request_args);
// Dada la URL https://example.com/foo/bar/foo-bar
if ($current_slug === 'foo-bar') {
// la condición coincidirá.
}
Esto funciona para todas las entradas, páginas y rutas personalizadas.

Esta es la función a utilizar cuando se desea obtener el slug fuera del loop.
get_post_field( 'post_name');
Respuesta encontrada aquí: ¿Cómo obtener el slug de la página actual en WordPress?

Si deseas una respuesta más detallada del funcionamiento interno, puedes usar la siguiente consulta SQL para obtener todas las entradas que son posts, páginas o taxonomías personalizadas en cualquier momento, incluso si no se han activado hooks hasta el momento.
SQL en bruto:
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`;
Esto funciona incluso en la primera línea de tu archivo functions.php, incluso antes de los hooks mu_plugins_loaded
o init
.
@nota
Esto asume que tienes un prefijo de base de datos estándar wp_posts
. Si necesitas tener en cuenta prefijos variables, puedes obtener la tabla de posts correcta a través de PHP fácilmente haciendo lo siguiente:
<?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`;"
Luego ejecuta con $wpdb
, mysqli
, o una instancia de PDO
. Como no hay entrada de usuario en esta consulta, es seguro ejecutarla sin una declaración preparada siempre que no inyectes ninguna variable en ella.
Sugiero almacenar esto como un valor estático privado de una clase, para que se pueda acceder sin tener que ejecutar la consulta más de una vez por página para un mejor rendimiento, algo como esto:
class Post_Cache
{
private static $post_cache;
public function __construct()
{
//De esta manera se omite la operación si ya está establecida
$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 ) )
{
//devuelve el valor específico de la columna para el id
return self::$post_cache[$id][$type];
}
//devuelve la fila completa
return self::$post_cache[$id];
}
private function initCache()
{
if ( is_null(self::$post_cache) )
{
$query = "...";
$result = some_query_method($query); //Realiza tu lógica de consulta aquí
self::$post_cache = $result;
{
}
}
Uso
$cache = new \Post_Cache();
//Obtener el slug de la página
$slug = $cache->get( get_the_ID(), 'slug');
if ($cache->get( get_the_ID() ))
{
//la entrada existe
} else {
//no existe, mostrar 404
}
if ( $cache->get( get_the_ID(), 'status') === 'publish' )
{
//es público
} else {
//verificar current_user_can('whatever_permission') o simplemente mostrar 404,
//dependiendo si quieres que sea visible para el usuario actual o no
}
if ( $cache->get( get_the_ID(), 'type') === 'post' )
{
//Es una entrada
}
if ( $cache->get( get_the_ID(), 'type') === 'page' )
{
//Es una página
}
Ya entiendes la idea. Si necesitas más detalles, puedes obtenerlos normalmente con new \WP_Post( get_the_ID() );
Esto te permitirá verificar las entradas en cualquier momento, incluso si el bucle de WordPress no ha llegado a un punto donde encuentre tu solicitud aceptable. Esta es una versión ligeramente más optimizada de la misma consulta ejecutada por el núcleo de WordPress. Esta filtra todo el contenido innecesario que no querrías que se devolviera, y te da una lista bien organizada con el ID del autor relevante, tipo de entrada, slug y visibilidad. Si necesitas más detalles, puedes obtenerlos normalmente con new \WP_Post($id);
, o usar cualquiera de las otras funciones nativas de WordPress con cualquiera de las filas de tabla relevantes, incluso fuera del bucle.
Uso una configuración similar en algunos de mis propios temas y plugins personalizados, y funciona muy bien. También es seguro y no deja datos internos flotando en el ámbito global donde pueden ser sobrescritos como lo hace la mayoría de las cosas en WordPress.

Si estás dentro del bucle entonces las otras respuestas te ayudarán.
Si no lo estás (por ejemplo, si estás usando los hooks init
o plugins_loaded
) puedes recurrir a una función primitiva de PHP como parse_url()
.
Aquí hay una función que funciona en ambos casos:
function get_the_slug() {
global $post;
// Intentamos obtener el slug del post actual
$slug = $post->post_name ?? '';
// Si no hay slug, lo extraemos de la URL
if ( ! $slug ) {
$slug = basename( parse_url( $_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH ) );
}
return $slug;
}
Ten en cuenta que este enfoque solo funciona en entradas/páginas en el nivel raíz, debido a cómo funciona basename()
.

Siguiendo la respuesta de @Matthew Boynes, si estás interesado en obtener también el slug del padre (si existe), he encontrado útil esta función:
// Función para obtener los slugs incluyendo el padre
function mytheme_get_slugs() {
if ( $link = get_permalink() ) {
// Remueve la URL base del sitio
$link = str_replace( home_url( '/' ), '', $link );
// Verifica si hay una barra al final y la elimina
if ( ( $len = strlen( $link ) ) > 0 && $link[$len - 1] == '/' ) {
$link = substr( $link, 0, -1 );
}
// Divide la URL en segmentos por las barras
return explode( '/', $link );
}
return false;
}
Por ejemplo, para agregar el/los slug(s) a la clase del body:
// Función para añadir los slugs a las clases del body
function mytheme_body_class( $classes ) {
if ( $slugs = mytheme_get_slugs() ) {
// Combina las clases existentes con los slugs
$classes = array_merge( $classes, $slugs );
}
return $classes;
}
add_filter( 'body_class', 'mytheme_body_class' );
