Remover slug de taxonomia de um link permanente de taxonomia hierárquica personalizado

21

Criei uma taxonomia de 'fórum', usando estas regras:

register_taxonomy(
  'forum',
  array('topic'),
  array(
    'public' => true,
    'name' => _a('Forums'),
    'singular_name' => _a('Forum'),
    'show_ui' => true,
    'show_in_nav_menus' => true,
    'hierarchical' => true,

    'labels' => array(
      'name' => _a('Forums'),
      'singular_name' => _a('Forum'),
      'search_items' => _a('Search Forums'),
      'popular_items' => _a('Popular Forums'),
      'all_items' => _a('All Forums'),
      'parent_item' => _a('Parent Forum'),
      'parent_item_colon' => _a('Parent Forum:'),
      'edit_item' => _a('Edit Forum'),
      'update_item' => _a('Update Forum'),
      'add_new_item' => _a('Add New Forum'),
      'new_item_name' => _a('New Forum Name'),
    ),
    'query_var' => true,
    'rewrite' => array('slug' => 'forums', 'with_front' => false, 'hierarchical' => true),  
  )
);

No front-end, os URLs se parecem com:

forums/general-discussion/sub-forum

Como posso remover a barra frontal ("fóruns")? Ou seja, altere os URLs para:

general-discussion/sub-forum

Se eu passar um argumento slug vazio para register_taxonomy (), ele funciona, mas causa problemas com os links permanentes do tipo de postagem associado a esta taxonomia

onetrickpony
fonte
@ One Trick Pony - Você já tentou em vez de deixar em 'slug' => 'forums'branco apenas removê-lo completamente e apenas ter 'rewrite' => array('with_front' => false, 'hierarchical' => true)? Eu acho que isso funcionou no passado para mim. Além disso, certifique-se de liberar os links permanentes.
Eileencodes
tentei isso, e os permalinks parecem iguais. Adicionando 'slug' => ''o faz funcionar, mas, em seguida, as mensagens que utilizam esta taxonomia gerar 404s
onetrickpony
@ One Trick Pony - Além da 'discussão geral', que outros segmentos de caminho de nível superior você precisa?
21411 MikeSchinkel
qualquer %forum%deve ser um segmento de nível superior
onetrickpony
@ One Trick Pony - Eu estava apenas esperando que você me desse alguns outros segmentos de caminho de nível superior para o contexto.
21811 MikeSchinkel

Respostas:

11

ATUALIZAR

Desde a criação deste núcleo do WordPress, foi adicionado um 'do_parse_request'gancho que permite que o roteamento de URL seja tratado com elegância e sem a necessidade de estender a WPclasse. Eu cobri o tópico em profundidade na minha palestra de 2014 do Atlanta WordCamp intitulada " Hardcore URL Routing " ; os slides estão disponíveis no link.

RESPOSTA ORIGINAL

O design de URL tem sido importante há mais de uma década; Eu até escrevi um blog sobre isso há vários anos. E, embora o WordPress seja um software brilhante, infelizmente , o sistema de reescrita de URLs está quase morto (IMHO, é claro. :) De qualquer forma, fico feliz em ver as pessoas se preocupando com o design do URL!

A resposta que vou fornecer é um plug-in que estou chamando WP_Extendedque é uma prova de conceito para esta proposta no Trac (observe que a proposta começou como uma coisa e evoluiu para outra, então você deve ler a coisa toda para ver onde foi dirigido.)

Basicamente, a idéia é subclassificar a WPclasse, substituir o parse_request()método e atribuir a $wpvariável global a uma instância da subclasse. Em seguida, parse_request()você inspeciona o caminho por segmento, em vez de usar uma lista de expressões regulares que devem corresponder ao URL na sua totalidade.

Portanto, para declarar explicitamente, essa técnica insere lógica na frente da parse_request()qual verifica correspondências de URL para RegEx e, em vez disso, procura primeiro correspondências de termos de taxonomia, mas apenas substitui parse_request()e deixa intacto o restante do sistema de roteamento de URL do WordPress, incluindo e especialmente o uso da $query_varsvariável

