各位观众老爷们,晚上好!我是今晚的主讲人,江湖人称“代码老中医”,专治各种疑难杂症,今天咱们就来聊聊 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 网站! 散会!