Supprimer le slug de taxonomie d'un permalien de taxonomie hiérarchique personnalisé

19

J'ai créé une taxonomie "forum" en utilisant les règles suivantes:

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

Sur le front-end, les URL ressemblent à:

forums/general-discussion/sub-forum

Comment puis-je supprimer le slug avant ("forums")? Par exemple, modifiez les URL en:

general-discussion/sub-forum

Si je transmets un argument slug vide à register_taxonomy (), cela fonctionne, mais cela pose des problèmes avec les permaliens du type de message associé à cette taxonomie

    
posée onetrickpony 15.02.2011 - 18:05

9 réponses

10

UPDATE

Depuis l’écriture de ce noyau WordPress, le crochet 'do_parse_request' a été ajouté, ce qui permet de gérer le routage des URL avec élégance et sans devoir étendre la classe WP . J'ai abordé le sujet en profondeur dans mon exposé sur le WordCamp d'Atlanta en 2014 intitulé " Hardcore URL Routage " ; les diapositives sont disponibles sur le lien.

RÉPONSE ORIGINALE

La

conception des URL est importante depuis plus de dix ans; J'ai même écrit un blog à ce sujet plusieurs années auparavant. Et bien que WordPress soit sum, c’est un logiciel brillant , malheureusement , son système de réécriture d’URL est un peu en-deçà de la mort cérébrale (à mon humble avis, bien sûr.:) Quoi qu’il en soit, content de voir les gens se soucier de la conception d'URL!

La réponse que je vais fournir est un plugin que j'appelle WP_Extended , qui est une preuve de concept pour cette proposition sur Trac (notez que cette proposition a commencé comme une chose et a évolué en une autre; vous devez donc lire toute la chose pour voir où elle allait.)

En gros, l’idée est de sous-classer la classe WP , de remplacer la méthode parse_request() , puis d’affecter la variable globale $wp à une instance de la sous-classe. Ensuite, dans parse_request() , vous inspectez réellement le chemin par segment de chemin au lieu d'utiliser une liste d'expressions régulières qui doivent correspondre à l'URL dans son intégralité.

Ainsi, pour l'exprimer explicitement, cette technique insère la logique devant le parse_request() qui vérifie les correspondances d'URL à RegEx et cherche plutôt les correspondances de termes de taxonomie, mais UNIQUEMENT remplace parse_request() et laisse intact le reste du système de routage WordPress, y compris et surtout l’utilisation de la variable $query_vars .

Pour votre cas d'utilisation, cette implémentation uniquement compare les segments de chemin d'URL avec des termes de taxonomie, car c'est tout ce dont vous avez besoin. Cette implémentation inspecte les termes de taxonomie respectant les relations de terme parent-enfant et, lorsqu'elle trouve une correspondance, attribue le chemin d'accès URL (moins les barres obliques de début et de fin) à $wp->query_vars['category_name'] , $wp->query_vars['tag'] ou $wp->query_vars['taxonomy'] & $wp->query_vars['term'] et il contourne la méthode parse_request() de la classe WP .

D'autre part, si le chemin de l'URL ne correspond pas à un terme d'une taxonomie que vous avez spécifiée, il délègue la logique de routage des URL au système de réécriture de WordPress en appelant la méthode parse_request() de la commande%.WP class.

Pour utiliser WP_Extended dans votre cas d'utilisation, vous devez appeler la fonction register_url_route() à partir du fichier functions.php de votre thème, comme suit:

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

Ce qui est le code source du 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

Bien que, pour un site donné, cette technique fonctionne de manière brillante, mais elle ne doit JAMAIS être utilisée pour qu'un plugin soit distribué sur WordPress.org pour que d'autres puissent l'utiliser . Si c'est au cœur d'un progiciel basé sur WordPress, cela pourrait bien se passer. Sinon, cette technique devrait être limitée à l'amélioration du routage des URL pour un site spécifique .

Pourquoi? Parce que un seul plug-in peut utiliser cette technique . Si deux plug-ins essaient de l'utiliser, ils entreront en conflit.

En passant, cette stratégie peut être étendue pour traiter de manière générique pratiquement tous les modèles de cas d'utilisation qui pourraient être requis, et c'est ce que je compte mettre en œuvre dès que je trouverai du temps libre ou un client pouvant parrainer le projet. le temps qu'il faudrait pour construire des implémentations entièrement génériques.

CAVEAT # 2

J'ai écrit ceci pour remplacer parse_request() qui est une très grande fonction, et il est fort possible que j'ai oublié une propriété ou deux de l'objet global $wp que j'aurais dû définir. et je me ferai un plaisir de le rechercher et de réviser la réponse si besoin est.

Quoi qu'il en soit ...

    
réponse donnée MikeSchinkel 23.02.2011 - 05:40
7

Simple, vraiment.

Étape 1: N'utilisez plus le paramètre de réécriture. Nous allons lancer vos propres réécritures.

'rewrite'=>false;

Étape 2: Définissez des règles de page commentées. Cela force les pages normales à avoir leurs propres règles au lieu d'être un fourre-tout au bas de la page.

