WordPress wp_kses Example: Allow Safe Custom HTML in Plugin Output
Use wp_kses with a narrow allowlist so plugin output supports limited formatting without trusting arbitrary HTML.
Published
April 24, 2026
Reading Time
2 min read
Updated
April 24, 2026

Hardening Notes
Baselines, access reduction, and default settings that stand up in production.
Best For
Teams preparing, launching, or maintaining WordPress as a backend service in a production stack.
Primary Topics
Editorial Focus
Control Ledger: Baselines, access reduction, and default settings that stand up in production. Updated on April 24, 2026.
Full Report
Last reviewed: April 24, 2026
Escaping output is not enough when a plugin intentionally allows limited HTML. A callout component, notice banner, or custom field may need links, emphasis, and line breaks, but that does not mean arbitrary HTML should pass straight through.
This guide shows how to use wp_kses() to allow a small set of safe tags in plugin output without opening the door to script injection or sloppy markup rules.
Start with a narrow allowlist
<?php
function vulnwp_allowed_notice_html() {
return array(
'a' => array(
'href' => true,
'target' => true,
'rel' => true,
),
'strong' => array(),
'em' => array(),
'br' => array(),
'code' => array(),
);
}
The allowlist should describe exactly what the feature needs, not what HTML happens to be convenient to support today.
Sanitize before rendering
$raw_notice = get_option( 'vulnwp_notice_html', '' );
echo wp_kses( $raw_notice, vulnwp_allowed_notice_html() );
wp_kses() removes tags and attributes that are not in the allowlist. That gives you controlled formatting without trusting the stored HTML blindly.
Use wp_kses_post only when post-style content is expected
If the content is truly post-like and should allow the same HTML WordPress allows in post bodies, wp_kses_post() may be appropriate. For plugin options and admin-configured snippets, a custom allowlist is usually better because it is much smaller and easier to audit.
$safe = wp_kses_post( $raw_post_like_fragment );
That is broader than a custom allowlist, so use it only when the feature genuinely needs post-style markup.
Pair sanitization with admin guidance
If editors can enter allowed HTML, document the supported tags in the UI. That reduces confusion and prevents support tickets caused by stripped markup.
echo '<p class=\"description\">' . esc_html__( 'Allowed tags: a, strong, em, br, code.', 'vulnwp' ) . '</p>';
Production checklist
- Prefer the smallest possible allowlist.
- Sanitize at render time, even if the value was sanitized earlier.
- Use
esc_url()and targeted validation when link destinations have extra rules. - Document supported tags in the UI.
- Do not allow style, script, or event handler attributes.
- Review new tags before adding them permanently.
Common mistakes
- Allowing too many tags. Bigger allowlists are harder to reason about.
- Escaping and sanitizing interchangeably. They solve different problems.
- Trusting saved admin content completely. Stored options can still be dangerous.
- Allowing
targetwithout handlingrel. External links need deliberate rules. - Using
wp_kses_post()for tiny UI snippets. That is often broader than necessary.
Related reading
If the HTML appears inside a shortcode or widget output, pair this with the shortcode example. If the content is saved from an admin form, combine it with the admin_post handler guide once that flow exists in your plugin.