Para seu caso de uso, essa implementação compara apenas os segmentos do caminho da URL com os termos de taxonomia, pois é tudo o que você precisa. Essa implementação inspeciona os termos de taxonomia que respeitam os relacionamentos pai-filho e, quando encontra uma correspondência, atribui o caminho da URL (menos as barras à esquerda e à direita) a $wp->query_vars['category_name'], $wp->query_vars['tag']ou $wp->query_vars['taxonomy']& $wp->query_vars['term']e ignora o parse_request()método da WPclasse.

Por outro lado, se o caminho da URL não corresponder a um termo de uma taxonomia especificada, ele delegará a lógica de roteamento de URL ao sistema de reescrita do WordPress chamando o parse_request()método da WPclasse.

Para usar WP_Extendedno seu caso de uso, você precisará chamar a register_url_route()função no functions.phparquivo do seu tema da seguinte maneira:

add_action('init','init_forum_url_route');
function init_forum_url_route() {
  register_url_route(array('taxonomy'=>'forum'));
}

Qual é o código fonte do plug-in:

<?php
/*
Filename: wp-extended.php
Plugin Name: WP Extended for Taxonomy URL Routes
Author: Mike Schinkel
*/
function register_url_route($args=array()) {
  if (isset($args['taxonomy']))
    WP_Extended::register_taxonomy_url($args['taxonomy']);
}
class WP_Extended extends WP {
  static $taxonomies = array();
  static function on_load() {
    add_action('setup_theme',array(__CLASS__,'setup_theme'));
  }
  static function register_taxonomy_url($taxonomy) {
    self::$taxonomies[$taxonomy] = get_taxonomy($taxonomy);
  }
  static function setup_theme() { // Setup theme is 1st code run after WP is created.
    global $wp;
    $wp = new WP_Extended();  // Replace the global $wp
  }
  function parse_request($extra_query_vars = '') {
    $path = $_SERVER['REQUEST_URI'];
    $domain = str_replace('.','\.',$_SERVER['SERVER_NAME']);
    //$root_path = preg_replace("#^https?://{$domain}(/.*)$#",'$1',WP_SITEURL);
$root_path = $_SERVER['HTTP_HOST'];

    if (substr($path,0,strlen($root_path))==$root_path)
      $path = substr($path,strlen($root_path));
    list($path) = explode('?',$path);
    $path_segments = explode('/',trim($path,'/'));
    $taxonomy_term = array();
    $parent_id = 0;
    foreach(self::$taxonomies as $taxonomy_slug => $taxonomy) {
      $terms = get_terms($taxonomy_slug);
      foreach($path_segments as $segment_index => $path_segment) {
        foreach($terms as $term_index => $term) {
          if ($term->slug==$path_segments[$segment_index]) {
            if ($term->parent!=$parent_id) { // Make sure we test parents
              $taxonomy_term = array();
            } else {
              $parent_id = $term->term_id; // Capture parent ID for verification
              $taxonomy_term[] = $term->slug; // Collect slug as path segment
              unset($terms[$term_index]); // No need to scan it again
            }
            break;
          }
        }
      }
      if (count($taxonomy_term))
        break;
    }
    if (count($taxonomy_term)) {
      $path = implode('/',$taxonomy_term);
      switch ($taxonomy_slug) {
        case 'category':
          $this->query_vars['category_name'] = $path;
          break;
        case 'post_tag':
          $this->query_vars['tag'] = $path;
          break;
        default:
          $this->query_vars['taxonomy'] = $taxonomy_slug;
          $this->query_vars['term'] = $path;
          break;
      }
    } else {
      parent::parse_request($extra_query_vars); // Delegate to WP class
    }
  }
}
WP_Extended::on_load();

PS CAVEAT # 1

Embora para um determinado site eu ache que essa técnica funcione de maneira brilhante, mas NUNCA deve ser usada para que um plug-in seja distribuído no WordPress.org para que outros o usem . Se estiver no centro de um pacote de software baseado no WordPress, tudo bem. Caso contrário, essa técnica deve se limitar a melhorar o roteamento de URL para um site específico .

