Remova a lesma dos URLs de postagem personalizados

48

Parece que todos os recursos da Web com base no assunto de remover uma lesma de tipo de postagem personalizada, ou seja,

yourdomain.com/CPT-SLUG/post-name 

agora são soluções muito desatualizadas, frequentemente referenciando as instalações anteriores à WP versão 3.5. Um comum é:

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

dentro da sua função register_post_type. Isso não funciona mais e é enganoso. Então, pergunto à comunidade no terceiro trimestre de 2018 à beira do WordPress 5 ...

Quais são as maneiras modernas e eficientes de remover o Slug de tipo de postagem do URL de uma postagem de tipo de postagem personalizada dentro do argumento de reescrita ou em qualquer outro lugar?

ATUALIZAÇÃO: Parece haver várias maneiras de forçar isso a trabalhar com regex. Especificamente, a resposta de Jan Beck, você deve estar sempre disposto a monitorar a criação de conteúdo para garantir que não sejam criados nomes de páginas / postagens conflitantes ... No entanto, estou convencido de que essa é uma grande fraqueza no núcleo do WP, onde deve ser tratada por nós. . Como opção / gancho ao criar um CPT ou um conjunto avançado de opções para links permanentes. Por favor, apoiem o bilhete de pista.

Nota de rodapé: Por favor, apoie este ticket trac assistindo / promovendo: https://core.trac.wordpress.org/ticket/34136#ticket

Ben Racicot
fonte
Acho que estou coçando a cabeça por que você quer fazer isso? Confuso.
Michael Ecklund
3
@MichaelEcklund porque qualquer CPT usado para criar páginas da Web voltadas para o público tem um nome de lesma forçado no URL. Na verdade, existem muitos desenvolvedores de wp procurando remover a lesma com segurança.
precisa

Respostas:

60

O código a seguir funcionará, mas você deve ter em mente que os conflitos podem ocorrer facilmente se a lesma do seu tipo de postagem personalizado for igual à página ou lesma da postagem ...

Primeiro, removeremos a lesma do link 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 );

Apenas remover a lesma não é suficiente. No momento, você receberá uma página 404 porque o WordPress espera apenas que postagens e páginas se comportem dessa maneira. Você também precisará adicionar o seguinte:

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

Basta alterar "eventos" para seu tipo de postagem personalizado e você estará pronto. Pode ser necessário atualizar seus links permanentes.

Nate Allen
fonte
obrigado. Você acha que isso é melhor do que criar as reescritas manualmente? Eu já vi essa solução e ela pode manter os conflitos que você menciona afastados?
quer
11
Falha com nginx porque a condição 2 != count( $query->query ). Com o nginx, você pode ter $ query-> query como array('page' => '', 'name' => '...', 'q' => '...'). Então @NateAllen, qual é o significado dessa condição?
Fabio Montefuscolo #
3
Precisamos de algo melhor que isso. Suporte para remover a lesma incorporada para que não possamos criar URLs conflitantes mais tarde. A maneira como postagens e páginas regulares criam seus URLs.
precisa
3
Sou eu ou isso quebra algumas tags condicionais do wordpress como is_single () e is_singular ()?
22417 robert gordon
11
Infelizmente, esta solução causou alguns links quebrados e meu blog parou de mostrar postagens e era apenas uma página normal. Veja uma solução melhor abaixo por Matt Keys.
Radley Sustaire
20

Escreva o seguinte código no registro da taxonomia.

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

O mais importante que você deve fazer após a alteração do código

Depois de alterar seu documento de taxonomia de tipo de postagem personalizado, tente ir para Configurações> Links permanentes e salve novamente as configurações , caso contrário, a página 404 não será encontrada.

Verifique aqui a melhor solução: http://www.krazzycodes.com/how-to-remove-custom-post-type-taxonomy-base-from-url-in-wordpress/

Mayank Dudakiya
fonte
Isso realmente funciona, eu não sei como ninguém percebeu isso antes. É claro que isso pode interferir em outras páginas se elas tiverem o mesmo link permanente, mas, se não, essa é uma ótima solução.
Aleksandar Đorđević
4
Tentei isso. Ele fornece o resultado desejado para meus links de tipo de postagem personalizados. No entanto, ele 'captura' todas as lesmas do tipo de postagem POST ou PAGE e tenta resolvê-las como uma URL para o meu tipo de postagem personalizado e, em seguida, 404s. (sim, eu salvei permalinks).
Matt Chaves
4
Isso não funciona. Dá 404 mesmo quando você atualizou os links permanentes.
Christine Cooper
3
Mais uma vez, mesmo depois de re-salvar as configurações permalink, posts e páginas não funcionam (404)
amklose
11
Esta solução funciona para remover a lesma do URL. Mas as páginas do arquivo não funcionam mais.
Annapurna
13

Eu tentei descobrir isso há não muito tempo e a resposta curta do que eu sei não é . Não de dentro do argumento de reescrita, pelo menos.

O longa explicação torna-se aparente se você olhar para o código real de register_post_typeno wp-includes / linha post.php 1454 :

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

