各位观众老爷们,晚上好!我是今晚的主讲人,江湖人称“代码老中医”,专治各种疑难杂症,今天咱们就来聊聊 WordPress 里一个神奇的过滤器:wp_kses_allowed_html
,保证药到病除,让你彻底掌握自定义 WordPress 允许的 HTML 标签的秘诀。
一、 什么是 wp_kses
?为什么要折腾 wp_kses_allowed_html
?
在深入 wp_kses_allowed_html
之前,咱们得先认识一下它的老大哥 wp_kses
。 wp_kses
是 WordPress 用来过滤 HTML 内容的函数,防止用户输入恶意代码,保证网站安全。它就像一个尽职尽责的保安,不允许任何可疑的家伙进入你的 WordPress 网站。
但是!问题来了,保安太尽职了,有时候也会把一些“好人”也拦在门外。比如,你想在文章里插入一个 <video>
标签,或者一个自定义的 HTML5 标签,结果被 wp_kses
无情地咔嚓掉了。这时候,你就需要 wp_kses_allowed_html
出马了。
wp_kses_allowed_html
是一个过滤器,它允许你自定义 wp_kses
允许的 HTML 标签和属性。你可以通过这个过滤器,告诉 wp_kses
:“嘿,这个 <video>
标签是好人,放它进来!”
二、 wp_kses_allowed_html
的工作原理:从源码说起
要理解 wp_kses_allowed_html
的工作原理,咱们就得扒开 WordPress 的裤衩,看看它的源码。
首先,wp_kses
函数的核心逻辑是,它会根据一个预定义的允许标签和属性列表,来判断哪些 HTML 标签和属性是允许的。这个列表就是通过 wp_kses_allowed_html
过滤器来修改的。
wp_kses_allowed_html
过滤器位于 wp-includes/kses.php
文件中(不同WordPress版本可能会有细微差异)。它在 wp_kses
函数内部被调用,大概是这么个意思:
function wp_kses( $data, $allowed_html, $allowed_protocols ) {
// ... 一些代码 ...
// 应用 wp_kses_allowed_html 过滤器
$allowed_html = apply_filters( 'wp_kses_allowed_html', $allowed_html, $data, $allowed_protocols );
// ... 剩下的过滤逻辑 ...
}
看到没?apply_filters( 'wp_kses_allowed_html', $allowed_html, $data, $allowed_protocols );
这行代码就是关键。它会调用所有注册到 wp_kses_allowed_html
过滤器的函数,并将当前允许的 HTML 标签列表 $allowed_html
作为参数传递给这些函数。
这意味着,你可以在你的主题或者插件里,注册一个函数到 wp_kses_allowed_html
过滤器,修改 $allowed_html
数组,从而达到自定义允许标签的目的。
三、 如何使用 wp_kses_allowed_html
:实战演练
好了,理论讲完了,咱们来点实际的。假设我们想允许 <video>
标签,并允许它拥有 src
, width
, height
, controls
属性。我们可以这样做:
- 在你的主题的
functions.php
文件或者插件里,添加以下代码:
<?php
add_filter( 'wp_kses_allowed_html', 'allow_video_tag', 10, 2 );
function allow_video_tag( $allowed_tags, $context ) {
if ( current_user_can('edit_posts') || current_user_can('edit_pages') ) {
$allowed_tags['video'] = array(
'src' => true,
'width' => true,
'height' => true,
'controls' => true,
'poster' => true, // 允许 poster 属性
'preload' => true, // 允许 preload 属性
'loop' => true, // 允许 loop 属性
'muted' => true, // 允许 muted 属性
'autoplay' => true // 允许 autoplay 属性
);
$allowed_tags['source'] = array(
'src' => true,
'type' => true
);
}
return $allowed_tags;
}
?>
-
代码解释:
add_filter( 'wp_kses_allowed_html', 'allow_video_tag', 10, 2 );
:这行代码将allow_video_tag
函数注册到wp_kses_allowed_html
过滤器。10
是优先级,数字越小优先级越高。2
表示传递给allow_video_tag
函数的参数个数,分别是$allowed_tags
和$context
。function allow_video_tag( $allowed_tags, $context ) { ... }
:这是我们的自定义函数,它接收两个参数:$allowed_tags
:当前允许的 HTML 标签列表,是一个数组。$context
:当前wp_kses
函数的上下文,例如post
,comment
等。我们可以根据上下文来决定是否允许某些标签。
if ( current_user_can('edit_posts') || current_user_can('edit_pages') ) { ... }
:这行代码判断当前用户是否有编辑文章或页面的权限。只有有权限的用户才能使用<video>
标签。这是一种安全措施,防止恶意用户滥用。$allowed_tags['video'] = array( ... );
:这行代码将<video>
标签添加到允许列表中,并指定了允许的属性。true
表示允许该属性。return $allowed_tags;
:最后,我们必须返回修改后的$allowed_tags
数组,否则wp_kses
还是会使用默认的允许列表。
-
使用
<video>
标签:现在,你就可以在你的文章或者页面里使用
<video>
标签了:
<video src="your-video.mp4" width="640" height="360" controls poster="your-poster.jpg">
Your browser does not support the video tag.
</video>
四、 深入理解 $allowed_tags
数组的结构:
$allowed_tags
数组是一个多维数组,它的结构如下:
$allowed_tags = array(
'tag_name' => array(
'attribute_name' => true,
'another_attribute' => true,
// ...
),
'another_tag' => array(
// ...
),
// ...
);
tag_name
:HTML 标签的名字,例如'video'
,'p'
,'a'
等。attribute_name
:HTML 属性的名字,例如'src'
,'href'
,'class'
等。true
:表示允许该属性。
更复杂的属性控制:协议过滤
有时候,我们不仅要允许某个属性,还要限制它的值。比如,我们想允许 <a>
标签的 href
属性,但只允许 http
, https
, mailto
协议。这时候,我们可以使用协议过滤。
$allowed_tags['a'] = array(
'href' => array( 'http', 'https', 'mailto' ),
'title' => true,
'class' => true,
'target'=> true // 允许 target 属性
);
这里,'href' => array( 'http', 'https', 'mailto' )
表示只允许 href
属性的值以 http
, https
, mailto
开头。
五、 常用 HTML 标签及其属性的配置示例:
为了方便大家,我整理了一些常用 HTML 标签及其属性的配置示例:
标签 | 常用属性 | 配置示例 |
---|---|---|
a |
href , title , target , class , rel |
php 'a' => array( 'href' => array( 'http', 'https', 'mailto' ), 'title' => true, 'target' => true, 'class' => true, 'rel' => true ) |
img |
src , alt , width , height , class , srcset , sizes |
php 'img' => array( 'src' => true, 'alt' => true, 'width' => true, 'height' => true, 'class' => true, 'srcset' => true, 'sizes' => true ) |
p |
class , style |
php 'p' => array( 'class' => true, 'style' => true ) |
div |
class , style , id , align |
php 'div' => array( 'class' => true, 'style' => true, 'id' => true, 'align' => true ) |
span |
class , style |
php 'span' => array( 'class' => true, 'style' => true ) |
h1 –h6 |
class , style , id |
php 'h1' => array( 'class' => true, 'style' => true, 'id' => true ), 'h2' => array( 'class' => true, 'style' => true, 'id' => true ), // ... |
ul , ol |
class , style |
php 'ul' => array( 'class' => true, 'style' => true ), 'ol' => array( 'class' => true, 'style' => true ) |
li |
class , style |
php 'li' => array( 'class' => true, 'style' => true ) |
table |
class , style , width , border , cellpadding , cellspacing |
php 'table' => array( 'class' => true, 'style' => true, 'width' => true, 'border' => true, 'cellpadding' => true, 'cellspacing' => true ) |
tr , td , th |
class , style , align , valign , colspan , rowspan |
php 'tr' => array( 'class' => true, 'style' => true, 'align' => true, 'valign' => true ), 'td' => array( 'class' => true, 'style' => true, 'align' => true, 'valign' => true, 'colspan' => true, 'rowspan' => true ), 'th' => array( 'class' => true, 'style' => true, 'align' => true, 'valign' => true, 'colspan' => true, 'rowspan' => true ) |
blockquote |
class , style , cite |
php 'blockquote' => array( 'class' => true, 'style' => true, 'cite' => true ) |
code |
class |
php 'code' => array( 'class' => true ) |
pre |
class |
php 'pre' => array( 'class' => true ) |
video |
src , width , height , controls , poster , preload , loop , muted , autoplay |
php 'video' => array( 'src' => true, 'width' => true, 'height' => true, 'controls' => true, 'poster' => true, 'preload' => true, 'loop' => true, 'muted' => true, 'autoplay' => true ) |
source |
src , type |
php 'source' => array( 'src' => true, 'type' => true ) |
audio |
src , controls , preload , loop , muted , autoplay |
php 'audio' => array( 'src' => true, 'controls' => true, 'preload' => true, 'loop' => true, 'muted' => true, 'autoplay' => true ) |
iframe |
src , width , height , frameborder , allowfullscreen (谨慎使用,需要严格验证 src 属性,防止 XSS 攻击!) |
php 'iframe' => array( 'src' => true, 'width' => true, 'height' => true, 'frameborder' => true, 'allowfullscreen' => true ) 重要提示: iframe 标签非常危险,因为它允许嵌入外部网页。如果 src 属性没有经过严格验证,可能会导致 XSS 攻击。请谨慎使用,并确保只允许可信任的来源。 |
六、 安全注意事项:防范 XSS 攻击
wp_kses_allowed_html
过滤器虽然强大,但同时也带来了安全风险。如果你不小心允许了恶意标签或者属性,可能会导致 XSS (Cross-Site Scripting) 攻击。
XSS 攻击的原理:
XSS 攻击是指攻击者通过在你的网站上注入恶意脚本,当其他用户访问你的网站时,这些脚本会在用户的浏览器上执行,从而窃取用户的信息或者进行其他恶意操作。
如何防范 XSS 攻击:
- 最小权限原则: 只允许必要的标签和属性。不要为了方便而允许一些不常用的标签。
- 严格验证属性值: 对于一些敏感的属性,例如
href
,src
,style
,要进行严格的验证,确保它们的值是安全的。可以使用 WordPress 提供的函数,例如esc_url()
,esc_attr()
,wp_kses_post()
等,对属性值进行转义。 - 使用白名单: 尽量使用白名单,只允许特定的标签和属性,而不是使用黑名单,禁止一些不安全的标签和属性。黑名单很容易被绕过,而白名单则更加安全。
- 定期更新 WordPress 和插件: WordPress 和插件的开发者会不断修复安全漏洞,所以要定期更新它们,确保你的网站使用的是最新的安全版本。
- 使用安全插件: 可以使用一些安全插件,例如 Wordfence, Sucuri Security 等,来增强你的网站的安全性。
七、 调试技巧:让错误无处遁形
在使用 wp_kses_allowed_html
过滤器时,可能会遇到一些问题,例如:
- 标签没有生效:可能是你的代码有错误,或者优先级太低,被其他过滤器覆盖了。
- 属性没有生效:可能是你没有正确配置
$allowed_tags
数组,或者属性名写错了。
如何调试:
- 使用
var_dump()
或者print_r()
函数: 在你的allow_video_tag
函数里,使用var_dump( $allowed_tags );
或者print_r( $allowed_tags );
函数,可以查看$allowed_tags
数组的内容,看看你的修改是否生效。 - 使用
error_log()
函数: 将错误信息写入到 WordPress 的错误日志里。例如,error_log( 'My custom error message' );
。 - 使用浏览器开发者工具: 查看网页的源代码,看看 HTML 标签是否被正确渲染。
- 禁用其他插件: 禁用其他插件,看看是否是插件冲突导致的。
- 检查主题的
functions.php
文件: 确保你的代码没有语法错误,并且被正确加载。
八、 高级用法:根据用户角色允许不同的标签
有时候,我们希望根据用户的角色,允许不同的 HTML 标签。例如,我们只允许管理员使用 <script>
标签。可以这样做:
<?php
add_filter( 'wp_kses_allowed_html', 'allow_script_tag_for_admins', 10, 2 );
function allow_script_tag_for_admins( $allowed_tags, $context ) {
if ( current_user_can('administrator') ) {
$allowed_tags['script'] = array(
'type' => true,
'src' => true
);
}
return $allowed_tags;
}
?>
这段代码只允许管理员使用 <script>
标签。其他用户会被 wp_kses
过滤掉。
九、 总结:wp_kses_allowed_html
的威力与责任
wp_kses_allowed_html
过滤器是一个强大的工具,它可以让你自定义 WordPress 允许的 HTML 标签和属性,从而实现更灵活的内容编辑。但是,它也带来了安全风险。在使用 wp_kses_allowed_html
过滤器时,一定要牢记安全第一,防范 XSS 攻击。
记住,能力越大,责任越大! 掌握 wp_kses_allowed_html
的秘诀后,别忘了用它来保护你的 WordPress 网站,而不是破坏它。
好了,今天的讲座就到这里。希望大家都能成为 wp_kses_allowed_html
的高手,打造更安全、更强大的 WordPress 网站! 散会!