JuZ Rich Text Extender

Description

JuZ Rich Text Extender allows developers to register custom inline format buttons in the Gutenberg (block editor) toolbar. Each button applies a specific HTML inline tag with an optional CSS class to the selected text.

The plugin includes a built-in nesting validation system: buttons are automatically disabled when their use would produce invalid HTML nesting (e.g. <a> inside <a>). When a format is already active, its button remains enabled so it can always be toggled off.

Key features:

  • Register custom inline formats (tag + CSS class) via a WordPress filter
  • tagName defaults to span, which is strongly recommended for compatibility
  • Smart nesting validation against the full active tag stack (for non-span tags)
  • Buttons are visually disabled when nesting is not allowed
  • Exhaustive inline tag ruleset (span, a, strong, em, mark, code, u, s, i, b, q, cite, abbr, small, sub, sup)
  • Inline tag rules are filterable for full customisation by themes or other plugins

For developers:

Formats and inline tag rules are both exposed via WordPress filters, making the plugin fully extensible without modifying core files.

Screenshots

  • Custom inline format buttons added to the Gutenberg toolbar.

Installation

  1. Upload the juz-rich-text-extender folder to the /wp-content/plugins/ directory.
  2. Activate the plugin through the Plugins menu in WordPress.
  3. Use the juz_rich_text_extender/formats filter to register your custom inline formats.

FAQ

How do I register a custom format?

Use the juz_rich_text_extender/formats filter to add your formats. Each format must be an associative array with the following keys:

  • name – unique identifier (used as the format type slug)
  • title – label shown in the toolbar tooltip
  • tagName – HTML inline tag to apply. Optional, defaults to span. See the caution note below.
  • className – CSS class applied to the tag
  • icon – a Dashicon slug or SVG string

Example:

add_filter( 'juz_rich_text_extender/formats', function( $formats ) {
    $formats[] = [
        'name'      => 'highlight',
        'title'     => __( 'Highlight', 'your-text-domain' ),
        'className' => 'my-highlight',
        'icon'      => 'editor-textcolor',
    ];
    return $formats;
} );

CAUTION: tagName is optional and defaults to span, which is strongly recommended. Using any other tag may produce invalid HTML nesting or conflict with Gutenberg’s internal formats (e.g. core/link for <a> tags). If you do specify a custom tag, the nesting validation system will still protect against invalid HTML where possible, but you may encounter editor limitations. See “How do I apply a custom class to a link?” for more details.

How do I customise the inline tag nesting rules?

Use the juz_rich_text_extender/inline_tags filter. Each tag entry has three keys: canSelfNest (bool), canNestIn (array of tag names), and canContain (array of tag names).

Example:

add_filter( 'juz_rich_text_extender/inline_tags', function( $tags ) {
    // Allow <kbd> as a custom inline tag
    $tags['kbd'] = [
        'canSelfNest' => false,
        'canNestIn'   => [ 'p', 'li', 'span', 'strong', 'em' ],
        'canContain'  => [],
    ];
    return $tags;
} );

Why is a button greyed out in the toolbar?

The nesting validation system detected that applying this format at the current cursor position would produce invalid HTML. For example, clicking <a> while already inside an <a> tag is forbidden by the HTML specification, so the button is disabled. This validation only applies to formats using a non-span tagName.

Can I override nesting rules for an existing tag?

Yes. Use the juz_rich_text_extender/inline_tags filter and modify the entry for the tag you want to change before returning the array.

How do I apply a custom class to a link?

Gutenberg manages <a> tags internally via its own core/link format, which makes it unreliable to apply a custom <a>-based format on top of an existing link. The recommended approach is to leave tagName unset (defaults to span) and target it in CSS using the :has() selector:

add_filter( 'juz_rich_text_extender/formats', function( $formats ) {
    $formats[] = [
        'name'      => 'button',
        'title'     => __( 'Button', 'your-text-domain' ),
        'className' => 'btn',
        'icon'      => 'button',
    ];
    return $formats;
} );

Then in your CSS:

a:has(> .btn) {
    display: inline-block;
    padding: 0.5em 1em;
    background: #0073aa;
    color: #fff;
    border-radius: 4px;
    text-decoration: none;
}

This approach produces valid HTML (<a href="..."><span class="btn">text</span></a>), survives the HTML visual editor round-trip without issues, and is supported by all modern browsers.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“JuZ Rich Text Extender” is open source software. The following people have contributed to this plugin.

Contributors

Changelog

1.0.0

  • Initial release.
  • Custom inline format registration via filter.
  • tagName defaults to span for maximum compatibility.
  • Smart nesting validation on the full active tag stack for non-span tags.
  • Exhaustive inline tag ruleset covering all standard HTML inline elements.
  • Filterable inline tag rules for themes and plugins.