Você pode ver o prefixo $args->rewrite['slug']da %$post_type%tag reescrever. Alguém poderia pensar "vamos definir a lesma para nullentão" até que você veja algumas linhas:

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

Você pode ver que a função sempre espera um valor de slug que não esteja vazio e, caso contrário, usa o tipo de postagem.

Jan Beck
fonte
Obrigado @JanBeck. Existe uma razão principal para que isso exista? Por que não hackear esse arquivo principal com a condição de omitir certos tipos de postagem desta regra?
Ben Racicot
9
Você deve dar a resposta a Jan Beck. O WordPress precisa da lesma post_type para rotear as solicitações corretamente. Essa regra evita conflitos de nomenclatura entre páginas WP nativas (que são renderizadas sem a lesma) e quaisquer tipos de postagem definidos personalizados. Se você cortar a lesma, o WordPress não saberá a diferença entre uma página chamada "picnic" e um evento (tipo de postagem personalizado) chamado "picnic".
dswebsme
3
@dswebsme Concordou, mas há situações em que você absolutamente deve alterar o URL. Além de por que você não pode nativamente e não deveria, como você o faz com eficiência?
Ben Racicot
7

Em resposta à minha resposta anterior : é claro que você pode definir o rewriteparâmetro ao falseregistrar um novo tipo de postagem e manipular as regras de reescrita da mesma forma

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

Você pode ver que a add_permastructchamada agora não inclui mais a lesma. Eu testei dois cenários:

  1. Quando criei uma página com o slug "calendar", essa página é substituída pelo arquivo do tipo de postagem, que também usa o slug "calendar".

insira a descrição da imagem aqui

  1. Quando criei uma página com a lesma "my-event" e um evento (CPT) com a lesma "my-event", o tipo de postagem personalizado é exibido.

insira a descrição da imagem aqui

  1. Quaisquer outras páginas também não funcionam. Se você observar a figura acima, fica claro o motivo: a regra do tipo de postagem personalizada sempre corresponderá a um slug de página. Como o WordPress não tem como identificar se é uma página ou um tipo de postagem personalizado que não existe, ele retornará 404. É por isso que você precisa de uma lesma para identificar a página ou o CPT. Uma solução possível seria interceptar o erro e procurar uma página que possa existir semelhante a esta resposta .
Jan Beck
fonte
Portanto, se o objetivo é remover a lesma dos CPTs, não podemos nomear o CPT como algo único que não colidiria, pois nunca será visto no URL? Ou o pós-nome é o possível conflito se tiver o mesmo nome de uma página?
Ben Racicot
Atualizei minha resposta para mostrar que isso realmente quebra todas as páginas. Sem uma lesma, o WP procurará um CPT em vez de uma página e, se não o encontrar, retornará um erro. Portanto, na verdade, não está relacionado ao nome do post.
Jan Beck
11
Eu vejo. Deve haver regras de reescrita que acrescentem '-1' a URLs conflitantes futuros, como postagens nativas do WP e páginas. Eu criei um ticket trac core.trac.wordpress.org/ticket/34136#ticket adoraria seus pensamentos.
Ben Racicot
7

Examinando as respostas aqui, acho que há espaço para uma solução melhor que combine algumas coisas que aprendi acima e adicione detecção automática e prevenção de post slugs duplicados.

NOTA: Altere 'custom_post_type' para o seu próprio nome de CPT em todo o meu exemplo abaixo. Existem muitas ocorrências, e um 'localizar / substituir' é uma maneira fácil de capturar todas elas. Todo esse código pode ser encontrado em seu functions.php ou em um plugin.

Etapa 1: desative reescritas no seu tipo de postagem personalizado, definindo reescritas para 'false' quando você registrar a postagem:

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

Etapa 2: adicione manualmente nossas regravações personalizadas na parte inferior das regravações do WordPress para o nosso 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: Dependendo das suas necessidades, convém modificar as reescritas acima (desativar trackbacks? Feeds ?, etc). Eles representam os tipos 'padrão' de regravações que teriam sido gerados se você não desativasse as regravações na etapa 1

Etapa 3: tornar os links permanentes para o seu post personalizado "bonitos" novamente

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: Você pode parar aqui se não estiver preocupado com a criação de uma postagem conflitante (duplicada) em outro tipo de postagem que criará uma situação em que apenas um deles poderá carregar quando a página for solicitada.

Etapa 4: impedir postagens 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: Isso anexará a string '-duplicate' ao final de qualquer lesma duplicada. Este código não pode impedir lesmas duplicadas se elas já existirem antes da implementação desta solução. Certifique-se de verificar as duplicatas primeiro.

Gostaria muito de receber uma resposta de alguém que dê uma chance para ver se funcionou bem para eles também.

