Loại bỏ sên phân loại từ một permalink phân loại phân cấp tùy chỉnh


21

Tôi đã tạo một phân loại 'diễn đàn', sử dụng các quy tắc sau:

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

Ở phần đầu, các URL trông như sau:

forums/general-discussion/sub-forum

Làm thế nào tôi có thể loại bỏ sên phía trước ("diễn đàn")? Tức là thay đổi URL thành:

general-discussion/sub-forum

Nếu tôi chuyển một đối số slug trống sang register_taxonomy () thì nó hoạt động, nhưng điều đó gây ra các vấn đề với permalinks của loại bài đăng liên quan đến phân loại này


@One Trick Pony - Bạn đã thử thay vì để 'slug' => 'forums'trống chỉ cần loại bỏ nó hoàn toàn và chỉ có 'rewrite' => array('with_front' => false, 'hierarchical' => true)? Tôi nghĩ rằng điều đó đã làm việc trong quá khứ cho tôi. Cũng chắc chắn rằng bạn tuôn ra permalinks.
eileencodes

đã thử điều đó, và permalinks trông giống nhau. Thêm 'slug' => ''làm cho nó hoạt động, nhưng sau đó các bài đăng sử dụng phân loại này tạo ra 404s
onetrickpony

@One Trick Pony - Bên cạnh 'thảo luận chung', bạn cần những phân đoạn đường dẫn cấp cao nhất nào khác?
MikeSchinkel

bất kỳ %forum%nên là một phân khúc cấp cao nhất
onetrickpony

@One Trick Pony - Tôi chỉ hy vọng bạn cung cấp cho tôi một số phân đoạn đường dẫn cấp cao nhất khác cho bối cảnh.
MikeSchinkel

Câu trả lời:


11

CẬP NHẬT

Kể từ khi viết lõi WordPress này đã thêm 'do_parse_request'móc cho phép định tuyến URL được xử lý một cách thanh lịch và không cần phải mở rộng WPlớp. Tôi đã đề cập sâu vào chủ đề trong bài nói chuyện Atlanta WordCamp 2014 của tôi có tên " Định tuyến URL cứng " ; các slide có sẵn tại liên kết.

CÂU TRẢ LỜI

Thiết kế URL rất quan trọng trong hơn một thập kỷ; Tôi thậm chí đã viết một blog về nó vài năm trước. Và trong khi WordPress là một phần mềm tuyệt vời thì thật không may , hệ thống viết lại URL của nó chỉ thiếu não (IMHO, tất nhiên. :) Dù sao, rất vui khi thấy mọi người quan tâm đến thiết kế URL!

Câu trả lời tôi sẽ cung cấp là một plugin tôi đang gọi WP_Extendedđó là bằng chứng về khái niệm cho đề xuất này trên Trac (Lưu ý rằng đề xuất bắt đầu như một thứ và phát triển thành một thứ khác, vì vậy bạn phải đọc toàn bộ để xem nó đã đứng đầu.)

Về cơ bản, ý tưởng là phân WPlớp lớp, ghi đè parse_request()phương thức và sau đó gán $wpbiến toàn cục với một thể hiện của lớp con. Sau đó, bên trong parse_request()bạn thực sự kiểm tra đường dẫn theo phân đoạn đường dẫn thay vì sử dụng danh sách các biểu thức chính quy phải khớp với toàn bộ URL.

Vì vậy, để nói rõ, kỹ thuật này chèn logic trước parse_request()kiểm tra các kết quả khớp URL-Reg-RegEx và thay vào đó trước tiên tìm các kết quả khớp thuật ngữ phân loại, nhưng nó CHỈ thay thế parse_request()và giữ nguyên toàn bộ phần còn lại của hệ thống định tuyến URL WordPress bao gồm và đặc biệt là việc sử dụng $query_varsbiến.

Đối với trường hợp sử dụng của bạn, việc triển khai này chỉ so sánh các phân đoạn đường dẫn URL với các thuật ngữ phân loại vì đó là tất cả những gì bạn cần. Điều này thực hiện kiểm tra về phân loại tôn trọng mối quan hệ lâu cha-con và khi nó tìm thấy một trận đấu nó gán đường dẫn URL (trừ ở đầu và đuôi dấu gạch chéo) để $wp->query_vars['category_name'], $wp->query_vars['tag']hoặc $wp->query_vars['taxonomy']& $wp->query_vars['term']và nó đi qua các parse_request()phương pháp của WPlớp.

