Entfernen Sie Taxonomie-Slugs aus einem benutzerdefinierten hierarchischen Taxonomie-Permalink


21

Ich habe eine 'Forum'-Taxonomie nach folgenden Regeln erstellt:

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

Im Frontend sehen die URLs so aus:

forums/general-discussion/sub-forum

Wie kann ich die vordere Schnecke ("Foren") entfernen? Ändern Sie also die URLs in:

general-discussion/sub-forum

Wenn ich ein leeres Slug-Argument an register_taxonomy () übergebe, funktioniert es, aber dies führt zu Problemen mit den Permalinks des mit dieser Taxonomie verknüpften Post-Typs


@One Trick Pony - Haben Sie versucht, das Feld 'slug' => 'forums'leer zu lassen, nur um es zu entfernen und nur zu haben 'rewrite' => array('with_front' => false, 'hierarchical' => true)? Ich denke, das hat in der Vergangenheit bei mir funktioniert. Stellen Sie auch sicher, dass Sie die Permalinks spülen.
Eileencodes

habe das ausprobiert und die permalinks sehen gleich aus. Das Hinzufügen 'slug' => ''macht es möglich, aber dann erzeugen Posts, die diese Taxonomie verwenden, 404s
onetrickpony

@One Trick Pony - Welche anderen Pfadsegmente der obersten Ebene benötigen Sie neben der allgemeinen Diskussion?
MikeSchinkel

Jeder %forum%sollte ein Top-Level-Segment sein
onetrickpony

@One Trick Pony - Ich hatte nur gehofft, dass Sie mir einige andere Pfadsegmente der obersten Ebene für den Kontext geben.
MikeSchinkel 20.02.11

Antworten:


11

AKTUALISIEREN

Seit dem Schreiben dieses WordPress-Kerns wurde der 'do_parse_request'Hook hinzugefügt, mit dem das URL-Routing elegant gehandhabt werden kann, ohne dass die WPKlasse erweitert werden muss. Ich habe das Thema in meinem WordCamp-Vortrag 2014 in Atlanta mit dem Titel " Hardcore URL Routing " ausführlich behandelt . Die Folien finden Sie unter dem Link.

URSPRÜNGLICHE ANTWORT

URL-Design ist seit mehr als einem Jahrzehnt wichtig. Ich habe sogar vor einigen Jahren einen Blog darüber geschrieben . Und obwohl WordPress eine großartige Software ist , ist das URL-Rewrite-System leider nur kurz vor dem Tod (IMHO, natürlich. :) Wie auch immer, ich bin froh, Leute zu sehen, die sich um das URL-Design kümmern!

Die Antwort, die ich geben werde, ist ein Plugin, das ich anrufe und WP_Extendeddas ein Proof of Concept für diesen Vorschlag auf Trac ist. (Beachten Sie, dass der Vorschlag als eine Sache begann und sich in eine andere entwickelte. Sie müssen also die gesamte Sache lesen, um zu sehen, wo es ging voran.)

Grundsätzlich besteht die Idee darin, die WPKlasse in Unterklassen zu unterteilen , die parse_request()Methode zu überschreiben und dann die globale $wpVariable mit einer Instanz der Unterklasse zuzuweisen . Dann parse_request()inspiziere in dir tatsächlich den Pfad nach Pfadsegment, anstatt eine Liste regulärer Ausdrücke zu verwenden, die mit der URL in ihrer Gesamtheit übereinstimmen müssen.

Um es explizit auszudrücken, fügt diese Technik eine Logik ein, vor der parse_request()nach URL-zu-RegEx-Übereinstimmungen gesucht wird und stattdessen zuerst nach Taxonomiebegriffsübereinstimmungen gesucht wird. Sie ersetzt jedoch NURparse_request() den gesamten Rest des WordPress-URL-Routingsystems, einschließlich und vor allem die Verwendung der $query_varsVariablen.

