Eliminar el slug de las URLs de entradas de tipos de contenido personalizados

28 sept 2015, 19:18:46
Vistas: 164K
Votos: 84

Parece que todos los recursos web basados en el tema de eliminar un slug de tipo de contenido personalizado, es decir

tudominio.com/SLUG-CPT/nombre-entrada 

son ahora soluciones muy desactualizadas que a menudo hacen referencia a instalaciones anteriores a WP versión 3.5. Una común es:

'rewrite'   => array( 'slug' => false, 'with_front' => false ),  

dentro de tu función register_post_type. Esto ya no funciona y puede llevar a confusión. Así que pregunto a la comunidad en el cuarto trimestre de 2020...

¿Cuáles son las formas modernas y eficientes de eliminar el Slug del Tipo de Contenido de la URL de una entrada de Tipo de Contenido Personalizado desde el argumento rewrite o cualquier otro lugar?

ACTUALIZACIÓN: Parece haber varias formas de forzar esto para que funcione con regex. Específicamente la respuesta de Jan Beck, si estás dispuesto a monitorear constantemente la creación de contenido para asegurar que no se creen nombres de páginas/entradas conflictivas... Sin embargo, estoy convencido de que esta es una debilidad importante en el núcleo de WP que debería manejarse por nosotros. Tanto como una opción/hook al crear un CPT o un conjunto avanzado de opciones para enlaces permanentes. Por favor, apoya el ticket de seguimiento.

Nota al pie: Por favor, apoya este ticket de trac observándolo/promocionándolo: https://core.trac.wordpress.org/ticket/34136#ticket

3
Comentarios

Supongo que me rasco la cabeza preguntándome por qué querrías hacer eso? Confundido.

Michael Ecklund Michael Ecklund
29 may 2017 18:22:54

@MichaelEcklund porque cualquier CPT que se usa para crear páginas web públicas tiene un nombre de slug forzado en la URL. En realidad hay muchos desarrolladores de WordPress buscando eliminar el slug de manera segura.

Ben Racicot Ben Racicot
18 jul 2017 03:11:36

Esta pregunta (junto con algunas otras cosas de WP...) marcó el momento en que mi carrera se alejó de WordPress.

Ben Racicot Ben Racicot
14 mar 2025 16:17:22
Todas las respuestas a la pregunta 15
15
102

El siguiente código funcionará, pero debes tener en cuenta que pueden ocurrir conflictos fácilmente si el slug de tu tipo de publicación personalizada es el mismo que el slug de una página o entrada...

Primero, eliminaremos el slug del enlace permanente:

function na_remove_slug( $post_link, $post, $leavename ) {

    if ( 'events' != $post->post_type || 'publish' != $post->post_status ) {
        return $post_link;
    }

    $post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );

    return $post_link;
}
add_filter( 'post_type_link', 'na_remove_slug', 10, 3 );

Solo eliminar el slug no es suficiente. En este momento, obtendrás un error 404 porque WordPress solo espera que las entradas y páginas se comporten de esta manera. También necesitarás agregar lo siguiente:

function na_parse_request( $query ) {

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

    if ( ! empty( $query->query['name'] ) ) {
        $query->set( 'post_type', array( 'post', 'events', 'page' ) );
    }
}
add_action( 'pre_get_posts', 'na_parse_request' );

Solo cambia "events" por tu tipo de publicación personalizada y estarás listo. Puede que necesites refrescar tus enlaces permanentes.

30 sept 2015 23:45:51
Comentarios

gracias. ¿Crees que esto es mejor que crear las reescrituras manualmente? He visto esa solución y podría mantener los conflictos que mencionas a raya?

Ben Racicot Ben Racicot
1 oct 2015 16:29:45

Creo que esta es una buena solución automatizada si estás seguro de que no crearás conflictos. No es una buena solución si se la vas a proporcionar a... digamos un cliente que no tiene conocimientos técnicos.

Nate Allen Nate Allen
1 oct 2015 16:53:24

¿puedes actualizar por favor, cómo usar este código para múltiples tipos de post?

Abin Abin
25 ene 2016 13:29:09

Falla con nginx debido a la condición 2 != count( $query->query ). Con nginx, puedes tener $query->query como array('page' => '', 'name' => '...', 'q' => '...'). Entonces @NateAllen, ¿cuál es el significado de esa condición?

Fabio Montefuscolo Fabio Montefuscolo
8 nov 2016 14:25:05

Necesitamos algo mejor que esto. Que tenga soporte integrado para eliminar el slug y así evitar crear URLs conflictivas más adelante. De la misma manera en que las entradas y páginas regulares crean sus URLs.

Ben Racicot Ben Racicot
18 jul 2017 03:13:34

¿Soy solo yo o esto rompe algunas etiquetas condicionales de WordPress como is_single() e is_singular()?

rob-gordon rob-gordon
18 jul 2017 21:53:38

Esta solución desafortunadamente causó algunos enlaces rotos y mi blog dejó de mostrar publicaciones y era solo una página normal. Consulta una mejor solución a continuación de Matt Keys.

Radley Sustaire Radley Sustaire
8 oct 2018 03:10:20

Este código asume que el nombre del post_type es el mismo que el slug del tipo de entrada personalizada, lo cual no necesariamente tiene que ser así en todos los casos. Pero por lo demás, gran solución aunque estoy de acuerdo en que una solución nativa de WP sería mejor.

Marco Miltenburg Marco Miltenburg
14 jun 2019 23:26:35

single-{cpt}.php deja de funcionar usando este enfoque

Saleh Mahmood Saleh Mahmood
5 ene 2020 15:24:10

Para aquellos que tienen un problema con el código anterior, funciona perfectamente si reemplazan la segunda función ( function na_parse_request() ) por la que se encuentra en esta respuesta. No olviden modificar el código con el nombre de su propio Custom Post Type.

