WordPress中设置Post Type自定义文章类型的实例教程


Posted in PHP onMay 10, 2016

什么是自定义post?
不要想当然的认为这里的post就是就是指博客中的文章,它只不过是一个文章类的代理词而已,甚至你还可以认为它是内容。
自定义模型是没有一个很标准的什么规定的,文章模型可以是你想的任何一个内容模型,就拿wordpress本身来说就内置了以下几个内容文章模型:

  • 博客文章
  • 页面
  • 附件
  • 修正
  • 导航等

你可以这样去理解:它只要是想我们使用博客文章那样用来创建、编辑和储存数据的一种很灵活的内容形式。

不过在这里我还是需要提醒下,博客内置的post还是有点点不同的,你可以利用它含有分类、标签等去标识内容的!
为什么要自定义文章模型?
Wordpress已经提供一些完善的默认文章模型,并适用于大多数站点,但我们还是需要更多的选择。我列举了一些我想到的一些可能有用内容模型,并链接到相对应的例子。

  • 房产清单
  • 活动日历(我知道很多人对这个感兴趣)
  • 影视资料库
  • 书籍资料库
  • 没有很多集成问题的论坛系统
  • 类似WordPress Trac的票务系统
  • 设计相册或作品集

你还可以想到我列举之外的更多内容模型。而且我也想在以后学习更多关于论坛和票务系统的想法。这两个系统我已经实现并希望的得到一些反馈。

创建一个 post type
创建一个新的 Post Type 需要使用 register_post_type 函数来注册一下。需要在你主题的 functions.php 文件下调用该函数:

register_post_type( $post_type, $args );

$post_type 参数就是你自定义 Post Type 的名称,Post Type 可以自定义的功能非常多,所以这个函数里面的 $args 参数会很多。所以通常会用下面这种格式来注册:

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 上。
参数很多,为了写教程方便,只列出比较常用的参数,大体结构如下:

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 选项,这样表示注册成功:

WordPress中设置Post Type自定义文章类型的实例教程

这时候我们可以新建 Movie 发表一篇电影类型的文章了。但是这样与文章类型基本相同,我们需要更多的自定义来完善我们的 Movie 类型。
为 Post Type 添加分类功能
就电影来说,可以分为科幻、动作、战争等类别,那么我们就为自定义的 Movie 添加分类功能,这样就可以编辑新分类以及归类我们的电影了。这个分类跟文章里面的分类性质是一样的。
添加分类功能需要使用函数 register_taxonomy,使用方法也很简单,跟注册 Post Type 函数类似,只不过多了一个参数用来指定对应的 Post Type :

register_taxonomy( $taxonomy, $object_type, $args );

就本例而言,可以配置如下常用参数:

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

添加到主题之后,我们看到出现了熟悉的文章分类功能,只不过上面的文案全部变成我们自定义的内容了:

WordPress中设置Post Type自定义文章类型的实例教程

这里我们添加两个分类作为演示。
为 Post Type 添加自定义 Meta Box
我们想要添加的电影类型不能仅仅只有正文内容,我们还需要额外添加一些 导演 之类的有关内容。那么就需要添加自定义 Meta Box,Meta Box 可以在文章发表页面中添加自定义的表单,编写文章的时候可以填写额外的信息然后在前端调用出来。
自定义 Meta Box 需要用到 add_meta_box 函数:

add_meta_box( $id, $title, $callback, $post_type, $context,$priority, $callback_args );

老规矩,具体参数内容查看官方文档,这里只介绍常用用法。我们注册一个 Meta Box :

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,我们需要在这个函数里面创建表单:

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
}

这样就可以在文章界面边栏显示出来刚刚创建的表单了:

WordPress中设置Post Type自定义文章类型的实例教程

但是这时候,你的表单是没法用的,因为你提交文章之后并没有保存这个 Meta Box 的内容,下面是验证保存内容的代码:

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 就可以正常工作了。如果你需要更多表单,按照这个模式自定义表单结构,然后添加保存函数即可。
下面,我们迫不及待的添加两部电影《鱼与锅之战:宿命对决》 和 《鱼与锅之战:我爱水煮鱼》 内容如下:

WordPress中设置Post Type自定义文章类型的实例教程

WordPress中设置Post Type自定义文章类型的实例教程

添加完之后,我们可以看下所有电影:

WordPress中设置Post Type自定义文章类型的实例教程

列表空荡荡的,好难看,我可不可以加上导演字段?当然可以,使用 [manage $post type posts custom column](http://codex.wordpress.org/Plugin_API/Action_Reference/manage_$post_type_posts_custom_column) 即可实现,我们添加:

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;
}

即添加了列导演字段,并从每篇文章中读取出来。这样我们的列表就变成了:

WordPress中设置Post Type自定义文章类型的实例教程

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 信息:

echo '导演:'.get_post_meta( get_the_ID(), '_movie_director', true );

