web-dev-qa-db-de.com

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

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

21
onetrickpony

AKTUALISIEREN

Seit dem Schreiben dieses WordPress-Kerns wurde der Hook 'do_parse_request' hinzugefügt, mit dem das URL-Routing elegant gehandhabt werden kann, ohne dass die Klasse WP 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 sind unter dem Link verfügbar.

URSPRÜNGLICHE ANTWORT

URL Design ist seit mehr als einem Jahrzehnt wichtig; Ich habe sogar schrieb einen Blog darüber vor einigen Jahren. Und während WordPress die Summe ist, ist es ein brillantes Stück Software leider das URL - Umschreibesystem ist nur kurz vor dem Tod (IMHO, of Natürlich. :) Wie auch immer, ich bin froh, Leute zu sehen, die sich für URL-Design interessieren!

Die Antwort, die ich geben werde, ist ein Plugin, das ich WP_Extended anrufe und das ein Proof-of-Concept für diesen Vorschlag auf Trac (Beachten Sie, dass der Vorschlag als eine Sache begann und sich weiterentwickelte in ein anderes, also musst du das ganze lesen, um zu sehen, wohin es führte.)

Grundsätzlich besteht die Idee darin, die Klasse WP einer Unterklasse zuzuordnen, die Methode parse_request() zu überschreiben und dann der globalen Variablen $wp eine Instanz der Unterklasse zuzuweisen. Dann überprüfen Sie innerhalb von parse_request() tatsächlich den Pfadnach 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 vor die parse_request() ein, die nach URL-to-RegEx-Übereinstimmungen sucht und stattdessen zuerst nach Taxonomiebegriffsübereinstimmungen sucht, jedoch NUR die parse_request() ersetzt und die gesamte Funktion verlässt Rest des WordPress-URL-Routingsystems intakt, einschließlich und insbesondere der Verwendung der Variablen $query_vars.

Für Ihren Anwendungsfall vergleicht diese ImplementierungnurURL-Pfadsegmente mit Taxonomie-Begriffen, da dies alles ist, was Sie benötigen. Diese Implementierung überprüft Taxonomiebegriffe unter Berücksichtigung von Eltern-Kind-Beziehungen und weist den URL-Pfad (ohne führende und nachfolgende Schrägstriche zu $wp->query_vars['category_name'], $wp->query_vars['tag'] oder $wp->query_vars['taxonomy'] & $wp->query_vars['term'] zu und umgeht die Methode parse_request() von die WP Klasse.

Wenn der URL-Pfad stimmt nicht überein ein Begriff aus einer von Ihnen angegebenen Taxonomie ist, delegiert er die URL-Routing-Logik an das WordPress-Umschreibesystem, indem er die Methode parse_request() der Klasse WP aufruft.

Um WP_Extended für Ihren Anwendungsfall zu verwenden, müssen Sie die Funktion register_url_route() in der functions.php-Datei Ihres Themas wie folgt 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();

P.S. 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 Benutzer verwenden können. Wenn es sich um das Kernstück eines auf WordPress basierenden Softwarepakets handelt, ist dies möglicherweise in Ordnung. Andernfalls sollte sich diese Technik auf die Verbesserung des URL-Routings beschränken für eine bestimmte Site .

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 Freizeit finde oder einen Kunden, der die Zeit sponsern kann würde dauern, um vollständig generische Implementierungen zu erstellen.

CAVEAT # 2

Ich habe dies geschrieben, um parse_request() zu überschreiben, was eine sehr große Funktion ist, und es ist gut möglich, dass ich ein oder zwei der globalen $wp -Objekte verpasst habe, die ich hätte setzen sollen. Wenn sich also etwas wackelig verhält, lass es mich wissen und ich werde es tun gerne recherchieren und ggf. die antwort überarbeiten.

Sowieso...

11
MikeSchinkel

Ganz 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: Anmerkung: Diese Methode funktioniert wahrscheinlich nur, 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.

7
Otto

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 vor dem Beitragstyp definiert werden muss.

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.

4
scribu

Ich bin mir nicht sicher, ob dies für Taxonomien funktioniert, aber für benutzerdefinierte Beitragstypen

Obwohl es seit 2 Jahren nicht mehr aktualisiert wurde, funktionierte das folgende Plugin für mich: http://wordpress.org/plugins/remove-slug-from-custom-post-type/

Zu Ihrer Information Ich führe WP 3.9.1 mit WP Typen 1.5.7 aus

2
Max

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

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

Ich würde vorschlagen, einen Blick auf das Custom Post Permalinks Plugin zu werfen. Ich habe momentan keine Zeit zum Testen, aber es kann in Ihrer Situation hilfreich sein.

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';
2
Pabline

Da ich mit Ihrer anderen Frage vertraut bin, antworte ich 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 Umschreiberegeln gespeichert.

2
John P Bloch

Es gibt ein Plugin für diese .

Der Typ-Slug wird entfernt, indem für jede benutzerdefinierte Post-Typ-Seite eine bestimmte Regel hinzugefügt wird.

2
Adam Bell