WordPress 技巧: 钩子、过滤器以及禁用字符转义 wptexturize()

这两天给网站换了一个不错的“文章目录”插件:ezTOC,然后无意中发现有些标题无法被正确跳转。查了半天,发现是跟 WordPress 的 wptexturize() 函数有关系。

一、WordPress 中的钩子与过滤器

钩子(hook)是 WordPress 中一种用来修改代码执行逻辑的机制。

1、首先在原来的代码中,使用 apply_filters($hook_name, ...) 或者 do_action($hook_name, ...),埋入一个钩子 hook_name,表示在此处执行这个 hook_name 关联的函数。

2、WordPress 自己,或者插件开发者,或者用户本身,可以通过 add_filter($hook_name, $callback, $priority, ...)add_action($hook_name, $callback, $priority, ...) 向钩子 hook_name 注册自定义的 callback 函数(就叫它钩子函数吧)。一个钩子 hook 可以关联多个钩子函数。priority 表示这个函数在钩子中的执行优先级。然后当原来的代码执行到 apply_filters($hook_name) 或者 do_cation($hook_name) 时候,就会自动调用已经注册到 hook_name 下的所有 callback 函数。

WordPress 提供了两种类型的钩子,过滤器钩子(filter)与动作钩子(action)。二者的机制是一样的,只是目的有所不同。可以简单的理解为过滤器 filter 更倾向于对数据的修改、过滤(需要返回数据);动作 action 则倾向于对执行流程的修改(不需要返回数据)。

过滤器(filter)主要会用到的方法:

add_filter($hook_name, $callback, $priority, ...) 给过滤器钩子 hook_name 增加一个钩子函数 callback。

apply_filters($hook_name, ...) 执行过滤器钩子 hook_name。

remove_filter($hook_name, $callback) 从过滤器钩子 hook_name 下移除 callback 函数。

has_filter( string $hook_name, $callback) 判断过滤器钩子 hook_name 下面是否注册有 callback 函数。

动作(action) 同样的,主要有 add_action(), do_action(), remove_action(), has_action() 这几个函数。

二、字符转义函数 wptexturize()

WordPress 内置函数 wptexturize($text) 会将文本中的特定字符进行转换,比如将横杠「-」转换成「–」,将三个横杠「—」转换成「—」,将三个点「…」转换成「…」。

但让我觉得有点烦人的就是,WordPress 默认会对几乎所有的文本进行 wptexturize 转义。可以在 wordpress/wp-includes/default-filters.php 文件中看到,WordPress 将 wptexturize() 函数注册到了很多过滤器钩子中。比如 the_content 钩子,是用来返回文章内容的,the_title 钩子,是用来返回文章标题的。

三、禁用 wptexturize

但是实际上,我是并不希望 WordPress 对我的内容进行转义的。所以我需要想办法把 WordPress 的这个默认行为禁用掉。

3.1 普遍但不太安全的禁用方式

早期的禁用方式,大家普遍都是采用 remove_filter() 函数,将 wptexturize() 从过滤器钩子中去掉。我也是如此。(甚至现在用中文关键字搜索 “wordpress 字符 转义”,出来的结果还几乎都是这种方法!)

在自定义主题的 functions.php,添加如下代码:

// 取消文章内容转义
remove_filter('the_content', 'wptexturize');
// 取消文章摘要转义
remove_filter('the_excerpt', 'wptexturize');
// 取消评论转义
remove_filter('comment_text', 'wptexturize');

直到这几天换了一个“文章目录”插件 ezTOC,发现它在生成目录的时候,对于一些标题中存在特殊符号的,会无法跳转。查了半天,才发现原来是跟我禁用 wptexturize() 冲突了。

因为它在匹配标题(heading)的时候,默认会应用 wptexturize() 进行转义。

然后在生成目录时候它使用的就是转义后的文本。并且会再次匹配文章中的 heading,将 heading 加上锚点。(类似将「<h1>这是标题</h1>」转换成「<h1><span class=’ezTOC’ id=’anchor_1′>这是标题</span></h>」这样子)

而我们文章实际输出的 heading 是取消转义的。这时候如果有一个标题里面有横杠「-」,它在最终生成标题锚点的时候就会失败。

3.2 更安全的禁用方式

查看 wptexturize()说明文档或者源码,会发现它其实提供了 $run_texturize = apply_filters( 'run_wptexturize', $run_texturize ) 这个开关来允许全局禁用 texturize。

这时候,我们只需要在自定义主题的 functions.php 文件中使用如下代码:

// 全局禁用 wptexturize 转义
// __return_false 是 WordPress 内置的一个便捷函数,直接返回 false。
add_filter('run_wptexturize', '__return_false');

这样,不论是 WordPress 还是第三方插件,在任意地方调用 wptexturize() 方法,都不会进行转义了。

3.3 针对特定标签禁用 wptexturize

此外,wptexturize() 函数体中还有两个钩子可以用来禁用指定的 HTML 标签和 shortcode 标签([shortcode] 是 WordPress 自己提供的标签格式,用来供给第三方插件进行自动替换的)。

禁用指定的 HTML 标签:

 apply_filters( 'no_texturize_tags', string[] $default_no_texturize_tags )

禁用指定的 [shortcode] 标签:

 apply_filters( 'no_texturize_shortcodes', string[] $default_no_texturize_shortcodes )

如果只想针对某些特定 HTML 标签禁用 wptexturize,那么可以在 functions.php 中使用如下代码:

add_filter( 'no_texturize_tags', 'my_no_texturzie_tags' );

function my_no_texturzie_tags( $tags ) {
   $tags[] = 'blockquote';   // <blockquote> 标签
   $tags[] = 'h1';           // <h1> 标签
   return $tags;
}

 

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top