WordPress钩子详解:如何使用动作、过滤器和自定义钩子

WordPress钩子详解:如何使用动作、过滤器和自定义钩子

WordPress钩子(Hook)是WordPress开发人员的武器库中最重要的工具之一。它们是WordPress插件和主题开发的基础。您可以使用WordPress的许多内置钩子将自定义代码“连接到”WordPress核心,并执行修改某些内容。

有两种类型的WordPress钩子:ActionsFilters。Hook非常普遍,甚至WordPress Core本身也广泛使用它们。WordPress还提供了一种让您定义自己的自定义钩子的方法,以便其他开发人员可以挂钩到您的代码中。

了解动作、过滤器和自定义钩子的工作原理对于掌握WordPress开发至关重要。

本文的前半部分介绍了WordPress钩子的基础知识,并解释了它们如何与多个示例一起工作。在后半部分,您将学习如何使用钩子来自定义WordPress,创建自己的自定义钩子,并使用它们来构建自己的可扩展插件。

  1. 什么是WordPress钩子?
  2. 钩子 vs 动作 vs 过滤器
  3. WordPress钩子如何工作?
  4. 在哪里注册钩子及其函数?
  5. 使用WordPress钩子
  6. WordPress钩子列表和资源
  7. 查找在WordPress页面上注册的钩子
  8. “所有”钩子
  9. WordPress钩子存储在哪里?
  10. 如何创建自定义WordPress钩子
  11. 从WordPress钩子中删除回调函数
  12. 更多WordPress钩子教程

什么是WordPress钩子?

一个WordPress的页面是由很多的功能和数据库查询组装。WordPress核心、插件和主题协同工作以输出页面元素,如文本、图像、脚本和样式。完全组装后,浏览器会将它们放在一起并呈现页面。

WordPress钩子允许您在某些点“钩入”这个构建过程并运行您的自定义代码。钩子的主要功能是让你在不接触核心文件的情况下修改或添加功能到WordPress 。

钩子将帮助您使用自己的代码扩展WordPress

钩子将帮助您使用自己的代码扩展WordPress

WordPress的插件API赋予WordPress钩子的功能。您可以通过在WordPress运行时在特定实例中调用某些称为Hook Functions的WordPress函数来使用钩子。

使用钩子函数,您可以将自定义代码捆绑在回调函数中,并将其注册到任何钩子中。注册后,此回调将在钩子所在的任何地方运行,允许您增加或替换默认的WordPress功能。

钩子在代码执行过程中的位置是一个重要的因素。您将在接下来的部分中详细了解其重要性。

两种类型的WordPress钩子:动作和过滤器

WordPress包括两种类型的钩子,称为ActionsFilters。动作允许您在WordPress运行时的某些预定义点执行某些操作,而过滤器允许您修改WordPress处理的任何数据并返回这些数据。

动作Actions)在WordPress代码中定义为:

do_action( 'action_name', [optional_arguments] );

action_name字符串是动作的名称。您可以指定[optional_arguments]变量以将附加参数传递给回调函数。如果未指定此字段,则其默认值将为空。

示例:do_action( 'wp_head' )每次WordPress处理站点标题时,都可以挂接该动作以运行自定义代码。此动作没有任何其他参数。

过滤器(Filters)在WordPress代码中定义为:

apply_filters( 'filter_name', 'value_to_be_filtered', [optional_arguments] );

filter_name是过滤器的名称,value_to_be_filtered是可以被过滤器函数修改的值,[optional_arguments]可选,若干个可以传递给过滤器函数的参数。

例如:apply_filters( 'admin_footer_text' , string $text ) 这个过滤器可以用来修改管理页脚显示的文本。从WordPress 5.4开始,其默认在管理区域页脚中显示该句子:Thank you for creating with WordPress.

稍后您将通过WordPress核心中的许多示例来学习如何使用动作和过滤器钩子,这将有助您通过代码在网站上执行自定义某些内容。例如,您可以使用钩子在发布文章后自动发送电子邮件,或加载自定义样式表来更改站点的外观。

WordPress挂钩可帮助您与网站互动或修改您的网站

WordPress钩子可帮助您与网站互动或修改您的网站

为更好理解Wordpress钩子, 可将您的WordPress网站想象成盖房子。钩子类似于使用起重机来回移动建筑物品,在传输的项目是回调函数,其中包括您的自定义代码。这些项目(或功能)可以帮助您建造或改造房屋。

在WordPress中挂钩“wp_head”操作的示例

在WordPress中“wp_head”动作钩子的示例

回调函数可以是常规PHP函数、默认WordPress函数或您定义的自定义函数。

我们只能在连接到特定挂钩的特定载体上运输某些物品。因此,动作只能与动作函数挂钩同样,过滤器只能与过滤器函数挂钩。

虽然更换起重机上的吊钩和托架很乏味,但WordPress通过包含超过2,200种默认钩子使其变得非常容易。

WordPress 5.1有2200多个原生钩子(来源:Adam Brown)

WordPress 5.1有2200多个原生钩子(来源:Adam Brown)

您可以发现WordPress核心流程遍布有钩子,让您可以方便地钩子的确切位置运行您的自定义代码。

钩子(Hook) vs 动作(Action) vs 过滤器(Filter)

根据WordPress插件手册

钩子(Hook)是以一段代码交互/修改另一段代码的一种方式……

钩子(Hook)包括两种类型:动作(Action)和过滤器(Filter)。

一些教程和指南将HookActionFilter的使用方式与之相关的函数混合在一起介绍,让初学者误以为它们之间存在广泛的不一致。但您仔细查看WordPress核心代码,您会发现添加动作和过滤器之间其实没有太大区别。

下面是wp-includes/plugin.php文件中为ADD_ACTION()函数的源代码:

function add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {      
return add_filter( $tag, $function_to_add, $priority, $accepted_args );
}

可留意到add_action()函数其实只是调用该add_filter()函数并返回其值。为什么?因为从根本上它们几乎以相同的方式工作,除了一个区别:apply_filters()函数返回一个可以更改现有数据的值,而该do_action() 函数不返回任何内容(PHP中的NULL值)。

如果您仍然感到困惑,请不要担心!读完本文的前半部分后,一切就都清楚了。

我们将坚持使用官方清晰、准确且通用的WordPress Codex术语来帮助你理解。现在请先熟悉下面显示的钩子示意图:

钩子程序:钩子、钩子函数和回调函数

钩子程序:钩子、钩子函数和回调函数

让我们分解一下Actions和Filters之间的区别。

WordPress钩子 (Hook)
动作 (Actions) 过滤器 (Filter)
动作用于在WordPress Core执行期间的特定点运行自定义函数。 过滤器用于修改或自定义其他功能使用的数据。
动作由do_action( ‘action_name’ )WordPress代码中的函数定义/创建。 过滤器由apply_filters( ‘filter_name’, ‘value_to_be_filtered’ )WordPress代码中的函数定义/创建。
动作也称为动作钩子 过滤器也称为过滤器钩子
动作只能与动作函数挂钩。例如add_action()remove_action() 过滤器只能与过滤器函数挂钩。例如add_filter()remove_filter()
动作函数不需要向它们的回调函数传递任何参数。 过滤器函数需要至少传递一个参数给它们的回调函数。
动作函数可以执行任何类型的任务,包括改变WordPress工作方式的行为。 过滤器函数仅用于修改过滤器传递给它们的数据。
动作函数应该不return什么。但是,它们可以echo输出或与数据库交互。 过滤器函数必须最有return动作,即使过滤器函数什么都不改变,它仍然必须将未修改的数据重新return
只要代码有效,动作几乎可以执行任何操作。 过滤器应该以孤立的方式工作,因此它们不会产生任何意外的副作用。
总结:一个动作会中断常规的代码执行过程,用它接收到的信息做一些事情,但什么都不返回,然后退出。 总结:过滤器修改它接收到的信息,将其返回给调用钩子函数,其他函数可以使用它返回的值。

有时,您可以使用动作或过滤器来实现相同的目标。例如,如果您想修改文章中的文本,您可以使用publish_post动作注册一个回调函数,并在将文章内容保存到数据库时更改文章内容。

// define the callback function to change the text
function change_text_callback() { 
// add the code to change text here
}
// hook in to the 'publish_post' action with the add_action() function
add_action( 'publish_post', 'change_text_callback' );

或者您可以使用the_content过滤器注册另一个回调函数,以在浏览器中显示之前修改文章内容。

// define the callback function to modify the text
function change_text_another_callback( $content ) { 
// add the code to change text here and then return it 
return $filtered_content;
}
// hook in to 'the_content' filter with the add_filter() function
add_filter( 'the_content', 'change_text_another_callback');

两种不同的方法,结果相同。知道何时使用那个而不是另一个是成为优秀WordPress开发人员的关键。

WordPress钩子如何工作?

通过房子的例子可很简单理解钩子的基本功能,但它没有捕捉到它们如何工作的复杂性。而最关键的是放置钩子的位置和特异性的概念。

一个更好的例子是将处理WordPress网页想象成组装汽车。与制造汽车需要时间不同,组装网页几乎是瞬间完成的。

组装网页就像组装汽车

组装网页就像组装汽车

就像汽车如何在现代装配线中逐个组装在一起一样,WordPress网页由服务器和客户端逐个组装。WordPress核心就像汽车引擎、底盘和其他必需品,为网站的“核心”功能提供动力。您可以仅使用WordPress核心就拥有一个功能强大的网站,但这有什么乐趣呢?您需要向站点添加令人兴奋的功能。这就是WordPress插件和主题介入的地方,它们都广泛使用钩子。

在上面的示例中,每个编号的站点就像WordPress核心中的一个钩子。有两种类型的站点,例如动作和过滤器。每个站都包含一个特定类型的插槽,它只接受某些工具,类似于动作函数和过滤器函数。为了模块化和效率,所有站点都以频繁的间隔放置。

根据特定位置的要求,我们可以为该特定站点的工作安装(或钩子)最合适的工具。这些工具就像用于与WordPress交互或修改WordPress的回调函数。一些工具可以显著改变汽车的工作,注册到动作钩子的回调如同其一样;而其他工具仅用于自定义汽车的外观,注册到过滤器的回调对应类比如此。在正确的站点使用正确的工具对于制造一流的汽车至关重要。同样,钩子能帮助我们满足独特需求来实现定制WordPress。

如果你扩展这个类比,可以是:插件就像添加有用的汽车功能,如安全气囊、娱乐控制台、远程无钥匙系统等(像这些是为了增强WooCommerce的功能);主题类似于自定义汽车的视觉部分,如整体设计、喷漆、轮辋等(这是自定义WordPress主题的方法)。

在哪里注册钩子及其函数?

在WordPress中添加钩子有两种推荐的方法:

  • 插件:制作您自己的插件并在其中添加所有自定义代码。
  • 主题:在子主题的functions.php文件中注册钩子和回调函数。

接下来让我们从创建插件开始来说明具体方法细节。

首先,请在您的/wp-content/plugins/目录中创建一个新文件夹。我给我的插件命名salhooks,当然你可以随意命名它。根据 WordPress 指南,您需要在插件目录中创建一个具有相同名称 (salhooks.php )的PHP文件。

将以下标题字段添加到您的插件文件以将其注册到WordPress。您可以在WordPress Codex中了解有关插件标头要求的更多信息。

<?php
/*
Plugin Name:  Salhooks
Version    :  1.0
Description:  Demonstrating WordPress Hooks (Actions and Filters) with multiple examples.
Author     :  Salman Ravoof
Author URI :  https://www.salmanravoof.com/
License    :  GPLv2 or later
License URI:  https://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  salhooks
*/
//=================================================
// Security: Abort if this file is called directly
//=================================================
if ( !defined('ABSPATH') ) { 
die;
}

保存此文件,然后在您的WordPress仪表盘中激活该插件。我将在最新版本WordPress本地环境搭建与安装教程中使用这个插件来演示钩子是如何工作的。

作为旁注,您可以直接编辑WordPress核心文件以注册钩子。但是,不建议这样做,因为每次更新WordPress时,您的所有自定义代码都会被覆盖。出于同样的原因,如果您使用的是某个子主题,您不应该在其对应的父主题中添加钩子。

使用WordPress钩子

一个WordPress钩子本身什么都不做。它只是置于代码中,等待一些钩子函数来激活它。要使用钩子,您至少需要调用2个其他函数。

首先,您需要使用钩子函数注册钩子并在其中引用回调函数。然后你需要定义你之前在钩子函数中提到的回调函数。每次触发钩子时,WordPress都会运行此回调函数。定义这些函数的顺序无关紧要,但最好将它们放在一起。

动作和过滤器具有不同的钩子函数。从现在开始,让我们将它们称为Action FunctionsFilter Functions。正如您将看到的,它们有自己的语法和参数要求。

  1. 钩住一个动作
  2. 钩住过滤器
  3. 使用Hooks自定义WordPress登录页面

钩住一个动作

动作(action)提供了一种在WordPress 核心、插件或主题执行中的特定点运行自定义代码的方法。

add_action() 动作函数

您可以按照以下步骤使用动作注册回调函数:

  1. 定义一个带有自定义代码的回调函数。当WordPress的代码执行期间触发它注册到的任何动作时,此回调函数将运行。
  2. 使用该add_action()函数将您的回调函数连接到您想要的动作。参照WordPress Codex说明,add_action()函数至少需要传递两个参数:
      • 要挂钩的动作的名称。
      • 触发动作时将运行的回调函数的名称。
  3. add_action()函数还接受两个可选参数来设置priority (执行优先级次序) 和number of arguments (参数数量),我们稍后会讨论它们。

最好将回调函数参数命名为尽可能接近钩子函数传递的参数。

让我们看一个使用该add_action()函数的例子。

// define the callback function, the arguments are optional
function example_callback( $arg1, $arg2 ) {
// make your code do something with the arguments
}
// hook the callback function to the 'example_action'
add_action( 'example_action', 'example_callback', [priority], [no_of_args] );
// 'priority' and 'number of arguments' are optional parameters

挂钩动作的示例

WordPress包含一个名为init的内置动作,它会在WordPress完成加载并验证用户之后,但在发送任何标头之前触发。许多插件使用此钩子作为实例化其代码的起点,因为在WordPress运行此动作时,几乎所有主要的WordPress功能都已完成加载。

WordPress有一个类似的动作叫做admin_init。它在初始化管理界面时init触发,而动作仅在WordPress完成加载后触发。

让我们实现在init动作执行期间运行一个自定义代码来echo一条简单的消息。代码如下:

function custom_callback_function(){
// add your custom code here to do something
echo 'I will be fired on WordPress initialization';
}
add_action( 'init', 'custom_callback_function' );

您可以在我最新版本WordPress本地环境搭建与安装教程的提及的实例的页面左上角看到这条消息。

不是很漂亮,但这是一个很好的开始!

不是很漂亮,但这是一个很好的开始!

查找WordPress支持的动作

WordPress每次执行某些动作时都会包含一些动作钩子,例如用户登录或发布新文章。您可以在插件API/动作参考页面中找到WordPress运行的所有动作的完整参考列表。

几乎每次使用都有一个动作

几乎每次使用都有一个动作

Codex将其中列出的所有动作分为不同的类别,并按照WordPress执行顺序从头到尾排列。

在大多数情况下,许多这些动作不会做任何事情,因为没有任何东西与它们挂钩。但是,如果您需要它们,它们就在那里供您使用。

对所有的动作感到有点不知所措?这是自然的。随着您获得更多经验并浏览WordPress核心源代码,找到满足您需求的完美钩子将变得更加容易。只需搜索术语“ do_action ”,您就会发现许多可以钩子的动作。

add_action() 的附加参数

add_action()函数可以接受另外两个参数:一个用于设置priority,另一个用于设置number of arguments。虽然它们是可选的,但如果使用得当,它们会非常有用。

优先事项

函数支持的第一个附加参数add_action()设置priority. 该参数只能是正整数。优先级数字越低,函数运行得越早。如果不指定,其默认值为10。

为了看看它是如何工作的,让我们为init动作注册三个回调函数,但每个都有不同的优先级。

// priority is set to 9, which is lower than 10, hence it ranks higher
add_action( 'init', 'i_am_high_priority', 9 );
// if no priority is set, the default value of 10 will be used
add_action( 'init', 'i_am_default_priority');
// priority is set to 11, which is higher than 11, hence it ranks lower
add_action( 'init', 'i_am_low_priority', 11 );

