Rimuovi la lumaca della tassonomia da un permalink personalizzato di tassonomia gerarchica


21

Ho creato una tassonomia del 'forum', usando queste regole:

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

Nel front-end gli URL sembrano:

forums/general-discussion/sub-forum

Come posso rimuovere la lumaca frontale ("forum")? Vale a dire, modificare gli URL in:

general-discussion/sub-forum

Se passo un argomento slug vuoto a register_taxonomy () funziona, ma ciò causa problemi con i permalink del tipo di post associato a questa tassonomia


@One Trick Pony - Hai provato invece di lasciare in 'slug' => 'forums'bianco semplicemente rimuovendolo del tutto e avendo 'rewrite' => array('with_front' => false, 'hierarchical' => true)? Penso che abbia funzionato in passato per me. Assicurati anche di lavare i permalink.
eileencodes

ci ho provato e i permalink sembrano uguali. L'aggiunta lo 'slug' => ''fa funzionare, ma i post che utilizzano questa tassonomia generano 404 secondi
onetrickpony,

@One Trick Pony - Oltre alla "discussione generale" di quali altri segmenti di percorso di livello superiore hai bisogno?
MikeSchinkel,

qualcuno %forum%dovrebbe essere un segmento di livello superiore
onetrickpony,

@One Trick Pony - Speravo solo che mi fornissi altri segmenti di percorso di livello superiore per il contesto.
MikeSchinkel,

Risposte:


11

AGGIORNARE

Da quando ho scritto questo core di WordPress ha aggiunto l' 'do_parse_request'hook che consente di gestire il routing URL in modo elegante e senza la necessità di estendere la WPclasse. Ho approfondito l'argomento nel mio discorso WordCamp di Atlanta del 2014 intitolato " Hardcore URL Routing " ; le diapositive sono disponibili al link.

RISPOSTA ORIGINALE

La progettazione di URL è stata importante per oltre un decennio; Ne ho persino scritto un blog diversi anni fa. E mentre WordPress è la somma è un brillante pezzo di software, sfortunatamente il suo sistema di riscrittura degli URL è a corto di cervello morto (IMHO, ovviamente. :) Comunque, sono contento di vedere le persone preoccupate della progettazione degli URL!

La risposta che fornirò è un plug-in che sto chiamando WP_Extendedche è una prova di concetto per questa proposta su Trac (nota che la proposta è iniziata come una cosa e si è evoluta in un'altra, quindi devi leggere l'intera cosa per vedere dove era diretto.)

Fondamentalmente l'idea è di sottoclassare la WPclasse, sovrascrivere il parse_request()metodo e quindi assegnare la $wpvariabile globale con un'istanza della sottoclasse. Quindi, in parse_request()te, controlla effettivamente il percorso per segmento di percorso invece di utilizzare un elenco di espressioni regolari che devono corrispondere all'URL nella sua interezza.

Quindi, per dirlo esplicitamente, questa tecnica inserisce la logica davanti alla parse_request()quale verifica le corrispondenze da URL a RegEx e cerca innanzitutto le corrispondenze dei termini della tassonomia, ma sostituisce SOLOparse_request() e lascia intatto l'intero resto del sistema di routing degli URL di WordPress, incluso e in particolare l'uso della $query_varsvariabile.

Nel tuo caso d'uso questa implementazione confronta solo i segmenti del percorso URL con i termini della tassonomia poiché è tutto ciò di cui hai bisogno. Questa implementazione controlla i termini della tassonomia rispettando le relazioni dei termini genitore-figlio e quando trova una corrispondenza assegna il percorso URL (meno le barre iniziali e finali) a $wp->query_vars['category_name'], $wp->query_vars['tag']e $wp->query_vars['taxonomy']& $wp->query_vars['term']e ignora il parse_request()metodo della WPclasse.

D'altra parte se il percorso dell'URL non corrisponde a un termine di una tassonomia che hai specificato, delega la logica di routing dell'URL al sistema di riscrittura di WordPress chiamando il parse_request()metodo della WPclasse.

Per utilizzare WP_Extendedper il tuo caso d'uso dovrai chiamare la register_url_route()funzione dal functions.phpfile del tuo tema in questo modo:

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

Qual è il codice sorgente per il plugin:

<?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

Anche se per un determinato sito penso che questa tecnica funzioni alla perfezione, ma questa tecnica non dovrebbe MAI essere utilizzata per un plugin da distribuire su WordPress.org per essere utilizzato da altri . Se è al centro di un pacchetto software basato su WordPress, potrebbe andare bene. Altrimenti questa tecnica dovrebbe essere limitata al miglioramento del routing degli URL per un sito specifico .

