自定义元数据

什么是元数据框

当用户编辑文章时,编辑页面由几个默认框组成:编辑器、发布、类别、标签等。这些框是元数据框。插件可以将自定义元数据框添加到任何文章类型的编辑页面。

自定义元数据框的内容通常是 HTML 表单元素,用户可以在其中输入与插件相关的数据,但内容实际上可以是您想要的任何 HTML。

为什么要使用元数据框?

首先元数据框很方便和灵活,可用于模块化编辑和收集与正在编辑的文章相关的信息。自定义元数据框将会与所有其他文章相关的信息显示一同显示在页面上,这样就与文章建立了明确的关系。

你也可以针对不同的用户显示或隐藏元数据框,元数据框可以由用户在编辑屏幕上自由排列。用户可以将它们拖拽到适合的地方。

提示:此页面上的所有示例仅用于说明目的。该代码不适用于生产环境。

添加元数据框

要创建元框,请使用 add_meta_box() 函数并将其置入 add_meta_boxes 动作。 以下示例将元数据框添加到文章编辑页面和 wporg_cpt 编辑页面。

function wporg_add_custom_box()
{
    $screens = ['post', 'wporg_cpt'];
    foreach ($screens as $screen) {
        add_meta_box(
            'wporg_box_id',           // Unique ID
            'Custom Meta Box Title',  // Box title
            'wporg_custom_box_html',  // Content callback, must be of type callable
            $screen                   // Post type
        );
    }
}
add_action('add_meta_boxes', 'wporg_add_custom_box');

wporg_custom_box_html 函数将保存元数据框的 HTML。 以下示例演示添加表单元素、标签和其他 HTML 元素。

function wporg_custom_box_html($post)
{
    ?>
    <label for="wporg_field">Description for this field</label>
    <select name="wporg_field" id="wporg_field" class="postbox">
        <option value="">Select something...</option>
        <option value="something">Something</option>
        <option value="else">Else</option>
    </select>
    <?php
}

注意:元数据框中没有提交按钮。元数据框 HTML 包含在编辑页面的表单标签中,当用户单击“发布”或“更新”按钮时,包括元数据框在内的所有文章数据都通过 POST 传输。

此处示例仅包含一个表单字段,即一个下拉列表。您可以在任何特定元数据框中根据需要创建任意数量。如果您有很多字段要显示,请考虑使用多个元数据框,在每个元数据框中将相似的字段组合在一起。这有助于保持页面更有条理。

获取数据

您可以使用 get_post_meta() 获取存储在 postmeta 表中的数据。以下示例使用元数据框值的预填充数据增强了先前的表单元素。您将在下一节中学习如何保存元框值。

function wporg_custom_box_html($post)
{
    $value = get_post_meta($post->ID, '_wporg_meta_key', true);
    ?>
    <label for="wporg_field">Description for this field</label>
    <select name="wporg_field" id="wporg_field" class="postbox">
        <option value="">Select something...</option>
        <option value="something" <?php selected($value, 'something'); ?>>Something</option>
        <option value="else" <?php selected($value, 'else'); ?>>Else</option>
    </select>
    <?php
}

保存数据

保存或更新文章时,会触发多个操作,可以与其中任何一个挂钩以保存输入的值。在这个例子中,我们使用了 save_post 动作钩子,但某些情况下其他钩子可能更适合。注意,对于单个更新事件,save_post 可能会触发多次。您可以将输入的数据保存在您想要的任何位置,甚至在 WordPress 之外。由于您可能正在处理与文章相关的数据,因此 postmeta 表通常是存储数据的好地方。以下示例将 wporg_field 字段值保存在隐藏的 _wporg_meta_key 元键中。

function wporg_save_postdata($post_id)
{
    if (array_key_exists('wporg_field', $_POST)) {
        update_post_meta(
            $post_id,
            '_wporg_meta_key',
            $_POST['wporg_field']
        );
    }
}
add_action('save_post', 'wporg_save_postdata');

移除元数据框

要从编辑页面中移除元数据框,请使用 remove_meta_box() 函数。传递的参数必须与 add_meta_box() 添加元数据框时的参数完全匹配。

OOP

使用 OOP 添加元数据框很容易,而且您不必担心命名空间中的命名冲突。 为了节省内存,以下示例使用具有静态方法的抽象类。

abstract class WPOrg_Meta_Box
{
    public static function add()
    {
        $screens = ['post', 'wporg_cpt'];
        foreach ($screens as $screen) {
            add_meta_box(
                'wporg_box_id',          // Unique ID
                'Custom Meta Box Title', // Box title
                [self::class, 'html'],   // Content callback, must be of type callable
                $screen                  // Post type
            );
        }
    }
 
    public static function save($post_id)
    {
        if (array_key_exists('wporg_field', $_POST)) {
            update_post_meta(
                $post_id,
                '_wporg_meta_key',
                $_POST['wporg_field']
            );
        }
    }
 