Mặt khác, nếu đường dẫn URL không khớp với một thuật ngữ từ phân loại học, bạn đã chỉ định nó ủy quyền logic định tuyến URL cho hệ thống viết lại WordPress bằng cách gọi parse_request()phương thức của WPlớp.

Để sử dụng WP_Extendedcho trường hợp sử dụng của bạn, bạn sẽ cần gọi register_url_route()hàm từ trong functions.phptệp chủ đề của mình như sau:

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

Mã nguồn của plugin là gì:

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

Mặc dù đối với một trang web nhất định tôi nghĩ rằng kỹ thuật này hoạt động rất tốt nhưng kỹ thuật này KHÔNG BAO GIỜ được sử dụng cho một plugin được phân phối trên WordPress.org cho người khác sử dụng . Nếu đó là cốt lõi của gói phần mềm dựa trên WordPress thì điều đó có thể ổn. Mặt khác, kỹ thuật này nên được giới hạn để cải thiện định tuyến URL cho một trang web cụ thể .

Tại sao? Bởi vì chỉ có một plugin có thể sử dụng kỹ thuật này . Nếu hai plugin cố gắng sử dụng, chúng sẽ xung đột với nhau.

Vì một bên, chiến lược này có thể được mở rộng để xử lý một cách tổng quát mọi mô hình trường hợp sử dụng có thể được yêu cầu và đó là điều tôi dự định thực hiện ngay khi tôi tìm thấy thời gian rảnh rỗi hoặc khách hàng có thể tài trợ thời gian cần thiết xây dựng thực hiện hoàn toàn chung chung.

CÁCH SỐ 2

Tôi đã viết cái này để ghi đè lên parse_request()một chức năng rất lớn và hoàn toàn có khả năng tôi đã bỏ lỡ một hoặc hai tài sản toàn cầu $wpmà tôi nên đặt .. Vì vậy, nếu có hành động nào đó, hãy cho tôi biết và tôi sẽ rất vui nghiên cứu nó và sửa lại câu trả lời nếu cần.

Dù sao...


Sau khi viết bài này, tôi nhận ra rằng tôi đã thử nghiệm các danh mục thay vì các thuật ngữ phân loại nói chung vì vậy phần trên sẽ không hoạt động cho 'forum'phân loại học. Tuy nhiên, tôi sẽ sửa lại để làm việc sau ngày hôm nay ...
MikeSchinkel

Vì vậy, tôi đã cập nhật mã để giải quyết vấn đề tôi đã đề cập trong bình luận trước.
MikeSchinkel

không thể có được công việc này ... tôi có cần thay đổi các quy tắc viết lại không?
onetrickpony

@One Trick Pony - Một chút thông tin chẩn đoán sẽ giúp ích. :) Bạn đã thử những gì? Điều gì xảy ra khi bạn nhập URL vào trình duyệt của bạn? Bạn có từng có cơ hội gọi phân loại của bạn 'forums'hơn là 'forum'? Bạn có mong đợi các URL liên kết đến các trang này sẽ thay đổi không (nếu có, không có gì lạ, mã của tôi không giải quyết việc in URL, chỉ định tuyến các URL.)
MikeSchinkel

không, tôi có thể thay đổi các URL (tôi nghĩ đó là hàm term_link mà tôi cần nối vào đó). site/rootforum/hoạt động, nhưng site/rootforum/subforum/không (lỗi 404) ...
onetrickpony

7

Đơn giản, thực sự.

Bước 1: Ngừng sử dụng tham số viết lại. Chúng tôi sẽ cuộn các bản viết lại của riêng bạn.

'rewrite'=>false;

Bước 2: Đặt quy tắc trang dài. Điều này buộc các Trang bình thường phải có các quy tắc riêng thay vì bắt tất cả ở cuối trang.

Bước 3: Tạo một số quy tắc viết lại để xử lý các trường hợp sử dụng của bạn.

Bước 4: Buộc thủ công một quy tắc tuôn ra. Cách dễ nhất: đi tới cài đặt-> permalink và nhấp vào nút lưu. Tôi thích điều này hơn một phương thức kích hoạt plugin cho việc sử dụng của riêng tôi, vì tôi có thể buộc các quy tắc tuôn ra bất cứ khi nào tôi thay đổi mọi thứ xung quanh.