在上面的示例中,优先级编号最低的回调函数将首先运行,编号最高的回调函数将最后运行。如果它们的优先级相同,那么它们将按照您注册它们的先后顺序运行。

当单个钩子可以注册多个回调函数时,优先级起着重要作用。为避免意外结果,您可以为每个回调函数设置优先级,以便它们按您希望的顺序触发。

参数数量

默认情况下,通过该函数注册的任何回调函数add_action()将只接收一个参数。但是,有时您可能需要向回调函数传递额外的数据。出于这个原因,add_action()函数接受一个可选参数来设置参数的数量。

展示这一点的一个很好的例子是comment_post动作。此动作会在WordPress向数据库添加评论后立即运行。如果您不设置number of arguments参数,它只会将一个值传递给回调函数,在这种情况下将是comment_ID.

// register the hook with 'priority' and 'number of arguments' parameters
add_action( 'comment_post', 'show_message_function', 10, 3 );
// define the callback function
function show_message_function( $comment_ID, $comment_approved, $commentdata ) {
// check whether a comment is approved with the second parameter
if( 1 === $comment_approved ){
// runs the code only if the comment is approved
}
}

如果如上例所示将参数number of arguments设置为3,则动作函数将传递三个值:comment_IDcomment_approvedcommentdata

WordPress将comment_approved的值设置为1,如果未批准,则设置为0,如果评论标记为垃圾评论,则设置为“spam”。

commentdata变量是一个包含所有评论数据的数组,例如评论作者的姓名、电子邮件地址、网站和评论本身的内容。您可以查看WordPress Codex以查找包含在 ‘commentdata’ 数组中的所有键值对

您可以拥有任意数量的参数,但回调函数和add_action()函数需要指定相同数量的参数。

通过将附加参数传递给回调函数,您可以对代码执行更多动作。例如,您可以检查评论是否获得批准,并在获得批准后自动将评论文本通过电子邮件发送给管理员。不指定附加参数就不可能做到这一点,因为您的回调函数将无法访问comment_content数据。

如果不想设置优先级,只想改变参数个数,还是需要设置一个优先级。只需使用其默认值(即 10)。

WordPress核心如何使用动作钩子

WordPress Core本身使用许多内置动作来执行各种功能。

wp_head动作为例。当WordPress输出网页的标题部分(在<head>和之间的代码)时,它会被触发</head>

你可以在wp includes/default-filters.php文件中找到大多数与wp_head钩子相关的WordPress核心动作函数。我仔细查看了代码并编译了所有调用wp_head动作的add_action()函数的列表。

add_action( 'wp_head', 'rest_output_link_wp_head', 10, 0 );
add_action( 'wp_head', '_wp_render_title_tag', 1 );
add_action( 'wp_head', 'wp_enqueue_scripts', 1 );
add_action( 'wp_head', 'wp_resource_hints', 2 );
add_action( 'wp_head', 'feed_links', 2 );
add_action( 'wp_head', 'feed_links_extra', 3 );
add_action( 'wp_head', 'rsd_link' );
add_action( 'wp_head', 'wlwmanifest_link' );
add_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 );
add_action( 'wp_head', 'locale_stylesheet' );
add_action( 'wp_head', 'noindex', 1 );
add_action( 'wp_head', 'print_emoji_detection_script', 7 );
add_action( 'wp_head', 'wp_print_styles', 8 );
add_action( 'wp_head', 'wp_print_head_scripts', 9 );
add_action( 'wp_head', 'wp_generator' );
add_action( 'wp_head', 'rel_canonical' );
add_action( 'wp_head', 'wp_shortlink_wp_head', 10, 0 );
add_action( 'wp_head', 'wp_custom_css_cb', 101 );
add_action( 'wp_head', 'wp_site_icon', 99 );
add_action( 'wp_head', 'wp_no_robots' );

很多回调函数只与一个动作钩子。设置priority此处对于确保最重要的钩子函数首先运行至关重要。

在上面的例子中,加载带有wp_enqueue_scripts()回调函数的脚本(priority = 1)比加载带有wp_site_icon()回调函数的站点图标元标记(priority = 99)更重要。

上面例子中使用的所有回调函数都是WordPress函数。您也可以在任何代码中使用它们。有关更多信息,请访问我们工具频道的开发宝典中的函数参考页面

其他动作函数

add_action()是最常用的动作函数,而其实还有许多其他函数同样有用。让我们看看它们是如何工作的。

(1)has_action()

这个动作函数检查一个动作是否已经被挂钩。它接受两个参数。第一个是动作的名称。第二个参数是可选的,是回调函数的名称。

has_action( 'action_name', 'function_to_check' );

如果只指定第一个参数,则只要有任何函数连接到action_name参数,都返回true

但是,如果您还指定了第二个参数,那么如果指定的回调函数未注册到上述动作,那么它将返回false。如果它找到附加到动作动作的回调函数,它将返回该动作钩子上为该函数设置的priority(整数)。

(2)do_action()

我们以前遇到过此动作函数。WordPress使用它来定义它的所有默认动作,使其他函数能够钩住它们。与WordPress一样,您也可以使用do_action()函数通过指定新动作名称作为参数来创建新的自定义动作。

do_action( 'action_name', [argument1], [argument2] );

仅仅声明这个函数本身不会做任何事情。但它将保存在代码中,等待其他动作函数激活它。传递任何额外的参数都是可选的,但如果希望回调函数使用它们,这一点很重要。

(3)do_action_ref_array()

此动作函数与do_action()相同,只是有一个区别:通过它传递的任何参数都必须是数组。当您有很多参数要传递,或者您的参数已经在数组中时,此函数非常有用。

// here's an example array
$arguments_array = array( 'arg_1', 'foo', true, 'arg_4' );
do_action_ref_array( 'example_action', $arguments_array );

由于PHP数组是有序映射,因此请确保传递的参数顺序正确。

此动作函数的使用示例是admin_bar_menu动作。它可以被挂钩以添加、操作或删除各种管理栏项目。所有管理栏项目都定义为数组元素。

(4)did_action()

如果你想计算任何动作被触发的次数,你可以调用这个动作函数。

did_action( 'action_name' );

此函数返回一个整数值。

当您只想在第一次运行动作时运行回调函数时,did_action()函数非常方便,参考示例代码判断处理,以后不再运行。

function example_callback_function() {
if( did_action( 'example_action' ) === 1 ) {
// checks if the 'example_action' hook is fired once, and only runs then, and never again!
}
}
add_action('example_action', 'example_callback_function');

(5)remove_action()

这个动作函数移除一个与指定动作钩子的回调函数。例如,您可以使用此函数删除连接到内置动作的默认WordPress函数,并将其替换为您自己的函数。

remove_action( 'action_name', 'function_to_be_removed', [priority] );

调用remove_action()函数有几个先决条件:

  1. function_to_be_removedpriority参数必须与最初在add_action()函数中使用的参数相同。
  2. 不能直接调用该函数remove_action(),您需要从另一个函数内部调用它。
  3. 如果回调函数是从类注册的,那么删除它还有其他要求。您可以查看WordPress Codex文档了解更多详细信息。
  4. 您不能在注册回调函数之前或运行回调函数之后删除它。

这是WooCommerce如何使用此动作函数删除主商店页面上的默认产品缩略图的示例。

remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );

(6)remove_all_actions()

这个动作函数删除所有与动作钩子的东西。优先级参数是可选的。

remove_all_actions( 'action_name', [priority] );

请记住,不能从您要取消注册回调函数的动作中调用此函数。那会导致无限循环。您可以挂钩之前触发的动作以运行此函数而不会出现任何错误。

(7)doing_action()

这个动作函数检查指定的动作是否正在运行。它返回一个布尔值(truefalse)。

// check whether the 'action_name' action is being executed
if ( doing_action( 'action_name' ) ) {
// execute your code here
}

您可以将action_name参数留空以检查是否正在执行任何动作。每次触发任何动作时它都会返回true

// check if any action is running and do something
if ( doing_action() ) {
// the code here is run when any action is fired
}

动作示例 1:向站点访问者显示维护消息

有时,最好让您的网站脱机并设置维护中页面。幸运的是,WordPress提供了一种简单的方法来做到这一点。

// show a maintenance message for all your site visitors
add_action( 'get_header', 'maintenance_message' );
function maintenance_message() {
if (current_user_can( 'edit_posts' )) return;
wp_die( '<h1>Stay Pawsitive!</h1><br>Sorry, we\'re temporarily down for maintenance right meow.' );
}

