WP笔记

如何修改自定义文章类型的固定链接 | Permalink of Custom Post Type

WordPress的自定义文章类型(Custom Post Type)允许我们创建一种有别于blog posts但又能分组管理的文章类型,Custom Post Type在属性上更接近于Page,而非Post,它们的固定链接(Permalink)也不受制于后台-设置-固定链接中为Post规定的链接格式。

如何注册自定义文章类型

假设我们要注册名为Books的文章类型,放写书籍杂志的信息。目标如下图所示:

WordPress注册自定义文章类型

方法一:用代码

注册自定义文章类型用到的函数是register_post_type,可以套用官方文档的代码示例,将下面的代码放到主题的functions.php中。

add_action( 'init', 'sola_register_cpt_book' );
function sola_register_cpt_book() {
  $labels = array(
    'name' => _x('Books', 'post type general name'),
    'singular_name' => _x('Book', 'post type singular name'),
    'add_new' => _x('Add New', 'book'),
    'add_new_item' => __('Add New Book'),
    'edit_item' => __('Edit Book'),
    'new_item' => __('New Book'),
    'all_items' => __('All Books'),
    'view_item' => __('View Book'),
    'search_items' => __('Search Books'),
    'not_found' =>  __('No books found'),
    'not_found_in_trash' => __('No books found in Trash'),
    'parent_item_colon' => '',
    'menu_name' => 'Books'
 
  );
  $args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true,
    'show_in_menu' => true,
    'query_var' => true,
    'rewrite' => true,
    'capability_type' => 'post',
    'has_archive' => true,
    'hierarchical' => false,
    'menu_position' => null,
    'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' )
  );
  register_post_type('book',$args);
}

方法二:代码生成器

WordPress里标准化的东西基本都有代码生成器,刻意记住是没必要的,知道原理,合理利用代码生成器。比如,生成Custom Post Type可以用 – Generate WordPress Post Type

默认的格式是什么样的

自定义文章类型默认的固定链接格式是post-slug/postname,若不指定slug,则用post type作为slug,本例中没有指定,所有post slug就是book。与固定链接相关的参数有rewriteslug。下面重点讲以下rewrite参数。

rewrite为true – 使用SEO有友好的链接格式。假设创建了一个book类型的文章,标题是“Harry Potter Book”,产生的链接如下:

http://mydomain.com/?post_type=book&p=3

这是最原始的格式,使用了数据库wp_post表里的ID,所以我们将rewrite设为false,去掉参数,且SEO友好。

http://mydomain.com/book/harry-potter-book

这里要注意结尾的反斜杠,结尾是否有反斜杠,取决于设置-固定链接中的格式结尾是否有反斜杠,建议这里结尾不要带反斜杠,否则可能出现http://mydomain.com/book/harry-potter-bookhttp://mydomain.com/book/harry-potter-book/指向同一个地址的情况,对搜索引擎不友好。

怎样改成自己想要的格式

依然以book类型为例,当标题是中文时,默认的链接也是中文,url的会变得很长,分享不方便。不想手动输入英文slug,那就修改固定连接的格式,使用ID。例如,让http://mydomain.com/book/harry-potter-book变成http://mydomain.com/book/33.html要达到这个目的:

  1. 创建新的rewrite规则翻译URL
  2. 用filter post_type_link 返回我们想要的地址。

下面有两段代码,都可以实现这个要求,代码加到functions.php中,并且要到后台-设置-固定链接中重新保存固定链接,代码才能生效。

方法一

/**
 * 添加book类型的rewrite rule
 */
add_action( 'init', 'sola_custom_book_rewrite' );
function sola_custom_book_rewrite() {
  global $wp_rewrite;
  $queryarg = 'post_type=book&p=';
  $wp_rewrite->add_rewrite_tag('%qid%', '([^/]+)', $queryarg);
  $wp_rewrite->add_permastruct('book', '/book/%qid%.html', false);
}


/**
 * 修改book类型的固定连接格式
 */
add_filter( 'post_type_link', 'sola_custom_book_permalink', 1, 3 );
function sola_custom_book_permalink( $post_link, $post ) {
  global $wp_rewrite;

  if ( $post->post_type == 'book' ){

    $post = get_post();

    if ( is_wp_error( $post ) ){
      return $post;
    }
    
    $newlink = $wp_rewrite->get_extra_permastruct('book');
    $newlink = str_replace("%qid%", $post->ID, $newlink);
    $newlink = home_url(user_trailingslashit($newlink));
    return $newlink;
  }

  return $post_link;
}

