Necesito ayuda con add_rewrite_rule
SOLUCIÓN
He optado por la Actualización 3 y lo he conseguido hacer funcionar. Lo que había malinterpretado era que creía que una regla de reescritura cambiaría designers/?designer=some-designer&bid=9
a /designers/some-designer
. Pero es al revés, por supuesto.
He estado investigando, pero no entiendo bien cómo usar add_rewrite_rule().
Esta publicación es bastante cercana a lo que necesito, pero ¿realmente necesito tanto código?
Mi enlace actual es este:
http://www.norwegianfashion.no/designers/?designer=Batlak-og-Selvig&bid=9
Lo que quiero es esto
http://www.norwegianfashion.no/designers/Batlak-og-Selvig/
- ¿Cómo uso
add_rewrite_rule()
? - Necesito pasar el ID del diseñador (bid). ¿Cómo puedo hacer eso cuando uso reglas de reescritura sin que se muestre en la URL?
Actualización 1
Encontré esto que es un poco más explicativo. Pero no funciona:
function add_rewrite_rules( $wp_rewrite )
{
$new_rules = array(
// Reglas nuevas para la página de diseñadores
'('.$template_page_name.')/designers/(.*?)/?([0-9]{1,})/?$' => 'designers.php?designer='.
$wp_rewrite->preg_index(1).'&bid='.
$wp_rewrite->preg_index(2)
);
// Siempre añade tus reglas al principio, para asegurar que tus reglas tienen prioridad
$wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
}
add_action('generate_rewrite_rules', 'add_rewrite_rules');
function query_vars($public_query_vars) {
$public_query_vars[] = "designer";
$public_query_vars[] = "bid";
return $public_query_vars;
}
add_filter('query_vars', 'query_vars')
Actualización 2
Aquí hay otra solución que he probado, que Jan Fabry sugirió en otro hilo. Lo puse en mi functions.php, pero no tiene efecto.
add_action('generate_rewrite_rules', 'add_rewrite_rules');
add_filter('query_vars', 'query_vars');
/* Reglas de reescritura personalizadas para diseñadores
------------------------------------------------------------------------------*/
function add_rewrite_rules( $wp_rewrite )
{
add_rewrite_rule('^designers/([^/]*)/([^/]*)$ /designers/?designer=$1&bid=$2 [L]', 'top');
flush_rewrite_rules(false);
}
function query_vars($public_query_vars) {
$public_query_vars[] = "designer";
$public_query_vars[] = "bid";
return $public_query_vars;
}
Actualización 3
Encontré algunos ejemplos aquí también. Pero esto tampoco funciona :(
add_filter('rewrite_rules_array','wp_insertMyRewriteRules');
add_filter('query_vars','wp_insertMyRewriteQueryVars');
add_filter('init','flushRules');
// Recuerda usar flush_rules() cuando añadas reglas
function flushRules(){
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
// Añadiendo una nueva regla
function wp_insertMyRewriteRules($rules)
{
$newrules = array();
$newrules['(designers)/(\d*)$'] = 'index.php?pagename=designers&designer=$matches[1]';
return $newrules + $rules;
}
// Añadiendo la variable bid para que WP la reconozca
function wp_insertMyRewriteQueryVars($vars)
{
array_push($vars, 'designer');
return $vars;
}
Actualización 4 También probé esta solución, pero sigue sin funcionar.
add_filter('search_rewrite_rules', 'designers_createRewriteRules');
function designers_createRewriteRules($rewrite) {
global $wp_rewrite;
// añadir tokens de reescritura
$designer_token = '%designers%';
$wp_rewrite->add_rewrite_tag($designer_token, '(.+)', 'designers=');
$bid_token = '%bid%';
$wp_rewrite->add_rewrite_tag($bid_token, '(.+)', 'bid=');
$keywords_structure = $wp_rewrite->root . "designers/$designer_token/$bid_token";
$keywords_rewrite = $wp_rewrite->generate_rewrite_rules($keywords_structure);
return ( $rewrite + $keywords_rewrite );
}
Actualización 5
Parece que mis reglas de reescritura no se están añadiendo.
Ejecutar lo siguiente después de añadir nuevas reglas: print_r($wp_rewrite)
, no incluye mis nuevas reglas de reescritura.
Actualización 6
Probé la solución de Jan. Pero la URL no cambia :(
/* Script de iniciación para plantilla NF
------------------------------------------------------------------------------*/
add_action('after_setup_theme','norwegianfashion_setup');
if ( ! function_exists( 'norwegianfashion_setup' ) ):
function norwegianfashion_setup() {
/* Aquí hago muchas cosas */
// URL amigable para SEO para diseñadores
add_action( 'init', 'wpa5413_init' );
add_filter( 'query_vars', 'wpa5413_query_vars' );
}
endif;
/* Reglas de reescritura personalizadas para diseñadores
------------------------------------------------------------------------------*/
function wpa5413_init()
{
// ¡Recuerda vaciar las reglas manualmente una vez después de añadir este código!
add_rewrite_rule(
'designers/([^/]+)/?',
'index.php?pagename=designers&designer=$matches[1]',
'top' );
}
function wpa5413_query_vars( $query_vars )
{
$query_vars[] = 'designer';
return $query_vars;
}
Realmente agradecería si alguien pudiera ayudarme a resolver este problema.

Algo de contexto sobre las reglas de reescritura
El sistema de reescritura de WP parece complicado, pero en realidad no es tan difícil entender cómo funciona. Se utiliza para analizar URLs amigables (/diseñadores/
) como si fueran no amigables (/index.php?pagename=diseñadores
). La idea básica es que tienes una lista de reglas de reescritura, expresiones regulares que pueden coincidir con las URLs entrantes, y reescribirlas en otras URLs, principalmente en forma de index.php
con algunas variables de consulta. Estas variables se establecen en partes de la expresión regular que coincidieron con la URL. Las reglas se evalúan de arriba abajo, por lo que si dos reglas podrían coincidir, la primera "gana".
Estas reglas de reescritura se almacenan en la base de datos llamando a flush_rewrite_rules()
, pero como generar y escribir estas reglas es una operación costosa, no deberías hacerlo en cada init
. En su lugar, solo debes hacerlo cuando cambies las reglas: probablemente en la activación del plugin (usando register_activation_hook()
), o manualmente visitando la página de configuración de Enlaces permanentes (porque es difícil hacer esto automáticamente en la activación del tema). Si no vacías las reglas, llamar a add_rewrite_rule()
no tiene efecto. No hay problema en llamar a add_rewrite_rule()
en cada init
, incluso después de haber vaciado las reglas.
Hay muchas formas de agregar tus reglas de reescritura, y si solo quieres agregar una regla, puedes hacerlo con add_rewrite_rule()
. Debido a que las reglas para entradas, páginas, taxonomías, ... resultan en múltiples reglas, se crean con funciones de alto nivel como add_rewrite_tag()
, add_permastruct()
, ... Pero estas no son necesarias para el caso simple que tenemos aquí.
También hay algunos filtros, por lo que también puedes agregar tus reglas usando los hooks generate_rewrite_rules
o generate_rewrite_rules_array
. Estos te dan un control muy detallado sobre las reglas completas, pero de nuevo, add_rewrite_rule()
es suficiente si solo quieres agregar una regla.
Creé un pequeño plugin que te permite analizar las reglas de reescritura actuales, y (por supuesto) te recomiendo que lo uses cuando intentes cambiar algo.
Obteniendo tu información extra de la URL
Vamos a construir sobre el ejemplo que diste. Tienes la marca de diseñador Batlak og Selvig
, con el ID numérico (bid
) 9
. No quieres este ID en la URL, solo el nombre. Llamamos a la versión amigable para URL del nombre (sin espacios ni caracteres especiales) el slug: Batlak-og-Selvig
.
En general, la URL debe contener toda la información para identificar el contenido que deseas mostrar en la página. Puedes usar cookies o solicitudes POST para almacenar el ID real del diseñador que deseas mostrar, pero esto se romperá si alguien comparte el enlace, enviándolo por correo, Facebook, Twitter, o simplemente leyéndolo en voz alta por teléfono. Si no deseas usar el ID numérico en tu URL, debes asegurarte de que el slug sea único: entonces primero haces una búsqueda del ID basado en el slug, y continúas como lo hacías antes.
Entonces, lo que hemos aprendido ahora es que queremos agregar una regla de reescritura para el patrón "/diseñadores/
seguido de cualquier cosa hasta el siguiente /
", y guardar esa "cualquier cosa" en la variable de consulta designer_slug
. En tu caso, creo que también deseas usar la página con el slug diseñadores
como el contenido general de la página, así que también le diremos eso a WordPress.
add_action( 'init', 'wpa5413_init' );
function wpa5413_init()
{
// ¡Recuerda vaciar las reglas manualmente una vez después de agregar este código!
add_rewrite_rule(
// La regex para coincidir con la URL entrante
'diseñadores/([^/]+)/?',
// La URL interna resultante: `index.php` porque seguimos usando WordPress
// `pagename` porque usamos esta página de WordPress
// `designer_slug` porque asignamos la primera parte capturada de la regex a esta variable
'index.php?pagename=diseñadores&designer_slug=$matches[1]',
// Esta es una URL bastante específica, así que la agregamos al principio de la lista
// De lo contrario, las reglas "catch-all" en la parte inferior (para páginas y adjuntos) "ganarán"
'top' );
}
Lo único que queda por hacer es decirle a WordPress que también mantenga el designer_slug
en las variables de consulta, para que puedas acceder a él más tarde. WordPress utiliza una lista blanca de variables de consulta permitidas, para evitar que las personas modifiquen cada parámetro de la consulta de publicaciones a través de la URL. Todo lo que no esté en esta lista se ignora. Simplemente engancha el hook query_vars
y agrega tu variable extra:
add_filter( 'query_vars', 'wpa5413_query_vars' );
function wpa5413_query_vars( $query_vars )
{
$query_vars[] = 'designer_slug';
return $query_vars;
}
Como puedes ver, esta respuesta es básicamente la misma que mi respuesta anterior, pero sin el vaciado de reglas en el código (para que puedas usarlo en el functions.php
de tu tema en lugar de un plugin), y con un poco más de certeza y explicación porque aprendí mucho sobre las reglas de reescritura desde (y debido a) responder tu primera pregunta.
Discusión en la sala de chat
Aclaramos los problemas finales para esta pregunta en la sala de chat. Al final, Steven usó el hook generate_rewrite_rules
, porque la función add_rewrite_rule()
no parecía funcionar para él.

¡Gracias por la retroalimentación detallada! Sigo viendo index.php?pagename=designers
. Mi página/plantilla Designers
está usando el archivo designers.php. ¿No deberíamos estar usando este?

@Steven: pagename
es el slug de la página de WordPress que quieres mostrar (registro en la base de datos). Esta página puede entonces indicar que quiere usar el archivo de plantilla designers.php
en el área de administración de WP. Así que apuntas al slug de la página, no al nombre de la plantilla, ya que la misma plantilla puede usarse para múltiples páginas: en este caso WordPress no sabe lo que quieres hacer.

Mira mi Actualización 6, este es el código que estoy probando ahora. Pero la URL sigue mostrando /?designer=Batlak-og-Selvig&bid=9
:( ¿Hay alguna forma de verificar si se han agregado las reglas de reescritura?

@Steven: Creo que estás complicando demasiado la forma en que configuras los hooks. Elimina la función add_rewrite_rules()
y llama a add_filter()/add_action()
directamente. Si esto está en un archivo de tema, elimina flush_rewrite_rules()
y simplemente visita la página de configuración de enlaces permanentes para actualizar las reglas (o agrégalas en wpse5413_init()
y elimínalas más tarde). Mi plugin muestra las reglas de reescritura actuales. Recuerda que esto solo cambia la forma en que se manejan las URLs entrantes, no cómo tu código escribirá las URLs en el HTML.

@Jan Fabry: Ok, he actualizado el código para reflejar los cambios, eliminando la función add_rewrite_rules()
. También intenté colocar add_filter
y add_Action
al principio de mi archivo de funciones. ¿La única forma que veo para actualizar manualmente los enlaces permanentes es presionando el botón de guardar? Aún así, la URL en el navegador sigue siendo la misma :(

@Steven: No creo que ni siquiera tengas que presionar el botón de guardar, simplemente abrir la página de enlaces permanentes también los actualizará. Y nuevamente, esto solo agregará la capacidad para que WordPress acepte URLs como /designers/designer-slug/
, tú necesitas cambiar manualmente los lugares donde escribes estas URLs en tu HTML. Pruébalo yendo a /designers/Batlak-og-Selvig/
tú mismo, si eso funciona, busca todos los lugares que generan estas URLs y cámbialos para usar la nueva estructura.

Ah, ahora creo que empiezo a entender. Pensaba que las reglas de reescritura cambiarían cómo se mostraba la URL en la barra de direcciones del navegador. Pero lo que significa es que tengo que generar realmente la URL www.misitio.com/batlat-og-selvig/9
y luego esto se "traduce" a /?designer=Batlak-og-Selvig&bid=9

@Steven: Sí, exactamente: las reglas de reescritura manejan los enlaces entrantes, y (solo en unos pocos casos seleccionados) no afectan a los enlaces generados en tu código.

@Jan Fabry: Ok, ahora he creado un slug único para cada diseñador. El enlace a la página del diseñador ahora luce así http://norwegianfashion.com/designers/batlak-og-selvig
(estoy usando .com en localhost). Pero mi regla de reescritura no lo está capturando. Simplemente obtengo un error 404 Página no encontrada.

@Steven: ¿Y tu regla de reescritura está en la lista, al principio? Si puedes venir a la sala de chat, podemos intentar resolverlo ahí.

@Jan Fabry: ¿Se supone que debo poder usar $_GET['designer'] para obtener el slug/nombre del diseñador?

@Steven: Creo que el método "oficial" es $wp_query->get( 'designer' )

@Jan Fabry: Gracias Jan. Ahora puedes verlo en acción :) http://www.norwegianfashion.no/designers/batlak-og-selvig/

jan - ¿cuál sería el pagename si quisiéramos cargar un post de custom post_type (directors) llamado test-director en single-directors.php? Actualmente tengo problemas para que funcione: 'directors/(.+?)/showreels/([^/])/video/([^/])/?', 'index.php?whatgoeshere!!!=???&showreel=$matches[2]&video=$matches[3]'
