Cuándo registramos un tipo de post personalizado (custom post type), la URL que genera WordPress para estos posts incluye el nombre del tipo post (siempre que tengamos la configuación de permalinks en %postname%, la más habitual).

Por ejemplo, si registramos “receta” como un tipo de post, las URL que genera WordPress serían del tipo misitio.com/receta/una-receta-riquisima-cualquiera.

Esta cadena que precede al nombre del post, en este ejemplo “receta”, se conoce como post type slug. De forma predeterminada, WordPress tomará el parámetro $post_type (vea register_post_type) y lo utilizará como slug, pero durante el proceso de registro del tipo de post podemos definir un slug diferente a través del argumento rewrite.

Por ejemplo, para tener URL tipo misitio.com/comida/una-receta-riquisima-cualquiera, manteniendo “receta” como el tipo de post:

add_action( 'init', 'register_my_post_type' );
function register_my_post_type() {
    
    $post_type = "receta";
    
    $args = array(
        'rewrite'    => array(
            'slug' => 'comida'
        )
    );
    
    register_post_type( $post_type, $args );   
    
}

¿Y si queremos que la URL no contenga nada delante del nombre del post, igual que las URL de los posts estándar?. Veamos como hacerlo.

1

Definir slug=> '/'

Dejar el argumento slug vacío, slug => '', no eliminará el slug de la URL. Como dije antes, si no se define ningún slug WordPress elegirá el valor del parámetro $post_type. La solución es definir el slug como slug=> '/':

add_action( 'init', 'register_receta_post_type' );
function register_receta_post_type() {

    $post_type = "receta";
    
    $args = array(
        'rewrite'    => array(
            'slug' => '/'
        )
    );
    
    register_post_type( $post_type, $args ); 
    
}

Con este senciilo paso ya tenemos las URL del custom post type sin el slug precedente. La URL de una receta sería ahora misitio.com/una-receta-riquisima-cualquiera. Pero esta URL nos dará error 404 (no encontrado).

2

Incluir el tipo post personalizado en el query principal

Las URL generadas mediante el paso anterior generan error 404 porque si no hay slug precedente al nombre del post, WordPress buscará únicamente entre los posts estándar y las páginas (son los tipo de post post y page). Para solucionarlo tenemos que decirle a WordPress que incluya también nuestro custom post type.

El mejor momento para hacerlo es en el action pre_get_posts, momento en el que todavía podemos modificar el query principal antes de que se ejecute la consulta a la base de datos:

add_action( 'pre_get_posts', 'cyb_include_custom_post_type_in_query' );
function cyb_include_custom_post_type_in_query( $query ) {

     // Si no es el query principal salir
     if ( ! $query->is_main_query() ) {
         return;
     }

     if ( 2 != count( $query->query ) || ! isset( $query->query['page'] ) ) {
         return;
     }

      // Incluir custom post type en el query
     if ( ! empty( $query->query['name'] ) ) {
          $post_types = array( 'post', 'page', 'receta' );
          $query->set( 'post_type', $post_types );
     }

 }
3

Solucionar conflictos

En algunas situaciones, al introducir estos cambios que interfieren con el funcionamiento normal de WordPress, el sistema parece no distinguir si se está visualizando una página (page post type) o un tipo de post personalizado.

Aunque estemos viendo el contenido correcto, pueden ocurrir otros errores debido a este conflicto. Para solucionarlo podemos comprobar si existe una página con el nombre solicitado y cambiar algunas propiedades del query principal:

add_action( 'parse_query', 'cyb_parse_query' );
function cyb_parse_query( $wp_query ) {

    if( get_page_by_path($wp_query->query_vars['name']) ) {
        $wp_query->is_single = false;
        $wp_query->is_page = true;
    }

}
NOTA: Si ya tienes registrado tu custom post type y haces los cambios mencionados aquí, es necesario que se reconstruyan las reglas “rewrite”. Para ello ve a la “administración de WordPress” → “Ajustes” → “Enlaces permanentes” y pulsa sobre “Guardar cambios”.