注意:部分文章发布时间较长,可能存在未知因素,购买时建议在本站搜索商家名称,先充分了解商家动态。
交流:唯一投稿邮箱:hostvps@88.com。
什么是自定义post?
不要想当然的认为这里的post就是就是指博客中的文章,它只不过是一个文章类的代理词而已,甚至你还可以认为它是内容。
自定义模型是没有一个很标准的什么规定的,文章模型可以是你想的任何一个内容模型,就拿wordpress本身来说就内置了以下几个内容文章模型:
- 博客文章
- 页面
- 附件
- 修正
- 导航等
你可以这样去理解:它只要是想我们使用博客文章那样用来创建、编辑和储存数据的一种很灵活的内容形式。
不过在这里我还是需要提醒下,博客内置的post还是有点点不同的,你可以利用它含有分类、标签等去标识内容的!
为什么要自定义文章模型?
wordpress已经提供一些完善的默认文章模型,并适用于大多数站点,但我们还是需要更多的选择。我列举了一些我想到的一些可能有用内容模型,并链接到相对应的例子。
- 房产清单
- 活动日历(我知道很多人对这个感兴趣)
- 影视资料库
- 书籍资料库
- 没有很多集成问题的论坛系统
- 类似wordpress trac的票务系统
- 设计相册或作品集
你还可以想到我列举之外的更多内容模型。而且我也想在以后学习更多关于论坛和票务系统的想法。这两个系统我已经实现并希望的得到一些反馈。
创建一个 post type
创建一个新的 post type 需要使用 register_post_type 函数来注册一下。需要在你主题的 functions.php 文件下调用该函数:
1
|
register_post_type( $post_type , $args ); |
$post_type 参数就是你自定义 post type 的名称,post type 可以自定义的功能非常多,所以这个函数里面的 $args 参数会很多。所以通常会用下面这种格式来注册:
1
2
3
4
5
|
function my_custom_post_product() { $args = array (); register_post_type( 'product' , $args ); } add_action( 'init' , 'my_custom_post_product' ); |
包裹在一个函数中,定义一个数组,然后挂靠到 init 这个 action 上。这样 wordpress 在初始化的时候,就会执行这个函数注册一个自定义 post type,因为调用 register_post_type() 的时候,必须要在 admin_menu action 之前,在 after_setup_theme action 之后,所以这里最好挂靠到 init action 上。
参数很多,为了写教程方便,只列出比较常用的参数,大体结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
function my_custom_post_movie() { $labels = array ( 'name' => _x( 'movies' , 'post type 名称' ), 'singular_name' => _x( 'movie' , 'post type 单个 item 时的名称,因为英文有复数' ), 'add_new' => _x( '新建电影' , '添加新内容的链接名称' ), 'add_new_item' => __( '新建一个电影' ), 'edit_item' => __( '编辑电影' ), 'new_item' => __( '新电影' ), 'all_items' => __( '所有电影' ), 'view_item' => __( '查看电影' ), 'search_items' => __( '搜索电影' ), 'not_found' => __( '没有找到有关电影' ), 'not_found_in_trash' => __( '回收站里面没有相关电影' ), 'parent_item_colon' => '' , 'menu_name' => 'movies' ); $args = array ( 'labels' => $labels , 'description' => '我们网站的电影信息' , 'public' => true, 'menu_position' => 5, 'supports' => array ( 'title' , 'editor' , 'thumbnail' , 'excerpt' , 'comments' ), 'has_archive' => true ); register_post_type( 'movie' , $args ); } add_action( 'init' , 'my_custom_post_movie' ); |
这里为了直观方便,我直接使用了中文,更好的应该是使用英文然后通过本地化函数来翻译成中文。
参数有点多,也可以使用 generatewp 工具自定义参数,然后改改,会稍微方便一点。
从上面代码可以看到 $args 数组里面有一个 labels 配置项,用来配置显示文案有关的内容,为了清晰所以单独拿出来创建了一个数组。其他配置项看下英文也能猜出大体意思,如果想要详细了解,可以看下官方文档:register_post_type 。
将上面代码加到主题 functions.php 的最下面,进入后台你会发现多出了 movies 选项,这样表示注册成功:
贝壳主机网、bkvps.com
这时候我们可以新建 movie 发表一篇电影类型的文章了。但是这样与文章类型基本相同,我们需要更多的自定义来完善我们的 movie 类型。
为 post type 添加分类功能
就电影来说,可以分为科幻、动作、战争等类别,那么我们就为自定义的 movie 添加分类功能,这样就可以编辑新分类以及归类我们的电影了。这个分类跟文章里面的分类性质是一样的。
添加分类功能需要使用函数 register_taxonomy,使用方法也很简单,跟注册 post type 函数类似,只不过多了一个参数用来指定对应的 post type :
1
|
register_taxonomy( $taxonomy , $object_type , $args ); |
就本例而言,可以配置如下常用参数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
function my_taxonomies_movie() { $labels = array ( 'name' => _x( '电影分类' , 'taxonomy 名称' ), 'singular_name' => _x( '电影分类' , 'taxonomy 单数名称' ), 'search_items' => __( '搜索电影分类' ), 'all_items' => __( '所有电影分类' ), 'parent_item' => __( '该电影分类的上级分类' ), 'parent_item_colon' => __( '该电影分类的上级分类:' ), 'edit_item' => __( '编辑电影分类' ), 'update_item' => __( '更新电影分类' ), 'add_new_item' => __( '添加新的电影分类' ), 'new_item_name' => __( '新电影分类' ), 'menu_name' => __( '电影分类' ), ); $args = array ( 'labels' => $labels , 'hierarchical' => true, ); register_taxonomy( 'movie_category' , 'movie' , $args ); } add_action( 'init' , 'my_taxonomies_movie' , 0 ); |
添加到主题之后,我们看到出现了熟悉的文章分类功能,只不过上面的文案全部变成我们自定义的内容了:
这里我们添加两个分类作为演示。
为 post type 添加自定义 meta box
我们想要添加的电影类型不能仅仅只有正文内容,我们还需要额外添加一些 导演 之类的有关内容。那么就需要添加自定义 meta box,meta box 可以在文章发表页面中添加自定义的表单,编写文章的时候可以填写额外的信息然后在前端调用出来。
自定义 meta box 需要用到 add_meta_box 函数:
1
|
add_meta_box( $id , $title , $callback , $post_type , $context , $priority , $callback_args ); |
老规矩,具体参数内容查看官方文档,这里只介绍常用用法。我们注册一个 meta box :
1
2
3
4
5
6
7
8
9
10
11
|
add_action( 'add_meta_boxes' , 'movie_director' ); function movie_director() { add_meta_box( 'movie_director' , '电影导演' , 'movie_director_meta_box' , 'movie' , 'side' , 'low' ); } |
然后在配置参数里面指定了回调函数 movie_director_meta_box,我们需要在这个函数里面创建表单:
1
2
3
4
5
6
7
8
9
10
|
function movie_director_meta_box( $post ) { // 创建临时隐藏表单,为了安全 wp_nonce_field( 'movie_director_meta_box' , 'movie_director_meta_box_nonce' ); // 获取之前存储的值 $value = get_post_meta( $post ->id, '_movie_director' , true ); ?> <label for = "movie_director" ></label> <input type= "text" id= "movie_director" name= "movie_director" value= "<?php echo esc_attr( $value ); ?>" placeholder= "输入导演名称" > <?php } |
这样就可以在文章界面边栏显示出来刚刚创建的表单了:
但是这时候,你的表单是没法用的,因为你提交文章之后并没有保存这个 meta box 的内容,下面是验证保存内容的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
add_action( 'save_post' , 'movie_director_save_meta_box' ); function movie_director_save_meta_box( $post_id ){ // 安全检查 // 检查是否发送了一次性隐藏表单内容(判断是否为第三者模拟提交) if ( ! isset( $_post [ 'movie_director_meta_box_nonce' ] ) ) { return ; } // 判断隐藏表单的值与之前是否相同 if ( ! wp_verify_nonce( $_post [ 'movie_director_meta_box_nonce' ], 'movie_director_meta_box' ) ) { return ; } // 判断该用户是否有权限 if ( ! current_user_can( 'edit_post' , $post_id ) ) { return ; } // 判断 meta box 是否为空 if ( ! isset( $_post [ 'movie_director' ] ) ) { return ; } $movie_director = sanitize_text_field( $_post [ 'movie_director' ] ); update_post_meta( $post_id , '_movie_director' , $movie_director ); } |
虽然最关键的函数就在最后一句,但是一定要注意安全的校验。把这些代码添加进 functions.php 文件之后,你的 meta box 就可以正常工作了。如果你需要更多表单,按照这个模式自定义表单结构,然后添加保存函数即可。
下面,我们迫不及待的添加两部电影《鱼与锅之战:宿命对决》 和 《鱼与锅之战:我爱水煮鱼》 内容如下:
添加完之后,我们可以看下所有电影:
列表空荡荡的,好难看,我可不可以加上导演字段?当然可以,使用 [manage $post type posts custom column](http://codex.wordpress.org/plugin_api/action_reference/manage_$post_type_posts_custom_column) 即可实现,我们添加:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
add_action( "manage_posts_custom_column" , "movie_custom_columns" ); add_filter( "manage_edit-movie_columns" , "movie_edit_columns" ); function movie_custom_columns( $column ){ global $post ; switch ( $column ) { case "movie_director" : echo get_post_meta( $post ->id, '_movie_director' , true ); break ; } } function movie_edit_columns( $columns ){ $columns [ 'movie_director' ] = '导演' ; return $columns ; } |
即添加了列导演字段,并从每篇文章中读取出来。这样我们的列表就变成了:
ok,我们的后端部分就这样愉快的完成了。打开生成好的链接看下,咦,not found?是这样的,如果你的网站设置了固定连接,当你新建了 post type 之后,你必须要在后台更新一下固定连接设置才行。找到后台固定连接,再点击一下下面的“保存设置”,之后就可以正常访问了。
展示 post type 的内容
单纯创建 post type 只是可以让你输入内容,没有什么意义,我们还需要在前台输出自定义 post type 的内容。
自定义 post type 的模板和样式
根据 wordpress 的模板调用规则 我们可以得知,我们只需要创建 archive-[post_type].php 和 single-[post_type].php 就可以实现该 post type 的列表自定义和文章自定义。当访问 post type,wordpress 会优先调用这些模板来渲染。
需要注意的是,你需要在注册 post type 的时候设置 'has_archive' => true 才会有列表。
现在我们就把主题里自带的 archive.php 和 single.php 文件复制一份命名为 archive-movie.php 和 single-movie.php,为了演示,这里我不做很多自定义,只是输出导演信息表示一下。
我们分别在 l.56 和 l.23 附近的合适位置输出 meta box 信息:
1
|
echo '导演:' .get_post_meta( get_the_id(), '_movie_director' , true ); |
然后刷新访问电影列表和具体的电影就可以看到输出的导演信息了。
这里只是举个例子,实际中往往会自定义结构和输出的信息格式等,这里不再进一步修改。这里不再麻烦演示了。
调用 wp_query 高度自定义调用 post type 的内容
上面操作依赖模板,如果需要高度自定义或者在页面的某个模块中调用列表,就需要用到 wp_query 类来调用:
1
2
3
4
5
6
7
8
|
$args = array ( 'post_type' => 'product' , 'posts_per_page' => 10 ); $loop = new wp_query( $args ); while ( $loop ->have_posts() ) : $loop ->the_post(); the_title(); echo '<div class="entry-content">' ; the_content(); echo '</div>' ; endwhile ; |
查询出来之后就跟常规的主循环一样了,自定输出结构即可。
在首页列表中显示自定义 post type 的内容
虽然我们自定义好了 post type 同时也编写了一些内容,但是在首页的列表里面并没有显示出来。自定义的 post type 的内容不会自动混入主循环里面。那如何让自定义 post type 的内容显示出来?
你需要使用 pre_get_posts 这个 action 来做一些处理:
1
2
3
4
5
6
|
add_action( 'pre_get_posts' , 'add_my_post_types_to_query' ); function add_my_post_types_to_query( $query ) { if ( is_home() && $query ->is_main_query() ) $query ->set( 'post_type' , array ( 'post' , 'page' , 'movie' ) ); return $query ; } |
在上面的 $query 变量里面设置的 post_type 数组就是要在主循环里面展示的内容,将你的自定义 post type 填写进去就可以在首页中显示出来了。
设置自定义 post type 的固定连接
创建一个新的 post type 有时候也是为了更方便做 seo,所以设置它的固定连接也非常重要。这里主要用到注册 post type 的参数数组里面的 rewrite 参数,常用以下几两项:
slug =》自定义固定连接结构别名,默认是使用 post type 名(例如本例的 movie),可以被翻译。一般来说 post type 名可能与实际需要的 url 不一样( post type 为 movie,但 url 可能需要 movies),就可使用该项自定义。
with_front =》 固定连接是否以根目录为基础路径。如果你在固定连接设置页面设置你的结构为 /archives/,那么你的 post type 生成的连接默认为 /archives/movie 如果设置该项为 false 即可去掉前面的 /archives/ 直接基于根路径生成固定连接。
大功告成,但这只是 post type 最基础的用法,post type 还有其他更高级的用法,更详细的参数配置还需要你去进一步挖掘来适应你网站的功能需求。