Matt Keys
fonte
Apenas testei e parece que está funcionando até agora.
Christine Cooper
Estava esperançoso por essa abordagem, mas me deu um erro 404 nas minhas postagens do CPT, mesmo depois de salvar novamente os Permalinks.
Garconis 7/08
Desculpe, não funcionou para você Garconis. Eu estava conversando com alguém sobre isso há algum tempo e eles também estavam tendo problemas com isso em seu site. Parece-me que me lembro que importava que os permalinks dos seus posts tivessem um prefixo. No site que desenvolvi para as postagens do blog, use a estrutura do link permanente: / blog /% postname% /. Se você não tem um prefixo nas postagens do seu blog e é aceitável, experimente e me avise como é!
Matt Chaves
2
Isso funcionou para mim. Ao contrário de outras soluções na página, ele não quebrava as páginas normais ou o layout do blog e não causava redirecionamentos infinitos. Ele até mostra o URL correto na área "Link permanente" ao editar essas páginas cpt. Solução muito boa aqui, apenas ressalva é que a página do arquivo não funciona. Lembre-se de trocar "custom_post_type" e atualizar seus links permanentes posteriormente .
Radley Sustaire
@MattKeys, as configurações padrão de link permanente têm uma estrutura personalizada de /%category%/%postname%/. Ao adicionar seu código, as lesmas do CPT parecem OK (embora esteja faltando a barra final) ... e o verificador de conflitos também funciona. Mas o post real resulta em um 404.
Garconis 03/07
1

Você não precisa de tanto código físico. Basta usar o plugin leve:

Possui opções personalizáveis.

T.Todua
fonte
Agora eu sei por que você recebeu votos negativos, impedindo a resolução de links de páginas normais. Não o vi porque estava recebendo cópias em cache das páginas existentes, apesar da atualização.
Walf
@ Walf Você pode me falar sobre o problema em detalhes?
T.Todua
Os links para páginas (que não eram do tipo personalizado de postagem) no menu principal deram 404 erros, como se a página não existisse; é isso aí.
Walf
@Walf, você pode me dar um exemplo de URL da sua ocasião? (você pode cobrir nome de domínio se você quiser, eu só preciso de um ex exemplo), obrigado, eu wil atualizá-lo
T.Todua
1

Tive os mesmos problemas aqui e parece não haver movimento no site wordpress. Na minha situação particular, onde para posts únicos, era necessária a estrutura / blog /% postname% /

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

terminou em um monte de 404s

Mas, junto com essa abordagem maravilhosa, que não está usando a estrutura de suporte permanente para o post do blog, ela finalmente funciona como charme. https://www.bobz.co/add-blog-prefix-permalink-structure-blog-posts/

Muito obrigado.

Friedrich Siever
fonte
0

e podemos fazer algumas alterações na função mencionada acima:

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

para:

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 definir o valor correto de post_type.

Max Kondrachuk
fonte
0

Isso funcionou para mim: 'rewrite' => array('slug' => '/')

Malki Mohamed
fonte
11
Isso não funciona. Dá 404 mesmo quando você atualizou os links permanentes.
Christine Cooper
0

Para quem leu isso que teve problemas com publicações secundárias como eu, achei a melhor maneira de adicionar suas próprias regras de reescrita.

O principal problema que eu estava enfrentando era que o WordPress trata o redirecionamento de páginas com 2 níveis (posts filhos) com profundidade um pouco diferente do que com 3 níveis de profundidade (filho de posts filhos).

Isso significa que quando eu tenho / post-type / post-name / post-child / posso usar / post-name / post-child e ele me redireciona para aquele com pós-type na frente, mas se eu tiver pós-type / post-name / pós-filho / pós-neto, então não posso usar pós-nome / pós-filho / pós-neto.

Examinando as regras de reescrita, parece que ela corresponde a outras coisas que não o nome da página no primeiro e no segundo nível (acho que o segundo nível corresponde ao anexo) e, em seguida, faz algo para redirecioná-lo para a postagem apropriada. Em três níveis de profundidade, não funciona.

A primeira coisa que você precisa fazer é remover o link do tipo de postagem das crianças também. Essa lógica deve acontecer aqui se você olhar a resposta de Nate Allen acima:

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

Eu mesmo usei uma mistura de condicionais diferentes para verificar se o post tinha filhos e outros enfeites, a fim de obter o link permanente certo. Esta parte não é muito complicada e você encontrará exemplos de pessoas fazendo isso em outros lugares.

O próximo passo é que as coisas mudam a partir da resposta dada. Em vez de adicionar coisas à consulta principal (que funcionava para postagens personalizadas e seus filhos, mas não para os filhos posteriores), adicionei uma reescrita que foi para a parte inferior das regras do WordPress, para que, se o nome da página não saísse e estivesse prestes a ao atingir um 404, ele faria uma última verificação para ver se uma página dentro do tipo de postagem personalizada tinha o mesmo nome, caso contrário, descartaria o 404.

Aqui está a regra de reescrita que usei assumindo que 'evento' é o nome do seu 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 isso ajude outra pessoa, não consegui encontrar mais nada que tivesse a ver com filhos de posts filhos e remover a lesma deles.

Moe Loubani
fonte
Parece haver um erro de digitação no regex. Entre '(:' a '?' É necessário para usá-lo como subpadrão sem captura => '(?:'. O terceiro? Parece fora de lugar, pois permite um primeiro subpadrão vazio. Provavelmente, ele deve estar posicionado entre (e:. Sem esse erro de digitação, a expressão será a mesma que pode ser encontrada para o tipo de postagem incorporada 'página'.
jot