Perché? Perché solo un plugin può usare questa tecnica . Se due plugin tentano di usarlo, entreranno in conflitto tra loro.

A parte questo, questa strategia può essere ampliata per gestire praticamente praticamente ogni modello di caso d'uso che potrebbe essere richiesto ed è quello che intendo implementare non appena trovo il tempo libero o un cliente che può sponsorizzare il tempo necessario per costruire implementazioni completamente generiche.

CAVEAT # 2

Ho scritto questo per sovrascrivere parse_request()che è una funzione molto grande, ed è del tutto possibile che mi sia sfuggita una o due proprietà $wpdell'oggetto globale che avrei dovuto impostare .. Quindi se qualcosa si comporta in modo strano, fammi sapere e sarò felice di cercare e rivedere la risposta, se necessario.

Comunque...


Dopo aver scritto questo mi sono reso conto che ho provato per le categorie anziché per i termini della tassonomia in generale, quindi quanto sopra non funzionerà per la 'forum'tassonomia, ma lo
rivedremo

Quindi ho aggiornato il codice per risolvere il problema che menziono nel commento precedente.
MikeSchinkel,

non riesco a farlo funzionare ... devo cambiare le regole di riscrittura?
onetrickpony,

@One Trick Pony - Un po 'più di informazioni diagnostiche potrebbero aiutare. :) Cosa hai provato? Cosa succede quando inserisci gli URL nel tuo browser? Per caso hai chiamato la tua tassonomia 'forums'piuttosto che 'forum'? Ti aspetti che cambino gli URL che rimandano a queste pagine (se sì, non c'è da stupirsi, il mio codice non riguarda la stampa degli URL, ma solo il routing degli URL.)
MikeSchinkel

no, posso cambiare gli URL (penso che sia la funzione term_link a cui devo collegarmi per quello). site/rootforum/funziona, ma site/rootforum/subforum/non funziona (errore 404) ...
onetrickpony,

7

Semplice, davvero.

Passaggio 1: interrompere l'utilizzo del parametro rewrite. Lanceremo le tue riscritture.

'rewrite'=>false;

Passaggio 2: impostare regole di pagina dettagliate. Questo costringe le normali Pagine ad avere le proprie regole invece di essere un vero e proprio toccante in fondo alla pagina.

Passaggio 3: creare alcune regole di riscrittura per gestire i casi d'uso.

Passaggio 4: forzare manualmente le regole di flush. Il modo più semplice: vai su Impostazioni-> Permalink e fai clic sul pulsante Salva. Preferisco questo rispetto a un metodo di attivazione del plug-in per il mio uso, poiché posso forzare le regole a svuotare ogni volta che cambio cose.

Quindi, tempo del codice:

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

Ricorda che dopo aver aggiunto questo codice, devi averlo attivo quando vai a filo con le regole del permalink (salvando la pagina su Impostazioni-> Permalink)!

Dopo aver scaricato le regole e salvato nel database, allora / qualunque cosa dovrebbe andare sul tuo forum = qualunque pagina di tassonomia.

Riscrivere le regole non è poi così difficile se capisci le espressioni regolari. Uso questo codice per aiutarmi durante il debug:

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

In questo modo, posso vedere le regole attuali a colpo d'occhio sulla mia pagina. Basta ricordare che dato qualsiasi URL, il sistema si avvia nella parte superiore delle regole e scorre attraverso di loro fino a quando non trova quello che corrisponde. La corrispondenza viene quindi utilizzata per riscrivere la query in un set di valori? Key = value dall'aspetto più normale. Quelle chiavi vengono analizzate in ciò che va nell'oggetto WP_Query. Semplice.

Modifica: nota a margine, questo metodo probabilmente funzionerà solo se la tua normale struttura di post personalizzata inizia con qualcosa che non è un catchall, come% category% o qualcosa del genere. Devi avviarlo con una stringa statica o un numero, come% year%. Questo per evitare che catturi il tuo URL prima che arrivi alle tue regole.


Se desideri un debug più semplice delle tue regole di riscrittura, ti consiglio (di nuovo) il mio plug-in dell'analizzatore di riscrittura , che ti consente di provare le regole e vedere le variabili di query al volo.
Jan Fabry,

