Remova o slug de taxonomia de um permalink de taxonomia hierárquica personalizada

19

Eu criei uma taxonomia de "fórum" usando essas 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 parecem:

forums/general-discussion/sub-forum

Como posso remover o slug frontal ("fóruns")? Ou seja, mude as URLs para:

general-discussion/sub-forum

Se eu passar um argumento slug vazio para register_taxonomy () ele funciona, mas isso causa problemas com os permalinks do tipo de post associado a essa taxonomia

    
por onetrickpony 15.02.2011 / 18:05

9 respostas

10

UPDATE

Desde que este núcleo do WordPress foi escrito, foi adicionado o 'do_parse_request' hook que permite que o roteamento de URL seja tratado com elegância e sem a necessidade de estender a classe WP . Eu abordei o tópico em profundidade na minha palestra de 2014 no Atlanta WordCamp intitulada " Hardcore URL Roteamento " ; os slides estão disponíveis no link.

RESPOSTA ORIGINAL

O design de URL tem sido importante por mais de uma década; Eu mesmo escrevi um blog sobre isso vários anos atrás. E enquanto o WordPress é uma soma brilhante de um software infelizmente o seu sistema de reescrita de URL é um pouco curto de morte cerebral (IMHO, claro.:) De qualquer forma, feliz em ver pessoas importando-se com o design de URL!

A resposta que vou fornecer é um plugin que estou chamando de WP_Extended , que é uma prova de conceito para esta proposta no Trac (Note que a proposta começou como uma coisa e evoluiu para outra, então você tem que ler a coisa toda para ver para onde ela estava indo.)

Basicamente, a ideia é subclassificar a classe WP , substituir o método parse_request() e, em seguida, atribuir a variável global $wp a uma instância da subclasse. Em seguida, dentro de parse_request() , você inspeciona o caminho pelo segmento de caminho em vez de usar uma lista de expressões regulares que devem corresponder à URL na sua totalidade.

Portanto, para explicitar explicitamente, essa técnica insere lógica na frente do parse_request() , que verifica as correspondências URL-RegEx e, em vez disso, procura correspondências de termos de taxonomia, mas APENAS substitui parse_request() e deixa todo o restante do sistema de roteamento de URL do WordPress intacto incluindo e especialmente o uso da variável $query_vars .

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

Por outro lado, se o caminho da URL não corresponder a um termo de uma taxonomia que você especificou, ele delega a lógica de roteamento de URL ao sistema de reescrita do WordPress chamando o método parse_request() da WP class.

Para usar WP_Extended para seu caso de uso, você precisará chamar a função register_url_route() do arquivo functions.php do seu tema da seguinte forma:

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

O que aqui é 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();

P.S. CAVEAT # 1

Embora para um determinado site eu ache que esta técnica funcione brilhantemente mas esta técnica NUNCA deve ser usada para um plugin ser distribuído no WordPress.org para outros usarem . Se é o núcleo de um pacote de software baseado no WordPress, então isso pode ser bom. 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 um com o outro.

Como um aparte, esta estratégia pode ser expandida para lidar genericamente com praticamente todos os padrões de caso de uso que poderiam ser necessários e é isso que pretendo implementar assim que eu 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() , que é uma função muito grande, e é bem possível que eu tenha perdido uma propriedade ou dois do objeto global $wp que eu deveria ter definido. Eu sei e ficarei feliz em pesquisar e revisar a resposta, se necessário.

De qualquer forma ...

    
por MikeSchinkel 23.02.2011 / 05:40
7

Simples, realmente.

Passo 1: Pare de usar o parâmetro de reescrita. Nós vamos rolar suas próprias reescritas.

'rewrite'=>false;

Etapa 2: defina regras de página detalhadas. Isso força o Pages normal a ter suas próprias regras, em vez de ser um pega-tudo na parte inferior da página.

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

Etapa 4: forçar manualmente a ocorrência de regras de liberação. Maneira mais fácil: vá para configurações- > permalink e clique no botão Salvar. Eu prefiro isso ao invés de um método de ativação de plugins para meu próprio uso, já que eu posso forçar as regras a serem liberadas sempre que eu 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 que depois de adicionar este código, você precisa ativá-lo quando for liberar as regras de permalink (salvando a página em Configurações- > Permalinks)!

Depois de ter liberado as regras e salvo no banco de dados, então / whatever deve ir para o seu fórum = qualquer página de taxonomia.

Reescrever regras realmente não são tão difíceis se você entender expressões regulares. Eu uso esse código para me ajudar ao depurá-los:

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 as regras atuais de relance na minha página. Basta lembrar que, dada qualquer URL, o sistema começa no topo das regras e desce através delas até encontrar uma que corresponda. A correspondência é então usada para reescrever a consulta em um conjunto de valores = chave = normal. Essas chaves são analisadas no que entra no objeto WP_Query. Simples.

Editar: Nota lateral, este método provavelmente só funcionará se a sua estrutura normal de postagens personalizadas começar com algo que não é um catchall, como% category% ou algo parecido. Você precisa iniciá-lo com uma string estática ou um numérico, como% year%. Isso evita que ele capture sua URL antes de chegar às suas regras.

    
por Otto 24.02.2011 / 02:30
4

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

Você também tem que se conectar ao 'pedido' e impedir o 404, definindo o post query var em vez do taxonomy one.

Algo parecido com isto:

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.

Este seria um bom momento para apontar que ter uma taxonomia e um tipo de post com a mesma consulta var é uma Idéia Ruim.

Além disso, você não poderá alcançar postagens com o mesmo tamanho que um dos termos.

    
por scribu 18.02.2011 / 01:43
2

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

enlace

Você pode facilmente adaptar isso para procurar por seu slug de taxonomia personalizada alterando o

$category_base = get_option('category_base');

na linha 74 para algo como:

$category_base = 'forums';
    
por Pabline 15.02.2011 / 18:17
2

Sugiro dar uma olhada no plug-in permalinks de postagens personalizadas . Não tenho tempo para testar agora, mas isso pode ajudar na sua situação.

    
por Travis Northcutt 17.02.2011 / 23:11
2

Desde que eu esteja familiarizado com sua outra pergunta , Vou responder com isso em mente.

Eu não testei isso, mas pode funcionar se você executar isso uma vez logo após registrar todos os permastructs desejados.

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 isto faz: remove as regras de regravação geradas pelos tópicos permalink do fluxo normal do array de regras e as reúne no final do array. Isso impede que essas regras interfiram em outras regras de reconfiguração. Em seguida, ele força regras de reescrita detalhadas (cada página recebe uma regra individual com uma expressão regular específica). Isso impede que as páginas interfiram nas regras do seu tópico. Finalmente, ele executa um hard flush (verifique se o seu arquivo .htaccess é gravável, caso contrário, isso não funcionará) e salva a grande e muito complexa série de regras de reescrita.

    
por John P Bloch 18.02.2011 / 00:00
2

Existe um plugin para isso .

Remove o tipo slug adicionando uma regra específica para cada página de tipo de postagem personalizada.

    
por Adam Bell 26.11.2011 / 17:28
2

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

Embora não tenha sido atualizado por 2 anos, o plugin abaixo funcionou para mim: enlace

FYI Estou executando o% W de 3.9.1 com tipos de WP 1.5.7

    
por Max 22.06.2014 / 17:25
2

Use uma barra como valor para slug ... 100% funcionando

'rewrite' => array(
    'slug'       => '/', 
    'with_front' => FALSE
 ),
    
por Sathish Jayaraman 09.04.2015 / 15:01