增强 WordPress Shortcode 检测和判断能力,实现 doing_shortcode() 和 current_shortcode() 函数
我们之前详细介绍过 WordPress 的简码功能:Shortcode / 简码是什么?有什么用?一文详解 WordPress Shortcode。
这里再简单介绍一下,简码(Shortcode)指的是使用[]包含的简码或者短代码,WordPress 会识别这些代码并根据它们定义的回调函数输出相应的内容,使用它可以给日志内容添加各种功能,并且它的接口非常容易使用,并且功能非常强大。
为什么需要正在处理的 Shortcode 查询和判断函数
但是使用过程中,发现简码功能没有提供 了 doing_filter()和 current_filter()来追踪当前正在执行的过滤器和过滤器名称的函数,其实我们也需要 current_shortcode() 和 doing_shortcode($tag)函数,用于正在处理的 Shortcode 来获取和判断当前正在执行的短代码。。
我们先看看 WordPress Hook 的检测和判断函数有什么用处,current_filter() 和 doing_filter($hook_name=null),或者 current_action() 和 doing_action($hook_name=null)。他们分别用于返回正在的执行的 Hook,和某个特定的 Hook $hook_name 是否正在执行,具体怎么用呢?
比如我的文章目录扩展在文章开头加上目录的代码:
add_filter('the_content', function($content){
if(!doing_filter('get_the_excerpt') && is_single(get_the_ID())){
// 在文章前面加上目录
}
return $content;
});
我们是通过 the_content 这个 filter 实现的,但是很多时候,如果文章没有摘要,那么获取摘要的函数通过 get_the_excerpt 会调用 get_the_content() 函数来获取内容,然后再生成摘要,这样就会使得生成目录的代码被调用两次,所以我们通过 doing_filter('get_the_excerpt') 来判断这时候是在处理摘要,而不是内容,来实现文章目录只调用一次。
同样我们在 shortcode 处理函数的时候,可能有些时候也需要有同样的判断,比如我的内容模板插件,在实现密码保护的时候,再实现 password shortcode 时候,判断当前文章密码保护是不是需要的时候,就存在在外面和在执行 shortcode 回调的时候不同。
add_filter('post_password_required', function($required, $post){
if($required){
return doing_shortcode('password') ? true : !has_shortcode($post->post_content, 'password')
}
return $required;
}, 10, 2);
如何实现正在处理的 Shortcode 查询和判断函数
那么如何实现 current_shortcode 和 doing_shortcode($tag) 这两个函数呢?
Shortcode 的实际处理函数 do_shortcode_tag 有两个 filter,开始处理之前的 pre_do_shortcode_tag 和处理完成之后的 do_shortcode_tag,我们可以创建一个全局数组变量,用于存储正在处理的 Shorttag 的栈,在处理 Shortcode 之前推入当前,处理完成则推出。
//初始化队列
global $wp_current_shortcode;
if(!isset($wp_current_shortcode)){
$wp_current_shortcode = [];
}
// 处理之前,推入队列
add_filter('pre_do_shortcode_tag', function($pre, $tag){
global $wp_current_shortcode;
$wp_current_shortcode[] = $tag;
return $pre;
}, 1, 2);
add_filter('do_shortcode_tag', function($output, $tag){
global $wp_current_shortcode;
array_pop($wp_current_shortcode);
return $output;
}, 999, 2)
// 获取当前的 Shortcode
if(!function_exists('current_shortcode')){
function current_shortcode(){
global $wp_current_shortcode;
return end($wp_current_shortcode);
}
}
// 判断当前的 Shortcode
if(!function_exists('doing_shortcode')){
function doing_shortcode($tag=null){
global $wp_current_shortcode;
return null === $tag ? !empty($wp_current_shortcode) : in_array($tag, $wp_current_shortcode, true);
}
}
WPJAM Basic 插件中已经整合了这两个函数,可以直接使用。😎 也可以参考这个思路在自己的项目中实现类似的功能。