WP笔记

Meta Box vs. Custom Fields

WordPress的文章除了有标题、内容、固定链接等属性以外,还可以添加很多用户自定义属性,例如基于WP的电子商务网站,会为每个post添加产品价格、产品库存等属性。而完成这个功能最简单的方式就是custom fields(自定义栏目)

如何使用Custom Fields

Custom Felds是WordPress默认的功能,通过勾选显示选项中的自定义栏目(Custom Fields)就可以调出它的界面,如下

自定义栏目

用户需要手动输入自定义栏目的关键字和值。

存储custom fields(添加、更新和删除)

add_post_meta()

update_post_meta()

delete_post_meta()

读取custom fields

get_post_custom()

get_post_custom_values()

get_post_custom_keys()

以上三个函数返回某个post所有的custom fields信息

get_post_meta() 返回指定的meta key信息。

从读取custom fields的函数你可以猜到,custom_fields是一组“键值对”,所以你可以获取它的key和value值。

custom fields的本质是post meta,WordPress有一个数据表叫做wp_postmeta,专门存放post相关信息(也就是post meta信息)。表的数据库结构如下图所示

从图中可以看出meta_key和meta_value键值对的关系。

wp postmeta表结构

meta_key和meta_value不仅可以一对一,也可以是一对多的关系,如果善加利用,功能很强大。

Custom Fields很强大,但是…

用户喜欢友好的界面,手动输入自定义的值显然让大多数用户头痛,你需要先和他们沟通输入什么样的键值对代表什么意义,或许你还要准备一份文档防止用户忘记。

有没有对用户更加友好的自定义栏目解决方案?答案是肯定的——Post Meta Box

什么是Post Meta Box

Post Meta Box是一种将custom fields分组管理的表现形式,例如用来做SEO的title和keywords可以放到一个Post Meta Box里,custom fields的键是什么客户不需要知道,客户只会看到两个input box,要求输入title和keywords,如下图所示

SEO Settings Meta Box

看起来比custom fields直观的对,对吧。下面的问题是如何在创建/编辑post或者page的界面添加这样一个post meta box。

如何使用Post Meta Box

步骤归纳为以下几点:

  1. 创建Post Meta Box
  2. 通过回调函数输出Meta Box的HTML结构
  3. 验证用户填写的数据是否合法
  4. 存储或者更新数据
  5. 在前台读取数据应用

首先,创建Post Meta Box

创建Post Meta Box用到的函数:

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

$id: 指生成的meta box的html ID,当然要具有唯一性

$title: meta box的标题,如果要多语言化,这里就要写成__(‘the title’,’the title对应的翻译’)的形式。

$callback: 回调函数,很重要,用这个函数输出meta box的HTML结构。

$post_type: 指定这个meta box要用于那种文章类型,例如post、page、link或者自定义的类型(例如幻灯片、portfolio等)

$context: 指定meta box放在哪。可以填normal、advanced或者side,nromal和advanced都在文章底部,side在文章边栏。

$priority: 优先级,系统根据这个优先级对所有的meta box来排序,值可以是efault、core、high或者low

$callback_args:传递给回调函数的参数,回调函数接收$post以及$callback_args指定的参数。

//通过load-$page_hook 钩子指定仅在post或page编辑页面加载这段代码
add_action( 'load-post.php', 'sola_post_meta_boxes_setup' );
add_action( 'load-post-new.php', 'sola_post_meta_boxes_setup' );

function sola_post_meta_boxes_setup() {

	//通过'add_meta_boxes'钩子添加Post Meta Box
	add_action( 'add_meta_boxes', 'sola_add_post_meta_boxes' );

	//存储自定义Post Meta Box时用到的函数
	add_action( 'save_post', 'sola_save_post_meta_boxes', 10, 2 );
}

//创建Meta Box,名为SEO Settings
function sola_add_post_meta_boxes() {

	add_meta_box(
		'sola-seo-box-class',	// Unique ID
		'SEO Settings',		// Title
		'sola_seo_box_format',	// Callback function
		'post',			// Admin page (or post type)
		'normal',		// Context
		'default'		// Priority
	);
}

这段代码会产生如下所示的HTML结构

SEO Settings

这段代码中用到了load-$page_hook action,这个action的作用是使代码仅在某个页面执行,$page_hook代表页面脚本名称,这里我们限制sola_add_post_meta_boxes()函数只能在创建/编辑post或者page的页面执行,注意文章和页面的脚本名称都是post.php。

了解load-$page_hook action详情->

用回调函数打印HTML结构

我要向post添加一个Meta Box,所以类型就是post,为了方便起见,将需要添加的字段(title,keywords)存到一个$fields数组中

