Allow HTML in Category and Tag Descriptions

By default, WordPress strips most HTML from category and tag descriptions when you save them. Only a short list of inline tags survives, so headings, lists, images and paragraphs with classes disappear the moment you click Update.

That gets in the way when you use category pages as landing pages with real intro content, which is one of the easier ways to optimize category pages for SEO. The snippet below allows HTML in category, tag and custom taxonomy descriptions.

The Code

Add this code to your child theme’s functions.php file or to a custom plugin:

/**
 * Allow HTML in term (category, tag) descriptions
 */
foreach ( array( 'pre_term_description' ) as $filter ) {
	remove_filter( $filter, 'wp_filter_kses' );
	if ( ! current_user_can( 'unfiltered_html' ) ) {
		add_filter( $filter, 'wp_filter_post_kses' );
	}
}

foreach ( array( 'term_description' ) as $filter ) {
	remove_filter( $filter, 'wp_kses_data' );
}

How It Works

WordPress sanitizes term descriptions with two filters, and the snippet removes both. Learn more about adding and removing filters in WordPress Hooks Explained.

  • pre_term_description runs before the description is saved. Core attaches wp_filter_kses here, which strips everything except a few basic tags.
  • term_description runs when the description is displayed. In the admin only, core adds wp_kses_data, which would strip the HTML again in the terms list table.

The current_user_can( 'unfiltered_html' ) check keeps it safe. Users with that capability can save any HTML, just like in the post editor.

Everyone else who can edit terms gets wp_filter_post_kses, the allowlist WordPress uses for post content. Tags like <h2>, <ul> and <img> work but <script> doesn’t.

Don’t remove wp_filter_kses without adding the fallback. That would let any user who can edit terms save scripts that run for every visitor.

What Changes After You Add It

The filters apply to every taxonomy, so the snippet covers categories, tags, custom taxonomies and WooCommerce product categories.

Situation Allowed HTML
Default, all users a, abbr, acronym, b, blockquote, cite, code, del, em, i, q, s, strike, strong
With the snippet, users with unfiltered_html Any HTML
With the snippet, other users The post content allowlist

Keep three things in mind:

  • Old descriptions aren’t restored. HTML was stripped before it reached the database, so re-enter it after adding the code.
  • On multisite, only super admins have unfiltered_html. Site admins get the post allowlist. The same applies to everyone if DISALLOW_UNFILTERED_HTML is set in wp-config.php.
  • Your theme has to print the description. term_description(), the_archive_description() and the Term Description block all output the stored HTML. A theme that escapes the description will show the tags as text.

If you’re building your own taxonomies, see how to create and query custom taxonomies. The wp_filter_kses() reference documents the sanitizer this snippet replaces.

FAQs

Common questions about HTML in category and tag descriptions:

Why does WordPress remove HTML from category descriptions?
Core runs wp_filter_kses on pre_term_description for every user, including administrators. It's a security default, and it only keeps basic inline tags such as links, bold and italics.
Does this work for WooCommerce product categories?
Yes. pre_term_description and term_description run for every taxonomy, including product_cat and product_tag. On product archives WooCommerce prints the description through wp_kses_post(), so scripts are removed there even if an admin saved them.
Does this add a visual editor to the description field?
No. The field stays a plain textarea, and you type the HTML yourself. The snippet only stops WordPress from stripping it.
Discussion
[  0 Comments  ]

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!