Necesito ayuda con add_rewrite_rule

15 dic 2010, 17:04:34
Vistas: 69.2K
Votos: 58

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/

  1. ¿Cómo uso add_rewrite_rule()?
  2. 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.

4
Comentarios

Esto se ve muy similar a la primera pregunta que hiciste aquí, y para la cual di una respuesta. ¿Ha cambiado la situación desde entonces, por lo que mi respuesta ya no es válida? Si no quieres el ID del diseñador en tu URL, necesitarás convertir el "slug" al ID tú mismo, WordPress no puede hacer esto por ti. ¿Siguen siendo los diseñadores un objeto externo?

Jan Fabry Jan Fabry
16 dic 2010 00:47:11

@Jan Fabry Sí, lo descubrí después de publicar esto (lo había olvidado). Ahora también entiendo mejor tu sugerencia. Mira mi código actualizado aquí. Mis diseñadores siguen siendo entradas en una base de datos personalizada. ¿Es posible usar POST en lugar de GET para pasar el bid?

Steven Steven
16 dic 2010 01:04:44

Usar una solicitud POST no funcionará si copio el enlace y se lo envío a alguien más. ¿Es un problema hacer que el slug sea único y realizar la búsqueda de datos desde ahí?

Jan Fabry Jan Fabry
16 dic 2010 01:57:32

@Jan Fabry: ¿Qué quieres decir con slug? Recuperar datos del Diseñador es mucho más fácil usandobiden lugar dedesigner`

Steven Steven
16 dic 2010 03:18:13
Todas las respuestas a la pregunta 1
15
91

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.

16 dic 2010 12:07:23
Comentarios

¡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 Steven
16 dic 2010 12:18:27

@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.

Jan Fabry Jan Fabry
16 dic 2010 12:35:00

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 Steven
16 dic 2010 12:43:09

@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 Jan Fabry
16 dic 2010 12:52:04

@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 Steven
16 dic 2010 13:01:11

@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.

Jan Fabry Jan Fabry
16 dic 2010 13:05:19

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 Steven
16 dic 2010 13:23:54

@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 Jan Fabry
16 dic 2010 13:32:10

@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 Steven
16 dic 2010 15:18:33

@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 Jan Fabry
16 dic 2010 15:28:29

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

Steven Steven
16 dic 2010 20:01:46

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

Jan Fabry Jan Fabry
17 dic 2010 00:50:00

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

Steven Steven
17 dic 2010 02:09:40

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]'

v3nt v3nt
22 may 2012 16:40:32

Muchas gracias. Por alguna razón, también tuve que usar el filtro. ¡Seguir tu conversación ayudó mucho!

Alexandre Bourlier Alexandre Bourlier
21 feb 2015 20:20:16
Mostrar los 10 comentarios restantes