让我们分解代码并完成每个步骤:

  • get_header是在站点的头模板文件加载之前触发的动作。如果您想中断主站点的加载,这是一个完美的动作。
  • get_header使用add_action()带有maintenance_message()回调函数的函数连接到动作中。
  • 定义maintenance_message()回调函数。
  • current_user_can( 'edit_posts' )是一个用户能力测试函数,用于检查当前用户是否已登录并可以编辑文章。除了具有订阅者角色的用户之外,在WordPress站点上注册的每个用户都可以编辑文章。还有其他可靠的方法来执行此检查,但我们将在这里坚持使用这种简单的方法。
  • 使用默认的wp_die()函数优雅地终止WordPress执行并显示带有错误消息的HTML页面。您可以在错误消息参数中使用HTML语法对其进行格式化。

在我的自定义插件中保存代码后,我以隐私浏览模式加载了本地WordPress安装。将在维护页是成功的!

向站点访问者显示错误消息

向站点访问者显示错误消息

如果我在通过用户能力测试时登录,该站点将成功加载。您现在可以继续修复您的网站,同时它会向常客显示此页面。

动作示例 2:对非管理员用户隐藏仪表板菜单项

如果您正在运行一个多作者博客或为您的客户管理一个站点,那么您可能需要为非管理员用户在WordPress仪表盘中隐藏某些管理菜单。你可以通过挂钩到admin_menu动作来做到这一点。

// remove specific dashboard menus for non-admin users
add_action( 'admin_menu', 'hide_admin_menus' );
function hide_admin_menus() {
if (current_user_can( 'create_users' )) return;
if (wp_get_current_user()->display_name == "Salman") return; 
remove_menu_page( 'plugins.php' ); 
remove_menu_page( 'themes.php' ); 
remove_menu_page( 'tools.php' ); 
remove_menu_page( 'users.php' ); 
remove_menu_page( 'edit.php?post_type=page' ); 
remove_menu_page( 'options-general.php' );
}

以下是上述代码片段的分步演练:

  • admin_menu是在WordPress仪表盘区域中加载管理菜单之前触发的动作。
  • 使用add_action()函数和hide_admin_menus()回调函数,以实现钩住admin_menu动作。
  • hide_admin_menus()回调函数定义的代码的逻辑。每次admin_menu动作触发时它都会运行。
  • 在回调函数中,current_user_can( 'create_users' )函数检查登录用户是否为管理员。由于只有站点管理员具有create_user功能,如果用户是管理员,则该函数以return声明结束。
  • WordPress的函数wp_get_current_user() 检索当前用户对象。通过这个函数,我们可以检查登录用户是否有设置特定的display_name。这是一个可选行,以防您想省略某些非管理员用户由于此回调函数而被锁定。
  • WordPress的函数remove_menu_page() 删除顶级管理菜单。在上面的代码示例中,我删除了以下管理菜单:插件、主题、工具、用户、页面和选项。

保存插件文件后,这是管理员登录的WordPress仪表盘的快照。

默认的WordPress管理仪表盘

默认的WordPress管理仪表盘

这是非管理员用户登录的WordPress仪表盘的屏幕截图。

对非管理员用户隐藏敏感的管理菜单项

对非管理员用户隐藏敏感的管理菜单项

此解决方案仅隐藏指定的管理菜单项,以免出现在WordPress仪表盘中。所有用户仍然可以通过在浏览器中输入菜单URL来访问它们。

要禁止某些用户角色访问特定菜单,您需要编辑他们的能力。

挂钩过滤器

过滤器为您的自定义代码提供了一种方法来修改其他WordPress功能使用的数据。与动作不同,挂钩到过滤器的函数需要返回一个值。

add_filter() 过滤函数

您可以按照以下步骤将回调函数挂接到过滤器:

  1. 定义一个回调函数,它将在WordPress触发过滤器时运行。过滤器的回调函数需要至少指定一个参数,因为所有过滤器都至少将一个值传递给它们的回调函数。
  2. 使用add_filter()函数将回调函数注册到过滤器。过滤器将负责调用回调函数。根据WordPress Codex,add_filter()函数至少需要传递两个参数:
    • 要挂钩的过滤器的名称。
    • 过滤器触发时将运行的回调函数的名称。
  3. add_filter()函数还接受两个额外的可选参数来设置prioritynumber of arguments。这些参数的工作方式与add_action()函数相同。

下面是一个示例,说明如何使用add_filter()函数将回调函数挂接到过滤器。

// define the filter callback function with at least one argument passed
// the number of arguments that you can pass depends on how the filter is defined
function filter_callback_function( $arg1, $arg2 ) {
// make your code do something with the arguments and return something
return $something;
}
// now hook the callback function to the 'example_filter'
add_filter( 'example_filter', 'filter_callback_function', [priority], [no_of_args] );
// '10' is the default priority set for the callback function
// and '1' is the default number of arguments passed

挂钩过滤器的示例

WordPress提供了一个名为login_message的过滤器来过滤登录表单上方登录页面上显示的消息。此过滤器返回的值可以带有HTML标记。

让我们挂入login_message过滤器并修改登录屏幕上显示的消息。

// show a custom login message above the login form
function custom_login_message( $message ) {
if ( empty( $message ) ) {
return "<h2>Welcome to Let's Develop by Salman Ravoof! Please log in to start learning.</h2>";
} 
else {
return $message;
}
}
add_filter( 'login_message', 'custom_login_message' );

if-else回调函数中的语句检查登录消息是否已经设置,主要是由另一个插件或主题设置的。在这种情况下,回调函数返回原始值,不做任何更改。这是避免与其他插件或主题冲突的一种方法。

您可以在WordPress登录页面的登录表单上方看到显示的消息。

在登录表单上方显示自定义登录消息

在登录表单上方显示自定义登录消息

您可以通过将自定义样式表排入队列来设置登录页面上所有元素的样式。这样做将允许您完全自定义默认的WordPress登录页面。

您将在“使用钩子自定义WordPress登录页面”部分中了解如何使用动作钩子加载自定义样式表。

查找WordPress支持的过滤器

在WordPress处理或修改数据的任何地方,您几乎肯定可以找到一个过滤器来连接和更改它。将过滤器视为WordPress数据库和浏览器之间的接口。

您可以在插件API/过滤器参考页面中找到WordPress支持的所有过滤器的详尽列表。

WordPress提供了多种过滤器来挂钩

WordPress提供了多种过滤器来挂钩

那里列出的所有过滤器都分为多个类别,并按照WordPress执行顺序从上到下排列。

如果您想在WordPress源代码中找到要挂钩的过滤器,请搜索术语“apply_filters”,您将获得大量结果。在WordPress的代码参考也来搜索随机配备在WordPress,包括动作和过滤器一切的好地方。

WordPress核心如何使用过滤器

WordPress Core本身使用许多内置过滤器来修改其各种功能使用的数据。

例如考虑the_content过滤器。它在从数据库中检索到文章内容之后和在浏览器上显示之前过滤文章内容。

就像动作一样,您可以the_contentwp-includes/default-filters.php文件中找到与钩子相关的大多数WordPress Core过滤器函数。

add_filter()是挂接到the_content过滤器的所有核心函数的列表:

add_filter( 'the_content', 'do_blocks', 9 );
add_filter( 'the_content', 'wptexturize' );
add_filter( 'the_content', 'convert_smilies', 20 );
add_filter( 'the_content', 'wpautop' );
add_filter( 'the_content', 'shortcode_unautop' );
add_filter( 'the_content', 'prepend_attachment' );
add_filter( 'the_content', 'wp_make_content_images_responsive' );
add_filter( 'the_content', 'do_shortcode', 11 ); // AFTER wpautop().

请注意为某些回调函数指定的优先级。

例如,do_blocks()函数解析文章内容中的任何动态块并重新渲染它们以与WordPress的新区块编辑器兼容。它指定了比默认值 (10) 更高的优先级,以确保在运行其他功能之前内容已准备好块。

convert_smilies()函数设置为较低的优先级运行它的任务是将文本转换表情图像精灵。在过滤所有文章内容后让它在最后运行是有道理的。

有趣的事实:短代码是过滤器的一个子集。他们从短代码中获取输入,对其进行处理,然后将输出返回给它。

其他过滤器函数

虽然add_filter()是最常用的过滤函数,但还有许多其他有用的过滤函数。让我们深入讨论它们。

(1)has_filter()

此函数检查指定的过滤器是否被任何函数挂钩。它接受两个参数。第一个参数用于输入过滤器名称。第二个参数是可选的,用于输入回调函数的名称。

has_filter( 'filter_name', 'function_to_check' );

如果您仅指定第一个参数,则它会在任何函数filter_name挂钩时返回true

但是,如果您同时指定了这两个参数,那么如果提到的回调函数未在给定的过滤器中注册,它将返回false。如果它找到了向过滤器注册的回调函数,那么它会在此过滤器上返回该函数的priority(整数)集。

has_filter()函数的一种可能应用是检查是否已经挂接了任何过滤器,并在此基础上继续执行代码。

// check to see if 'the_content' filter has been hooked
if ( ! has_filter( 'the_content' ) {
// hook the filter if and only if it hasn't been hooked before
add_filter( 'the_content', 'modify_the_content' );
}

(2)apply_filters()

这个过滤器函数就像do_action()动作函数。任何挂钩到此过滤器的回调函数都将在WordPress代码中此函数的任何位置运行。

您还可以使用此函数通过将过滤器名称和过滤器值指定为参数来创建新的自定义过滤器。

apply_filters( 'filter_name', 'value_to_filter', [argument1], [argument2] );

如果要将它们传递给回调函数,请不要忘记指定任何其他参数。大多数过滤器只使用一个参数,因此很容易错过定义其他参数。

这个函数就像apply_filters()函数一样,除了它接受的所有参数都捆绑成一个数组。

// an example array
$arguments_array = array( 'some_value', 'foo', false, 'another_value' );
apply_filters_ref_array( 'example_filter', $arguments_array );

当您有许多参数要传递或所有参数都已在数组中时,此过滤器函数会很方便。确保数组内的参数顺序正确。

(3)current_filter()

此过滤器函数检索当前正在运行的过滤器或动作的名称。您不需要指定任何参数,因为它在回调函数中运行。

下面是它的用法示例:

function example_callback() {
echo current_filter(); // 'the_title' will be echoed
return
}
add_filter( 'the_title', 'example_callback' );

尽管它的名字,这个函数可以检索动作和过滤器的名称。

(4)remove_filter()

此过滤器函数删除附加到指定过滤器的回调函数。它的工作原理与remove_action()函数完全一样。您可以使用它来删除使用特定过滤器注册的默认WordPress函数,并在必要时将其替换为您自己的函数。

remove_filter( 'filter_name', 'function_to_be_removed', [priority] );

要取消挂钩到过滤器的回调函数,function_to_be_removed,并且priority参数必须与挂钩回调函数时使用的参数相同。

如果过滤器是从类中添加的,通常是通过插件添加的情况,那么您需要访问类变量以删除过滤器

// access the class variable first, and then remove the filter through it
global $some_class;
remove_filter( 'the_content', array($some_class, 'class_filter_callback') );

让我们看看一个很好的例子remove_filter()

WooCommerce插件使用wc_lostpassword_url()挂接到它的通话函数lostpassword_url过滤器重定向用户的尝试“忘记密码?”。

它需要任何用户单击该链接到带有URL的自定义前端页面/my-account/lost-password。如果没有这个过滤器,它会将它们带到标准的WordPress登录URL/wp-login.php

假设您要重置此函数并将您的用户发送到默认密码检索页面 或完全单独的页面。您可以像这样删除此回调函数:

remove_filter( 'lostpassword_url', 'wc_lostpassword_url', 10 );

(5)remove_all_filters()

此过滤器函数删除注册到过滤器的所有回调函数。

remove_all_filters( 'filter_name', [priority] );

它的remove_all_actions()函数类似。

流行的Advanced Excerpts插件使用此函数删除所有与the_excerptget_the_excerpt过滤器钩子的默认函数。这样做之后,它然后将自己的回调函数挂接到过滤器。

// Ensure our filter is hooked, regardless of the page type 
if ( ! has_filter( 'get_the_excerpt', array( $advanced_excerpt, 'filter_excerpt' ) ) ) {
remove_all_filters( 'get_the_excerpt' ); 
remove_all_filters( 'the_excerpt' ); 
add_filter( 'get_the_excerpt', array( $advanced_excerpt, 'filter_excerpt' ) );
}

(6)doing_filter()

此过滤器函数检查指定的过滤器是否正在执行。

if ( doing_filter( 'save_post' ) ) {
// run your code here
}

它返回一个布尔值(truefalse)。

您应该注意此函数与current_filter()返回正在运行的过滤器或动作的名称(字符串)的函数之间的区别。

过滤器示例 1:为评论添加敏感词过滤器

管理WordPress网站上的所有评论可能是一个繁琐的过程。 comment_text过滤器允许您设置规则,以便在将评论输出到显示器上之前对其进行修改。

带有敏感词标记的未经过滤的评论

带有敏感词标记的未经过滤的评论

您可以指示WordPress在任何敏感词显示给您的网站访问者之前自动删除它们。

// hook into the 'comment_text' filter with the callback function
add_filter( 'comment_text', 'the_profanity_filter' );
// define a callback function to filter profanities in comments 
function the_profanity_filter( $comment_text ) {
// define an array of profane words and count how many are there 
$profaneWords = array('fudge', 'darn', 'pickles', 'blows', 'dangit');
$profaneWordsCount = sizeof($profaneWords);
// loop through the profanities in $comment_text and replace them with '*'
for($i=0; $i < $profaneWordsCount; $i++) {
$comment_text = str_ireplace( $profaneWords[$i], str_repeat('*', strlen( $profaneWords[$i]) ), $comment_text );
} 
return $comment_text;
}

这是代码的逐行细分:

  • comment_text是一个过滤器钩子,允许您在浏览器显示之前修改评论的文本。您可以向它注册回调函数以过滤其输出。
  • 通过add_filter()函数,您可以连接到comment_text过滤器并为其附加回调函数。
  • the_profanity_filter()是回调函数的名称。它只接受一个参数,即一个包含评论文本的字符串。使用适当的代码逻辑定义此自定义函数。
  • 将所有敏感词存储在名为profaneWords 的PHP数组中。您可以向该数组添加任意数量的单词。在PHP函数sizeof()的帮助下,我将这个数组的大小存储在profaneWordsCount变量中。
  • 循环遍历所有敏感词,并使用PHP的默认str_ireplace() 函数将任何匹配的敏感词替换为*符号。由于这是一个不区分大小写的字符串替换函数,因此您不必担心大小写。查看执行搜索和替换的不同方法。
  • 使用return输出过滤后的评论文本。

将更改保存到您的自定义插件文件并重新加载任何带有评论的文章。您包含在profaneWords数组中的所有单词现在都应替换为“ *”符号。

审查带有“*”符号的评论中的敏感词

审查带有“*”符号的评论中的敏感词

原始评论仍将在数据库中保持原样。此过滤器仅在将评论文本输出到前端之前对其进行修改。

网站后台原评论

网站后台原评论

一旦你使用了正确的过滤器,你就可以用它做很多很酷的事情。

例如,您还可以使用comment_text过滤器从所有评论中删除任何 URL(请务必阅读有关如何阻止WordPress中的垃圾评论的深入指南)。

或者,您可以连接到pre_comment_approved过滤器,并根据预定义的标准将评论标记为已批准、垃圾邮件或驳回。

过滤器示例 2:在文章后插入内容

您已经看到WordPress如何使用the_content过滤器来修改文章或页面内容。让我们使用相同的过滤器在每篇文章的末尾添加一些内容。

// hook into 'the_content' filter with a callback function
add_filter( 'the_content', 'insert_content_below' );
// define the callback function to insert something below the post
function insert_content_below( $content ) {
// check to see if we're inside the main loop in a single post
if ( is_single() && in_the_loop() && is_main_query() ) {
return $content . "<h3 style=\"text-align: center;\">Let me insert myself here</h3><p style=\"text-align: center;border: 3px solid #5333ed;\">I'll appear after the post. You can insert anything here. Even HTML. Headers, links, images, scripts, I'll take them all and append it to the end of the post content. You can also give me a class, so you can style me easily with CSS style sheets.</p>" ;
} 
return $content;
}

理解上面例子中的代码逻辑:

  • the_content过滤器钩子可帮助您获取当前文章的内容并对其进行自定义。
  • 使用add_filter()函数通过insert_content_below()回调函数钩住the_content过滤器。
  • 通过将当前文章的内容作为参数 ( $content)传递来定义回调函数。
  • 在回调函数中,检查您是否只过滤了主查询中的内容,在本例中是文章内容。如果您不验证这一点,有时代码会无意中过滤来自其他地方的内容,例如侧边栏和页脚。
  • is_main_query()in_the_loop()条件确定查询是否为主查询以及是否发生在主WordPress循环中。
  • is_single()条件检查查询是否针对单个文章。
  • 使用PHP的字符串连接运算符$content . "your additions") 向页面内容添加额外内容。
  • 如果上述所有条件都检查出来,则return过滤后的评论。如果没有,则只返回内容而不做任何更改。