    public static function html($post)
    {
        $value = get_post_meta($post->ID, '_wporg_meta_key', true);
        ?>
        <label for="wporg_field">Description for this field</label>
        <select name="wporg_field" id="wporg_field" class="postbox">
            <option value="">Select something...</option>
            <option value="something" <?php selected($value, 'something'); ?>>Something</option>
            <option value="else" <?php selected($value, 'else'); ?>>Else</option>
        </select>
        <?php
    }
}
 
add_action('add_meta_boxes', ['WPOrg_Meta_Box', 'add']);
add_action('save_post', ['WPOrg_Meta_Box', 'save']);

AJAX

由于元数据框的 HTML 元素在编辑页面的表单标签内,默认行为是在用户提交页面后从 $_POST 全局解析元数据框值。您可以使用 AJAX 增强默认体验;这允许根据用户输入和行为执行操作;不管他们是否提交了页面。

定义触发器

首先,您必须定义触发器,可以是点击一个链接、改变一个值或任何其他 JavaScript 事件。 在下面的示例中,我们将更改定义为执行 AJAX 请求的触发器。

/*jslint browser: true, plusplus: true */
(function ($, window, document) {
    'use strict';
    // execute when the DOM is ready
    $(document).ready(function () {
        // js 'change' event triggered on the wporg_field form field
        $('#wporg_field').on('change', function () {
            // our code
        });
    });
}(jQuery, window, document));

前端代码

接下来,我们需要定义触发器的逻辑,换句话说,我们需要编写前端代码。在下面的示例中,我们将发出 POST 请求,返回的响应要么成功要么失败,这将表明 wporg_field 的值是有效的。

/*jslint browser: true, plusplus: true */
(function ($, window, document) {
    'use strict';
    // execute when the DOM is ready
    $(document).ready(function () {
        // js 'change' event triggered on the wporg_field form field
        $('#wporg_field').on('change', function () {
            // jQuery post method, a shorthand for $.ajax with POST
            $.post(wporg_meta_box_obj.url,                        // or ajaxurl
                   {
                       action: 'wporg_ajax_change',               // POST data, action
                       wporg_field_value: $('#wporg_field').val() // POST data, wporg_field_value
                   }, function (data) {
                        // handle response data
                        if (data === 'success') {
                            // perform our success logic
                        } else if (data === 'failure') {
                            // perform our failure logic
                        } else {
                            // do nothing
                        }
                    }
            );
        });
    });
}(jQuery, window, document));

下一步我们将通过创建的 wporg_meta_box_obj JavaScript 自定义对象动态获取 WordPress AJAX 文件 URL。

注意:如果您的元数据框只需要 WordPress AJAX 文件 URL;您可以使用 ajaxurl 预定义的 JavaScript 变量,而不是创建新的自定义 JavaScript 对象。

仅在 WordPress 管理中可用。在执行任何逻辑之前,请确保它不为空。

将前端代码置入相应的位置

下一步是将我们的代码放入脚本文件中,并将其放在我们的编辑页面。在下面的示例中,我们将 AJAX 功能添加到以下文章类型的编辑页面:post、wporg_cpt。 脚本文件将位于 /plugin-name/admin/meta-boxes/js/admin.jsplugin-name 是插件的文件夹,/plugin-name/plugin.php 是调用函数的文件。

function wporg_meta_box_scripts()
{
    // get current admin screen, or null
    $screen = get_current_screen();
    // verify admin screen object
    if (is_object($screen)) {
        // enqueue only for specific post types
        if (in_array($screen->post_type, ['post', 'wporg_cpt'])) {
            // enqueue script
            wp_enqueue_script('wporg_meta_box_script', plugin_dir_url(__FILE__) . 'admin/meta-boxes/js/admin.js', ['jquery']);
            // localize script, create a custom js object
            wp_localize_script(
                'wporg_meta_box_script',
                'wporg_meta_box_obj',
                [
                    'url' => admin_url('admin-ajax.php'),
                ]
            );
        }
    }
}
add_action('admin_enqueue_scripts', 'wporg_meta_box_scripts');

服务器端代码

最后一步是编写处理请求的服务器端代码。

function wporg_meta_box_ajax_handler()
{
    if (isset($_POST['wporg_field_value'])) {
        switch ($_POST['wporg_field_value']) {
            case 'something':
                echo 'success';
                break;
            default:
                echo 'failure';
                break;
        }
    }
    // ajax handlers must die
    die;
}
// wp_ajax_ is the prefix, wporg_ajax_change is the action we've used in client side code
add_action('wp_ajax_wporg_ajax_change', 'wporg_meta_box_ajax_handler');

提醒一下,本页所示的代码缺少安全保护的操作。请确保您的生产代码包含此类操作。