在本系列文章中 ,我们一直在研究如何在不使用Settings API的情况下在WordPress中创建自定义管理页面。 这并不是说Settings API没用( 因为它是 !),但是有时候我们需要实现某些自定义功能或可用API无法提供的功能的更专业的实现。
此外,我们正在研究一些最重要的软件开发原则,例如单一职责原则 ,并将其应用于我们的工作中。
如果您刚刚加入该系列,我建议您阅读以前的文章,以使您熟悉我们到目前为止所做的事情,以便您了解我们为什么要做出一些我们决定在编写我们的代码时进行。
快速回顾
尽管我无法总结本系列到目前为止所涵盖的所有内容,但是我可以确保突出显示重点。
- 我们已经介绍了核心插件,并在WordPress仪表板中为该插件添加了一个子菜单项和选项页面。
- 我们已经讨论了单一责任原则及其在我们的发展中所扮演的角色。
- 添加了单个
input
元素,它将接受用户的输入。 - 我们已经在页面上添加了现时值,但实际上并没有做任何事情。
综上所述,我假设您拥有最新版本的源代码( 在上一篇文章中作为附件提供),并且您可以继续前进。
开始之前
与其他文章一样,我假设您在计算机上设置了本地WordPress开发环境。
此外,我假设您拥有最新版本的源代码,并且您准备继续在其之上进行构建,或者您可以轻松阅读我们在此处提供的代码,并在有更多时间时实施它。
最后,我们将逐步逐步执行每一部分代码。 首先,我将谈论我们将要做什么,然后我将展示代码,然后我将解释代码正在执行的操作,因此不会有任何令人困惑的地方。
但是,如果您发现自己对代码中的任何内容感到困惑,并且本教程不能很好地解释正在发生的事情,请发表评论,我将确保与您联系。
让我们开始吧。
实施新功能
在上一篇文章中,我们离开了一个插件,该插件看起来好像在执行某些操作,但实际上并未将任何内容保存到数据库,更不用说从数据库中检索任何内容了。
简而言之,我们有一个看上去功能正常但没有功能的插件。 这就是我们将要学习本教程的地方。
具体来说,我们将处理以下主题:
- 我们将验证在上一教程中创建和定义的现时值,以了解WordPress安全的一个组件如何工作。
- 我们将验证现有用户是否有权实际提交信息(如果没有,则阻止他们这样做)。
- 如果提交的内容是安全的,并且用户具有权限,则我们将对信息进行清理,以确保没有恶意内容进入数据库。
以此为路线图,我们准备跳回到代码中并继续开发插件。
安全
回想上wp_nonce_field
文章,我们利用了WordPress API函数wp_nonce_field
。 此特定功能执行以下操作:
随机数字段用于验证表单请求的内容来自当前站点,而不是其他站点。 随机数不提供绝对保护,但应在大多数情况下提供保护。 在表单中使用随机数字段非常重要。
如果您尝试保存选项页面,则可能会出现白屏。 那永远都不是好事,但是鉴于插件的当前状态,这就是我们所期望的。
我们需要引入一个函数,该函数将钩接到可用的WordPress钩子之一中,并将检查现时值是否有效。 如果它是有效的,那么这将让我们继续进行保存信息; 否则,它不应让我们继续前进。
由于我们要创建一个自定义管理页面,因此我们需要一个不同于在这种情况下可能使用的钩子。 在此示例中,我们将使用admin_post
钩子 。
在未提供任何操作的经过身份验证的管理员发布请求上触发。
回想一下我们先前的讨论,我们不想让我们的班级负担过多的责任。 请记住,我们必须不断问自己的问题是:“这个阶级必须改变什么原因?”
目前,我们没有可以管理保存选项的类。 因此,我们来介绍一个。 在插件的admin目录中,让我们创建一个Serializer
类。 这将负责保存我们期权的价值。
如您所见,我已将文件命名为class-serializer.php
。 根据经验和上面的代码,我们知道它需要挂接到上面提到的admin_post
钩子中,并且我们知道我们将需要一个负责保存信息的函数。
现在定义一下。
<?php
/**
* Performs all sanitization functions required to save the option values to
* the database.
*
* @package Custom_Admin_Settings
*/
/**
* Performs all sanitization functions required to save the option values to
* the database.
*
* This will also check the specified nonce and verify that the current user has
* permission to save the data.
*
* @package Custom_Admin_Settings
*/
class Serializer {
public function init() {
add_action( 'admin_post', array( $this, 'save' ) );
}
public function save() {
// First, validate the nonce.
// Secondly, verify the user has permission to save.
// If the above are valid, save the option.
}
}
显然,还有很多工作要做(实际上,我们还没有实例化此类!),但是上面的代码足以了解我们的前进方向。
关于依赖关系的快速对话
在添加任何功能之前,让我们继续进行操作,并在插件首次加载时进行设置。 首先,返回custom-admin-settings.php
。 现在,在这一点上,我们需要问自己是否现有的任何类都应将序列化程序作为依赖项。
我认为可以这样一种情况,即Submenu_Page
应该具有对序列化程序的引用,因为该页面具有保存的选项。
另外,也可以将此文件完全分开,并使其可用于其他模式。 如果要这样做,我们将与手头的话题有所不同。 尽管我认为这很重要,但这超出了我们的目标范围。
因此,让我们实例化Serializer
类,对其进行初始化,然后将其传递到子菜单页面的构造函数中。 插件的引导文件中的代码现在应如下所示:
<?php
add_action( 'plugins_loaded', 'tutsplus_custom_admin_settings' );
/**
* Starts the plugin.
*
* @since 1.0.0
*/
function tutsplus_custom_admin_settings() {
$serializer = new Serializer();
$serializer->init();
$plugin = new Submenu( new Submenu_Page( $serializer ) );
$plugin->init();
}
这样,我们准备继续保存我们的选项。
回到发展
让我们回到Serializer
。 既然我们已经将其连接到插件的其余部分,那么实际上是时候编写一些代码了,因此,正如注释所建议的,让我们来验证一下我们在前端创建的现时值。
幸运的是,WordPress通过内置的API函数wp_verify_nonce
使此操作变得容易。 此函数接受两个参数:
- 那个行动
- 名字
如果您还记得上一篇文章,我们将acme-settings-save
作为我们的操作,将acme-custom-message
作为我们的现时价值。 为了验证它,我们需要检查它是否存在于$_POST
集合中,并且它是否通过了WordPress的本机检查。
为此,我想创建一个private
方法,该方法使我可以将此逻辑封装到一个函数中,以便在上面定义的save
函数中使用。
<?php
/**
* Determines if the nonce variable associated with the options page is set
* and is valid.
*
* @access private
*
* @return boolean False if the field isn't set or the nonce value is invalid;
* otherwise, true.
*/
private function has_valid_nonce() {
// If the field isn't even in the $_POST, then it's invalid.
if ( ! isset( $_POST['acme-custom-message'] ) ) { // Input var okay.
return false;
}
$field = wp_unslash( $_POST['acme-custom-message'] );
$action = 'acme-settings-save';
return wp_verify_nonce( $field, $action );
}
完成后,我可以合并对此函数的调用,这将使我们能够检查提交的有效性,并退出例程或继续进行下一个检查(稍后将进行介绍)。
请注意,在此条件下仅返回false并不是处理此问题的合适方法。 相反,引入显示在WordPress仪表板上的错误消息会更干净。 这是我们将在以后的教程中重新讨论的内容。
不过,到目前为止,我们主要关注的是确保我们能够成功提交数据。 这将使我们进入代码的下一部分。
允许
即使已使用一次(或随机数)验证的数字已签出,我们仍然需要检查另一件事:我们需要确保当前用户有权保存数据。
为了我们的目的,我们要确保当前用户是管理员。 为此,我们可以查看当前用户的功能(您可以看到此页面提供了每个角色及其相关功能的参考)。
注意,管理的功能之一是管理选项。 现在,我们可以使用WordPress API函数current_user_can
来检查当前用户是否可以在此页面上保存选项。
但是首先,这引发了一个问题:如果用户无法保存选项,为什么首先应该允许他们实际查看页面?
如果您回想起本系列文章的开头,我们编写了以下代码:
<?php
public function add_options_page() {
add_options_page(
'Tuts+ Custom Administration Page',
'Custom Administration Page',
'manage_options',
'custom-admin-page',
array( $this->submenu_page, 'render' )
);
}
这确保了选项页只提供给管理员; 但是,我们要格外小心,并在序列化过程中对此进行检查。
现在,我们可以更新条件,在该条件下我们还检查随机数值,以检查当前用户的权限:
<?php
/**
* Validates the incoming nonce value, verifies the current user has
* permission to save the value from the options page and saves the
* option to the database.
*/
public function save() {
// First, validate the nonce and verify the user as permission to save.
if ( ! ( $this->has_valid_nonce() && current_user_can( 'manage_options' ) ) ) {
// TODO: Display an error message.
}
// If the above are valid, save the option.
}
现在,我们已经有了代码来确保已设置了现时值,并且当前用户可以保存该值,我们可以进行清理了。
请记住,我们将返回显示需要显示错误消息的地方。 但这不在本教程中。
消毒
“但是等等,”你说。 “我以为我们已经准备好保存选择!” 是的,但是在我们能够做到这一点之前,我们必须经历一个消毒过程。 总之,消毒是制作的理念确保数据是干净的,安全的,并且, 啊哈 ,卫生数据库。
简而言之,它可以防止恶意用户将可能最终对我们的网站造成负面影响的信息插入数据库。
值得庆幸的是,WordPress提供了一个很好的帮助程序功能 ,使我们能够确保这尽可能地容易。 对于那些有兴趣的人,您可以阅读有关验证和清理数据的所有信息 (尽管我们将在下一个教程中介绍验证)。
在我们的代码中,我们将使用sanitize_text_field
(如上所示)。 此功能将执行以下操作:
- 检查无效的UTF-8
- 将单个“ <”字符转换为实体
- 剥离所有标签
- 删除换行符,制表符和多余的空格
- 去除八位字节
很高兴有这个功能,不是吗? 让我们来解决这个问题。 为此,找到我们一直在使用的save
功能并对其进行更新,使其看起来像这样:
<?php
/**
* Validates the incoming nonce value, verifies the current user has
* permission to save the value from the options page and saves the
* option to the database.
*/
public function save() {
// First, validate the nonce and verify the user as permission to save.
if ( ! ( $this->has_valid_nonce() && current_user_can( 'manage_options' ) ) ) {
// TODO: Display an error message.
}
// If the above are valid, sanitize and save the option.
if ( null !== wp_unslash( $_POST['acme-message'] ) ) {
$value = sanitize_text_field( $_POST['acme-message'] );
update_option( 'tutsplus-custom-data', $value );
}
}
请注意,我们正在从$_POST
集合中读取输入,对其进行$_POST
,然后将结果保存在单独的变量中。 接下来,使用update_option
函数将该变量写入数据库。
对于本文,我选择使用键tutsplus-custom-data
。 无论您使用什么,重要的是,它必须以唯一的前缀为前缀,这样另一个插件或主题就不会覆盖该选项,并且您也不会覆盖现有的选项。
最后,我们需要重定向回到选项页面。 由于我们没有使用内置的API,因此我们需要编写一个函数来为我们执行此操作。 幸运的是,这非常容易。
首先,创建一个名为redirect的函数,并确保它看起来像这样:
<?php
/**
* Redirect to the page from which we came (which should always be the
* admin page. If the referred isn't set, then we redirect the user to
* the login page.
*
* @access private
*/
private function redirect() {
// To make the Coding Standards happy, we have to initialize this.
if ( ! isset( $_POST['_wp_http_referer'] ) ) { // Input var okay.
$_POST['_wp_http_referer'] = wp_login_url();
}
// Sanitize the value of the $_POST collection for the Coding Standards.
$url = sanitize_text_field(
wp_unslash( $_POST['_wp_http_referer'] ) // Input var okay.
);
// Finally, redirect back to the admin page.
wp_safe_redirect( urldecode( $url ) );
exit;
}
上面的代码应该是不言自明的,但是为了确保清楚,它正在执行以下操作:
- 它检查以确保
$_POST
集合中存在私有WordPress值。 如果未设置,则将其设置为WordPress登录URL。 如果未设置引荐网址,这将迫使人们进入登录页面; 但是,没有理由不应该这样做。 - 接下来,我们将使用引荐来源网址并清理数据。 这是编码标准所要求的,并且可以确保数据是干净的。
- 最后,我们将
wp_safe_redirect
初始化为URL,以便返回到选项页面。
完成所有这些操作后,将其添加为上述save
功能的最后一行。 代码的最终版本应如下所示:
<?php
/**
* Performs all sanitization functions required to save the option values to
* the database.
*
* @package Custom_Admin_Settings
*/
/**
* Performs all sanitization functions required to save the option values to
* the database.
*
* This will also check the specified nonce and verify that the current user has
* permission to save the data.
*
* @package Custom_Admin_Settings
*/
class Serializer {
/**
* Initializes the function by registering the save function with the
* admin_post hook so that we can save our options to the database.
*/
public function init() {
add_action( 'admin_post', array( $this, 'save' ) );
}
/**
* Validates the incoming nonce value, verifies the current user has
* permission to save the value from the options page and saves the
* option to the database.
*/
public function save() {
// First, validate the nonce and verify the user as permission to save.
if ( ! ( $this->has_valid_nonce() && current_user_can( 'manage_options' ) ) ) {
// TODO: Display an error message.
}
// If the above are valid, sanitize and save the option.
if ( null !== wp_unslash( $_POST['acme-message'] ) ) {
$value = sanitize_text_field( $_POST['acme-message'] );
update_option( 'tutsplus-custom-data', $value );
}
$this->redirect();
}
/**
* Determines if the nonce variable associated with the options page is set
* and is valid.
*
* @access private
*
* @return boolean False if the field isn't set or the nonce value is invalid;
* otherwise, true.
*/
private function has_valid_nonce() {
// If the field isn't even in the $_POST, then it's invalid.
if ( ! isset( $_POST['acme-custom-message'] ) ) { // Input var okay.
return false;
}
$field = wp_unslash( $_POST['acme-custom-message'] );
$action = 'acme-settings-save';
return wp_verify_nonce( $field, $action );
}
/**
* Redirect to the page from which we came (which should always be the
* admin page. If the referred isn't set, then we redirect the user to
* the login page.
*
* @access private
*/
private function redirect() {
// To make the Coding Standards happy, we have to initialize this.
if ( ! isset( $_POST['_wp_http_referer'] ) ) { // Input var okay.
$_POST['_wp_http_referer'] = wp_login_url();
}
// Sanitize the value of the $_POST collection for the Coding Standards.
$url = sanitize_text_field(
wp_unslash( $_POST['_wp_http_referer'] ) // Input var okay.
);
// Finally, redirect back to the admin page.
wp_safe_redirect( urldecode( $url ) );
exit;
}
}
事情是这样的:我们已经实现了安全性,清理,序列化和重定向。 但是我们没有显示错误消息,也没有检索数据。
那是我们将在下一个教程中学习的地方。
结论
至此,我们已经有了一个半功能性插件,但是还有更多工作要做。 显然,我们提交给数据库的信息不会显示在任何地方,这不是一件好事。
但是,就像保存信息一样,检索信息时也需要考虑一些重要的事情。 在下一个教程中,我们将研究如何检索信息,将其显示在前端,将其显示在选项页面上以及在用户更改input元素的值时更新信息。
同时,如果您正在寻找其他实用程序来帮助您构建不断增长的WordPress工具集或用于研究代码并精通WordPress的代码,请别忘了看看Envato中提供的功能市场 。
记住,您可以在个人资料页面上捕获我的所有课程和教程,还可以通过@tommcfarlin 在我的博客和/或Twitter上关注我,在那里我讨论了各种软件开发实践以及如何在WordPress中使用它们。
最后,请不要在下面的Feed中留下任何问题或评论。 我会尽力参与并回答您提出的与该项目有关的每个问题或评论。
翻译自: https://code.tutsplus.com/tutorials/creating-custom-admin-pages-in-wordpress-3--cms-27017