Eliminar slug de las URL personalizadas de tipo de publicación

39

Parece que todos los recursos web se basan en el tema de eliminar una babosa de tipo de publicación personalizada, por ejemplo,

yourdomain.com/CPT-SLUG/post-name 

ahora son soluciones muy anticuadas que a menudo hacen referencia a instalaciones previas a la versión 3.5 de WP. Una común es:

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

dentro de su función register_post_type. Esto ya no funciona y es engañoso. Así que le pregunto a la comunidad en el tercer trimestre de 2018 al borde de WordPress 5 ...

¿Cuáles son las formas modernas y eficientes de eliminar la Barra de Tipo de publicación de la URL de una publicación de tipo de publicación personalizada desde el argumento de reescritura o en cualquier otro lugar?

ACTUALIZACIÓN: Parece que hay varias maneras de forzar esto para que funcione con expresiones regulares. Específicamente, la respuesta de Jan Beck debe estar siempre dispuesto a monitorear la creación de contenido para garantizar que no se creen nombres de página / publicación conflictivos ... Sin embargo, estoy convencido de que esta es una gran deficiencia en el núcleo de WP donde debería ser manejada por nosotros . Tanto como una opción / gancho al crear un CPT o un conjunto avanzado de opciones para enlaces permanentes. Por favor apoye el ticket de la pista.

Nota a pie de página: por favor, respalde este ticket de trac a través de verlo / promocionarlo: enlace

    
pregunta TR3B 28.09.2015 - 18:18

10 respuestas

56

El siguiente código funcionará, pero solo tienes que tener en cuenta que los conflictos pueden ocurrir fácilmente si la bala de tu tipo de publicación personalizada es la misma que la de una página o la bala de una publicación ...

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 );

Sólo quitar la babosa no es suficiente. En este momento, obtendrás una página 404 porque WordPress solo espera que las publicaciones y las páginas se comporten de esta manera. También deberá 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' );

Simplemente cambia "eventos" a tu tipo de publicación personalizada y listo. Es posible que necesites actualizar tus enlaces permanentes.

    
respondido por el Nate Allen 30.09.2015 - 22:45
11

Intenté resolver esto hace poco y la respuesta corta de lo que sé es no . Al menos no desde dentro del argumento de reescritura.

La explicación larga se hace evidente si nos fijamos en el código real de register_post_type en wp-includes / post.php line 1454 :

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

Puedes ver los prefijos $args->rewrite['slug'] a la etiqueta %$post_type% rewrite. Uno podría pensar "vamos a configurar el slug a null y luego" hasta que veas unas líneas:

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

Puede ver que la función siempre espera un valor de bala que no esté vacío y, de lo contrario, utiliza el tipo de publicación.

    
respondido por el Jan Beck 30.09.2015 - 16:01
11

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

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

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

Una vez que haya modificado su documento de taxonomía de tipo de publicación personalizado, intente ir a Configuración > Permalinks y vuelve a guardar tus configuraciones , de lo contrario obtendrás 404 páginas no encontradas.

Busque aquí la mejor solución: enlace

    
respondido por el Mayank Dudakiya 12.04.2017 - 20:16
6

En respuesta a mi respuesta anterior : por supuesto, podría establecer el parámetro rewrite en false al registrar un nuevo tipo de publicación y manejar las reglas de reescritura como usted mismo