Für Ihren Anwendungsfall vergleicht diese Implementierung nur URL-Pfadsegmente mit Taxonomiebegriffen, da dies alles ist, was Sie benötigen. Diese Implementierung prüft Begriffe Taxonomie Eltern-Kind - Zeitbeziehungen zu respektieren und wenn es eine Übereinstimmung findet es ordnet den URL - Pfad (minus vorderen und hinteren Schrägstriche) zu $wp->query_vars['category_name'], $wp->query_vars['tag']oder $wp->query_vars['taxonomy']& $wp->query_vars['term']und es umgeht die parse_request()Methode der WPKlasse.

Wenn der URL-Pfad andererseits nicht mit einem Begriff aus einer von Ihnen angegebenen Taxonomie übereinstimmt , delegiert er die URL-Routing-Logik durch Aufrufen der parse_request()Methode von an das WordPress-UmschreibesystemWP Klasse .

Um WP_Extendedfür Ihren Anwendungsfall zu verwenden, müssen Sie die register_url_route()Funktion aus der functions.phpDatei Ihres Themas folgendermaßen aufrufen :

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

Was ist hier der Quellcode für das 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

Obwohl ich denke, dass diese Technik für eine bestimmte Site hervorragend funktioniert, sollte diese Technik NIEMALS für ein Plugin verwendet werden, das auf WordPress.org verteilt wird, damit andere es verwenden können . Wenn es sich um den Kern eines auf WordPress basierenden Softwarepakets handelt, ist dies möglicherweise in Ordnung. Andernfalls sollte sich diese Technik auf die Verbesserung des URL-Routings für eine bestimmte Site beschränken .

Warum? Weil nur ein Plugin diese Technik anwenden kann . Wenn zwei Plugins versuchen, es zu verwenden, treten Konflikte auf.

Abgesehen davon kann diese Strategie erweitert werden, um praktisch jedes erforderliche Use-Case-Muster generisch zu handhaben, und das werde ich implementieren, sobald ich entweder die freie Zeit finde oder einen Kunden, der die Zeit sponsern kann, die es dauern würde Erstellen Sie vollständig generische Implementierungen.

CAVEAT # 2

Ich habe dies geschrieben, um zu überschreiben, parse_request()was eine sehr große Funktion ist, und es ist gut möglich, dass ich ein oder zwei der globalen Objekte verpasst habe$wp Objekts, das ich hätte setzen sollen habe recherchiere es und überarbeite die Antwort, wenn nötig.

Sowieso...


Nachdem ich dies geschrieben habe, wurde mir klar, dass ich generell nach Kategorien anstatt nach Taxonomie-Begriffen getestet habe, sodass das oben 'forum'
Genannte

Daher habe ich den Code aktualisiert, um das im vorherigen Kommentar erwähnte Problem zu beheben.
MikeSchinkel

kann diese Arbeit nicht bekommen ... muss ich die Umschreiberegeln ändern?
Onetrickpony

@ One Trick Pony - Ein bisschen mehr Diagnoseinformationen würden helfen. :) Was hast du versucht? Was passiert, wenn Sie die URLs in Ihren Browser eingeben? Haben Sie Ihre Taxonomie 'forums'eher zufällig als genannt 'forum'? Erwarten Sie, dass sich die URLs, die auf diese Seiten verlinken, ändern (falls ja, kein Wunder, mein Code behandelt nicht das Drucken von URLs, sondern nur das Weiterleiten von URLs.)
MikeSchinkel

Nein, ich kann die URLs ändern. site/rootforum/funktioniert, aber site/rootforum/subforum/nicht (404-Fehler) ...
onetrickpony

7

Wirklich einfach.

Schritt 1: Verwenden Sie den Rewrite-Parameter überhaupt nicht mehr. Wir werden Ihre eigenen Rewrites rollen.

'rewrite'=>false;

Schritt 2: Legen Sie ausführliche Seitenregeln fest. Dies erzwingt, dass normale Seiten ihre eigenen Regeln haben, anstatt ein Sammelbegriff am Ende der Seite zu sein.

Schritt 3: Erstellen Sie einige Umschreiberegeln für Ihre Anwendungsfälle.