保存您的插件文件,加载您网站上的任何文章,然后滚动到最后。

在文章内容的末尾插入一些东西

在文章内容的末尾插入一些东西

通过反转字符串连接参数 ( "your additions" . $content)的位置,您可以使用相同的逻辑在所有文章的开头添加任何内容。

使用钩子自定义WordPress登录页面

让我们同时使用动作和过滤器钩子来自定义默认的WordPress登录页面。我将创建一个名为Sal Custom Login Page的新插件来执行此动作。您可以在本节末尾找到此插件的完整源代码。

最终定制的WordPress登录页面

最终定制的WordPress登录页面

让我们开始添加标准插件标题字段并将其注册到WordPress。

<?php
/*
Plugin Name:  Sal Custom Login Page
Version:  1.0
Description:  Demonstrating WordPress Hooks (Actions and Filters) by customizing the WordPress login page.
Author:  Salman Ravoof
Author URI:  https://www.salmanravoof.com/License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  sal-custom-login-page
*/
// enqueueing the custom style sheet on WordPress login page
add_action( 'login_enqueue_scripts', 'salhooks_login_stylesheet');
function salhooks_login_stylesheet() {
// Load the style sheet from the plugin folder
wp_enqueue_style( 'sal-custom-login-page', plugin_dir_url( __FILE__ ).'sal-custom-login-page-styles.css' );
}

首先,login_enque_scripts动作钩子将您的自定义样式表排入队列。您在此处排队的任何脚本或样式都包含在登录页面的标题部分中。

如果您想在站点的前端(而不是在管理后端或登录区域)加载自定义脚本和样式表,那么您需要挂接到wp_enqueue_scripts动作。您可以在WordPress Codex关于如何使用wp_enqueue_scripts的文章中阅读更多相关信息。

salhooks_login_stylesheet()回调函数中,使用wp_enqueue_style()函数加载放置在同一插件目录中的自定义样式表 (sal-custom-login-page-styles.css)。WordPress的内置plugin_dir_url( __FILE__ )函数可以轻松获取当前插件目录的URL路径(带有斜杠)。

我不会解释这里应用的CSS样式,但您可以在本节末尾链接的源代码中找到它们。

// Custom login ERROR message to keep the site more secure
add_filter( 'login_errors', 'salhooks_remove_login_errors', 10 );
function salhooks_remove_login_errors() {
return 'Incorrect credentials. Please try again!';
}

接下来,login_errors过滤器钩子更改当有人输入错误凭据时显示的错误消息。过滤错误消息将阻止攻击者轻松猜测您的用户名。

// Remove the login form box shake animation for incorrect credentials
add_action( 'login_head', 'remove_login_error_shake' );
function remove_login_error_shake() {
remove_action( 'login_head', 'wp_shake_js', 12 );
}

每次有人输入错误的登录凭据时,登录表单框都会剧烈晃动。这是一个可选步骤,但我将其包含在内是为了表明您还可以从登录页面中删除某些功能。

您将在本文的最后一节中了解有关remove_action()remove_filter()函数的更多信息。

// Change the logo and header link above the login form
add_filter( 'login_headerurl', 'salhooks_login_headerurl');
function salhooks_login_headerurl( $url ) {
$url = 'https://salmanravoof.com';
return $url;
}
add_filter( 'login_headertext', 'salhooks_login_headertext');
function salhooks_login_headertext( $text ) {
$text = 'Salman Ravoof';
return $text;
}

最后一步是更改登录标题的URL和文本。您可以连接到login_headerurllogin_headertext过滤器来修改它们。

如果您想在此插件的基础上构建并进一步试验,您可以下载该插件的源代码并开始使用。

WordPress钩子列表和资源

很难记住WordPress的所有各种钩子。有数以千计的内置动作和过滤器可供使用。因此,找到一个合适的钩子有时感觉就像是在寻宝。

值得庆幸的是,您可以使用各种资源来确定满足您需求的完美钩子。

第一个熟悉钩子的地方是WordPress Codex,尤其是插件手册中的钩子部分。在这里您可以找到有关钩子和链接的基本信息,以完成有关所有动作和过滤器钩子的文档。

使用WordPress插件手册开始学习钩子

使用WordPress插件手册开始学习钩子

为插件手册中的这些有用链接添加书签以加快搜索速度:

动作参考和过滤器参考页面都会为您提供通常在特定WordPress请求期间运行的所有钩子的列表。

例如,您可以找到访问管理页面、处理文章页面附件或类别时触发的所有钩子。

WordPress Codex还包括一个方便的搜索工具,用于查找其所有函数、钩子、方法和类。此页面还列出了最新版本的WordPress中的新组件和更新组件。如果您想了解WordPress内部发生的事情,请先前往这里。

在此处搜索WordPress内的任何内容

在此处搜索WordPress内的任何内容

这个WordPress钩子索引按类型、它们首次亮相的WordPress版本以及它们是否被弃用对所有钩子进行排序。

Adam R Brown的WordPress钩子索引

Adam R Brown的WordPress钩子索引

按照它们的出现顺序对钩子进行排序会告诉你,最古老的WordPress钩子仍然是最常用的。如果您不熟悉WordPress开发,熟悉这些流行的动作和过滤器是最快的方法。

虽然此索引自WordPress 5.1以来尚未更新,但浏览所有主要钩子仍然很有帮助。

仍然很难找到你想要的钩子吗?使用正确的关键字进行在线搜索始终是一个很好的开始方式。如果其他一切都失败了,您可以随时深入研究WordPress代码。

查找在WordPress页面上注册的钩子

正如我们所见,WordPress有大量可用的钩子,但并非每个钩子都会在每个页面上触发。如果您能找到可以在特定页面上挂钩的动作和过滤器,那么您就赢了一半。

虽然您可以使用xdebugPHPCS等高级PHP调试工具来帮助解决此问题,但您可以在WordPress中运行更简单的开发工具,例如调试栏和查询监视器。

带有动作和过滤器插件的调试栏

Debug Bar是一个官方的WordPress插件,它为您的管理栏添加了一个Debug菜单。它显示PHP警告和通知、缓存请求、MySQL查询和其他有用的调试信息。

注:此插件最近未更新,也未使用WordPress的最新主要版本进行测试。我们提到它是一个方便的插件,用于了解有关WordPress钩子的更多信息。

WordPress插件-Debug Bar

WordPress插件-Debug Bar

安装插件后,您需要将下面的代码片段添加到您网站的wp-config.php文件中以启用其调试功能。

define( 'WP_DEBUG', true ); // tracks PHP Warnings and Notices
define( 'SAVEQUERIES', true ); // tracks and displays MySQL queries

您现在应该会在管理栏中看到Debug菜单选项。单击它会将您带到其仪表板,在那里您可以看到附加到您访问它的页面的各种查询和缓存。

WordPress管理栏中的“Debug”菜单

WordPress管理栏中的“Debug”菜单

接下来,您需要安装Debug Bar Actions and Filters Addon插件。这是一个方便的扩展程序,它将向您的调试栏仪表板添加另外两个选项卡,以显示在当前请求上触发的动作和过滤器钩子。

按当前页面加载顺序列出的操作

按当前页面加载顺序列出的动作钩子

它还将列出所有与其优先级钩子的函数。

列出的过滤器及其优先级和注册的回调函数

列出的过滤器及其优先级和注册的回调函数

您可以从站点上的任何页面单击Debug菜单,以了解可以在该页面上挂钩的所有动作和过滤器。

Query Monitor