$fields = array(
	array(
		'name' => 'Title',
		'desc' => 'characters. Most search engines use a maximum of 60 chars for the title. ',
		'id' => 'sola-seo-title',
		'type' => 'text',
		'default' => ''
	),
	array(
		'name' => 'Keywords (comma separated):',
		'desc' => '',
		'id' => 'sola-seo-keywords',
		'type' => 'text',
		'default' => ''
	)
);

在回调函数中读取数组$fields指定的字段,循环输出

function sola_seo_box_format(){
	global $fields,$post;

  // Use nonce for verification
  echo '
';

  echo '
';

  foreach ($fields as $field) {
      // get current post meta data
      $meta = get_post_meta($post->ID, $field['id'], true);

      echo '
'.
              '


'.
              '


';
  }

  echo '
'; switch ($field['type']) { case 'text': echo ' '. ''. $field['desc']; break; case 'textarea': echo ''. ''. $field['desc']; break; case 'select': echo ' '; break; case 'radio': foreach ($field['options'] as $option) { echo ' ' . $option['name']; } break; case 'checkbox': echo ' '; break; } echo ' '.'
'; }

这段代码具有一定的重用性,你可以通过扩充$fields数组输出不同的input类型(text、checkbox、select、radio、textarea)

处理/保存数据

现在名叫SEO Settings的Meta Box已经在文章/页面的编辑界面产生了,当用户输入信息后,需要保存这些数据。

  1. 验证nonce信息,一种安全机制,详情
  2. 检测是否正在自动保存,如果是就不用自己保存了,返回
  3. 获取文章类型,检查用户是否有编辑该类型文章的权限
  4. 保存数据
/*add_action( 'save_post', 'sola_save_post_meta_boxes', 10, 2 );指定的函数*/
function sola_save_post_meta_boxes($post_id) {
	global $fields, $post;

    //Verify nonce
    if (!wp_verify_nonce($_POST['sola_meta_box_nonce'], basename(__FILE__))) {
        return $post_id;
    }

    //Check autosave
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
        return $post_id;
    }
    //Get the post type object.
    $post_type = get_post_type_object( $post->post_type );
    //Check permissions
    if ( !current_user_can( $post_type->cap->edit_post, $post_id ) )
		return $post_id;

    foreach ($fields as $field) {
        $old = get_post_meta($post_id, $field['id'], true);
        $new = $_POST[$field['id']];

        if ($new && $new != $old) {
            update_post_meta($post_id, $field['id'], $new);
        } elseif ('' == $new && $old) {
            delete_post_meta($post_id, $field['id'], $old);
        }
    }
}

在前台调用Meta Box数据

Post Meta Box是custom fields的分组管理方式,因此本质还是custom fields,在数据库中的存储方式也是一样的,用调用custom fields的方法调用meta box信息即可。


源代码下载

[download id=27]

将post-seobox.php放到主题的根目录下,在functinos.php中引入即可

include dirname(__FILE__) . '/post-seobox.php';

参考资料

这些资料对你可能比较有用

Data Validation – 安全第一,用户数据要进行验证处理。

How To Create Custom Post Meta Boxes In WordPress

User-friendly custom fields with Meta Boxes in WordPress

WordPress Meta Box终极指导学习笔记

7条评论

  1. Pingback: WordPress博客添加首页、文章页、页面、分类页、标签页的关键字和描述进阶版 | 零零零的blog
  2. 做了个价格,想自动保持小数点两位,google后sprintf (“%-02.2f”, $money); 但是不会添加在metabox….晕死 求指导下

    1. /* 保存 */
      	foreach ($goods_meta as $meta_key) {
              $old = get_post_meta($post_id, $meta_key['id'], true);
              if ( $meta_key['id'] == 'goods_price' ) {
              	$goods_price_format = $_POST[$meta_key['id']];
              	$new = sanitize_text_field( sprintf( '%-02.2f', $goods_price_format ) );
              } else {
              	$new = sanitize_text_field( $_POST[$meta_key['id']] );
              }
      
              if ($new && $new != $old) {
                  update_post_meta($post_id, $meta_key['id'], $new);
              } elseif ('' == $new && $old) {
                  delete_post_meta($post_id, $meta_key['id'], $old);
              }
          }

      常识了下这样是ok, 大婶看下 可对或者更好的写法

  3. Pingback: WordPress博客添加首页、文章页、页面、分类页、标签页的关键字和描述进阶版 | 西门的后花园
  4. Pingback: 如何修改Post Meta信息 - Genesis Framework | ~SolagirL~
  5. Pingback: 如何nofollow Blogroll中的链接 | ~SolagirL~

评论已关闭。