前段时间,我尝试以子主题的模式制作了一个主题。原以为制作起来 So Easy,可是,却没有想象的那么容易。首当其冲的是函数替换问题。
WordPress 官方给出的替换方法
<?php
if (!function_exists('theme_special_nav')) {
function theme_special_nav() {
// Do something.
}
}
?>
事实上却没有那么简单。有些函数替换会报 Cannot redeclare 错误,怎么回事呢?
出错的原因
大家翻开支持子主题的主题的 Functions.php(这句话真绕口),会发现,那些可以替换的函数,在 Functions.php 中也是使用:
<?php
if (!function_exists('theme_special_nav')) {
function theme_special_nav() {
// Do something.
}
}
?>
写的,这样就是可以替换的原因,然而那些不能替换的函数呢?一般就是这样的写法:
<?php
function theme_special_nav() {
// Do something.
}
add_action('xxx', 'theme_special_nav');
?>
那么不能替换的函数怎么替换呢?其实也可以巧妙解决的。本文就以 theme_special_nav 这个函数为例,说一下怎么解决的。
解决方法
假设父主题的 Functions.php 是这样写的:
<?php
function theme_special_nav() {
// Do something.
}
add_action('xxx', 'theme_special_nav');
?>
其实已经隐含着替换方法了,我们可以在子主题加入以下代码:
<?php
function remove_parent_theme_hook() {
remove_action('xxx', 'theme_special_nav');
}
add_action('after_setup_theme', 'remove_parent_theme_hook');
function nikbobo_theme_special_nav() {
// Do Something.
}
add_action('xxx', 'theme_special_nav');
?>
原理就是利用 WordPress 的 Hook 机制,在 after_setup_theme 即主题设置完成这个时机删除掉原来的 Hook,然后添加自己的 Hook,为什么一定要在 after_setup_theme 这个时机呢?直接一句:
<?php
remove_action('xxx', 'theme_special_nav');
?>
不就行了么?
大家有无留意到,WordPress 的子主题介绍上有一句话:
其实它会在父主题文件加载之前先载入。
也就意味着,你 remove_action 的时候,这个 Hook 还没有建立,结果你自然知道了。