Vì vậy, mã thời gian:

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

Hãy nhớ rằng sau khi thêm mã này, bạn cần kích hoạt nó khi bạn xóa các quy tắc permalink (bằng cách lưu trang trên Cài đặt-> Permalinks)!

Sau khi bạn xóa các quy tắc và lưu vào cơ sở dữ liệu, sau đó / mọi thứ sẽ vào diễn đàn của bạn = bất kỳ trang phân loại nào.

Viết lại quy tắc thực sự không khó nếu bạn hiểu các biểu thức thông thường. Tôi sử dụng mã này để giúp tôi khi gỡ lỗi chúng:

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

Bằng cách này, tôi có thể thấy các quy tắc hiện tại trong nháy mắt trên trang của tôi. Chỉ cần nhớ rằng được cung cấp bất kỳ URL nào, hệ thống bắt đầu ở đầu các quy tắc và đi qua chúng cho đến khi tìm thấy một URL phù hợp. Trận đấu sau đó được sử dụng để viết lại truy vấn thành tập hợp tìm kiếm? Key = value bình thường hơn. Các khóa đó được phân tích cú pháp vào những gì đi vào đối tượng WP_Query. Đơn giản.

Chỉnh sửa: Lưu ý bên cạnh, phương pháp này có thể sẽ chỉ hoạt động nếu cấu trúc bài đăng tùy chỉnh thông thường của bạn bắt đầu bằng thứ gì đó không bắt mắt, như% category% hoặc một số thứ tương tự như vậy. Bạn cần bắt đầu nó bằng một chuỗi tĩnh hoặc một số, như% năm%. Điều này là để ngăn chặn việc bắt URL của bạn trước khi nó tuân theo quy tắc của bạn.


Nếu bạn muốn gỡ lỗi dễ dàng hơn cho các quy tắc viết lại của mình, tôi (một lần nữa) khuyên dùng plugin phân tích viết lại của tôi , cho phép bạn thử các quy tắc và xem các biến truy vấn nhanh chóng.
Jan Fabry

Thật không may, hệ thống viết lại URL hiện tại buộc phải làm phẳng tất cả các mẫu URL tiềm năng thành một danh sách lớn so với cấu trúc cây vốn có của các đường dẫn URL. Thiết lập hiện tại không thể phù hợp thuận tiện với một loạt các chữ như danh mục hoặc tên diễn đàn ; như bạn biết, nó buộc tất cả các URL "Trang" phải được đánh giá trước tiên. Kết hợp theo phân đoạn đường dẫn và khớp theo nhiều cách (mảng chữ, danh mục, thẻ, thuật ngữ thuế, tên người dùng, loại bài đăng, tên bài đăng, cuộc gọi lại, móc lọc và cuối cùng là RegEx) sẽ dễ dàng thay đổi quy mô hơn và sẽ dễ dàng hơn hiểu.
MikeSchinkel

Mike: Thật ra, điều đó không dễ hiểu chút nào, vì tôi chưa có manh mối đầu tiên WTF mà bạn đang nói ở đó. Ý tưởng của bạn về định tuyến URL là khó hiểu và khó khăn, và như bạn có thể biết, tôi không đồng ý với chúng. Tìm kiếm căn hộ có ý nghĩa hơn và linh hoạt hơn bạn có xu hướng cung cấp cho nó tín dụng. Hầu hết mọi người không muốn tất cả sự phức tạp không cần thiết trong URL của họ và hầu như không ai cần nó cả.
Otto

