Hace un tiempo plantearon una pregunta en WPSE sobre utilizar un template diferente según reglas de la URL de un custom post type. En concreto, el tipo de post era event con la URL event/{event-name} (la que genera WP de forma predeterminada) y se quería crear una URL con la estructura event/{event-name}/gallery. Esta nueva URL debería utilizar la plantilla single-event-gallery.php dónde se mostraría sólo la galería de imágenes que estaba insertada en el post.

Vamos a ver como conseguir este caso concreto pero con pequeños ajustes deberías ser capaz de implementar algo parecido según tus necesidades específicas.

¿Cómo hacerlo?

La diferencia entre la URL predeterminada que genera WordPress para el tipo de post event y la nueva URL es el query var gallery. El objetivo entonces es que si este query var está presente en la URL se cargue la plantilla single-event-gallery.php; en caso contrario dejar que WordPress utilice la ruta de plantillas normal. Se requieren tres pasos:

  1. Definir el rewrite rule para que WordPress sepa como interpretar la nueva URL
  2. Registrar los query var adicionales, en este caso gallery, para que WordPress no los rechace
  3. Cargar la plantilla single-event-gallery.php si el query var gallery está presente.
1

Definir el rewrite rule

Si tomas la URL de un post y le pones /gallery al final obtendrás un error 404 ya que es una URL que WordPress no entiende de por sí. Tenemos que decirle a WordPress como interpretar esta nueva estructura. Para ello simplemente añadimos una nueva regla de reescritura, más conocida por su nombre en inglés rewrite rule, con la función add_rewrite_rule:

add_action( 'init', function () {

    add_rewrite_rule( '^event/([^/]+)/gallery/?$', 'index.php?event=$matches[1]&gallery=1', 'top' );

} );

El código anterior le dice a WordPress que si la estructura de la URL comienza con event, le sigue cualquier valor entre / y / y termina con /gallery o /gallery/, tiene que interpretar que se solicita el post de tipo event definido con el slug entre el primer y segundo / y que añada el query var gallery. El valor dado al query var gallery es “1” pero has de tener claro que este es un valor arbitrario, en verdad no necesitamos ningún valor concreto en este caso, tan sólo que el query var gallery esté presente.

Después de añadir esta nueva regla de reescritura de URLs, es necesario reconstruir los rewrite rules. Para hacerlo simplemente ve a wp-admin → configuración → enlaces permentes y pulsa en el botón “Guardar”. No es necesario que cambies ninguna configuraicón, tan sólo pulsa en “Guardar”. (si estás desarrollando un plugin puedes utilizar flush_rewrite_rules() en el hook de activación).

2

Registrar el query var

En el paso anterior hemos añadido un query var a la URL que ha de interpretar WordPress. Ahora tenemos que añadir este nuevo query var en la lista de query vars válidos o WordPress lo rechazará. Para ello se utiliza el filtro query_vars:

add_filter( 'query_vars', function ( $vars ) {

    // Añadimos nuestro query var al array de query vars válidas
    $vars[] = 'gallery';

    return $vars;

} );
3

Cargar la plantilla según la URL

Ya tenemos la URL event/{event-name}/gallery funcionando pero se mostrará la plantilla single-event.php o, si esta no existe, single.php. Ahora tenemos que decirle a WordPress que si el query var gallery está presente queremos utilizar la plantilla single-event-gallery.php. Esto se consigue con el filtro template_include:

add_filter( 'template_include', function ( $template ) {

    // No es necesario ningún valor especifico del "gallery" query var,
    // tan sólo que esté presente y que la plantilla single-event-gallery.php existe

    // locate_template() devuelve el path de la plantilla, si existe, un string vacío si no
    // locate_template() es compatible con temas hijos
    $gallery_template = locate_template( 'single-event-gallery.php' );
    if ( ! empty( get_query_var( 'gallery' ) ) && $gallery_template ) {
    
        return $gallery_template;

    }

    return $template;

} );

En el código superior modificamos el template utilizado en caso de que el query var gallery esté presente con cualquier valor no vacío y que la plantilla single-event-gallery.php exista, si existe se utilizará esa plantilla. En caso contrario se deja a WordPress seguir su sistema de plantillas predeterminado.

Alternativas

La clave está en el último paso cuándo se utiliza el filtro template_include. Es ahí dónde intervenimos en el sistema de templates de WordPress y especificamos la plantilla que hay que cargar. Si nos da igual que la URL sea “pretty” o no, podríamos saltarnos todo lo del rewrite rule. Por ejemplo, podríamos utilizar una URL con este query string: event/{event-name}?gallery=1, saltarnos el paso 1 y 2 y el 3 cambiarlo por:

add_filter( 'template_include', function ( $template ) {

    $gallery_template = locate_template( 'single-event-gallery.php' );
    if ( isset( $_GET[ 'gallery' ] ) && $gallery_template ) {
        return $gallery_template;

    }

    return $template;

} );

También podríamos utilizar un endopoint registrado con add_rewrite_endpoint(). Al registrar un endpoint, WordPress creará el rewrite rule y query var correspondiente y nos podemos ahorrar hacer esos dos pasos nosostros mismos. El problema con el endopoint es que el rewrite rule se crea para todos los tipos de posts y sería necesario comprobar el tipo de post antes de cambiar la plantilla. También se utilizaría is_null() en lugar de empty() para comprobar que el query var gallery está presente sin importar su valor; si se utiliza empty() la URL del tipo event/{event-name}/gallery no funcionaría pues el valor del query var sería un string vacío y la comprobación con emtpy() fallaría, sería necesario dar algún valor, por ejemplo event/{event-name}/gallery/1. Con is in_null() esto no sería necesario. El código completo quedaría así:

add_action( 'init', function() {

    // Registrar el endopoint para los permalinks de posts
    add_rewrite_endpoint( 'gallery', EP_PERMALINK );

});

add_filter( 'template_include', function( $template ) {

    $gallery_template = locate_template( 'single-event-gallery.php' );

    // comprobar el tipo de post y que el query var no sea nulo
    if ( get_query_var( 'post_type' ) == 'event' && ! is_null( get_query_var( 'gallery' ) ) && $gallery_template ) {

        return $gallery_template;

    }

    return $template;

} );