<?php
function wpsx203951_custom_init() {

    $post_type = 'event';
    $args = (object) array(
        'public'      => true,
        'label'       => 'Events',
        'rewrite'     => false, // always set this to false
        'has_archive' => true
    );
    register_post_type( $post_type, $args );

    // these are your actual rewrite arguments
    $args->rewrite = array(
        'slug' => 'calendar'
    );

    // everything what follows is from the register_post_type function
    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' );

Puede ver que la llamada add_permastruct ahora ya no incluye la bala. Probé dos escenarios:

  1. Cuando creé una página con el slug "calendar" esa página se sobrescribe con el archivo de tipo de publicación que también usa el slug "calendar".

  • Cuando creé una página con el slug "my-event" y un evento (CPT) con el slug "my-event", se muestra el tipo de publicación personalizada.
  • Cualquier otra página tampoco funciona. Si observa la imagen de arriba, queda claro por qué: la regla de tipo de publicación personalizada siempre coincidirá con una barra de página. Debido a que WordPress no tiene forma de identificar si es una página o un tipo de publicación personalizada que no existe, devolverá 404. Es por eso que necesita un slug para identificar la página o CPT. Una posible solución sería interceptar el error y buscar una página que pueda existir similar a esta respuesta .
  • respondido por el Jan Beck 02.10.2015 - 14:13
    2

    Mirando a través de las respuestas aquí, creo que hay espacio para una mejor solución que combine algunas de las cosas que aprendí anteriormente y agregue la detección automática y la prevención de las babosas post duplicadas.

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

    Paso 1: inhabilite las reescrituras en su tipo de publicación personalizada estableciendo las reescrituras en 'falso' cuando registre la publicación:

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

    Paso 2: Agregar manualmente nuestras reescrituras personalizadas a la parte inferior de WordPress reescribe 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 sus necesidades, es posible que desee modificar las reescrituras anteriores (deshabilitar trackbacks? feeds ?, etc.). Estos representan los tipos "predeterminados" de reescrituras que se hubieran generado si no las hubiera deshabilitado en el paso 1

    Paso 3: Haz enlaces permanentes a tu publicación personalizada y escribe 'bonito' de nuevo

    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: Puede detenerse aquí si no le preocupa que sus usuarios creen una publicación conflictiva (duplicada) en otro tipo de publicación que cree una situación en la que solo uno de ellos puede cargar cuando se solicita la página.

    Paso 4: Evita las babosas post duplicadas

    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 ) {
            // Saving a custom_post_type post, check for duplicates in POST or PAGE post types
            $post_match = get_page_by_path( $slug, 'OBJECT', 'post' );
            $page_match = get_page_by_path( $slug, 'OBJECT', 'page' );
    
            if ( $post_match || $page_match ) {
                $slug .= '-duplicate';
            }
        } else {
            // Saving a POST or PAGE, check for duplicates in custom_post_type post type
            $custom_post_type_match = get_page_by_path( $slug, 'OBJECT', 'custom_post_type' );
    
            if ( $custom_post_type_match ) {
                $slug .= '-duplicate';
            }
        }
    
        return $slug;
    }
    add_filter( 'wp_unique_post_slug', 'prevent_slug_duplicates', 10, 6 );
    

    NOTA: Esto agregará la cadena '-duplicate' al final de cualquier bala duplicada. Este código no puede evitar las duplicaciones duplicadas si ya existen antes de implementar esta solución. Asegúrese de verificar si hay duplicados primero.

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

        
    respondido por el Matt Keys 06.10.2017 - 00:51
    0

    No necesitas mucho código. Solo usa el plugin ligero:

    Tiene opciones personalizables.

        
    respondido por el T.Todua 25.02.2017 - 23:12
    0

    y podemos realizar algunos cambios en 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 tipo_post.

        
    respondido por el Max Kondrachuk 01.03.2017 - 12:50
    0

    Esto me funcionó:   'rewrite' => array('slug' => '/')

        
    respondido por el Malki Mohamed 03.05.2017 - 18:39
    0

    Para cualquier persona que haya leído esto que haya tenido problemas con publicaciones de niños como yo, encontré que la mejor manera era agregar sus propias reglas de reescritura.

    El problema principal que estaba teniendo era que WordPress trata la redirección de las páginas que tienen 2 niveles (publicaciones secundarias) un poco diferente a la de 3 niveles (publicaciones de hijo de secundaria).

    Eso significa que cuando tengo / post-type / post-name / post-child / puedo usar / post-name / post-child y me redireccionaré a la que tiene post-type al frente, pero si tengo post-type / post-name / post-child / post-grandchild entonces no puedo usar post-name / post-child / post-grandchild.

    Mirando las reglas de reescritura, parece que coincide con otras cosas además de pagename en el primer y segundo nivel (creo que el segundo nivel coincide con el adjunto) y luego hace algo para redirigirte al post adecuado. A tres niveles de profundidad no funciona.

    Lo primero que debes hacer es eliminar el enlace de tipo de publicación de los niños también. Esta lógica debería ocurrir aquí si nos fijamos en la respuesta de Nate Allen:

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

    Yo mismo utilicé una combinación de diferentes condicionales para verificar si la publicación tenía hijos y otras cosas para obtener el enlace permanente correcto. Esta parte no es demasiado complicada y encontrarás ejemplos de personas que lo hacen en otros lugares.

    Sin embargo, el siguiente paso es cuando las cosas cambian de la respuesta dada. En lugar de agregar cosas a la consulta principal (que funcionó para las publicaciones personalizadas y sus hijos, pero no para los demás), agregué una reescritura que iba al final de las reglas de WordPress, de modo que si pagename no se presentaba y estaba a punto de al hacer un 404, haría una última comprobación para ver si una página dentro del tipo de publicación personalizada tenía el mismo nombre, de lo contrario, eliminarí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 publicaciones de hijo de niño y eliminar la babosa de esas.

        
    respondido por el Moe Loubani 29.05.2017 - 05:34
    -2

    Puedes hacerlo de una manera muy simple.

    1) Copia esta función a functions.php de tu tema:

    function changeURL ($id)
    {
        /* Get the slug you want to remove. */
        global $post;
        $slug = get_post($post)->post_name;
    
        $post_type = get_post_type ($id);
        $standard_posts = array("post", "page", "attachment", "revision", "nav_menu_item");
        /* 
            If the type of the current post is a custom one, use Javascript to
            replace the $slug for the default URL of the post.
        */
        if (!in_array ($post_type, $standard_posts))
        {
            echo '<script type="text/javascript">
                var stateObj = { register: "' . $slug . '" };
                history.pushState(stateObj, "ignore_this", "../?p='.$id.'");
                </script>';
        }
    }
    


    2) Llama esta función al single.php de tu tema debajo del while de The Loop:

    <?php /* The loop */ ?>
    <?php while ( have_posts() ) : the_post();?>
    
        <?php changeURL (get_the_ID ()); ?>
        /* etc. */
    
    <?php endwhile; ?>
    


    Y deja que el Javascript haga la magia :)

    Actualización:

    Resolví los inconvenientes señalados por @kraftner en los comentarios. Ahora, changeURL() reemplazará el enlace permanente por la URL predeterminada en la barra de direcciones.

        
    respondido por el Daniel Muñoz Parsapoormoghadam 03.10.2015 - 11:34

    Lea otras preguntas en las etiquetas