PhpDoe PhpDoe
3 abr 2020 19:28:16

He estado usando este buen código hasta que llegó WP 5.2. Después de la actualización, este código comienza a fallar en mi plugin de Custom Post Type y en el plugin de Advanced Custom Fields, porque, creo, están usando la misma función pre_get_posts, así que en lugar de Grupos de Advanced Custom Fields, veo mis publicaciones personalizadas en este plugin... También falla con el plugin CPT UI - no se pueden crear nuevas publicaciones, no aparecen en la lista después de crearlas. ¡¡Por favor ayuda!!

Gediminas Gediminas
4 may 2020 15:58:12

Funcionó para un solo tipo de publicación. ¿Cómo usar el código para múltiples tipos de publicación?

Swaranan Singha Barman Swaranan Singha Barman
2 jul 2020 11:07:43

Funciona para mí.

user9437856 user9437856
10 dic 2020 08:38:08

Ahh, finalmente una solución - ¡gracias! Me preguntaba por qué de repente estaba obteniendo errores 404 durante una hora antes de darme cuenta de que era por esto 'rewrite' => array( 'slug' => false) :)

Philarmon Philarmon
20 ago 2021 04:48:04

Esto puede funcionar pero es un enfoque de hackeo de WordPress. La respuesta correcta es el Paso 1 de Matt Keys: Simplemente define correctamente el tipo de publicación al registrarlo: register_post_type( 'custom_post_type', array( 'rewrite' => false ) );

gtamborero gtamborero
23 sept 2022 12:22:01
Mostrar los 10 comentarios restantes
10
34

Al revisar las respuestas aquí, creo que hay espacio para una mejor solución que combine algunas cosas que aprendí anteriormente y agregue detección automática y prevención de slugs de publicaciones duplicados.

NOTA: Asegúrate de cambiar 'custom_post_type' por el nombre de tu propio CPT en todo mi ejemplo a continuación. Hay muchas ocurrencias, y un 'buscar/reemplazar' es una manera fácil de capturarlas todas. Todo este código puede ir en tu functions.php o en un plugin.

Paso 1: Deshabilita las reescrituras en tu tipo de publicación personalizado configurando rewrites a 'false' cuando registres el post:

register_post_type( 'custom_post_type',
    array(
        'rewrite' => false
    )
);

Paso 2: Agrega manualmente nuestras reescrituras personalizadas al final de las reescrituras de WordPress para nuestro custom_post_type