Schritt 4: Manuelles Erzwingen von Flush-Regeln. Der einfachste Weg: Gehen Sie zu Einstellungen-> Permalink und klicken Sie auf die Schaltfläche Speichern. Ich bevorzuge dies einer Plugin-Aktivierungsmethode für meinen eigenen Gebrauch, da ich die Regeln zwingen kann, zu löschen, wenn ich etwas ändere.

Also Code Zeit:

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

Denken Sie daran, dass Sie diesen Code nach dem Hinzufügen aktivieren müssen, wenn Sie die Permalink-Regeln löschen (indem Sie die Seite unter Einstellungen-> Permalinks speichern)!

Nachdem Sie die Regeln gelöscht und in der Datenbank gespeichert haben, sollte / whatever in Ihrem Forum angezeigt werden = auf jeder Taxonomieseite.

Rewrite-Regeln sind wirklich nicht so schwierig, wenn Sie reguläre Ausdrücke verstehen. Ich verwende diesen Code, um beim Debuggen zu helfen:

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

Auf diese Weise kann ich die aktuellen Regeln auf meiner Seite auf einen Blick sehen. Denken Sie daran, dass das System bei jeder angegebenen URL an der Spitze der Regeln beginnt und diese durchläuft, bis es eine übereinstimmende findet. Die Übereinstimmung wird dann verwendet, um die Abfrage in einen normaleren? Key = value-Satz umzuschreiben. Diese Schlüssel werden in den Inhalt des WP_Query-Objekts analysiert. Einfach.

Bearbeiten: Nebenbei bemerkt, diese Methode wird wahrscheinlich nur funktionieren, wenn Ihre normale benutzerdefinierte Post-Struktur mit etwas beginnt, das kein Schlagwort ist, wie% category% oder so etwas. Sie müssen es mit einer statischen Zeichenfolge oder einer Zahl wie% year% beginnen. Dies soll verhindern, dass Ihre URL abgefangen wird, bevor sie Ihren Regeln entspricht.


Wenn Sie das Debuggen Ihrer Umschreiberegeln vereinfachen möchten, empfehle ich (erneut) mein Umschreibeanalysator-Plugin , mit dem Sie die Regeln ausprobieren und die Abfragevariablen im Handumdrehen anzeigen können.
Jan Fabry

Leider erzwingt das aktuelle URL-Umschreibesystem das Reduzieren aller potenziellen URL-Muster in eine große Liste im Vergleich zu der inhärenten Baumstruktur von URL-Pfaden. Das aktuelle Setup kann nicht mit einer Reihe von Literalen wie Kategorien oder Forennamen übereinstimmen . Wie Sie wissen, werden alle "Seiten" -URLs zuerst ausgewertet. Übereinstimmungen nach Pfadsegmenten und Übereinstimmungen auf verschiedene Arten (Array von Literalen, Kategorien, Tags, Steuerbegriffen, Benutzernamen, Post-Typen, Post-Namen, Rückrufen, Filter-Hooks und schließlich RegEx) würden sich hinsichtlich der Komplexität besser skalieren lassen und wären einfacher verstehen.
MikeSchinkel

Mike: Eigentlich ist das gar nicht so einfach zu verstehen, weil ich nicht die erste Ahnung habe, wovon du da sprichst. Ihre Vorstellungen von URL-Routing sind verwirrend und schwierig, und wie Sie wahrscheinlich wissen, bin ich damit nicht einverstanden. Die flache Suche ist sinnvoller und flexibler, als Sie es normalerweise zu schätzen wissen. Die meisten Leute wollen nicht die unnötige Komplexität ihrer URLs, und fast niemand braucht sie auch.
Otto

Danke, aber ich glaube, ich habe es bereits versucht ( wordpress.stackexchange.com/questions/9455/… )
onetrickpony

