=== JuZ Rich Text Extender === Contributors: juzed Tags: rich text, gutenberg, inline formats, toolbar Requires at least: 6.1 Tested up to: 6.9 Requires PHP: 7.0 Stable tag: 1.0.0 License: GPL-2.0+ License URI: http://www.gnu.org/licenses/gpl-2.0.txt Extends the Gutenberg block editor toolbar with custom inline format buttons, with smart nesting validation based on HTML spec rules. == 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. `` inside ``). 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. == 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. == Frequently Asked Questions == = 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 `` 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 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 `` while already inside an `` 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 `` tags internally via its own `core/link` format, which makes it unreliable to apply a custom ``-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 (`text`), survives the HTML ↔ visual editor round-trip without issues, and is supported by all modern browsers. == Screenshots == 1. Custom inline format buttons added to the Gutenberg toolbar. 2. A button is automatically disabled when its nesting would be invalid. == 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. == Upgrade Notice == = 1.0.0 = Initial release — no upgrade steps required.