然后刷新访问电影列表和具体的电影就可以看到输出的导演信息了。
这里只是举个例子,实际中往往会自定义结构和输出的信息格式等,这里不再进一步修改。这里不再麻烦演示了。
调用 WP_Query 高度自定义调用 Post Type 的内容
上面操作依赖模板,如果需要高度自定义或者在页面的某个模块中调用列表,就需要用到 WP_Query 类来调用:

$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 来做一些处理:

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 还有其他更高级的用法,更详细的参数配置还需要你去进一步挖掘来适应你网站的功能需求。

PHP 相关文章推荐
php购物车实现代码
Oct 10 PHP
php 错误处理经验分享
Oct 11 PHP
PHP register_shutdown_function函数的深入解析
Jun 03 PHP
thinkphp路由规则使用示例详解和伪静态功能实现(apache重写)
Feb 24 PHP
windows的文件系统机制引发的PHP路径爆破问题分析
Jul 28 PHP
php绘图之生成饼状图的方法
Jan 24 PHP
php将html转成wml的WAP标记语言实例
Jul 08 PHP
部署PHP时的4个配置修改说明
Oct 19 PHP
Thinkphp和Bootstrap结合打造个性的分页样式(推荐)
Aug 01 PHP
php之header的不同用法总结(实例讲解)
Nov 28 PHP
PHP使用ActiveMQ实现消息队列的方法详解
May 31 PHP
使用Entrust扩展包在laravel 中实现RBAC的功能
Mar 16 PHP
php+MySQL实现登录时验证登录名和密码是否正确
May 10 #PHP
PHP7+Nginx的配置与安装教程详解
May 10 #PHP
php+mysql实现的二级联动菜单效果详解
May 10 #PHP
浅析Yii2缓存的使用
May 10 #PHP
php简单统计在线人数的方法
May 10 #PHP
使用php实现从身份证中提取生日
May 09 #PHP
PHP使用内置函数生成图片的方法详解
May 09 #PHP
You might like
php checkdate、getdate等日期时间函数操作详解
2010/03/11 PHP
php类的扩展和继承用法实例
2015/06/20 PHP
PHP的Yii框架中YiiBase入口类的扩展写法示例
2016/03/17 PHP
Yii2中DropDownList简单用法示例
2016/07/18 PHP
php删除二维数组中的重复值方法
2018/03/12 PHP
解决laravel 出现ajax请求419(unknown status)的问题
2019/09/03 PHP
父窗口获取弹出子窗口文本框的值
2006/06/27 Javascript
Js 订制自己的AlertBox(信息提示框)
2009/01/09 Javascript
基于jquery的滚动鼠标放大缩小图片效果
2011/10/27 Javascript
Javascript和HTML5利用canvas构建Web五子棋游戏实现算法
2013/07/17 Javascript
Javascript无参数和有参数类继承问题解决方法
2015/03/02 Javascript
JS上传图片前实现图片预览效果的方法
2015/03/02 Javascript
JQuery简单实现锚点链接的平滑滚动
2015/05/03 Javascript
jquery判断单选按钮radio是否选中的方法
2015/05/05 Javascript
Bootstrap编写一个在当前网页弹出可关闭的对话框 非弹窗
2016/06/30 Javascript
js实现以最简单的方式将数组元素添加到对象中的方法
2017/12/20 Javascript
基于react后端渲染模板引擎noox发布使用
2018/01/11 Javascript
JavaScript实现异步图像上传功能
2018/07/12 Javascript
vue.js实现h5机器人聊天(测试版)
2020/07/16 Javascript
JavaScript基于SVG的图片切换效果实例代码
2020/12/15 Javascript
微信小程序弹窗禁止页面滚动的实现代码
2020/12/30 Javascript
[02:36]DOTA2亚洲邀请赛小组赛精彩集锦:奇迹哥卡尔秀翻全场
2017/03/28 DOTA
[03:04]2018年度DOTA2玩家最喜爱的主播-完美盛典
2018/12/16 DOTA
Python下载网络小说实例代码
2018/02/03 Python
对Python通过pypyodbc访问Access数据库的方法详解
2018/10/27 Python
搭建python django虚拟环境完整步骤详解
2019/07/08 Python
python re模块匹配贪婪和非贪婪模式详解
2020/02/11 Python
python继承threading.Thread实现有返回值的子类实例
2020/05/02 Python
朗仕(Lab series)英国官网:雅诗兰黛集团男士专属护肤品牌
2017/11/28 全球购物
奥地利领先的在线药房:SHOP APOTHEKE
2019/10/07 全球购物
优秀学生干部推荐材料
2014/02/03 职场文书
入党积极分子批评与自我批评思想汇报
2014/09/14 职场文书
教师党员自我评价2015
2015/03/04 职场文书
医院办公室主任岗位职责
2015/04/01 职场文书
2016年精神文明建设先进个人事迹材料
2016/02/29 职场文书
简历自我评价范文
2019/04/24 职场文书