方法二

/**
 * 注册rewrite rule
 */
add_action( 'init', 'sola_custom_book_rewrites_init' );
function sola_custom_book_rewrites_init(){
    add_rewrite_rule(
      'book/([0-9]+)?.html$',
      'index.php?post_type=book&p=$matches[1]',
      'top' 
    );
}

/**
 * 修改链接格式
 */
add_filter('post_type_link', 'sola_custom_book_link', 1, 3);
function sola_custom_book_link( $link, $post ){
    if ( $post->post_type == 'book' ){
        return home_url( 'book/' . $post->ID .'.html' );
    } else {
        return $link;
    }
}

效果如下图所示

自定义文章类型的固定链接格式

61条评论

  1. Hi Sola,
    想请教下针对多个Custom Post Type 如何更改结构为http://mydomain.com/slug1/postname.html?

    1. 用Custom Post Type Permalinks插件试过吗?要是不行就按照上面的代码改改吧,主要是修改正则。

  2. Hi Sola,
    我发现这种写法如果是配合多语言插件WPML使用,添加的文章链接没有多语言变化

    1. 如果你要自己写代码来改链接格式,必须连多语言的一起写进去,自定义代码wpml是照顾不到的。

  3. 你好问一下有没有办法把wordpress的文章内容分页后出现xxx.html/1 的这种情况改成xxx_1.html这样的形式呢,现在使用自定的/archives/%post_id%.html

  4. Pingback: WordPress 修改自定义文章类型的固定链接结构 - 杨俊伟
  5. 用了Custom Post Type Permalinks后,对于bbpress论坛的帖子,电脑访问没有问题,手机访问就404,能解决么

    1. 抱歉,bbpress很久没接触了,不清楚,是不是论坛有手机版,访问链接和pc的不一样?去bbpress论坛问问吧。

        1. 这样的。就是我想把新注册的文章类型的固定链接用/&postname%.html这种形式的。而不是你教程中的/%post_id%.html形式的,那上面那段规则代码该怎么整?我不懂规则不知道怎么改,楼主要是知道的话还请给我贴一段详细代码

        2. 用插件最好,这段代码评论分页时会出问题,custom post type permalink插件可以实现你的需求

        3. 用了这个插件。导致taxonomy.php模版不能正常调用。而且链接变得好长,里面abc.com/post_type/分类/这样的形式而且模版不能正常调用。

        4. 这个插件不涉及模板的东西,如果你的模板无法调用,可能是写的有问题最好检查一下。

        5. 好吧。那你那段代码postname形式的怎么写?我现在暂时还不想用插件

        6. $post里有title,你打印这个数组看看。把$post->ID都替换成title,当然title要处理成url可用的。我现在不方便写代码,大概意思就这样。

        7. 博主,之前按你说的写了不行,我不会重写,估计是出问题了。现在还是用着插件。。博主要是有空还是麻烦写一段自定义文章类型用/%postname%.html的吧

  6. 博主,你的文章对我启发很大。
    关于register_post_type,我有个问题,hierarchical这个参数是干什么用的?我改成true似乎没有任何变化。

    1. hierachical为true,表示这个post type可以有父子关系,就像page那样,如果你的support参数里有 page-attributes,那编辑页面就会显示Parent选项,就是page里选择parent page那个下拉菜单。

  7. Hi,

    請教一下, 我用了Custom Post Type Permalinks, 當我轉URL格式, 我也試過將它分類及不分類,
    依然都是 404問題, 請問知道甚麼原因嗎?

    1. 我不太明白你的意思,将他分类及不分类是指哪个选项?
      另外,修改设置后,保存两次试试。

  8. 方法1试过没用,方法2固定链接那里如果选择默认,打不开链接。必须要随便设置个链接格式才行,怎么回事呢,请问

    1. 这篇文章很久没更新过了,代码比较旧,好不好用我最近也没试验过。建议你直接装custom post type permalink插件,这些功能都能实现,省心。

  9. 楼主,这个代码无法评论啊,用户评论之后就出错啊,麻烦看看哈

    1. 貌似这问题你问了好几遍了,首先,不是所有的custom post type都需要评论功能,其次,用插件的话更省事,比如这个http://wordpress.org/plugins/custom-post-type-permalinks/

    1. 这个是我经常用的插件之一,还有custom permalinks。不过对我来说弄懂原理也是很重要的事。

  10. Sola你好,不知道为什么,我在本地调试,完全按照你的方法来弄,打开页面永远都是404啊。。。
    链接是已经转换成想要的格式了,但是就是打不开。不知道是什么缘故?

  11. 请问lz,使用文中提供的代码后,内容页只显示标题,不显示内容是什么问题呢??

    1. 内容显示是模板控制的,请问你用来显示custom post type的模板是怎么写的?the_content()输出了什么?更改固定链接格式通常情况下不会影响内容,最多是404错误,建议用默认主题测试一下。

  12. Pingback: 不用插件如何更改WordPress Page的固定链接格式 | ~SolagirL~
  13. Pingback: 通过插件注册Custom Post Type,如何在插件启用时更新固定链接 | ~SolagirL~
  14. 昨晚,试了下代码2,发觉可行。但是因为原来我用的固定链接是 /%year%%monthnum%%post_id%/ 这样的形式,为了统一,我把
    return home_url( $mytypes[$post->post_type].’/’ . $post->ID .’.html’ );
    } 里的 ‘.html’ 改成 ‘/’,但这样子就不行了,出现404错误。如何解决。

    1. 你用这段代码试一下,把book替换成你的custom post type

      add_filter('post_type_link', 'custom_book_link', 1, 3);
       
      function custom_book_link( $link, $post = 0 ){
          if ( $post->post_type == 'book' ){
              return home_url( 'book/' . $post->ID.'/'  );
          } else {
              return $link;
          }
      }
       
      add_action( 'init', 'custom_book_rewrites_init' );
       
      function custom_book_rewrites_init(){
          add_rewrite_rule(
              'book/([0-9]+)?$',
              'index.php?post_type=book&p=$matches[1]',
              'top' );
      }
      
      1. 这样能OK了。果然高也。其实我也改过最后的代码,
        add_rewrite_rule(
        ‘book/([0-9]+)?$’,

        改成
        add_rewrite_rule(
        ‘book/([0-9]+)?\/$’,

        这样子,后面加个 /, 好象也符合规则啊,怎么会行不通?看来我对add_rewrite_rule还是不了解。

        1. 其实我和你一样,也试验过你说的方法,哈哈,我也不太清楚为啥那样不行。只是发现如果固定链接中最后有/,wordpress就会自动把所有不带/重定向到带/的,具体是什么原理我也没研究过

  15. 博主你能不能把后面这固定连接重写的弄个注释啊。。。我总共有三四种自定义文章类型。。。加三四段这个代码太笨了

    1. 还有,就算用代码也不用写上三四遍,比如你可以这样写,只要把要更改地址的custom post type名称写到$mytypes数组中就行了

      $mytypes = array('type1','type2'); //custom post type注册名称 
      add_filter('post_type_link', 'custom_book_link', 1, 3); 
      function custom_book_link( $link, $post = 0 ){ 
         global $mytypes; 
         if ( in_array($post->post_type,$mytypes) ){ 
            return home_url( $post->post_type.'/' . $post->ID .'.html' ); 
         } else { 
            return $link; 
         } 
      } 
      
      add_action( 'init', 'custom_book_rewrites_init' ); 
      
      function custom_book_rewrites_init(){ 
         global $mytypes; 
         foreach( $mytypes as $mytype ) { 
            add_rewrite_rule( $mytype.'/([0-9]+)?.html$', 'index.php?post_type='.$mytype.'&p=$matches[1]', 'top' ); 
         } 
      }

       

  16. 哎呀。。博主我爱死你了。。。我的自定义类型的链接老是中文。。。我百度了好久。。都没资料。。然后看了好久英文资料。。没看懂。。。然后谷歌搜索一下。。就让我找到了。。。。

    1. 我一般都用register_post_type直接定义,插件没怎么用过。找了找,Custom Post Type UI这个插件基本上就是把register_post_type的参数UI化了,还可以。
      只是中文翻译比较让人头大,不如直接看英文的

  17. 太棒了,正在找这个资料。试用的Custom Content Type Manager和Types这2个自定义文章类型的插件,都没提供多样化的固定链接。

    1. 我知道Custom Post Type Permalinks挺好用,支持各种格式的custom post type固定链接格式,我不想弄太多插件就用了代码,不过这个插件挺精简的。

评论已关闭。