本文主要是介绍利用WordPress 的内置函数add_meta_box结合自定义字段调用函数get_post_meta在你的文章发布页或页面发页面添加个更方便的自字义字段输入框。

  • 快速例程

如果你刚开始写自定义填写面板,这张图是一个简明的例子,可以帮助你明白这项技术如何改善你的Wordpress体验。一切都是从最简单的开始。编者稍微改变了meta box数组(去除了从未实际用到的信息)并且添加了一个新的变量$key,用来标记新数据(在其他事件中)。

  • 要舍弃哪里 (在 functions.php)

注意: 代码缩进的格式请别介意。WordPress插件自动生成这样了。抱歉!

  1. <?php
  2. /*
  3. Plugin Name: Custom Write Panel
  4. Plugin URI: http://wefunction.com/2009/10/revisited-creating-custom-write-panels-in-wordpress
  5. Description: Allows custom fields to be added to the WordPress Post Page
  6. Version: 1.1
  7. Author: Spencer
  8. Author URI: http://wefunction.com
  9. /* ----------------------------------------------*/
  10. $key = "key";
  11. $meta_boxes = array(
  12. "image" => array(
  13. "name" => "image",
  14. "title" => "Image",
  15. "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here.
  16. Images will be resized. This is the Article's main image and will automatically be sized."),
  17. "tinyurl" => array(
  18. "name" => "tinyurl",
  19. "title" => "Tiny URL",
  20. "description" => "Add a small URL of this post that will be used to track tweets, and share the post.")
  21. );  

然后,为了取代它,我们添加自己的方法来建立面板:

  1. function create_meta_box() {
  2. global $key;
  3. if( function_exists( 'add_meta_box' ) ) {
  4. add_meta_box( 'new-meta-boxes', ucfirst( $key ) . ' Custom Post Options', 'display_meta_box', 'post', 'normal', 'high' );
  5. }
  6. }  

像以前一样,用$key变量标记标题。

  • 显示填写面板

接下来这步也很类似。我们来建立meta box。正如我说的,变动不大。稍微去掉了一些不需要的代码(检查标准值从数组中移除),改变了nonce的建立方式。

  1. <?php
  2. function display_meta_box() {
  3. global $post, $meta_boxes, $key;
  4. ?>
  5. <div class="form-wrap">
  6. <?php
  7. wp_nonce_field( plugin_basename( __FILE__ ), $key . '_wpnonce', false, true );
  8. foreach($meta_boxes as $meta_box) {
  9. $data = get_post_meta($post->ID, $key, true);
  10. ?>
  11. <div class="form-field form-required">
  12. <label for="<?php echo $meta_box[ 'name' ]; ?>"><?php echo $meta_box[ 'title' ]; ?></label>
  13. <input type="text" name="<?php echo $meta_box[ 'name' ]; ?>" value="<?php echo htmlspecialchars( $data[ $meta_box[ 'name' ] ] ); ?>" />
  14. <p><?php echo $meta_box[ 'description' ]; ?></p>
  15. </div>
  16. <?php } ?>
  17. </div>
  18. <?php
  19. }
  20. ?>  

现在我要使用WordPress的wp_nonce_field函数创建一个nonce。这次它在foreach循环之外,因为我们只需要一个!(不知道以前我怎么想的。)

就像我之前提到的那样,我去除了一些检测默认值的代码,换以$data值。通过key寻找我们的单独meta行,将所有必要的数据加到输入中去。

  • 存储数据

最后一步,数据存储,这是改动最大的一部分。基本思路是loop循环访问原来的$meta_boxes数组,创建一个新数组存值。用英语来说:for each array in $meta_boxes, get the value of the input field, and add it to a new $data array.

这样我们就得到了一个单独的数组。代码如下:

  1. foreach( $meta_boxes as $meta_box ) {
  2. $data[ $meta_box[ 'name' ] ] = $_POST[ $meta_box[ 'name' ] ];
  3. }  

在函数中,我们还需要验证数据。现在编者对nonce的工作方式有更深的理解了,编者会试着解释我们是如何验证的。我们用WordPress的wp_verify_nonce函数在有限时间之内验证正确的nonce。如果非真,返回$post_id中止脚本。这样可以防止你去做那些本不想做的。你可以阅读来自Mark Jaquith的关于nonce

接下来的snipet用来检测当前用户是否有权限编辑post.因为我们只在post页创建meta_boxes,所以只需要检测是否可编辑post。

  1. if ( !wp_verify_nonce( $_POST[ $key . '_wpnonce' ], plugin_basename(__FILE__) ) )
  2. return $post_id;
  3. if ( !current_user_can( 'edit_post', $post_id ))
  4. return $post_id;  

如果你还记得过去的脚本中,为了保存数据,我们首先要检测它是否存在,如果存在曾更新,不存在则添加,空则删除。要好多检测呢!想想看数据库这么搞十次会怎样?似乎会很慢吧?

在编者写旧版教程不久之后,WordPress更新了update_post_meta函数,如果行不存在会自动创建。这样就允许我们仅使用一个函数,而不是分出三个(编者决定去掉删除这项,因为总会新建些什么,而且一行也不像三四行那么糟糕)

于是我们最的终保存函数就像这样:

  1. function save_meta_box( $post_id ) {
  2. global $post, $meta_boxes, $key;
  3. foreach( $meta_boxes as $meta_box ) {
  4. $data[ $meta_box[ 'name' ] ] = $_POST[ $meta_box[ 'name' ] ];
  5. }
  6. if ( !wp_verify_nonce( $_POST[ $key . '_wpnonce' ], plugin_basename(__FILE__) ) )
  7. return $post_id;
  8. if ( !current_user_can( 'edit_post', $post_id ))
  9. return $post_id;
  10. update_post_meta( $post_id, $key, $data );
  11. }
  • 最终代码

下面就是所有的新代码了。最后几行是初始化脚本。

  1. <?php
  2. $key = "key";
  3. $meta_boxes = array(
  4. "image" => array(
  5. "name" => "image",
  6. "title" => "Image",
  7. "description" => "Using the "<em>Add an Image</em>" button, upload an image and paste the URL here.
  8. Images will be resized. This is the Article's main image and will automatically be sized."),
  9. "tinyurl" => array(
  10. "name" => "tinyurl",
  11. "title" => "Tiny URL",
  12. "description" => "Add a small URL of this post that will be used to track tweets, and share the post.")
  13. );
  14. function create_meta_box() {
  15. global $key;
  16. if( function_exists( 'add_meta_box' ) ) {
  17. add_meta_box( 'new-meta-boxes', ucfirst( $key ) . ' Custom Post Options', 'display_meta_box', 'post', 'normal', 'high' );
  18. }
  19. }
  20. function display_meta_box() {
  21. global $post, $meta_boxes, $key;
  22. ?>
  23. <div class="form-wrap">
  24. <?php
  25. wp_nonce_field( plugin_basename( __FILE__ ), $key . '_wpnonce', false, true );
  26. foreach($meta_boxes as $meta_box) {
  27. $data = get_post_meta($post->ID, $key, true);
  28. ?>
  29. <div class="form-field form-required">
  30. <label for="<?php echo $meta_box[ 'name' ]; ?>"><?php echo $meta_box[ 'title' ]; ?></label>
  31. <input type="text" name="<?php echo $meta_box[ 'name' ]; ?>" value="<?php echo htmlspecialchars( $data[ $meta_box[ 'name' ] ] ); ?>" />
  32. <p><?php echo $meta_box[ 'description' ]; ?></p>
  33. </div>
  34. <?php } ?>
  35. </div>
  36. <?php
  37. }
  38. function save_meta_box( $post_id ) {
  39. global $post, $meta_boxes, $key;
  40. foreach( $meta_boxes as $meta_box ) {
  41. $data[ $meta_box[ 'name' ] ] = $_POST[ $meta_box[ 'name' ] ];
  42. }
  43. if ( !wp_verify_nonce( $_POST[ $key . '_wpnonce' ], plugin_basename(__FILE__) ) )
  44. return $post_id;
  45. if ( !current_user_can( 'edit_post', $post_id ))
  46. return $post_id;
  47. update_post_meta( $post_id, $key, $data );
  48. }
  49. add_action( 'admin_menu', 'create_meta_box' );
  50. add_action( 'save_post', 'save_meta_box' );
  51. ?>
  • 执行

编者重写脚本的主要原因就是获得更高的执行效率。因为所有数据都被保存到单独的行,我们只需要调用一次。

  1. $data = get_post_meta( $post->ID, 'key', true );  

将它放到WordPress的while循环中。记住,将“key”变为任何你在脚本中输入的值。这个变量保存一个数组存储数据库中的信息。你可以像这样方便地获得:

  1. <?php echo $data[ 'tinyurl' ]; ?>  

或者

  1. <?php echo $data[ 'image' ]; ?>  

如编者说的那样,后端部分没有太大改变,仅仅是缩减了代码,但效率和可扩展性会得到相当的提升。

本文来源:Spencer