Glücklicherweise erlaubt WordPress Answers nun Menschen, die die Kontrolle über ihre URLs haben wollen , endlich eine Stimme zu haben, und sie scheinen viele zu sein (100+). Ich respektiere jedoch, dass Sie meinem Beispiel möglicherweise nicht folgen können, bevor eine vollständige Implementierung erfolgt ist. Ich gehe davon aus, dass nach der vollständigen Implementierung des von mir befürworteten Ansatzes in einem Plug-in dieser Methode nach etwa 6 bis 12 Monaten WordPress-basierte CMS-Websites ihre URLs bevorzugt weiterleiten werden. Nehmen wir diese Debatte also in ungefähr 9 Monaten wieder auf.
MikeSchinkel

4

Sie können dies nicht allein mit WP_Rewrite tun, da hier nicht zwischen Term-Slugs und Post-Slugs unterschieden werden kann.

Sie müssen sich auch in 'request' einklinken und 404 verhindern, indem Sie die Post-Query-Variable anstelle der Taxonomie-Variable festlegen.

Etwas wie das:

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

Beachten Sie, dass die Taxonomie definiert werden muss , bevor dem Beitragstyp .

Dies ist ein guter Zeitpunkt, um darauf hinzuweisen, dass eine Taxonomie und ein Beitragstyp mit derselben Abfragevariable eine schlechte Idee sind.

Außerdem können Sie keine Posts erreichen, die denselben Slug wie einer der Begriffe haben.


Einverstanden, dass die Verwendung einer Taxonomie und eines Post-Typs mit derselben Abfragevariable eine schlechte Idee ist. Dies könnte jedoch bedeuten, dass Personen mit einer Taxonomie und einem Post-Typ mit demselben Namen eine schlechte Idee sind, was nicht der Fall ist. Wenn Sie denselben Namen verwenden, sollte nur eine der beiden eine Abfragevariable haben.
MikeSchinkel 20.02.11

2

Ich würde mir den Code des Top-Level-Katzen-Plugins ansehen:

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

Sie können das leicht anpassen, damit es nach Ihrem benutzerdefinierten Taxonomie-Slug sucht, indem Sie das ändern

$category_base = get_option('category_base');

in Zeile 74 zu so etwas wie:

$category_base = 'forums';

Könnte für Kategorien funktionieren, aber nicht für benutzerdefinierte Taxonomien (zumindest in WP 3.1) ... Ich konnte die URLs ändern, erhalte aber 404-Fehler
onetrickpony

2

Ich würde vorschlagen, sich das Plugin für benutzerdefinierte Post-Permalinks anzuschauen . Ich habe momentan keine Zeit zum Testen, aber es kann in Ihrer Situation hilfreich sein.


es verarbeitet nur Posts, keine Taxonomien, und selbst wenn dies der Fall wäre, müsste ich vorher eine Art Präfix hinzufügen %forum%, was genau das ist, was ich zu vermeiden versuche ...
onetrickpony

2

Da kenne ich mich mit deiner anderen Frage aus bin, beantworte ich sie in diesem Sinne.

Ich habe das überhaupt nicht getestet, aber es könnte funktionieren, wenn Sie dies einmal ausführen, nachdem Sie alle gewünschten Permastrukturen registriert haben:

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

Dies bewirkt Folgendes: Die aus dem Themen-Permalink generierten Umschreibregeln werden aus dem normalen Ablauf des Regel-Arrays entfernt und am Ende des Arrays wieder zusammengeführt. Dadurch wird verhindert, dass diese Regeln andere Umschreibregeln beeinträchtigen. Als Nächstes werden ausführliche Umschreibregeln erzwungen (jede Seite erhält eine individuelle Regel mit einem bestimmten regulären Ausdruck). Dies verhindert, dass die Seiten die Regeln Ihres Themas stören. Schließlich wird ein Hard Flush ausgeführt (stellen Sie sicher, dass Ihre .htaccess-Datei schreibbar ist, da dies sonst nicht funktioniert) und das sehr große, sehr komplizierte Array von Umschreibregeln gespeichert.


versuchte es, nichts ändert sich
onetrickpony



2

Verwenden Sie einen Schrägstrich als Wert für slug ... 100% working

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

2
Nicht ganz, dies führt dazu, dass der gesamte pageBeitragstyp auf 404 gesetzt wird.
Milo
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.