Por quê? Porque apenas um plugin pode usar esta técnica . Se dois plugins tentarem usá-lo, eles entrarão em conflito.

Além disso, essa estratégia pode ser expandida para lidar genericamente com praticamente todos os padrões de casos de uso que possam ser necessários, e é isso que pretendo implementar assim que encontrar o tempo livre ou um cliente que possa patrocinar o tempo que levaria para construir implementações totalmente genéricas.

CAVEAT # 2

Eu escrevi isso para substituir parse_request()uma função muito grande, e é bem possível que eu tenha perdido uma propriedade ou duas do $wpobjeto global que eu deveria ter definido. Portanto, se algo funcionar errado, avise-me e ficarei feliz em pesquise e revise a resposta, se necessário.

De qualquer forma...

MikeSchinkel
fonte
Depois de escrever isso, eu percebi que eu testei para categorias em vez de para termos de taxonomia em geral de modo que o acima não irá funcionar para a 'forum'taxonomia no entanto vou revê-lo a trabalhar mais tarde hoje ...
MikeSchinkel
Portanto, atualizei o código para solucionar o problema mencionado no comentário anterior.
23611 MikeSchinkel
não é possível obter este trabalho ... preciso alterar as regras de reescrita?
Onetrickpony
@ One Trick Pony - Um pouco mais de informação de diagnóstico ajudaria. :) O que você tentou? O que acontece quando você insere os URLs no seu navegador? Você por acaso chamou sua taxonomia em 'forums'vez de 'forum'? Você está esperando as URLs que apontam para essas páginas para a mudança (se sim, não é de admirar, meu código não trata da impressão de URLs, apenas a encaminhamento de URLs.)
MikeSchinkel
não, eu posso alterar os URLs (acho que é a função term_link que eu preciso conectar para isso). site/rootforum/funciona, mas site/rootforum/subforum/não funciona (erro 404) ... #
1111 onetrickpony
7

Simples, realmente.

Etapa 1: Pare de usar o parâmetro reescrever. Vamos lançar suas próprias reescritas.

'rewrite'=>false;

Etapa 2: defina regras detalhadas da página. Isso força as páginas normais a terem suas próprias regras, em vez de serem um exemplo geral na parte inferior da página.

Etapa 3: Crie algumas regras de reescrita para lidar com seus casos de uso.

Etapa 4: force manualmente as regras de liberação. Maneira mais fácil: vá para configurações-> link permanente e clique no botão Salvar. Eu prefiro isso a um método de ativação de plug-in para meu próprio uso, pois posso forçar as regras a liberar sempre que mudar as coisas.

Então, hora do código:

function test_init() {
    // create a new taxonomy
    register_taxonomy(
        'forum',
        'post',
        array(
            'query_var' => true,
            'public'=>true,
            'label'=>'Forum',
            'rewrite' => false,
        )
    );

    // force verbose rules.. this makes every Page have its own rule instead of being a 
    // catch-all, which we're going to use for the forum taxo instead
    global $wp_rewrite;
    $wp_rewrite->use_verbose_page_rules = true;

    // two rules to handle feeds
    add_rewrite_rule('(.+)/feed/(feed|rdf|rss|rss2|atom)/?$','index.php?forum=$matches[1]&feed=$matches[2]');
    add_rewrite_rule('(.+)/(feed|rdf|rss|rss2|atom)/?$','index.php?forum=$matches[1]&feed=$matches[2]');

    // one rule to handle paging of posts in the taxo
    add_rewrite_rule('(.+)/page/?([0-9]{1,})/?$','index.php?forum=$matches[1]&paged=$matches[2]');

    // one rule to show the forum taxo normally
    add_rewrite_rule('(.+)/?$', 'index.php?forum=$matches[1]');
}

add_action( 'init', 'test_init' );

