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

WordPress Custom Post Type Permalink

如何注册自定义文章类型

注册自定义文章类型用到的函数是register_post_type,可以套用官方文档的代码示例,将下面的代码放到主题的functions.php中,到后台查看菜单,就会发现多了一个选项卡叫“Books”。

add_action( 'init', 'codex_custom_init' );
function codex_custom_init() {
  $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);
}

custom post type named book

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

Custom Post Type默认的固定链接格式是‘post-slug/postname’,如果没有指定slug,则用post type作为slug,本例中没有指定,所有post slug就是book。

与固定链接相关的参数有rewrite、和slug

rewrite参数指定是否开启固定链接功能,rewrite默认是true,如果设置成false,假设我创建了一个book类型的文章,标题是“Harry Potter Book”,产生的链接如下:

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

如果rewrite为true,链接为

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

结尾是否有反斜杠,取决于设置-固定链接中的格式结尾是否有反斜杠,建议这里结尾不要带反斜杠,否则可能出现

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

http://mydomain.com/book/harry-potter-book/
指向同一个地址的情况,对搜索引擎不友好。

如何修改自定义文章类型的固定链接格式

假设我们创建了book类型的文章,并且用中文当做文章标题,那么默认产生的链接也将是中文,中文链接通常会编码,比较长,分享不方便。你可以手动输入英文slug,也可以通过修改固定链接格式让了链接更简短。

例如,我想让http://mydomain.com/book/harry-potter-book变成http://mydomain.com/book/33.html,也就是用文章的ID作为链接格式。

要达到这个目的:

  1. 创建新的rewrite规则翻译URL
  2. 添加filter(post_type_link),当get_the_permalink()函数调用时,返回正确的链接格式

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

代码段1

add_action('init', 'custom_book_rewrite');
function 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);
}
 
add_filter('post_type_link', 'custom_book_permalink', 1, 3);
function custom_book_permalink($post_link, $post = 0) {
  global $wp_rewrite;
  if ( $post->post_type == 'book' ){
	  $post = &get_post($id);
	  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;
	} else {
		return $post_link;
	}
}

代码段2

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 .'.html' );
    } else {
        return $link;
    }
}
 
add_action( 'init', 'custom_book_rewrites_init' );
 
function custom_book_rewrites_init(){
    add_rewrite_rule(
        'book/([0-9]+)?.html$',
        'index.php?post_type=book&p=$matches[1]',
        'top' );
}

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

 针对多个Custom Post Type

将代码段2修改一下,就可以同时修改多个自定义文章类型的固定链接

$mytypes = array(
	'type1' => 'slug1',
	'type2' => 'slug2',
	'type3' => 'slug3'
);
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,array_keys($mytypes) ) ){
        return home_url( $mytypes[$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 $k => $v ) {
		add_rewrite_rule(
			$v.'/([0-9]+)?.html$',
			'index.php?post_type='.$k.'&p=$matches[1]',
			'top' );
	}
}

$mytypes数组存储需要更改固定链接的Custom Post Type和它们的固定链接前缀,例如类型为type1的固定链接将是
http://mydomain.com/slug1/875.html

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. 用了Custom Post Type Permalinks后,对于bbpress论坛的帖子,电脑访问没有问题,手机访问就404,能解决么

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

  5. 标签url怎么自定义?
    比如:/tag/xxx 改成 /s-tag/xxx

  6. 求教博主。/%postname%.html这种固定链接怎么处理?

      1. 加我Q详细跟你说下。谢过。

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

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

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

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

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

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

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

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

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

  8. Hi,

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

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

  9. 确实很强大,但如果做成插件的话,就更强大了。

    1. 有现成的插件,custom post type permalink

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

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

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

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

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

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

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

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

  14. 你好,怎么给它添加分类和标签呢?

  15. 昨晚,试了下代码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就会自动把所有不带/重定向到带/的,具体是什么原理我也没研究过

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

    1. 那我建议你用插件Custom Post Type Permalinks

    2. 还有,就算用代码也不用写上三四遍,比如你可以这样写,只要把要更改地址的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' ); 
         } 
      }

       

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

    1. 哈哈,找技术资料还是用谷歌的好

  18. 请教博主,能不能推荐一个制作自定义文章类型的插件?

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

  19. 博主,你说的 WordPress Answers 网址是多少?

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

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

评论功能已关闭