Sfortunatamente l'attuale sistema di riscrittura degli URL forza l'appiattimento di tutti i potenziali pattern URL in un ampio elenco anziché seguire la struttura ad albero intrinseca dei percorsi URL. L'impostazione corrente non può corrispondere convenientemente a una matrice di valori letterali come categorie o nomi di forum ; come sapete, impone che tutti gli URL "Pagina" vengano valutati per primi. La corrispondenza per segmento di percorso e la corrispondenza in più modi (array di valori letterali, categorie, tag, termini fiscali, nomi utente, tipi di post, nomi di post, callback, hook di filtro e infine RegEx) ridimensionerebbero meglio per la complessità e sarebbero più facili capire.
MikeSchinkel,

Mike: In realtà, non è affatto più facile da capire, perché non ho il primo indizio WTF di cui stai parlando lì. Le tue idee sul routing degli URL sono confuse e difficili e, come probabilmente sai, non sono d'accordo con loro. La ricerca semplice ha più senso ed è più flessibile di quanto tendi a dargli credito. Molte persone non vogliono tutta quella complessità inutile nei loro URL, e quasi nessuno ne ha nemmeno bisogno.
Otto,

Grazie, ma penso di averlo già provato prima ( wordpress.stackexchange.com/questions/9455/… )
onetrickpony,

Fortunatamente WordPress Answers consente ora le persone che fanno il controllo mancanza di loro URL finalmente hanno una voce, e sembrano essere molti (100+). Ma rispetto che potresti non essere in grado di seguire il mio esempio prima di una piena implementazione. Prevedo che, una volta che l'approccio che sto sostenendo sarà completamente implementato in un plugin e dopo circa 6-12 mesi sarà diventato il modo preferito per i siti CMS basati su WordPress di instradare i loro URL. Quindi riprendiamo questo dibattito tra circa 9 mesi.
MikeSchinkel,

4

Non sarai in grado di farlo usando WP_Rewrite da solo, poiché non è in grado di distinguere tra termini slug e post slug.

Devi anche agganciare 'richiesta' e prevenire il 404, impostando var post query invece di quello di tassonomia.

Qualcosa come questo:

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

Si noti che la tassonomia deve essere definita prima del tipo di posta.

Sarebbe un buon momento per sottolineare che avere una tassonomia e un tipo di post con la stessa query var è una cattiva idea.

Inoltre, non sarai in grado di raggiungere post con la stessa lumaca di uno dei termini.


Concordato sul fatto che avere una tassonomia e un tipo di post con la stessa query var sia una cattiva idea, ma ciò potrebbe implicare per le persone che hanno una tassonomia e un tipo di post con lo stesso nome è una cattiva idea, che non è il caso. Se si utilizza lo stesso nome, solo uno dei due dovrebbe avere una query var.
MikeSchinkel,

2

Darei un'occhiata al codice del plugin gatti di livello superiore:

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

Potresti facilmente adattarlo in modo che stia cercando la tua lumaca di tassonomia personalizzata modificando il

$category_base = get_option('category_base');

sulla linea 74 a qualcosa del tipo:

$category_base = 'forums';

Potrebbe funzionare per le categorie, ma non per le tassonomie personalizzate (almeno in wp 3.1) ... Sono riuscito a cambiare gli URL, ma ottengo 404 errori
onetrickpony,

2

Suggerirei di dare un'occhiata al plugin Permalink di Post personalizzati . Non ho tempo di testare in questo momento, ma potrebbe aiutarti con la tua situazione.


non lo fa, gestisce solo i post, non le tassonomie, e anche se lo fosse, dovrei aggiungere prima una sorta di prefisso %forum%, che è esattamente quello che sto cercando di evitare ...
onetrickpony

2

Dato che ho familiarità con l'altra tua domanda , risponderò con questo in mente.

Non l'ho provato affatto, ma potrebbe funzionare se lo esegui una volta subito dopo aver registrato tutti i permastrotti che desideri .:

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

Cosa fa: rimuove le regole di riscrittura generate dagli argomenti permalink dal normale flusso dell'array di regole e le unisce nuovamente alla fine dell'array. Ciò impedisce a tali regole di interferire con qualsiasi altra regola di riscrittura. Successivamente, impone regole di riscrittura dettagliata (ogni pagina ottiene una singola regola con un'espressione regolare specifica). Questo impedisce alle pagine di interferire con le regole del tuo argomento. Infine, esegue un flush reale (assicurati che il tuo file .htaccess sia scrivibile, altrimenti non funzionerà) e salva la matrice molto grande e molto complicata di regole di riscrittura.


provato, niente cambia
onetrickpony,



2

Usa una barra come valore per la lumaca ... 100% funzionante

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

2
non del tutto, questo fa sì che tutto il pagetipo di post sia 404.
Milo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.