Query Monitor是一个强大的WordPress开发者工具面板。您可以使用它来深入了解页面上可用的钩子及其加载顺序。

WordPress插件-Query Monitor

WordPress插件-Query Monitor

与调试栏不同,您无需安装任何插件即可查看在特定页面上触发的动作和过滤器。

您可以从管理栏访问Query Monitor

您可以从管理栏访问Query Monitor

Query Monitor还为您提供了有关从哪里触发钩子的更多信息。

Query Monitor中的Hooks & Actions面板

Query Monitor中的Hooks & Actions面板

在组件列中,您可以看到大部分钩子都是从Core注册的。但是有些钩子是从主题或插件注册的。可以从多个组件注册一些钩子。

您可以使用钩子和组件下拉菜单仅查看您需要的钩子。

注意: Query Monitor使用“Hooks”作为动作和过滤器的统称,但它将注册的回调函数称为“动作”。从技术上讲,这是一个错误的定义,可能会使您感到困惑,因此请记住这一点。

您可以做的不仅仅是使用Query Monitor检查所有查询和请求。它还包括高级功能,例如列表样式、脚本、语言、Ajax调用、用户能力检查和REST API调用

“所有”钩子

WordPress有一个名为“all”的特殊钩子,您可以钩住它来为每个钩子运行回调函数,无论它是否已全部注册。这对于调试页面崩溃或您想知道特定事件何时发生非常有用。

例如,您可以使用all下面示例中的钩子来echo运行所有正在运行的动作。

// echo all the actions being run
function debug_helper_function(){
echo '<p>' . current_action() . '</p>';
}
add_action( 'all', 'debug_helper_function' );

上面定义的debug_helper_function()将在触发任何动作时运行。了解上次运行动作是什么将使您更好地了解需要查看的位置。

WordPress钩子存储在哪里?

WordPress使用WP_Hook类来实现钩子的工作方式。这个核心类用于处理所有内置的WordPress动作和过滤器。您可以在wp-includes/class-wp-hook.php文件中找到几乎所有与此类相关的代码。

从技术上讲,WP_Hook该类是一个对象数组,包括回调、迭代、current_priority、nesting_level和doing_action等属性。它还定义了许多有用的钩子函数,可以使用WP_Hook方法调用这些函数。

大多数WordPress开发人员不必太担心WordPress存储钩子的位置,只要他们遵守插件API指南即可。

如何创建自定义WordPress钩子

您已经看到WordPress通过其插件API提供的各种钩子。您还了解了如何使用默认钩子将您自己的代码注入WordPress runtime。

如果您是插件或主题开发人员,最好为其他开发人员提供一种以相同方式与您的代码进行交互的方式。自定义钩子可让您做到这一点。它们允许其他开发人员扩展和修改您的插件和主题的功能。

创建您自己的动作和过滤器相当简单。您可以使用与WordPress Core相同的函数来创建钩子。让我们看几个例子。

  1. 如何在WordPress中创建自定义动作
  2. 如何在WordPress中创建自定义过滤器
  3. 自定义钩子命名约定
  4. 带有可扩展插件的自定义钩子演示
  5. 使用来自第三方开发者的自定义钩子
  6. 何时使用自定义钩子?

如何在WordPress中创建自定义动作

使用do_action()函数创建自定义动作钩子。这是你如何做到的:

// the position where you insert your action is where it'll run when called
do_action( ' my_unique_custom_action' );
// continue with the rest of your code

现在,其他开发人员无需修改源代码即可连接到您的插件或主题。他们所要做的就是使用该add_action()函数将他们的回调函数注册到您插件的自定义动作中。

add_action( 'my_unique_custom_action', 'some_callback_function' );
// define the callback function you mentioned in the above action function
some_callback_function() {
// this code will run wherever your custom action hook is 
}

确保彻底记录(document)您的自定义钩子,详细解释它们的作用。毕竟,创建自定义钩子的主要用途是帮助其他开发人员与您的代码进行交互。

如何在WordPress中创建自定义过滤器

使用apply_filters()函数创建自定义过滤器钩子。您可以这样做:

$value_to_filter = "I'm a string, but this can be any PHP data type";
// filters modify a value and are typically tied to a predefined variable
apply_filters( 'my_custom_filter', $value_to_filter );

您的自定义过滤器的参数应包括唯一标识符和要过滤的值。其他开发人员可以使用add_filter()函数连接到您的自定义过滤器并修改传递的值。

add_filter( 'my_custom_filter', 'some_callback_function' );
// define the callback function you mentioned in the above filter function
function some_callback_function( $value_to_filter ) {
// modify the passed value (or not) 
return $value_to_filter; // returning a value is a must for filters
}

当您定义自定义过滤器时,请确保它没有定位在它应该过滤的值被定义之前。如果您没有正确放置过滤器,过滤后的值将被默认值覆盖。

自定义钩子命名约定

为所有自定义钩子选择唯一名称非常重要。由于任何插件或主题都可以有自己的自定义钩子,因此具有相同的钩子名称可能会导致代码冲突和意外结果。

例如,如果您将动作命名为send_email,其他插件开发人员很可能也会选择相同的术语,因为它不够独特。如果任何网站同时安装了您和其他开发人员的插件,则可能会导致难以追踪的错误。

您可以为所有自定义钩子添加一个通用标识符作为前缀,以使它们既简单又独特。因此,您可以为其命名plugin_name_send_emailplugin_name_是此处的唯一前缀),而不是send_email

带有可扩展插件的自定义钩子演示

让我们创建一个可扩展插件(或可插拔插件),允许其他开发人员使用其自定义钩子与其交互。

我将这个插件命名为Custom Hooks Demo 它的主要功能是在您插入短代码的任何地方输出一个引用框。它将在正确的位置包含自定义动作和过滤器,以便其他开发人员可以修改或扩展其功能。

您可以参考我的WordPress简码指南以了解有关简码如何工作的更多信息。

让我们开始使用可扩展插件。

<?php
/*
Plugin Name :  Custom Hooks Demo
Description :  Demonstrating how to create an extensible WordPress plugin using custom hooks.
Author      :  Salman Ravoof
Author URI  :  https://salmanravoof.com/
License     :  GPLv2 or later
License URI :  https://www.gnu.org/licenses/gpl-2.0.html
Text Domain :  custom-hooks-demo
*/
/** 
* the [custom_hooks_demo] shortcode returns the HTML code for a quote box.
* @return string HTML code for a quote box
*/
add_shortcode( 'custom_hooks_demo', 'my_shortcode_callback' );
function my_shortcode_callback ( $arguments ) {
ob_start(); // start object buffering to collect all output before sending it to the browser
// set an action hook to run before you output anything
do_action( 'the_topmost_custom_action' );
// define your variables which you want to allow to be filtered
$quote_content = "Z.E.R.O. That's the number of people who'd like to have any website autoplay music on their browsers.";
$quote_author = "John Doenuts";
// create your custom filters after you've set the variables
$quote_content = apply_filters( 'custom_quote_content', $quote_content );
$quote_author = apply_filters( 'custom_quote_author', $quote_author );
// build the shortcode output template
echo "<div style=\"border:3px solid #5333ed;\"><blockquote style=\"margin:20px;border-color:#5333ed;\">";
echo $quote_content;
echo "<br><br>";
echo "― <strong>" . $quote_author . "</strong>";
echo "</blockquote></div>";
// set an action hook to run after you output everything
do_action( 'the_ending_custom_action' );
return ob_get_clean(); // get buffer contents, delete the buffer, and then stop buffering
}
  • add_shortcode()函数用于创建自定义短代码。然后您使用该插件的所有函数定义短代码的回调函数。
  • ob_start()是一个启用输出缓冲的PHP函数。这是一个超级方便的函数,它指示PHP保留服务器缓冲存储器中的任何输出,而不是立即输出。您可以使用它在PHP中构建复杂的、可读的HTML代码。
  • do_action( 'the_topmost_custom_action' )定义您的第一个自定义动作。为了使它有用,您需要在插件输出任何内容之前定义它。其他开发人员可以连接到这个自定义动作来运行他们的代码,然后这个自定义短代码打印出任何东西。
  • 创建要过滤的变量。在这个插件中,这些变量是$quote_content$quote_author。在本例中它们都是字符串,但您可以将它们设置为任何PHP数据类型(例如整数、布尔值、数组)。
  • 使用该apply_filters()函数创建您的自定义过滤器。由于所有过滤器都返回一个值,因此您可以将先前定义的变量分配给此过滤器的返回值。其他开发人员现在可以连接到这个过滤器来修改预定义变量的默认值。
  • 使用echo语句逐行构建短代码的输出。由于我们启用了输出缓冲,因此没有任何输出会立即到达浏览器。
  • do_action( 'the_ending_custom_action' )定义您的最后一个自定义动作。您需要在最后定义它,但在返回所有缓冲区内容之前。
  • ob_get_clean()是默认的三合一PHP函数。它将检索缓冲区内容,消除所有缓冲区数据,然后停止输出缓冲。它将以单个串联字符串的形式return收集的缓冲区内容。

