如果您有使用WordPress中的父主题和子主题的经验,您会知道子主题中的模板文件会覆盖父主题中的模板文件。例如,如果您的父主题具有page.php文件,并且您在子主题中创建了一个同名的新文件,那么WordPress在显示页面时将使用子主题的这个page.php文件。
推荐先阅读:如何创建和自定义WordPress子主题
您可能会认为函数(function)会以相同的方式工作:在子主题的functions.php文件中创建一个与父主题名称相同的新函数,它将优先运行。不幸的是,它并非如此简单。
在本教程中,我将向您展示三种方法,可用于覆盖子主题中父主题的功能函数:
- 可插拔函数
- 函数优先级
- 从它们连接的钩子上删除功能函数
父子主题的函数如何工作
在研究覆盖父主题中的函数的方法之前,它有助于了解函数在父主题和子主题中的工作方式。
首先,您需要知道当您使用子主题时,父主题中的所有函数都将运行。您无需在子主题的功能文件functions.php中添加任何内容即可实现此目的。这与CSS不同,在CSS中,您必须手动将父主题的样式表包括在子主题的样式表中。
此外,如果您的父主题和子主题具有相同名称的函数,则这将破坏您的网站,除非父主题中的函数是可插拔的函数(稍后将对此进行详细介绍)。这就是为什么为所有函数需要使用前缀并且在父主题和子主题中使用不同的前缀(以防万一)的原因。
但是,您可以更改函数的触发顺序,并且可以完全阻止函数触发,我们将很快看到。
可插拔函数
可插拔函数(Pluggable Functions)是您在父主题中编写的代码,因此,如果您正在使用不具有可插拔功能的现有父主题,则它们对您没有任何用处。
但是,如果您正在编写自己的父主题,或者作为将来项目的起点,或者正在创建自己的主题框架,则最好使函数可插拔,以便可以轻松地在子主题中覆盖它们。浏览正在使用的父主题中的函数也是一个好主意,因为其中许多函数(包括WordPress默认主题)将具有可插拔功能。
要编写可插拔函数,只需将其封装在条件标记中,以检查具有该名称的函数是否已运行:
<?php
if ( ! function_exists ( 'my_function' ) ) {
function my_function() {
// Contents of your function here.
}
}
?>
因此,如果您将父主题中的函数包含在这样的条件标记中,则WordPress将检查子主题中是否已经有同名函数已经运行过,如果是这种情况,它将不会运行父主题的函数。
然后,当您要在子主题中编写要覆盖父主题中的功能的函数时,只需为其命名与父主题中的名称相同即可:
<?php
function my_function() {
// Contents for your function override here.
}
?>
WordPress将首先在子主题中运行该函数,当涉及到父主题中的函数时,它将检查它是否已经存在,并且因为它已经存在,所以不会运行它。
函数优先级
如果您没有使用自己的父主题,或者正在使用没有可插拔函数的第三方主题,则需要另一种方法。
在编写函数时,可以为它们分配优先级,告诉WordPress何时运行它们。将函数添加到动作或过滤器挂钩时,可以执行此操作。WordPress将按照优先级的升序运行附加到给定钩子上的函数,因此优先级数字更大的那些将最后运行。
让我们想象一下父主题中的函数不可插拔,并且看起来像这样:
<?php
function parent_function() {
// Contents for your function here.
}
add_action( 'init', 'parent_function' );
?>
此函数已附加到init
钩子上,尚未获得优先级。默认情况下,WordPress会为尚未添加优先级的功能分配优先级为10
,因此要在该函数运行后执行新函数,请使用大于 10
的数字。我倾向于使用 15
,以便在以后要在两者之间添加另一个函数的情况下留出一些喘息的空间。
这意味着您的子主题中的函数将如下所示:
<?php
function child_function() {
// Contents for your function here.
}
add_action( 'init', 'child_function', 15 );
?>
或者,您父主题中的函数可能已分配了优先级:
<?php
function parent_function() {
// Contents for your function here.
}
add_action( 'init', 'parent_function', 20 );
?>
因此,您只需要确保在子主题中赋予该函数更高的的优先级:
<?php
function child_function() {
// Contents for your function here.
}
add_action( 'init', 'child_function', 25 );
?>
从挂钩中删除函数功能
有时,在第一个函数之后运行另一个函数不足以覆盖它 – 您需要确保父主题中的函数根本不运行。在这种情况下,您可以使用remove_action()
或 remove_filter()
函数将父主题函数从其附加的挂钩中删除 。您将使用的函数取决于该功能是附加到父主题中的动作挂钩还是过滤器挂钩。
让我们回到父主题中的上一个函数:
<?php
function parent_function() {
// Contents for your function here.
}
add_action( 'init', 'parent_function' );
?>
要将函数从其动作挂钩中删除并防止触发,请在子主题中创建一个函数,以使用remove_action()
以下方法将其删除 :
<?php
remove_action( 'init', 'parent_function' );
?>
但是,这不能单独工作-您需要将此函数附加到一个钩子上, 该钩子将在附加了父主题函数的钩子之后触发 。这是因为您无法在触发操作之前将其删除。您可以在官方文档中找到触发操作顺序的详细信息 。
<?php
function child_remove_parent_function() {
remove_action( 'init', 'parent_function' );
}
add_action( 'wp_loaded', 'child_remove_parent_function' );
?>
完成此操作后,您可以在子主题中编写一个替代函数来替换父主题的函数,或者如果您要做的只是从父主题中删除该功能,那您什么也不需要做了。
优先级说明
请注意,如果您尝试使用remove_action()
或remove_filter()
删除函数功能 , 并且该函数已分配了优先级,则删除时必须包含该优先级,否则它将无法正常工作。
因此,如果父主题中的函数如下所示:
<?php
function parent_function() {
// Contents for your function here.
}
add_action( 'init', 'parent_function', 15 );
?>
删除时,您需要包含相同的优先级值:
<?php
function child_remove_parent_function() {
remove_action( 'init', 'parent_function', 15 );
}
add_action( 'wp_loaded', 'child_remove_parent_function' );
?>
高级父子主题函数:可插拔和扩展函数
除上述内容外,在某些特定情况下,您可能需要进一步处理。以下提示是针对以下评论中提出的问题的解答。
如何部分覆盖父主题中的函数
严格来说,您不能部分覆盖函数。您只能让它运行或禁用它。但是有解决方法。
第一种是您要部分覆盖的函数本身包含可插拔的函数。您可能会发现该函数包括从父主题中调用另一个可插拔函数。
在这种情况下,如果您要更改的代码,则可以覆盖主函数中的任何函数。通过编写新版本的可插拔函数来做到这一点,该函数仅包含一条 return
语句或包含替代代码。请注意,这仅在该函数可插拔时才有效;否则,您的站点将中断。
但是,仅当您足够幸运地需要重写由另一个包含的可插入函数提供的函数中的功能时,此方法才有效。
在大多数情况下,这不是一个选择。在这种情况下,您将需要停用该函数,并使用其他名称的自己的函数来替换它。要创建新函数,您可以将函数从父主题复制并粘贴到子主题的 functions.php 文件中,然后对其进行编辑以删除不需要的代码。
您将使用两个自己的函数:一个删除原始函数,第二个提供新代码,如下面的示例覆盖在init钩子上调用的父主题:
<?php
function remove_parent_function(
remove_action( 'init', 'parent_theme_function');
)
add_action( 'wp_loaded', 'remove_parent_function');
function child_theme_function(
// contents of child theme function based on original parent theme function
)
add_action( 'init', 'child_theme_function');
?>
如何重写不可插拔函数
父主题中不可插拔的函数不能以任何特殊方式覆盖。因此,您必须使用上述方法,从其动作挂钩中删除该函数,然后在提供新代码的同一动作挂钩上编写一个新函数。
不要给子主题中的函数命名与父主题中的函数相同的名称,因为这会破坏您的站点!
如何扩展父主题函数
函数通常不设计为可扩展的。但是,如果您的函数包含对其他可插拔函数的调用,则可能会有例外。
在这种情况下,您可以通过覆盖主功能中的函数来扩展功能,而不必替换整个主函数。
在大多数情况下,您只能通过以下三种方式之一扩展父主题函数:
- 如果您要扩展的函数是可插拔的,请将其复制到您的子主题中并添加额外的代码以对其进行扩展。
- 如果该函数不可插拔,请使用
remove_action()
将该钩子从其挂钩中删除,并使用相同的代码在同一个钩子上编写一个新函数(名称不同)。您可以将代码从原始函数复制到新函数中并进行编辑。 - 编写第二个函数,该函数在与第一个函数相同的钩子上调用,并添加将在第一个函数之前或之后运行的额外代码。在
add_action()
中使用优先级(priority)参数,指定您的第二个函数将在原始函数之前还是之后运行。
总结
父主题中的覆盖函数比覆盖模板文件或样式更复杂,但是可以做到。在这里,我向您展示了三种执行此操作的方法:
- 如果您要编写自己的父主题,或者使用具有父主题的主题,请使用可插拔函数,以便子主题中与父主题名称相同的函数将替换它。
- 为子主题中的函数分配更高的优先级,以确保它们在父主题中的功能之后运行。
- 完全使用
remove_action()
或remove_filter()
删除父主题中的函数功能。
您使用哪种方法将取决于父主题的编码方式以及是否需要完全删除父主题的函数功能,还是仅在其后运行另一个函数以覆盖它。
注:本文内容来自 tutsplus.com,由 WordPress大学 翻译整理。
继续阅读: