阐述 WordPress `wp_kses_allowed_html` 过滤器在 Gutenberg 中的源码:如何自定义允许的 HTML 标签。

各位老铁,大家好!今天咱们来聊聊WordPress里一个既重要又有点“闷骚”的家伙:wp_kses_allowed_html 过滤器,以及它在Gutenberg时代如何大放异彩,允许咱们自定义HTML标签。

想象一下,WordPress就像一个兢兢业业的门卫,wp_kses_allowed_html 就是他手里的通行证清单。只有清单上的HTML标签和属性,才能顺利进入WordPress的世界,否则就会被无情地“净化”掉。

在Gutenberg出现之前,我们修改这个清单的方式比较“粗暴”,直接全局修改,影响整个网站。但Gutenberg的出现,让我们可以更精细地控制,针对特定的区块,允许特定的HTML标签。这就像门卫可以根据不同的访客,给出不同的通行权限。

一、wp_kses:HTML卫士的核心

在深入wp_kses_allowed_html 之前,咱们先简单了解一下wp_kses,它是整个HTML净化机制的核心。wp_kses函数负责过滤掉不安全的HTML标签和属性,防止XSS攻击。它依赖于wp_kses_allowed_html 提供的允许标签列表。

wp_kses的基本用法如下:

$unsafe_html = '<script>alert("XSS");</script><p>This is a paragraph.</p><a href="javascript:void(0);">Click me</a>';
$safe_html = wp_kses( $unsafe_html, 'post' ); // 'post' 是一个预定义的允许标签集合
echo $safe_html; // 输出:<p>This is a paragraph.</p><a>Click me</a> (script标签和javascript:void(0)被移除了)

在这里,'post' 是一个预定义的允许标签集合,定义在wp-includes/kses.php 文件中。 我们可以看到,script标签被完全剥离,而a标签的href属性中的javascript:void(0)也被移除了,因为默认情况下是不允许的。

二、wp_kses_allowed_html:通行证清单

wp_kses_allowed_html 过滤器允许我们修改wp_kses使用的允许HTML标签和属性列表。 它的基本用法是:

add_filter( 'wp_kses_allowed_html', 'my_custom_kses_allowed_html', 10, 2 );

function my_custom_kses_allowed_html( $allowed_tags, $context ) {
    // 在这里修改 $allowed_tags
    return $allowed_tags;
}
  • $allowed_tags:是一个数组,包含了允许的HTML标签和属性。 它的结构是:array( 'tag' => array( 'attribute' => true, ... ), ... )
  • $context:表示wp_kses被调用的上下文。 常见的上下文包括 'post', 'comment', 'user_description' 等。不同的上下文可能需要不同的允许标签集合。

三、Gutenberg与wp_kses_allowed_html:定制化的通行证

Gutenberg的出现,让我们可以在更细粒度上控制允许的HTML标签。 我们可以针对特定的区块类型,修改wp_kses_allowed_html,允许该区块使用特定的HTML标签,而不会影响整个网站。

下面,我们通过几个案例来演示如何在Gutenberg中自定义允许的HTML标签。

案例1:允许 <iframe> 标签嵌入视频

默认情况下,出于安全考虑,<iframe> 标签通常是不允许的。 但是,我们可能需要在某个特定的区块中嵌入视频。 我们可以这样做:

add_filter( 'wp_kses_allowed_html', 'my_allow_iframe_in_my_block', 10, 2 );

function my_allow_iframe_in_my_block( $allowed_tags, $context ) {
    // 检查是否是特定的区块
    if ( is_admin() && isset( $_GET['context'] ) && $_GET['context'] === 'my-custom-block' ) {
        // 允许 iframe 标签,并设置允许的属性
        $allowed_tags['iframe'] = array(
            'src'             => true,
            'height'          => true,
            'width'           => true,
            'frameborder'     => true,
            'allowfullscreen' => true,
        );
    }
    return $allowed_tags;
}

// 在你的 Gutenberg 区块注册代码中:
register_block_type( 'my-plugin/my-custom-block', array(
    'attributes'      => array(
        'videoUrl' => array(
            'type' => 'string',
        ),
    ),
    'render_callback' => 'render_my_custom_block',
) );

function render_my_custom_block( $attributes ) {
    $video_url = isset( $attributes['videoUrl'] ) ? esc_url( $attributes['videoUrl'] ) : '';
    // 在渲染区块内容时,传递 context 参数
    $context = array( 'context' => 'my-custom-block' );
    return wp_kses( '<iframe src="' . $video_url . '" width="640" height="360" frameborder="0" allowfullscreen></iframe>', apply_filters( 'wp_kses_allowed_html', wp_kses_allowed_html( 'post' ), 'post' , $context ) );
}