保存并激活后,将[custom_hooks_demo]短代码添加到您的文章内容将输出一个带有默认值的引用框。

使用Custom Hooks Demo插件的原始引用框

使用Custom Hooks Demo插件的原始引用框

现在,让我们创建另一个名为Custom Hooks Demo Extension的插件。它将挂钩到由前一个插件创建的所有自定义钩子并执行或修改某些内容。

<?php
/*
Plugin Name :  Custom Hooks Demo Extension
Description :  Demonstrating how you can extend WordPress plugin functionality with its custom hooks.
Author      :  Salman Ravoof
Author URI  :  https://salmanravoof.com/
License     :  GPLv2 or later
License URI :  https://www.gnu.org/licenses/gpl-2.0.html
Text Domain :  custom-hooks-demo-extension
*/
/**
* replace the quote content by hooking into the 'custom_quote_content' filter
*/
add_filter( 'custom_quote_content', 'new_quote_content_callback' );
function new_quote_content_callback( $content ) {
$content = "There are no bugs in programming. Only unexpected features.";
return $content;
}
/**
* replace the quote author by hooking into the 'custom_quote_author'
*/
add_filter( 'custom_quote_author', 'new_quote_author_callback' );
function new_quote_author_callback( $author ) {
$author = "Jane Doodle";
return $author;
}
/**
* add an image to the top of the shortcode output by hooking into the 'the_topmost_custom_action'
*/
add_action( 'the_topmost_custom_action', 'quote_image_callback' );
function quote_image_callback() {
$url = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f9/Quote-right-cs.svg/75px-Quote-right-cs.svg.png";
echo '<div><img class="aligncenter" src="'.$url.'"></div>';
}
/**
* add a button below the shortcut output by hooking into the 'the_ending_custom_action'
*/
add_action( 'the_ending_custom_action', 'add_button_callback' );
function add_button_callback() {
echo '<div style="text-align:center;"><button name="nice">Nice Quote!</button></div>';
}

如您所见,此扩展插件仅包含在正确位置挂钩到原始插件以进行修改的动作和过滤器函数。

它使用add_action()add_filter()函数将其回调函数注册到由原始插件(例如the_topmost_custom_actioncustom_quote_author)创建的自定义动作和过滤器。

扩展插件修改原引用框

扩展插件修改原引用框

自定义动作钩子允许您在原始插件中以正确的时间间隔插入您的代码并运行您自己的脚本。在这里,我们在顶部添加一个图像,在底部添加一个按钮。

同样,自定义过滤器钩子可让您修改引用内容的值及其作者姓名。最终的结果是一个任何人都可以完全扩展而无需修改其源代码的插件。

使用来自第三方开发者的自定义钩子

自定义钩子使单个WordPress插件和主题能够拥有丰富的可扩展插件生态系统。参考WooCommerce插件。它为WordPress添加了电子商务功能,但它还在其代码中包含了大量钩子

WooCommerce动作和过滤器钩子参考

WooCommerce动作和过滤器钩子参考

WooCommerce有数百个扩展和插件,它们使用其钩子来构建其核心功能并使其变得更好。

您可以使用这些扩展将WooCommerce与Stripe、MailChimp、Salesforce、Zapier等集成。

扩展扩展了WooCommerce的功能

扩展扩展了WooCommerce的功能

一个好的做法是查看流行的WordPress插件的文档部分,看看它们是如何实现自定义钩子的。我的一些主要建议是Easy Digital DownloadsBuddyPressQuiz and Survey Master以及Gravity Forms

何时使用自定义钩子?

根据您正在创建的主题或插件,以及它的目标用户,您可能想知道是否需要添加任何自定义钩子。

在决定是否添加自定义钩子时,一个好的经验法则是检查它们是否为其他开发人员提供了任何可扩展性好处。如果没有,那么最好推迟到其他开发人员要求您添加它们。

您需要非常确定将自定义钩子添加到您的插件或主题。一旦发布,并且如果其他开发人员已经使用过它,那么在不破坏向后兼容性的情况下您永远无法更改它。

从WordPress钩子中删除回调函数

您已经看到了如何删除注册到某些钩子的回调函数的示例。这些回调可以由插件、主题甚至WordPress核心本身注册。让我们用更多的例子来看看移除钩子的回调函数。

要从钩子中删除回调函数,取决于它是注册到动作还是过滤器,您需要使用remove_action()remove_filter()函数。

一个警告是,您需要使用用于注册回调函数的相同参数来调用这些函数。基本上,从它们add_action()add_filter()函数中复制粘贴参数。

此外,您只能在注册后删除回调函数。如果您在注册之前尝试删除它们,则删除过程将失败。您需要正确获取钩子的执行顺序。

假设您想删除一个主题注册的回调函数,该函数会给您的网站增加膨胀(您想要一个速度更快的网站,不是吗?)。

function wp_bloated_callback_function() {    
// some code that adds a lot of bloat to the site
}
add_action( 'template_redirect', 'wp_bloated_callback_function', 5 );

例如,上面的回调函数可能会加载许多不必要的脚本和样式表。删除它会给您的网站带来巨大的性能提升

但是,您需要确保remove_action()函数仅在template_redirect动作之后运行。一种方法是after_setup_theme动作钩子,因为它是在template_redirect动作之后触发的。

function wp_remove_bloat() {
// ensure all parameters are identical to the original add_action() function
remove_action( 'template_redirect', 'wp_bloated_callback_function', 5 );
}
// ensure that remove_action() is called only after add_action()
add_action( 'after_setup_theme', 'wp_remove_bloat' );

wp_bloated_callback_function()现在将从放掉自身template_redirect的行动。

删除回调函数的特殊情况

删除回调函数不仅仅是完全禁用它们。有时您可能需要暂时删除它们,运行您的代码,然后再次添加它们。

例如,每次调用wp_insert_post()wp_publish_post()函数时,都会触发save_post动作。您可以在wp-includes/post.php找到它们。

因此,如果您有一个回调函数挂接到save_post动作,并且如果您在回调函数中调用wp_insert_post()wp_publish_post()函数,save_post动作将多次触发。

function some_callback_function( $post_id, $post ) {
// do something here
wp_insert_post( [some_array] ); // this function also calls the 'save_post' action
// maybe do something more
}
add_action( 'save_post', 'some_callback_function', 10, 2 );

调用动作的函数也调用它可能会产生意想不到的结果。解决此问题的一种方法是remove_action()在调用wp_insert_post().

function some_callback_function( $post_id, $post ) {
// do something here
// remove the callback function from the ‘save_post’ action
remove_action( 'save_post', 'some_callback_function', 10, 2 );
// now run the wp_insert_post() function
wp_insert_post( [some_array] );
// add the callback function back to the ‘save_post’ action
add_action( 'save_post', 'some_callback_function', 10, 2 );
// maybe do something more
}
add_action( 'save_post', 'some_callback_function', 10, 2 );

这是remove_action()remove_filter()函数的另一个实际用途。深入挖掘WordPress的核心将帮助您了解如何更好地避免这些情况。

其他WordPress钩子教程

小结

如果您是WordPress开发人员,则使用WordPress钩子有多种优势。

钩子不仅可以让您修改或扩展WordPress的核心功能,还可以使用它们来修改插件、主题,并让其他开发人员与您的插件或主题进行交互。

评论留言

唇枪舌剑 (2)

  • xu的头像

    xu

    2022.8.28 13:08

    文章都是自己码的吗? 乍一看还以为是爬的外文再翻译

    回复
    • WBOLT_COM

      2022.8.28 21:08

      机翻加人工翻,不是采集,手动搬运。有启发?