什么是元框?
当用户编辑文章时,编辑屏幕由几个默认框组成:编辑器、发布、分类、标签等。这些框是元框。插件可以向任何文章类型的编辑屏幕添加自定义元框。
自定义元框的内容通常是 HTML 表单元素,用户在其中输入与插件目的相关的数据,但内容可以是您想要的任何 HTML。
为什么要使用元框?
元框是方便、灵活、模块化的编辑屏幕元素,可用于收集与正在编辑的文章相关的信息。您的自定义元框将与所有其他文章相关信息在同一屏幕上;因此建立了清晰的关系。
元框可以轻松隐藏给不需要看到它们的用户,并显示给需要看到的用户。元框可以在编辑屏幕上由用户排列。用户可以自由地以适合他们的方式排列编辑屏幕,使用户能够控制其编辑环境。
本页面中的所有示例仅用于说明目的。代码不适合生产环境。
诸如 输入安全、用户权限、一次性令牌 和 国际化 等操作已故意省略。请务必始终处理这些重要操作。
添加元框
要创建元框,请使用 add_meta_box() 函数并将其执行连接到 add_meta_boxes 操作钩子。
以下示例向 post 编辑屏幕和 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 传输。此处显示的示例仅包含一个表单项,即下拉列表。您可以在任何特定的元框中创建所需的任意数量。如果您有很多字段要显示,请考虑使用多个元框,在每个元框中将相似的字段分组在一起。这有助于保持页面更加有条理和美观。
获取值
要检索保存的用户数据并利用它,您需要从最初保存它的地方获取它。如果它存储在 postmeta 表中,您可以使用 get_post_meta() 获取数据。
以下示例通过基于保存的元框值预填充数据来增强先前的表单元素。您将在下一节中学习如何保存元框值。
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
}
有关 selected() 函数的更多信息。
保存值
当文章类型被保存或更新时,会触发几个操作,其中任何一个都可能适合钩入以保存输入的值。在本示例中,我们使用 save_post 操作钩子,但其他钩子可能更适合某些情况。请注意,save_post 可能会为单个更新事件触发多次。相应地构建您的数据保存方法。
您可以将输入的数据保存在任何您想要的地方,即使在 WordPress 之外。由于您可能正在处理与文章相关的数据,因此 postmeta 表通常是存储数据的好地方。
以下示例将在 _wporg_meta_key 元键中保存 wporg_field 字段值,该元键是隐藏的。
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' );在生产代码中,请记住遵循信息框中概述的安全措施!
幕后
您通常不需要担心幕后的情况。本节是为了完整性而添加的。
当文章编辑屏幕想要显示所有添加到它的元框时,它会调用 do_meta_boxes() 函数。该函数遍历所有元框并调用每个关联的 callback。
在每次调用之间,会添加干预标记(例如 div、标题等)。
删除元框
要从编辑屏幕中删除现有的元框,请使用 remove_meta_box() 函数。传递的参数必须与使用 add_meta_box() 添加元框时使用的参数完全匹配。
要删除默认元框,请检查源代码以查看使用的参数。默认的 add_meta_box() 调用来自 wp-includes/edit-form-advanced.php。
实现变体
到目前为止,我们一直使用过程式技术来实现元框。许多插件开发人员发现需要使用各种其他技术来实现元框。
面向对象编程 (OOP)
使用 OOP 添加元框很简单,并且可以节省您担心全局命名空间中的命名冲突。
为了节省内存并允许更简单的实现,以下示例使用带有静态方法的抽象类。
abstract class WPOrg_Meta_Box {
/**
* Set up and add the 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
);
}
}
/**
* Save the meta box selections.
*
* @param int $post_id The post ID.
*/
public static function save( int $post_id ) {
if ( array_key_exists( 'wporg_field', $_POST ) ) {
update_post_meta(
$post_id,
'_wporg_meta_key',
$_POST['wporg_field']
);
}
}
/**
* Display the meta box HTML to the user.
*
* @param WP_Post $post Post object.
*/
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 元素在编辑屏幕的 form 标签内,默认行为是在用户提交页面后从 $_POST 超全局变量解析元框值。
您可以使用 AJAX 增强默认体验;这允许根据用户输入和行为执行操作;无论他们是否提交了页面。
定义触发器
首先,您必须定义触发器,它可以是链接点击、值更改或任何其他 JavaScript 事件。
在下例中,我们将定义 change 作为执行 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
post_ID: jQuery('#post_ID').val() // The ID of the post currently being edited
}, 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;而不是创建新的自定义 JavaScript 对象,您可以使用预定义的 JavaScript 变量
ajaxurl。仅在 WordPress 管理界面中可用。在执行任何逻辑之前确保它不为空。
注册客户端代码
下一步是将我们的代码放入脚本文件并在编辑屏幕上注册它。
在下例中,我们将 AJAX 功能添加到以下文章类型的编辑屏幕:post, wporg_cpt。
脚本文件将位于 /plugin-name/admin/meta-boxes/js/admin.js,plugin-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');服务端代码
最后一步是编写我们的服务端代码来处理请求。
// The piece after `wp_ajax_` matches the action argument being sent in the POST request.
add_action( 'wp_ajax_wporg_ajax_change', 'my_ajax_handler' );
/**
* Handles my AJAX request.
*/
function my_ajax_handler() {
// Handle the ajax request here
if ( array_key_exists( 'wporg_field_value', $_POST ) ) {
$post_id = (int) $_POST['post_ID'];
if ( current_user_can( 'edit_post', $post_id ) ) {
update_post_meta(
$post_id,
'_wporg_meta_key',
$_POST['wporg_field_value']
);
}
}
wp_die(); // All ajax handlers die when finished
}作为最后的提醒,本页面说明的代码缺少处理安全的重要操作。请确保您的生产代码包含此类操作。
有关 AJAX 的更多信息,请参阅 手册的 AJAX 章节 和 Codex。