web-dev-qa-db-fra.com

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

J'ai créé une taxonomie 'forum', en utilisant ces règles:

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

Dans le front-end, les URL ressemblent à ceci:

forums/general-discussion/sub-forum

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

general-discussion/sub-forum

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

21
onetrickpony

METTRE À JOUR

Depuis l'écriture de ce noyau WordPress, le hook 'do_parse_request' permet de gérer le routage des URL de manière élégante et sans avoir à étendre la classe WP. J'ai traité le sujet en profondeur dans mon exposé d'Atlantic WordCamp de 2014 intitulé " Hardcore URL Routing " ; les diapositives sont disponibles sur le lien.

RÉPONSE ORIGINALE

URL Design} est important depuis plus de dix ans; J'ai même écrit un blog à ce sujet plusieurs années en arrière. Et bien que WordPress soit sum, c’est un logiciel génial malheureusement son système de réécriture d’URL est à deux doigts de la mort cérébrale (IMHO, bien sûr. :) Quoi qu’il en soit, heureux de voir que les gens s’intéressent à nous 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 qu’elle a évolué. dans un autre, vous devez donc lire la chose en entier pour voir où elle se dirigeait.)} _

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 le cheminsegment de cheminau lieu d'utiliser une liste d'expressions régulières qui doivent correspondre à l'URL dans son intégralité.

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

Pour votre cas d'utilisation, cette implémentationuniquementcompare 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'URL (moins les barres obliques) à $wp->query_vars['category_name'], $wp->query_vars['tag'] ou $wp->query_vars['taxonomy'] & $wp->query_vars['term'] et contourne la méthode parse_request() de la classe WP.

Par contre, 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 classe WP.

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 de la manière suivante:

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

Quel 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é, je pense que cette technique fonctionne de manière brillante, mais cette technique ne devrait JAMAIS être utilisée pour qu'un plugin soit distribué sur WordPress.org pour que les autres utilisateurs 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 URL pour un site spécifique .

Pourquoi? Parce que un seul plugin peut utiliser cette technique . Si deux plugins essaient de l'utiliser, ils entreront en conflit.

D'un côté, 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 j'ai l'intention de mettre en œuvre dès que je trouverai un temps disponible ou qu'un client pourra sponsoriser le temps qu'il lui reste. prendrait pour construire des implémentations entièrement génériques.

CAVEAT # 2

J'ai écrit ceci pour surcharger parse_request() qui est une très grande fonction, et il est fort possible que j'ai raté une propriété ou deux de l'objet global $wp que j'aurais dû définir .. Donc, si quelque chose ne va pas, faites le moi savoir et je serai heureux de le rechercher et de réviser la réponse si besoin est.

En tous cas...

11
MikeSchinkel

Simple, vraiment.

Étape 1: Arrêtez d'utiliser le paramètre rewrite. Nous allons lancer vos propres réécritures.

'rewrite'=>false;

Étape 2: Définissez les règles de la page commentée. 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. Le moyen le plus simple: allez dans Paramètres-> Permalink 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 les choses.

Donc, code time:

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

Rappelez-vous qu'après avoir ajouté ce code, vous devez l'activer lorsque vous allez vider les règles de permalien (en enregistrant la page dans Paramètres-> Permaliens)!

Une fois que vous avez vidé les règles et enregistré dans la base de données, alors/quoi que ce soit devrait aller sur votre forum = quelle que soit la page de taxonomie.

Les règles de réécriture ne sont pas vraiment difficiles 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');

De cette façon, 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 clés? Look = value plus normal. Ces clés sont analysées dans ce qui entre dans l'objet WP_Query. Simple.

Edit: Note: 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 permet d'éviter de capturer votre URL avant que vos règles ne soient traitées.

7
Otto

Vous ne pourrez pas faire cela en utilisant WP_Rewrite seul, car il ne peut pas distinguer les slugs terme des post slugs.

Vous devez également vous connecter à 'request' et empêcher le 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.

En outre, vous ne pourrez pas accéder aux messages qui ont le même slug que l'un des termes.

4
scribu

Vous ne savez 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: http://wordpress.org/plugins/remove-slug-from-custom-post-type/

FYI j'utilise WP 3.9.1 avec WP Types 1.5.7

2
Max

Utilisez un slash comme valeur pour slug ... 100% de travail

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

Je suggère de jeter un coup d'oeil au plugin Custom Post Permalinks . Je n'ai pas le temps de faire un test pour l'instant, mais cela peut vous aider dans votre situation.

2
Travis Northcutt

J'aimerais jeter un coup d'œil au code du plugin chats de haut niveau:

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

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

$category_base = get_option('category_base');

à la ligne 74, quelque chose comme:

$category_base = 'forums';
2
Pabline

Puisque 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 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 obtient 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.

2
John P Bloch

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.

2
Adam Bell