Étape 3: créez des règles de réécriture pour gérer vos cas d'utilisation.

Étape 4: forcez manuellement l’application d’une règle de vidage. Manière la plus simple: allez dans Paramètres - > permalien et cliquez sur le bouton Enregistrer. Je préfère ceci à une méthode d’activation de plug-in pour mon propre usage, car je peux forcer les règles à se vider chaque fois que je change de choses.

Donc, l'heure du code:

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

N'oubliez pas qu'après avoir ajouté ce code, vous devez l'activer lorsque vous rincez les règles de permalien (en enregistrant la page dans Paramètres- & Perm.)!

Après avoir vidé les règles et les avoir enregistrées dans la base de données, alors / tout ce qui devrait aller sur votre forum = quelle que soit la page de taxonomie.

Les règles de réécriture ne sont vraiment pas si difficiles à comprendre si vous comprenez les expressions régulières. J'utilise ce code pour m'aider lors du débogage:

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

Ainsi, je peux voir les règles actuelles d'un coup d'œil sur ma page. Rappelez-vous simplement que, quelle que soit l'adresse URL, le système commence en haut des règles et les traverse jusqu'à ce qu'il en trouve une qui corresponde. La correspondance est ensuite utilisée pour réécrire la requête dans un jeu de paramètres? Clé = valeur plus normaux. Ces clés sont analysées dans ce qui se trouve dans l'objet WP_Query. Simple.

Modifier: Remarque: cette méthode ne fonctionnera probablement que si votre structure de publication personnalisée normale commence par quelque chose qui n'est pas un fourre-tout, comme% category% ou quelque chose comme ça. Vous devez commencer par une chaîne statique ou numérique, telle que% year%. Ceci afin d'éviter qu'il ne récupère votre URL avant que vos règles ne soient traitées.

    
réponse donnée Otto 24.02.2011 - 02:30
4

Vous ne pourrez pas faire cela en utilisant WP_Rewrite seul, car il ne peut pas faire la distinction entre les slugs de terme et les slugs de publication.

Vous devez également vous connecter à 'request' et empêcher le code 404 en définissant la variable post query au lieu de la taxonomie.

Quelque chose comme ça:

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

Notez que la taxonomie doit être définie avant le type de publication.

Ce serait un bon moment pour souligner qu’avoir une taxonomie et un type de publication avec la même requête var est une mauvaise idée.

De plus, vous ne pourrez pas atteindre les publications qui ont le même slug que l'un des termes.

    
réponse donnée scribu 18.02.2011 - 01:43
2

Je jetterais un coup d'œil au code du plugin chats de haut niveau:

enlace

Vous pouvez facilement l'adapter afin qu'il recherche votre slug de taxonomie personnalisée en modifiant la

$category_base = get_option('category_base');

sur la ligne 74 à quelque chose comme:

$category_base = 'forums';
    
réponse donnée Pabline 15.02.2011 - 18:17
2

Je vous conseillerais de consulter le plug-in Custom Post Permalinks . Je n'ai pas le temps de faire un test pour l'instant, mais cela peut vous aider dans votre situation.

    
réponse donnée Travis Northcutt 17.02.2011 - 23:11
2

Comme je connais bien votre autre question , Je vais répondre avec cela à l'esprit.

Je n'ai pas testé cela du tout, mais cela pourrait fonctionner si vous l'exécutez une fois juste après avoir enregistré tous les permastructs souhaités.:

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

Ce que cela fait: cela supprime les règles de réécriture générées à partir des sujets permalink du flux normal du tableau de règles et les re-fusionne à la fin du tableau. Cela empêche ces règles d'interférer avec d'autres règles de réécriture. Ensuite, il force les règles de réécriture verbeuses (chaque page reçoit une règle individuelle avec une expression régulière spécifique). Cela empêche les pages d'interférer avec les règles de votre sujet. Enfin, il exécute un flush (assurez-vous que votre fichier .htaccess est accessible en écriture, sinon cela ne fonctionnera pas) et enregistre le très grand nombre très complexe de règles de réécriture.

    
réponse donnée John P Bloch 18.02.2011 - 00:00
2

Il existe un plugin pour cela .

Il supprime le slug de type en ajoutant une règle spécifique pour chaque page de type de publication personnalisée.

    
réponse donnée Adam Bell 26.11.2011 - 17:28
2

Je ne sais pas si cela fonctionnera pour les taxonomies, mais cela fonctionnera pour les types de publication personnalisés

Bien qu'il n'ait pas été mis à jour depuis 2 ans, le plugin ci-dessous a fonctionné pour moi: enlace

FYI j'utilise WP 3.9.1 avec les types WP 1.5.7

    
réponse donnée Max 22.06.2014 - 17:25
2

Utilisez une barre oblique comme valeur pour le slug ... 100% actif

'rewrite' => array(
    'slug'       => '/', 
    'with_front' => FALSE
 ),
    
réponse donnée Sathish Jayaraman 09.04.2015 - 15:01

Lire d'autres questions sur les étiquettes