Cảm ơn, nhưng tôi nghĩ rằng tôi đã thử điều này trước đây ( wordpress.stackexchange.com/questions/9455/
mẹo

May mắn thay WordPress câu trả lời bây giờ cho phép những người làm quản lý muốn các URL của họ để cuối cùng có một giọng nói, và họ dường như có nhiều (100). Nhưng tôi tôn trọng rằng bạn có thể không theo được ví dụ của tôi trước khi thực hiện đầy đủ. Tôi dự đoán rằng, một khi cách tiếp cận mà tôi ủng hộ được thực hiện đầy đủ trong một plugin và sau khoảng 6-12 tháng, nó sẽ trở thành cách ưa thích để các trang web CMS dựa trên WordPress định tuyến URL của họ. Vì vậy, hãy tiếp tục cuộc tranh luận này trong khoảng 9 tháng.
MikeSchinkel

4

Bạn sẽ không thể làm điều này bằng cách sử dụng WP_Rewrite một mình, vì nó không thể phân biệt giữa sên hạn và sên bài.

Bạn cũng phải nối vào 'yêu cầu' và ngăn 404, bằng cách đặt var truy vấn bài thay vì phân loại.

Một cái gì đó như thế này:

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

Lưu ý rằng phân loại phải được xác định trước loại bài.

Đây sẽ là thời điểm tốt để chỉ ra rằng có một phân loại và loại bài đăng có cùng một truy vấn var là một ý tưởng tồi.

Ngoài ra, bạn sẽ không thể truy cập các bài đăng có cùng sên như một trong các điều khoản.


Đồng ý rằng việc phân loại và loại bài đăng có cùng một truy vấn var là một ý tưởng tồi, nhưng điều đó có thể ám chỉ những người có phân loại và loại bài đăng có cùng tên là một ý tưởng tồi, không phải vậy. Nếu sử dụng cùng tên thì chỉ một trong hai nên có một truy vấn var.
MikeSchinkel

2

Tôi sẽ xem mã của plugin mèo cấp cao nhất:

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

Bạn có thể dễ dàng điều chỉnh để nó tìm kiếm sên phân loại tùy chỉnh của bạn bằng cách thay đổi

$category_base = get_option('category_base');

trên dòng 74 đến một cái gì đó như:

$category_base = 'forums';

Có thể hoạt động cho các danh mục, nhưng nó không dành cho các phân loại tùy chỉnh (ít nhất là trong wp 3.1) ... Tôi đã quản lý để thay đổi URL, nhưng tôi gặp lỗi 404
onetrickpony

2

Tôi khuyên bạn nên xem qua plugin Permalinks tùy chỉnh . Tôi không có thời gian để kiểm tra ngay bây giờ, nhưng nó có thể giúp ích cho tình huống của bạn.


nó không, nó chỉ xử lý bài viết, không phải nguyên tắc phân loại, và thậm chí nếu nó sẽ, tôi muốn có thêm một số loại tiền tố trước %forum%, đó là chính xác những gì tôi đang cố gắng để tránh ...
onetrickpony

2

Vì tôi quen thuộc với câu hỏi khác của bạn , tôi sẽ trả lời trong đầu.

Tôi chưa thử nghiệm điều này chút nào, nhưng nó có thể hoạt động nếu bạn thực hiện điều này một lần ngay sau khi bạn đăng ký tất cả các hoán vị bạn muốn:

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

Điều này làm gì: nó loại bỏ các quy tắc viết lại được tạo ra từ các chủ đề permalink khỏi luồng thông thường của mảng quy tắc và hợp nhất lại chúng ở cuối mảng. Điều này ngăn những quy tắc đó can thiệp vào bất kỳ quy tắc viết lại nào khác. Tiếp theo, nó buộc các quy tắc viết lại dài dòng (mỗi trang có một quy tắc riêng với một biểu thức chính quy cụ thể). Điều này ngăn các trang can thiệp vào các quy tắc của chủ đề của bạn. Cuối cùng, nó thực thi một thao tác xóa mạnh (đảm bảo tệp .htaccess của bạn có thể ghi được, nếu không điều này sẽ không hoạt động) và lưu mảng quy tắc viết lại rất phức tạp rất lớn.


đã thử nó, không có gì thay đổi
onetrickpony


2

Không chắc chắn nếu điều này sẽ làm việc cho các nguyên tắc phân loại, nhưng nó đã làm việc cho các loại bài tùy chỉnh

Mặc dù nó đã không được cập nhật trong 2 năm, nhưng plugin dưới đây hoạt động với tôi: http://wordpress.org/plugins/remove-slug-from-custom-post-type/

FYI Tôi đang chạy WP 3.9.1với các loại WP1.5.7


2

Sử dụng dấu gạch chéo làm giá trị cho sên ... hoạt động 100%

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

2
không hoàn toàn, điều này gây ra tất cả các pageloại bài đăng thành 404.
Milo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.