代码解释:

  1. my_allow_iframe_in_my_block 函数:
    • 这个函数是wp_kses_allowed_html 过滤器的回调函数。
    • is_admin() 确保这段代码只在后台运行。
    • isset( $_GET['context'] ) && $_GET['context'] === 'my-custom-block' 检查是否是我们的特定区块。这里通过GET参数传递context信息。在Gutenberg的上下文中,我们可以通过各种方式传递这个上下文信息,例如自定义的属性或元数据。
    • 如果条件满足,就将<iframe> 标签添加到允许的标签列表中,并设置允许的属性(src, height, width, frameborder, allowfullscreen)。
  2. register_block_type 函数:
    • 这是注册Gutenberg区块的代码。
    • 我们定义了一个 videoUrl 属性,用于存储视频URL。
  3. render_my_custom_block 函数:
    • 这是渲染区块内容的回调函数。
    • esc_url( $video_url ) 对视频URL进行转义,防止XSS攻击。
    • 重点:我们使用wp_kses过滤HTML内容,并传递了一个 $context 参数。 这个参数的值是 'my-custom-block',与我们在过滤器函数中检查的值相匹配。
    • apply_filters( 'wp_kses_allowed_html', wp_kses_allowed_html( 'post' ), 'post', $context ),这里先获取默认post的允许标签,然后应用wp_kses_allowed_html 过滤器,并传递 $context 参数。

重点:

  • 传递context 这是关键所在。 通过传递context参数,我们可以在wp_kses_allowed_html 过滤器中区分不同的区块,并针对不同的区块设置不同的允许标签。
  • 安全: 即使允许<iframe> 标签,也要确保对src 属性进行适当的验证和转义,防止恶意URL。

*案例2:允许 `data-` 属性**

data-* 属性是一种用于存储自定义数据的HTML5属性。 我们可能需要在某个区块中使用data-* 属性,例如存储一些配置信息。

add_filter( 'wp_kses_allowed_html', 'my_allow_data_attributes', 10, 2 );

function my_allow_data_attributes( $allowed_tags, $context ) {
    if ( is_admin() && isset( $_GET['context'] ) && $_GET['context'] === 'my-custom-block' ) {
        // 允许所有标签的 data-* 属性
        foreach ( $allowed_tags as $tag => $attributes ) {
            $allowed_tags[ $tag ]['data-*'] = true;
        }
    }
    return $allowed_tags;
}

// 在你的 Gutenberg 区块渲染代码中:
function render_my_custom_block( $attributes ) {
    // ...
    $context = array( 'context' => 'my-custom-block' );
    return wp_kses( '<div data-my-custom-data="value">Content</div>', apply_filters( 'wp_kses_allowed_html', wp_kses_allowed_html( 'post' ), 'post', $context ) );
}

代码解释:

  • my_allow_data_attributes 函数:
    • 遍历所有允许的标签,并为每个标签添加 data-* 属性。
  • render_my_custom_block 函数:
    • 在渲染区块内容时,我们使用了一个带有 data-my-custom-data 属性的 <div> 标签。
    • 同样,我们传递了context 参数。

案例3:更优雅的传递Context

上面的案例使用$_GET参数传递context,这在实际开发中可能不太方便。 我们可以使用其他方式传递context,例如自定义的区块属性或元数据。

// 在你的 Gutenberg 区块注册代码中:
register_block_type( 'my-plugin/my-custom-block', array(
    'attributes'      => array(
        'context' => array(
            'type' => 'string',
            'default' => '',
        ),
        // ... 其他属性
    ),
    'render_callback' => 'render_my_custom_block',
) );

function render_my_custom_block( $attributes ) {
    $context = isset( $attributes['context'] ) ? $attributes['context'] : '';
    // ...
    return wp_kses( '<p>Content</p>', apply_filters( 'wp_kses_allowed_html', wp_kses_allowed_html( 'post' ), 'post', array('context' => $context) ) );
}

add_filter( 'wp_kses_allowed_html', 'my_allow_custom_tags', 10, 2 );

function my_allow_custom_tags( $allowed_tags, $context ) {
  if ( isset($context['context']) && $context['context'] === 'my-custom-block-context' ) {
    $allowed_tags['mycustomtag'] = array(); //允许自定义标签<mycustomtag>
  }
  return $allowed_tags;
}

在这个例子中,我们在区块属性中添加了一个context 属性。 这样,我们就可以在编辑区块时设置context 的值,并在渲染区块内容时直接从属性中获取context

四、注意事项

  • 安全第一: 即使允许了某些HTML标签,也要确保对标签的属性进行适当的验证和转义,防止XSS攻击。 特别是对于URL、JavaScript代码等,要格外小心。
  • 性能: 频繁地修改wp_kses_allowed_html 可能会影响性能。 尽量避免在前端频繁修改,或者使用缓存机制。
  • 兼容性: 修改wp_kses_allowed_html 可能会影响其他插件或主题的功能。 在修改之前,最好进行充分的测试。
  • Context 的传递方式: 选择合适的context传递方式。 可以使用$_GET 参数、区块属性、元数据等。 关键是要确保在过滤器函数中能够正确获取到context信息。

五、总结

wp_kses_allowed_html 过滤器是一个强大的工具,可以让我们自定义WordPress允许的HTML标签。 在Gutenberg时代,我们可以利用这个过滤器,针对特定的区块类型,允许特定的HTML标签,从而实现更灵活的内容编辑和展示。 但是,在使用这个过滤器时,一定要注意安全和性能,并进行充分的测试。

希望今天的讲座对大家有所帮助。 如果有什么问题,欢迎提问。

下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注