Lembre-se de que, após adicionar esse código, você precisa ativá-lo quando liberar as regras do link permanente (salvando a página em Configurações-> Link permanente)!

Depois de liberar as regras e salvar no banco de dados, / o que quer que vá para o seu fórum = qualquer página de taxonomia.

Regras de reescrita realmente não são tão difíceis se você entender expressões regulares. Eu uso esse código para me ajudar na depuração:

function test_foot() {
    global $wp_rewrite;
    echo '<pre>';
    var_dump($wp_rewrite->rules);
    echo '</pre>';
}
add_action('wp_footer','test_foot');

Dessa forma, posso ver rapidamente as regras atuais em minha página. Lembre-se de que, dado qualquer URL, o sistema inicia no topo das regras e as segue até encontrar uma que corresponda. A correspondência é então usada para reescrever a consulta em um conjunto mais normal de? Key = value. Essas chaves são analisadas no que entra no objeto WP_Query. Simples.

Edit: Nota lateral, esse método provavelmente só funcionará se a sua estrutura de postagem personalizada normal começar com algo que não é uma catchall, como% category% ou algo parecido. Você precisa iniciá-lo com uma sequência estática ou numérica, como% ano%. Isso evita que ele pegue seu URL antes que ele atinja suas regras.

Otto
fonte
Se você deseja uma depuração mais fácil das suas regras de reescrita, recomendo meu plug-in de reescrita do analisador , que permite testar as regras e ver as variáveis ​​de consulta em tempo real.
Jan Fabry
Infelizmente, o atual sistema de reescrita de URL força o achatamento de todos os possíveis padrões de URL em uma lista grande, em comparação com a estrutura em árvore inerente aos caminhos de URL. A configuração atual não pode corresponder convenientemente a uma matriz de literais , como categorias ou nomes de fóruns ; como você sabe, força todos os URLs da "Página" a serem avaliados primeiro. A correspondência por segmento de caminho e a correspondência de várias maneiras (matriz de literais, categorias, tags, termos fiscais, nomes de usuários, tipos de postagem, nomes de postagens, retornos de chamada, ganchos de filtro e, finalmente, RegEx) aumentariam a complexidade e seriam mais fáceis para entender.
25711 MikeSchinkel
Mike: Na verdade, isso não é mais fácil de entender, porque eu não tenho a primeira pista da WTF que você está falando lá. Suas idéias sobre o roteamento de URL são confusas e difíceis e, como você provavelmente sabe, eu discordo delas. A pesquisa plana faz mais sentido e é mais flexível do que você costuma atribuir. A maioria das pessoas não quer toda essa complexidade desnecessária em seus URLs, e quase ninguém também precisa.
Otto
Obrigado, mas acho que já tentei isso antes ( wordpress.stackexchange.com/questions/9455/… )
onetrickpony
Felizmente WordPress Respostas agora permite que as pessoas que fazem o controle falta de seus URLs para finalmente ter uma voz, e eles parecem ser muitos (100+). Mas eu respeito que você talvez não consiga seguir meu exemplo antes de uma implementação completa. Prevejo que, uma vez que a abordagem que estou defendendo seja totalmente implementada em um plug-in, e após cerca de 6 a 12 meses, ela se tornará a maneira preferida dos sites CMS baseados em WordPress rotearem seus URLs. Então, vamos retomar esse debate em cerca de 9 meses.
MikeSchinkel
4

Você não poderá fazer isso usando WP_Rewrite sozinho, pois não é possível distinguir entre termo slugs e post slugs.

Você também deve conectar-se a 'request' e impedir o 404, configurando a consulta pós var em vez da taxonomia.

Algo assim:

function fix_post_request( $request ) {
    $tax_qv = 'forum';
    $cpt_name = 'post';

    if ( !empty( $request[ $tax_qv ] ) ) {
        $slug = basename( $request[ $tax_qv ] );

        // if this would generate a 404
        if ( !get_term_by( 'slug', $slug, $tax_qv ) ) {
            // set the correct query vars
            $request[ 'name' ] = $slug;
            $request[ 'post_type' ] = $cpt_name;
            unset( $request[$tax_qv] );
        }
    }

    return $request;
}
add_filter( 'request', 'fix_post_request' );