function custom_post_type_rewrites() {
    add_rewrite_rule( '[^/]+/attachment/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'bottom');
    add_rewrite_rule( '[^/]+/attachment/([^/]+)/trackback/?$', 'index.php?attachment=$matches[1]&tb=1', 'bottom');
    add_rewrite_rule( '[^/]+/attachment/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'bottom');
    add_rewrite_rule( '[^/]+/attachment/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'bottom');
    add_rewrite_rule( '[^/]+/attachment/([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?attachment=$matches[1]&cpage=$matches[2]', 'bottom');
    add_rewrite_rule( '[^/]+/attachment/([^/]+)/embed/?$', 'index.php?attachment=$matches[1]&embed=true', 'bottom');
    add_rewrite_rule( '([^/]+)/embed/?$', 'index.php?custom_post_type=$matches[1]&embed=true', 'bottom');
    add_rewrite_rule( '([^/]+)/trackback/?$', 'index.php?custom_post_type=$matches[1]&tb=1', 'bottom');
    add_rewrite_rule( '([^/]+)/page/?([0-9]{1,})/?$', 'index.php?custom_post_type=$matches[1]&paged=$matches[2]', 'bottom');
    add_rewrite_rule( '([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?custom_post_type=$matches[1]&cpage=$matches[2]', 'bottom');
    add_rewrite_rule( '([^/]+)(?:/([0-9]+))?/?$', 'index.php?custom_post_type=$matches[1]', 'bottom');
    add_rewrite_rule( '[^/]+/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'bottom');
    add_rewrite_rule( '[^/]+/([^/]+)/trackback/?$', 'index.php?attachment=$matches[1]&tb=1', 'bottom');
    add_rewrite_rule( '[^/]+/([^/]+)/feed/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'bottom');
    add_rewrite_rule( '[^/]+/([^/]+)/(feed|rdf|rss|rss2|atom)/?$', 'index.php?attachment=$matches[1]&feed=$matches[2]', 'bottom');
    add_rewrite_rule( '[^/]+/([^/]+)/comment-page-([0-9]{1,})/?$', 'index.php?attachment=$matches[1]&cpage=$matches[2]', 'bottom');
    add_rewrite_rule( '[^/]+/([^/]+)/embed/?$', 'index.php?attachment=$matches[1]&embed=true', 'bottom');
}
add_action( 'init', 'custom_post_type_rewrites' );

NOTA: Dependiendo de tus necesidades, es posible que desees modificar las reescrituras anteriores (¿deshabilitar trackbacks? ¿feeds?, etc.). Estas representan los tipos de reescrituras 'predeterminadas' que se habrían generado si no hubieras deshabilitado las reescrituras en el paso 1.

Paso 3: Vuelve a hacer que los enlaces permanentes a tu tipo de publicación personalizado sean 'bonitos'

function custom_post_type_permalinks( $post_link, $post, $leavename ) {
    if ( isset( $post->post_type ) && 'custom_post_type' == $post->post_type ) {
        $post_link = home_url( $post->post_name );
    }

    return $post_link;
}
add_filter( 'post_type_link', 'custom_post_type_permalinks', 10, 3 );

NOTA: Puedes detenerte aquí si no te preocupa que tus usuarios creen una publicación conflictiva (duplicada) en otro tipo de publicación que generará una situación en la que solo una de ellas podrá cargarse cuando se solicite la página.

Paso 4: Prevenir slugs de publicaciones duplicados

function prevent_slug_duplicates( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
    $check_post_types = array(
        'post',
        'page',
        'custom_post_type'
    );
    
    if ( ! in_array( $post_type, $check_post_types ) ) {
        return $slug;
    }

    if ( 'custom_post_type' == $post_type ) {
        // Guardando una publicación de custom_post_type, verifica duplicados en los tipos de publicación POST o PAGE
        $post_match = get_page_by_path( $slug, 'OBJECT', 'post' );
        $page_match = get_page_by_path( $slug, 'OBJECT', 'page' );

        if ( $post_match || $page_match ) {
            $slug .= '-duplicado';
        }
    } else {
        // Guardando un POST o PAGE, verifica duplicados en el tipo de publicación custom_post_type
        $custom_post_type_match = get_page_by_path( $slug, 'OBJECT', 'custom_post_type' );

        if ( $custom_post_type_match ) {
            $slug .= '-duplicado';
        }
    }

    return $slug;
}
add_filter( 'wp_unique_post_slug', 'prevent_slug_duplicates', 10, 6 );

NOTA: Esto agregará la cadena '-duplicado' al final de cualquier slug duplicado. Este código no puede prevenir slugs duplicados si ya existen antes de implementar esta solución. Asegúrate de verificar primero si hay duplicados.

Me encantaría recibir comentarios de cualquier otra persona que pruebe esto para ver si también funcionó bien para ellos.

6 oct 2017 01:51:15
Comentarios

Acabo de probarlo y parece que está funcionando por ahora.

Christine Cooper Christine Cooper
12 nov 2017 20:02:48

Tenía esperanzas con este enfoque, pero me da un error 404 en mis posts CPT, incluso después de regenerar los Permalinks.

Garconis Garconis
7 ago 2018 21:32:09

Lamento que no te haya funcionado Garconis. Hace un tiempo hablé con otra persona sobre esto y también tenía problemas en su sitio. Recuerdo que importaba si los permalinks de tus posts de blog tenían un prefijo. En el sitio para el que desarrollé esto, los posts del blog usan la estructura de permalink: /blog/%postname%/. Si no tienes un prefijo en tus posts de blog, y es aceptable que lo añadas, pruébalo y dime cómo te va.

Matt Keys Matt Keys
7 ago 2018 23:54:20

Esto funcionó para mí. A diferencia de otras soluciones en la página, no rompió las páginas normales ni el diseño del blog, y no causó redirecciones infinitas. Incluso muestra la URL correcta en el área "Enlace permanente" al editar esas páginas de CPT. Una solución bastante buena aquí, la única advertencia es que la página de archivo no funciona. RECUERDA reemplazar "custom_post_type" y actualizar tus enlaces permanentes después.

Radley Sustaire Radley Sustaire
8 oct 2018 03:08:13

@MattKeys, la configuración predeterminada de Enlaces Permanentes tiene una Estructura Personalizada de /%category%/%postname%/. Al agregar tu código, los slugs de CPT se ven bien (aunque les falta la barra diagonal final) ... y el comprobador de conflictos también funciona. Pero el resultado real de la publicación muestra un error 404.

Garconis Garconis
3 jul 2019 17:39:38

¡Funciona muy bien! Sin embargo, tuve que agregar una variable de consulta en el paso 2 add_rewrite_tag( "%custom_post_type%", '([^/]+)', "post_type=custom_post_type&name=" ); para ver las páginas de CPT en lugar de un mensaje 404.

Philipp Philipp
8 may 2021 19:16:55

Esta fue la única solución que funcionó para mí. Solo tuve que agregar una barra diagonal al final de return $post_link en el paso 3.

EmilyH EmilyH
26 ago 2021 22:44:03

Funcionó bien, pero falta la barra diagonal final. ¡Por favor actualiza la respuesta para incluir esto! Una posible desventaja: ya no podrás personalizar el enlace permanente desde el front-end (por ejemplo, cuando quieras acortarlo en comparación con el título).

Alex Alex
18 oct 2021 17:01:31

Esto funciona bien para el CPT, pero hace que todas las publicaciones de mi sitio devuelvan error 404. Estoy usando esto en un plugin, por lo que debe funcionar con todas las posibles estructuras de enlaces permanentes, y no estoy seguro de si eso es posible.

Morgan Kay Morgan Kay
15 feb 2024 22:32:55

@MorganKay sí, tienes razón en que esto no puede funcionar con todas las estructuras de enlaces permanentes posibles. Por lo tanto, no será adecuado para integrarlo en algo como un plugin que quieras distribuir.

Matt Keys Matt Keys
23 feb 2024 00:33:21
Mostrar los 5 comentarios restantes
11
32

Escribe el siguiente código en el registro de la taxonomía.

'rewrite' => [
  'slug' => '/',
  'with_front' => false
]

Lo más importante que debes hacer después de cambiar el código

Después de haber modificado el documento de taxonomía de tu tipo de entrada personalizado, intenta ir a Ajustes > Enlaces permanentes y vuelve a guardar tus ajustes, de lo contrario obtendrás un error 404 página no encontrada.

12 abr 2017 21:16:53
Comentarios

Esto realmente funciona, no sé cómo nadie se había dado cuenta antes. Claro que esto puede interferir con otras páginas si tienen el mismo enlace permanente, pero si no, es una gran solución.

lonerunner lonerunner
31 jul 2017 20:33:02

Probé esto. Da el resultado deseado para los enlaces de mi tipo de entrada personalizado. Sin embargo, 'captura' todos los slugs de tipo POST o PAGE e intenta resolverlos como una URL para mi tipo de entrada personalizado, luego muestra error 404 (sí, he guardado los enlaces permanentes).

Matt Keys Matt Keys
5 oct 2017 23:49:14

Podría haber el mismo slug para alguna página y tipo de entrada personalizado, cambia el slug de tu página y luego verifica..

Mayank Dudakiya Mayank Dudakiya
11 oct 2017 19:51:23

Esto no funciona. Da error 404 incluso cuando has actualizado los enlaces permanentes.

Christine Cooper Christine Cooper
12 nov 2017 20:02:15

@ChristineCooper Debes seguir este paso

Después de modificar tu documento de taxonomía de tipo de entrada personalizada, intenta ir a Ajustes > Enlaces permanentes y guardar nuevamente tus configuraciones, de lo contrario obtendrás un error 404 de página no encontrada.

Mayank Dudakiya Mayank Dudakiya
15 nov 2017 18:56:26

Como mencioné en mi último comentario, obtendrás un error 404 incluso después de haber actualizado los enlaces permanentes. Por favor, pruébalo tú mismo.

Christine Cooper Christine Cooper
15 nov 2017 22:11:20

Funciona a la perfección, especialmente cuando lees el mensaje completo, incluyendo la parte de "volver a guardar tus configuraciones". +1

Dadou Dadou
25 ene 2018 16:12:26

De nuevo, incluso después de volver a guardar la configuración de enlaces permanentes, las entradas y páginas ya no funcionan (404)

amklose amklose
13 feb 2018 21:18:58

Esta solución funciona para eliminar el slug de la URL. Pero las páginas de archivo ya no funcionan.

Annapurna Annapurna
25 sept 2018 07:42:57

Como otros han mencionado, esto funciona para los posts de CPT en sí mismos. Pero ahora está causando un error 404 en las Páginas regulares.

Garconis Garconis
3 jul 2019 19:52:06

Quizás esto funcione para algunos pero no para otros debido a la interferencia de otros plugins? Es decir, esto tampoco funciona para mí en un entorno donde WPML con subdirectorios está configurado: www.misitio.com/en/CPT-item/ da error 404.

WoodrowShigeru WoodrowShigeru
21 may 2021 19:22:31
Mostrar los 6 comentarios restantes
3
16

Intenté resolver esto hace poco y la respuesta corta, por lo que sé, es no. Al menos no desde el argumento de reescritura (rewrite).

La explicación larga se hace evidente si miras el código real de register_post_type en wp-includes/post.php línea 1454:

add_permastruct( $post_type, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );

Puedes ver que antepone $args->rewrite['slug'] a la etiqueta de reescritura %$post_type%. Uno podría pensar "entonces simplemente establezcamos el slug como null", hasta que miras unas líneas más arriba:

if ( empty( $args->rewrite['slug'] ) )
    $args->rewrite['slug'] = $post_type;

Puedes ver que la función siempre espera un valor de slug que no esté vacío y, de lo contrario, usa el tipo de publicación (post type).

30 sept 2015 17:01:33
Comentarios

Gracias @JanBeck. ¿Hay una razón importante para que esto exista? ¿Por qué no modificar este archivo central con una condición para omitir ciertos tipos de publicaciones de esta regla?

Ben Racicot Ben Racicot
30 sept 2015 21:02:57

Deberías otorgar la respuesta a Jan Beck. WordPress necesita el slug de post_type para enrutar las solicitudes correctamente. Esta regla evita conflictos de nombres entre las páginas nativas de WP (que se renderizan sin el slug) y cualquier tipo de publicación personalizado definido. Si eliminas el slug, WordPress no sabrá la diferencia entre una página llamada "picnic" y un evento (tipo de publicación personalizado) llamado "picnic".

dswebsme dswebsme
30 sept 2015 22:34:09

@dswebsme De acuerdo, pero hay situaciones en las que absolutamente debes cambiar la URL. Entonces, aparte de por qué no puedes hacerlo de forma nativa y no deberías, ¿cómo lo haces de manera eficiente?

Ben Racicot Ben Racicot
1 oct 2015 16:27:31
3
16

Resumen de Plugins

Estamos casi en 2020 y muchas de estas respuestas ya no funcionan. Aquí está mi propio resumen de las opciones actuales:

  • La respuesta de Matt Keys parece ser la única en el camino correcto si buscas una solución de código personalizado. Ninguno de los plugins que encontré puede hacer todo lo listado aquí, especialmente la verificación de duplicados. Este enfoque parece una gran oportunidad para un plugin si alguien quisiera tomarlo.
  • Permalink Manager Lite
    • El mejor de los plugins gratuitos que probé.
    • Ofrece control completo sobre toda la estructura de enlaces permanentes de Páginas/Posts/CPTs y permite que sean iguales. La interfaz gráfica es, con mucho, la más completa en funciones.
    • Permite anulación completa por cada post y también te permite ver cuál sería el enlace original/predeterminado y restablecerlo si es necesario.
    • Soporta multisitio.
    • No verifica duplicados entre tipos de post, lo cual es lamentable. Si una página y un CPT tienen la misma URL, la página se carga y el CPT es inaccesible. Sin advertencias ni errores, solo debes hacer tu propia verificación manual de duplicados.
    • Todas las funciones de taxonomía están en la versión PRO. Los recordatorios para actualizar son bastante intensos.
  • Custom Permalinks
    • La versión gratuita hace mucho. Los enlaces permanentes de taxonomía y el soporte premium parecen ser las únicas cosas reservadas para la versión pro.
    • Permite cambiar el enlace permanente completo para cualquier página/post/CPT individual.
    • Soporta multisitio.
    • No permite cambiar la estructura predeterminada, por lo que tus Custom Post Types seguirán siendo ejemplo.com/cpt-slug/post-title pero puedes cambiarlos individualmente.
    • No verifica duplicados entre tipos de post, lo cual es lamentable.
  • Custom Post Type Permalinks
    • Permite a usuarios no desarrolladores cambiar las cosas que ya son fáciles de cambiar con register_post_type
    • No permite cambiar el slug base del CPT, solo la parte que viene después, por lo que prácticamente inútil para desarrolladores y para el tema de esta pregunta.
  • remove base slug... - muerto desde hace varios años... no usar.
17 dic 2019 02:09:40
Comentarios

El plugin Permalink Manager Lite es definitivamente la mejor solución: estable, robusto, limpio, y la versión gratuita te permite eliminar el slug base. ¡Y también funciona con Polylang! Probado en WordPress 5.4, con el tema TwentyTwenty, sin ningún otro plugin activado. Funciona perfectamente en Custom Post Type, sin importar si has creado uno jerárquico (con posts hijos y nietos). Para cualquiera que busque una solución limpia.

PhpDoe PhpDoe
4 abr 2020 14:57:17

Buen resumen. El código de mi respuesta ha estado funcionando en un sitio de cliente durante años sin ningún problema. La única desventaja que algunos han señalado en mi solución es que no funciona en los permalinks 'por defecto' para el tipo de post integrado 'blog' (post). En su lugar debe haber un prefijo como: /blog/%postname%/. Para aquellos que usan WordPress como CMS, ya pueden estar haciendo esto, pero para otros esto podría ser un obstáculo desafortunadamente.

Matt Keys Matt Keys
1 feb 2021 22:23:09

Usé el plugin manager lite y funcionará para mi situación

Tahir Shahzad Tahir Shahzad
28 ene 2022 19:51:07
3

En respuesta a mi respuesta anterior: por supuesto podrías establecer el parámetro rewrite como false al registrar un nuevo tipo de entrada y manejar las reglas de reescritura tú mismo de la siguiente manera

<?php
function wpsx203951_custom_init() {

    $post_type = 'event';
    $args = (object) array(
        'public'      => true,
        'label'       => 'Eventos',
        'rewrite'     => false, // siempre establece esto como false
        'has_archive' => true
    );
    register_post_type( $post_type, $args );

    // estos son tus argumentos reales de reescritura
    $args->rewrite = array(
        'slug' => 'calendario'
    );

    // todo lo que sigue es de la función register_post_type
    if ( is_admin() || '' != get_option( 'permalink_structure' ) ) {

        if ( ! is_array( $args->rewrite ) )
            $args->rewrite = array();
        if ( empty( $args->rewrite['slug'] ) )
            $args->rewrite['slug'] = $post_type;
        if ( ! isset( $args->rewrite['with_front'] ) )
            $args->rewrite['with_front'] = true;
        if ( ! isset( $args->rewrite['pages'] ) )
            $args->rewrite['pages'] = true;
        if ( ! isset( $args->rewrite['feeds'] ) || ! $args->has_archive )
            $args->rewrite['feeds'] = (bool) $args->has_archive;
        if ( ! isset( $args->rewrite['ep_mask'] ) ) {
            if ( isset( $args->permalink_epmask ) )
                $args->rewrite['ep_mask'] = $args->permalink_epmask;
            else
                $args->rewrite['ep_mask'] = EP_PERMALINK;
        }

        if ( $args->hierarchical )
            add_rewrite_tag( "%$post_type%", '(.+?)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&pagename=" );
        else
            add_rewrite_tag( "%$post_type%", '([^/]+)', $args->query_var ? "{$args->query_var}=" : "post_type=$post_type&name=" );

        if ( $args->has_archive ) {
            $archive_slug = $args->has_archive === true ? $args->rewrite['slug'] : $args->has_archive;
            if ( $args->rewrite['with_front'] )
                $archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
            else
                $archive_slug = $wp_rewrite->root . $archive_slug;

            add_rewrite_rule( "{$archive_slug}/?$", "index.php?post_type=$post_type", 'top' );
            if ( $args->rewrite['feeds'] && $wp_rewrite->feeds ) {
                $feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
                add_rewrite_rule( "{$archive_slug}/feed/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
                add_rewrite_rule( "{$archive_slug}/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
            }
            if ( $args->rewrite['pages'] )
                add_rewrite_rule( "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$", "index.php?post_type=$post_type" . '&paged=$matches[1]', 'top' );
        }

        $permastruct_args = $args->rewrite;
        $permastruct_args['feed'] = $permastruct_args['feeds'];
        add_permastruct( $post_type, "%$post_type%", $permastruct_args );
    }
}
add_action( 'init', 'wpsx203951_custom_init' );

Puedes ver que la llamada a add_permastruct ya no incluye el slug. Probé dos escenarios:

  1. Cuando creé una página con el slug "calendario", esa página fue sobreescrita por el archivo del tipo de entrada que también usa el slug "calendario".

Descripción de la imagen aquí

  1. Cuando creé una página con el slug "mi-evento" y un evento (CPT) con el slug "mi-evento", se muestra el tipo de entrada personalizado.

Descripción de la imagen aquí

  1. Otras páginas tampoco funcionan. Si miras la imagen de arriba queda claro por qué: la regla del tipo de entrada personalizado siempre coincidirá con un slug de página. Como WordPress no tiene forma de identificar si es una página o un tipo de entrada personalizado que no existe, devolverá un 404. Por eso necesitas un slug para identificar ya sea la página o el CPT. Una posible solución sería interceptar el error y buscar una página que pueda existir similar a esta respuesta.
2 oct 2015 15:13:12
Comentarios

Entonces, si el objetivo es eliminar el slug para los CPT's, ¿no podríamos nombrar el CPT con algo único que no colisione, ya que de todos modos nunca se verá en la URL? ¿O es el nombre de la publicación el posible conflicto si se nombra igual que una página?

Ben Racicot Ben Racicot
2 oct 2015 17:35:15

He actualizado mi respuesta para mostrar que esto en realidad rompe todas las páginas. Sin un slug, WP buscará un CPT en lugar de una página y, si no lo encuentra, devolverá un error. Por lo tanto, en realidad no está relacionado con el nombre de la publicación.

Jan Beck Jan Beck
2 oct 2015 18:49:31

Ya veo. Debería haber reglas de reescritura que agreguen '-1' a las URL futuras con conflictos, como ocurre con las publicaciones nativas de WP frente a las páginas. He creado un ticket en trac https://core.trac.wordpress.org/ticket/34136#ticket, me encantaría conocer tu opinión.

Ben Racicot Ben Racicot
3 oct 2015 02:22:54
3

Antecedentes

Incluso después de buscar por todas partes, no pude encontrar una solución adecuada para eliminar el slug de CPT de los enlaces permanentes que realmente funcione y sea consistente con la forma en que WordPress realmente analiza las solicitudes. Al parecer, todos los demás que buscan la misma solución están en la misma situación que yo.

Resulta que esto es en realidad una solución de dos partes.

  1. Eliminar el slug de CPT de los enlaces permanentes
  2. Indicar a WordPress cómo encontrar las publicaciones desde los nuevos enlaces permanentes

La primera parte es bastante sencilla y muchas respuestas existentes ya lo hacen correctamente. Esto es lo que parece:

// eliminar slug de CPT de los enlaces permanentes
function remove_cpt_slug( $post_link, $post, $leavename ) {

    if ( $post->post_type != 'custom_post_type' ) {
        return $post_link;
    } else {
        $post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
        return $post_link;
    }
}
add_filter( 'post_type_link', 'remove_cpt_slug', 10, 3 );

Ahora, la segunda parte es donde las cosas se complican. Después de resolver la primera parte, tus enlaces permanentes de CPT ya no tienen slugs de CPT. Pero ahora, el problema es que WordPress no sabe cómo encontrar tus publicaciones desde esos nuevos enlaces permanentes porque todo lo que sabe es que los enlaces permanentes de CPT tienen slugs de CPT. Entonces, sin un slug de CPT en el enlace permanente, no puede encontrar tu publicación. Es por eso que cuando haces una solicitud para tus publicaciones en este punto, muestra un error 404 no encontrado.

Así que, todo lo que necesitas hacer ahora es indicar a WordPress cómo encontrar tus publicaciones utilizando los nuevos enlaces permanentes. Pero esta es la parte donde las respuestas existentes no funcionan muy bien. Veamos algunas de esas respuestas como ejemplo:

La siguiente función funciona bastante bien, pero solo funcionará si tu estructura de enlaces permanentes está configurada como Nombre de la publicación.

function parse_request_remove_cpt_slug( $query ) {

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

    if ( ! empty( $query->query['name'] ) ) {
        global $wpdb;
        $cpt = $wpdb->get_var("SELECT post_type FROM $wpdb->posts WHERE post_name = '{$query->query['name']}'");

        // Agrega CPT a la lista de tipos de publicación que WP incluirá cuando consulte basado en el nombre de la publicación.
        $query->set( 'post_type', $cpt );
    }
}
add_action( 'pre_get_posts', 'parse_request_remove_cpt_slug' );

La siguiente función funciona bien para tu tipo de publicación personalizado independientemente de la estructura de enlaces permanentes, pero mostrará un error en todos los demás tipos de publicación.

function rewrite_rule_remove_cpt_slug() {

    add_rewrite_rule(
        '(.?.+?)(?:/([0-9]+))?/?$',
        'index.php?custom_post_type=$matches[1]/$matches[2]&post_type=custom_post_type',
        'bottom'
    );
}
add_action( 'init', 'rewrite_rule_remove_cpt_slug', 1, 1 );

Hay otra respuesta que se supone funciona como solución independiente, pero termina causando más problemas que soluciones, como mostrar errores en tus publicaciones de CPT así como en otras. Esta requiere modificar el argumento de reescritura en el registro de tu CPT de la siguiente manera:

'rewrite' => array( 'slug' => '/', 'with_front' => false )

Hasta ahora, todas las respuestas existentes que encontré son como las anteriores. O funcionan parcialmente o ya no funcionan. Esto probablemente se debe a que WordPress no ofrece una manera estandarizada de eliminar el slug de CPT de los enlaces permanentes de tipos de publicación personalizados y, por lo tanto, estas respuestas se basan en considerar escenarios particulares o en una forma poco elegante.

Respuesta

Esto es lo que he ideado al intentar crear una solución que funcione en la mayoría, si no en todos, los escenarios. Esto eliminará correctamente el slug de CPT de los enlaces permanentes de CPT y también indicará a WordPress cómo encontrar publicaciones de CPT desde esos nuevos enlaces permanentes. No reescribe reglas en la base de datos, por lo que no necesitarás volver a guardar tu estructura de enlaces permanentes. Además, esta solución es consistente con la forma en que WordPress realmente analiza las solicitudes para encontrar publicaciones desde enlaces permanentes, lo que ayuda a que sea una solución más aceptable.

Asegúrate de reemplazar custom_post_type con el nombre de tu propio tipo de publicación personalizado. Aparece una vez en cada función, por lo que dos ocurrencias en total.

// eliminar slug de CPT de los enlaces permanentes
function remove_cpt_slug( $post_link, $post, $leavename ) {

    if ( $post->post_type != 'custom_post_type' ) {
        return $post_link;
    } else {
        $post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );
        return $post_link;
    }
}
add_filter( 'post_type_link', 'remove_cpt_slug', 10, 3 );


// indicar a wordpress cómo encontrar publicaciones desde los nuevos enlaces permanentes
function parse_request_remove_cpt_slug( $query_vars ) {

    // regresar si es el panel de administración 
    if ( is_admin() ) {
        return $query_vars;
    }

    // regresar si los enlaces permanentes bonitos no están habilitados
    if ( ! get_option( 'permalink_structure' ) ) {
        return $query_vars;
    }

    $cpt = 'custom_post_type';

    // almacenar el valor del slug de publicación en una variable
    if ( isset( $query_vars['pagename'] ) ) {
        $slug = $query_vars['pagename'];
    } elseif ( isset( $query_vars['name'] ) ) {
        $slug = $query_vars['name'];
    } else {
        global $wp;
        
        $path = $wp->request;

        // usar la ruta de la URL como slug
        if ( $path && strpos( $path, '/' ) === false ) {
            $slug = $path;
        } else {
            $slug = false;
        }
    }

    if ( $slug ) {
        $post_match = get_page_by_path( $slug, 'OBJECT', $cpt );

        if ( ! is_admin() && $post_match ) {

            // eliminar cualquier elemento de error 404 no encontrado del array query_vars porque ya existe una coincidencia de publicación en CPT
            if ( isset( $query_vars['error'] ) && $query_vars['error'] == 404 ) {
                unset( $query_vars['error'] );
            }

            // eliminar elementos innecesarios del array query_vars original
            unset( $query_vars['pagename'] );
    
            // agregar elementos necesarios al array query_vars
            $query_vars['post_type'] = $cpt;
            $query_vars['name'] = $slug;
            $query_vars[$cpt] = $slug; // esto construye el elemento "cpt=>post_slug"
        }
    }

    return $query_vars;
}
add_filter( 'request', "parse_request_remove_cpt_slug" , 1, 1 );

Consideraciones:

  1. Esta solución intencionalmente excluye la estructura de enlaces permanentes Simple de su alcance, ya que no es una de las estructuras de enlaces permanentes bonitos. Por lo tanto, funcionará con todas las estructuras de enlaces permanentes excepto con la Simple.

  2. Como WordPress no evita automáticamente la creación de slugs duplicados en diferentes tipos de publicación, puedes encontrar problemas al acceder a publicaciones que tienen los mismos slugs de publicación debido a la pérdida de singularidad en los enlaces permanentes de CPT después de eliminar los slugs de CPT. Este código no incluye ninguna funcionalidad para evitar ese comportamiento, por lo que es posible que desees encontrar una solución separada para abordarlo.

  3. En caso de que haya un enlace permanente duplicado, este código priorizará tu CPT sobre los demás y, por lo tanto, mostrará la publicación en tu CPT cuando se solicite.

26 may 2021 21:16:58
Comentarios

Al momento de escribir, esta solución es la mejor. Es simple y correcta. Su lógica es fácil de entender y personalizar. De hecho, personalicé esta solución para eliminar también los slugs de taxonomía.

Tom Nguyen Tom Nguyen
23 ene 2024 09:27:40

Para evitar crear slugs duplicados, puedes leer y personalizar el código en el "Paso 4" de la respuesta de Matt Keys.

Tom Nguyen Tom Nguyen
30 ene 2024 17:07:22

He consolidado este código y el de Matt Keys en este gist, necesita más pruebas pero parece funcionar bien. Básicamente solo modifiqué el -duplicado del slug a algo como -1, -2, etc. Seguramente hay una mejor manera de hacerlo. Incluso podría ser bueno construir una pequeña interfaz para configurar 'location' con el slug CPT deseado. https://gist.github.com/cdsaenz/291d9599e1f20313c3a87edf48233176

cdsaenz cdsaenz
31 ene 2025 19:35:01
0

y podemos hacer algunos cambios a la función mencionada anteriormente:

function na_parse_request( $query ) {

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

if ( ! empty( $query->query['name'] ) ) {
    $query->set( 'post_type', array( 'post', 'events', 'page' ) );
}
}

a:

function na_parse_request( $query ) {

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

if ( ! empty( $query->query['name'] ) ) {

    global $wpdb;
    $pt = $wpdb->get_var(
        "SELECT post_type FROM `{$wpdb->posts}` " .
        "WHERE post_name = '{$query->query['name']}'"
    );
    $query->set( 'post_type', $pt );
}
}

para establecer el valor correcto de post_type.

1 mar 2017 13:50:14
1

Esto funcionó para mí: 'rewrite' => array('slug' => '/')

3 may 2017 19:39:48
Comentarios

Esto no funciona. Da error 404 incluso cuando has actualizado los enlaces permanentes.

Christine Cooper Christine Cooper
12 nov 2017 20:02:23
1

Para cualquiera que esté leyendo esto y haya tenido problemas con posts hijos como yo, descubrí que la mejor manera era agregar tus propias reglas de reescritura.

El problema principal que tenía era que WordPress trata la redirección de páginas que tienen 2 niveles (posts hijos) de manera un poco diferente a cómo trata 3 niveles de profundidad (hijos de posts hijos).

Esto significa que cuando tengo /tipo-de-post/nombre-del-post/hijo-del-post/ puedo usar /nombre-del-post/hijo-del-post y me redirigirá al que tiene el tipo-de-post al principio. Pero si tengo tipo-de-post/nombre-del-post/hijo-del-post/nieto-del-post, entonces no puedo usar nombre-del-post/hijo-del-post/nieto-del-post.

Al revisar las reglas de reescritura, parece que coincide con cosas diferentes a pagename en el primer y segundo nivel (creo que el segundo nivel coincide con adjuntos) y luego hace algo ahí para redirigirte al post correcto. A tres niveles de profundidad no funciona.

Lo primero que necesitas hacer es eliminar el enlace del tipo de post también de los hijos. Esta lógica debería ocurrir aquí si miras la respuesta de Nate Allen mencionada arriba:

$post_link = str_replace( '/' . $post->post_type . '/', '/', $post_link );

Yo usé una mezcla de diferentes condicionales para verificar si el post tenía hijos y cosas por el estilo para llegar al permalink correcto. Esta parte no es muy complicada y encontrarás ejemplos de personas haciéndolo en otros lugares.

El siguiente paso es donde las cosas cambian de la respuesta dada. En lugar de agregar cosas a la consulta principal (que funcionaba para posts personalizados y sus hijos pero no para hijos más profundos), agregué una regla de reescritura que iba al final de las reglas de WordPress para que si pagename no coincidía y estaba a punto de mostrar un 404, haría una última verificación para ver si una página dentro del tipo de post personalizado tenía el mismo nombre, de lo contrario mostraría el 404.

Aquí está la regla de reescritura que usé asumiendo que 'evento' es el nombre de tu CPT:

function rewrite_rules_for_removing_post_type_slug()
{
    add_rewrite_rule(
        '(.?.+?)(?:/([0-9]+))?/?$',
        'index.php?event=$matches[1]/$matches[2]&post_type=event',
        'bottom'
    );
}

add_action('init', 'rewrite_rules_for_removing_post_type_slug', 1, 1);

Espero que esto ayude a alguien más, no pude encontrar nada más que tuviera que ver con hijos de posts hijos y eliminar el slug de esos.

29 may 2017 06:34:40
Comentarios

Parece haber un error tipográfico en la expresión regular. Entre '(:' se necesita un '?' para usarlo como un subpatrón sin captura => '(?:'. El tercer '?' parece estar mal colocado, ya que permite un primer subpatrón vacío. Probablemente debería estar ubicado entre ( y :. Sin este error tipográfico, la expresión será la misma que se puede encontrar para el tipo de publicación incorporado 'page'.

jot jot
28 oct 2019 21:46:45
1

Tuve los mismos problemas aquí y parece que no hay movimiento en el sitio de WordPress. En mi caso particular, donde para publicaciones individuales de blog se necesitaba la estructura /blog/%postname%/, esta solución

https://kellenmace.com/remove-custom-post-type-slug-from-permalinks/

terminó en un montón de errores 404

Pero junto con este maravilloso enfoque, que no utiliza la estructura de enlaces permanentes del backend para las entradas del blog, finalmente funciona de maravilla. https://www.bobz.co/add-blog-prefix-permalink-structure-blog-posts/

Muchas gracias.

19 jun 2019 18:39:51
Comentarios

Las respuestas que solo contienen enlaces no son recomendadas. Si encontraste una respuesta en este artículo que es diferente a las otras respuestas en la página, por favor incluye un resumen y un ejemplo de código en tu respuesta.

squarecandy squarecandy
17 dic 2019 00:50:24
2

Para mí funcionó ahora:

'rewrite' => array( 
'slug' => '/',
'with_front' => false
)

Insertar dentro de la función register_post_type().

14 dic 2020 22:37:29
Comentarios

Esta solución rompe páginas simples

mihdan mihdan
23 jun 2021 17:36:13

Lo intenté y funcionó.

Este es el código simple que debes usar

register_post_type('wporg_product', array( 'labels' => array( 'name' => 'Portfolio', 'singular_name' => 'Portfolio', ), 'menu_icon' => 'dashicons-id', 'rewrite' => array( 'slug' => 'portfolio', 'with_front' => false ), // mi slug personalizado

        )
    );

Después de cambiar este código, debes guardar la configuración de enlaces permanentes una vez.

Rohit Rohit
4 ago 2024 11:38:03
0

Esto es lo que funcionó para mí. Reemplaza podcast con el slug de tu CPT:

add_action('init', function () {
    register_post_type(
        'podcast',
        [
            'rewrite' => false,
        ]
    );
});

add_filter('post_type_link', function ($post_link, $post, $leavename) {
    if (isset($post->post_type) && $post->post_type === 'podcast') {
        $post_link = home_url($post->post_name);
    }

    return $post_link;
}, 10, 3);

add_action('init', function () {
    add_rewrite_rule('(.+?)/?$', 'index.php?podcast=$matches[1]', 'bottom');
});
17 ago 2021 01:46:25
0

El plugin "Remove CPT base" funciona correctamente.

https://wordpress.org/plugins/remove-cpt-base/

16 feb 2024 07:30:34
5
-1

No necesitas tanto código duro. Simplemente usa un plugin ligero:

Tiene opciones personalizables.

26 feb 2017 00:12:35
Comentarios

Ahora entiendo por qué te votaron negativo, evita que los enlaces normales de la página se resuelvan. No lo noté porque estaba obteniendo copias en caché de las páginas existentes a pesar de actualizar.

Walf Walf
14 sept 2017 05:36:54

@Walf ¿Puedes contarme sobre el problema con más detalle?

T.Todua T.Todua
14 sept 2017 11:17:53

Al seguir enlaces a páginas (que no eran del tipo de entrada personalizada) desde el menú principal, mostraban errores 404, como si la página no existiera; eso es todo.

Walf Walf
14 sept 2017 14:45:16

@Walf ¿puedes darme alguna URL de ejemplo de tu caso? (puedes ocultar el nombre del dominio si quieres, solo necesito un ejemplo) gracias, lo actualizaré

T.Todua T.Todua
15 sept 2017 10:31:07

"Este plugin ha sido cerrado desde el 19 de septiembre de 2018 y no está disponible para descarga. Este cierre es permanente."

squarecandy squarecandy
17 dic 2019 00:51:24