Observe que a taxonomia deve ser definida antes do tipo de postagem.

Seria um bom momento para ressaltar que ter uma taxonomia e um tipo de postagem com a mesma consulta var é uma má ideia.

Além disso, você não poderá acessar postagens com a mesma lesma de um dos termos.

scribu
fonte
Concordou que ter uma taxonomia e um tipo de postagem com a mesma consulta var é uma Má Idéia, mas isso pode implicar em pessoas com uma taxonomia e um tipo de postagem com o mesmo nome, uma má idéia, o que não é o caso. Se você usar o mesmo nome, apenas um dos dois deverá ter uma consulta var.
21711 MikeSchinkel
2

Eu daria uma olhada no código do plugin de gatos de nível superior:

http://fortes.com/projects/wordpress/top-level-cats/

Você pode adaptar isso facilmente, procurando a lesma de taxonomia personalizada, alterando o

$category_base = get_option('category_base');

na linha 74 para algo como:

$category_base = 'forums';
Pabline
fonte
Pode funcionar para categorias, mas não faz para taxonomias personalizadas (pelo menos em wp 3.1) ... Eu consegui mudar as URLs, mas eu recebo 404 erros
onetrickpony
2

Eu sugiro dar uma olhada no plugin Custom Post Permalinks . Não tenho tempo para testar agora, mas isso pode ajudar na sua situação.

Travis Northcutt
fonte
isso não acontecer, ele só lida com as mensagens, não taxonomias, e mesmo que fosse, eu teria que adicionar algum tipo de prefixo antes %forum%, que é exatamente o que eu estou tentando evitar ...
onetrickpony
2

Já que estou familiarizado com sua outra pergunta , responderei com isso em mente.

Ainda não testei isso, mas pode funcionar se você executá-lo uma vez logo após registrar todas as permastructs que deseja:

class RRSwitcher {
  var $rules;
  function RRSwitcher(){
    add_filter( 'topic_rewrite_rules', array( $this, 'topics' ) );
    add_filter( 'rewrite_rules_array', array( $this, 'rules' ) );
  }
  function topics( $array ){
    $this->rules = $array;
    return array();
  }
  function rules( $array ){
    return array_merge( (array)$array, (array)$this->rules );
  }
}
$RRSwitcher = new RRSwitcher();
global $wp_rewrite;
$wp_rewrite->use_verbose_rules = true;
$wp_rewrite->flush_rules();

O que isso faz: remove as regras de reescrita geradas dos links permanentes de tópicos do fluxo normal da matriz de regras e as mescla novamente no final da matriz. Isso impede que essas regras interfiram com outras regras de reescrita. Em seguida, força regras de reescrita detalhadas (cada página obtém uma regra individual com uma expressão regular específica). Isso evita que as páginas interfiram nas regras do seu tópico. Por fim, ele executa um hard flush (verifique se o arquivo .htaccess é gravável, caso contrário isso não funcionará) e salva a grande variedade de regras de reescrita.

John P Bloch
fonte
tentei, nada muda #
onetrickpony 17/02/11
2

Existe um plugin para isso .

Ele remove a lesma de tipo adicionando uma regra específica para cada página de tipo de postagem personalizada.

Adam Bell
fonte
2

Não tenho certeza se isso funcionará para taxonomias, mas funcionou para tipos de postagem personalizados

Embora não seja atualizado há 2 anos, o plug-in abaixo funcionou para mim: http://wordpress.org/plugins/remove-slug-from-custom-post-type/

Para sua informação, estou executando o WP 3.9.1com tipos de WP1.5.7

Máx.
fonte
2

Use uma barra como valor para a lesma ... 100% funcionando

'rewrite' => array(
    'slug'       => '/', 
    'with_front' => FALSE
 ),
Sathish Jayaraman
fonte
2
Não é bem assim, isso faz com que todo o pagetipo de post para 404.
Milo