{"id":400898,"date":"2026-11-11T11:58:22","date_gmt":"2026-11-11T11:58:22","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/custom-block-attributes\/"},"modified":"2026-11-12T11:12:42","modified_gmt":"2026-11-12T11:12:42","slug":"mtwdev-custom-html-attributes-for-blocks","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/mtwdev-custom-html-attributes-for-blocks\/","author":23594101,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.2","stable_tag":"1.1.2","tested":"7.1.4","requires":"6.6","requires_php":"7.4","requires_plugins":null,"header_name":"mtwdev Custom HTML Attributes for Blocks","header_author":"Marco Torres Walker (mtwdev)","header_description":"Easily add custom HTML attributes (data-*, aria-*, boolean, and key-value pairs) to any Gutenberg block with active security, quick presets, and native rendering.","last_updated":"2026-11-12 11:12:42","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/mtwdeveloper\/mtwdev-custom-attributes","header_author_uri":"https:\/\/mtwdev.com\/","rating":0,"author_block_rating":0,"active_installs":0,"downloads":146,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.0":{"tag":"1.1.0","author":"mtwdev","date":"2026-11-11 11:58:14","revision":3796225},"1.1.1":{"tag":"1.1.1","author":"mtwdev","date":"2026-11-11 12:19:17","revision":3796262},"1.1.2":{"tag":"1.1.2","author":"mtwdev","date":"2026-11-12 11:12:42","revision":3798131}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3796262,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3796262,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3796225,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3796262,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.0","1.1.1","1.1.2"],"block_files":[],"assets_screenshots":{"screenshot-1.jpg":{"filename":"screenshot-1.jpg","revision":3796225,"resolution":"1","location":"assets","locale":"","width":1070,"height":1285},"screenshot-2.jpg":{"filename":"screenshot-2.jpg","revision":3796225,"resolution":"2","location":"assets","locale":"","width":3044,"height":1577},"screenshot-3.jpg":{"filename":"screenshot-3.jpg","revision":3796225,"resolution":"3","location":"assets","locale":"","width":3057,"height":779}},"screenshots":{"1":"The <strong>Custom HTML Attributes<\/strong> control inside the native <em>Advanced<\/em> panel of the block settings sidebar.","2":"A block with key-value attributes (<code>data-track<\/code>, <code>aria-label<\/code>) and boolean attributes (<code>download<\/code>) configured.","3":"The rendered front-end markup with the attributes injected into the block's opening tag."}},"plugin_section":[],"plugin_tags":[1953,9032,180937,148076,246],"plugin_category":[34],"plugin_contributors":[292023],"plugin_business_model":[],"class_list":["post-400898","plugin","type-plugin","status-publish","hentry","plugin_tags-accessibility","plugin_tags-attributes","plugin_tags-data-attributes","plugin_tags-gutenberg","plugin_tags-html","plugin_category-accessibility","plugin_contributors-mtwdev","plugin_committers-mtwdev"],"banners":{"banner":"https:\/\/ps.w.org\/mtwdev-custom-html-attributes-for-blocks\/assets\/banner-772x250.png?rev=3796262","banner_2x":"https:\/\/ps.w.org\/mtwdev-custom-html-attributes-for-blocks\/assets\/banner-1544x500.png?rev=3796225","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/mtwdev-custom-html-attributes-for-blocks\/assets\/icon-128x128.png?rev=3796262","icon_2x":"https:\/\/ps.w.org\/mtwdev-custom-html-attributes-for-blocks\/assets\/icon-256x256.png?rev=3796262","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/mtwdev-custom-html-attributes-for-blocks\/assets\/screenshot-1.jpg?rev=3796225","caption":"The <strong>Custom HTML Attributes<\/strong> control inside the native <em>Advanced<\/em> panel of the block settings sidebar."},{"src":"https:\/\/ps.w.org\/mtwdev-custom-html-attributes-for-blocks\/assets\/screenshot-2.jpg?rev=3796225","caption":"A block with key-value attributes (<code>data-track<\/code>, <code>aria-label<\/code>) and boolean attributes (<code>download<\/code>) configured."},{"src":"https:\/\/ps.w.org\/mtwdev-custom-html-attributes-for-blocks\/assets\/screenshot-3.jpg?rev=3796225","caption":"The rendered front-end markup with the attributes injected into the block's opening tag."}],"raw_content":"<!--section=description-->\n<p><strong>Custom HTML Attributes for Blocks<\/strong> is a lightweight extension for the WordPress Block Editor (Gutenberg) that allows site editors and developers to inject standard and custom HTML attributes into any supported block.<\/p>\n\n<p>Whether you need to add custom attributes for analytics tracking (<code>data-track-event=\"click\"<\/code>), improve accessibility (<code>aria-label<\/code>, <code>aria-describedby<\/code>, <code>role<\/code>), or use modern HTML5 boolean attributes (<code>download<\/code>, <code>inert<\/code>), this plugin provides an intuitive, high-performance interface directly within the native Gutenberg <strong>Advanced<\/strong> panel.<\/p>\n\n<h3>Key Features<\/h3>\n\n<ul>\n<li><strong>Native Block Inspector Integration:<\/strong> Seamlessly placed in the block settings sidebar (Advanced panel) without intrusive floating buttons or separate inspectors.<\/li>\n<li><strong>Quick Presets Bar:<\/strong> One-click shortcuts for commonly used attributes (<code>data-*<\/code>, <code>aria-label<\/code>, <code>title<\/code>, <code>download<\/code>, <code>role<\/code>, <code>tabindex<\/code>, <code>inert<\/code>).<\/li>\n<li><strong>Clean Boolean Attribute Support:<\/strong> True HTML5 boolean attributes rendered cleanly without empty quotes or values (<code>download<\/code>, <code>inert<\/code>).<\/li>\n<li><strong>Allow-List Validation:<\/strong> Only <code>data-*<\/code>, <code>aria-*<\/code>, and a documented set of standard attributes (<code>role<\/code>, <code>title<\/code>, <code>tabindex<\/code>, <code>lang<\/code>, <code>dir<\/code>, <code>inert<\/code>, <code>hidden<\/code>, <code>download<\/code>, <code>rel<\/code>, <code>target<\/code>, <code>name<\/code>, <code>for<\/code>, <code>autocomplete<\/code>, <code>xml:lang<\/code>) are injected. URL-bearing and namespace attributes (<code>href<\/code>, <code>src<\/code>, <code>xmlns:*<\/code>, <code>xlink:*<\/code>) are always refused.<\/li>\n<li><strong>Multi-Layer Security Hardening:<\/strong>\n\n<ul>\n<li>Automatic blocking of inline JavaScript event handlers (any name starting with <code>on<\/code>, see the FAQ).<\/li>\n<li>Deep validation against dangerous pseudo-protocols (<code>javascript:<\/code>, <code>vbscript:<\/code>, <code>data:text\/html<\/code>).<\/li>\n<li>Blocked modification of reserved layout and style attributes (<code>class<\/code>, <code>id<\/code>, <code>style<\/code>).<\/li>\n<li>Capability check (<code>unfiltered_html<\/code>, fully customizable via filter) enforced on save for every post type and editor through <code>parse_blocks()<\/code>\/<code>serialize_blocks()<\/code>.<\/li>\n<\/ul><\/li>\n<li><strong>Zero Frontend Bloat:<\/strong> Enqueues zero extra CSS or JS files on the frontend. Attribute injection is handled dynamically at render time via WordPress core's native <code>WP_HTML_Tag_Processor<\/code>.<\/li>\n<li><strong>Zero Block Invalidation:<\/strong> Attributes are stored safely in block metadata. Disabling the plugin will never break or invalidate your blocks.<\/li>\n<li><strong>Translatable:<\/strong> Every string uses the plugin text domain and is ready for the community translations published as language packs on translate.wordpress.org. A <code>.pot<\/code> template ships in <code>languages\/<\/code>.<\/li>\n<li><strong>Fully Extensible:<\/strong> Customizable via PHP filters for developers and agencies.<\/li>\n<\/ul>\n\n<h3>Source Code<\/h3>\n\n<p>The plugin ships with its compiled assets (<code>build\/<\/code>). The human-readable source of every compiled file is available in the public repository: <a href=\"https:\/\/github.com\/mtwdeveloper\/mtwdev-custom-attributes\">https:\/\/github.com\/mtwdeveloper\/mtwdev-custom-attributes<\/a>. It is also included in the distributed ZIP (<code>src\/<\/code>), together with the build configuration (<code>package.json<\/code>).<\/p>\n\n<h3>Developer Extensibility &amp; Hooks<\/h3>\n\n<ul>\n<li><code>mtwdev_custom_attributes_capability<\/code>: Customize the required user capability (default: <code>unfiltered_html<\/code>).<\/li>\n<li><code>mtwdev_custom_attributes_allowed<\/code>: Extend the allowed attribute names and prefixes.<\/li>\n<li><code>mtwdev_custom_attributes_unsupported_blocks<\/code>: Add or remove block slugs that should not allow custom attributes.<\/li>\n<li><code>mtwdev_custom_attributes_disallowed<\/code>: Extend the additional disallowed HTML attribute blacklist.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>mtwdev-custom-html-attributes-for-blocks<\/code> directory to your <code>\/wp-content\/plugins\/<\/code> directory, or install directly through the WordPress plugin installer.<\/li>\n<li>Activate the plugin via the <strong>Plugins<\/strong> menu in WordPress.<\/li>\n<li>Edit any post, page, or template in the Block Editor, select a block, and expand the <strong>Advanced<\/strong> panel in the right sidebar to configure your attributes.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20plugin%20affect%20frontend%20page%20load%20speed%3F\"><h3>Does this plugin affect frontend page load speed?<\/h3><\/dt>\n<dd><p>No. The plugin enqueues zero additional CSS or JS files on the frontend. Attribute injection is handled dynamically via WordPress core's native <code>WP_HTML_Tag_Processor<\/code> during the <code>render_block<\/code> filter in less than 0.1 ms.<\/p><\/dd>\n<dt id=\"which%20attributes%20can%20i%20add%3F\"><h3>Which attributes can I add?<\/h3><\/dt>\n<dd><p>Any <code>data-*<\/code> and <code>aria-*<\/code> attribute, plus <code>role<\/code>, <code>title<\/code>, <code>tabindex<\/code>, <code>lang<\/code>, <code>dir<\/code>, <code>inert<\/code>, <code>hidden<\/code>, <code>download<\/code>, <code>rel<\/code>, <code>target<\/code>, <code>name<\/code>, <code>for<\/code>, <code>autocomplete<\/code> and <code>xml:lang<\/code>. The list can be extended with the <code>mtwdev_custom_attributes_allowed<\/code> filter. Attribute names outside the list are refused, both in the editor and when rendering.<\/p><\/dd>\n<dt id=\"why%20is%20an%20attribute%20like%20%60onboarding-label%60%20rejected%3F\"><h3>Why is an attribute like `onboarding-label` rejected?<\/h3><\/dt>\n<dd><p>Every name starting with <code>on<\/code> is treated as a potential inline event handler and blocked, because that is the prefix browsers use for event attributes (<code>onclick<\/code>, <code>onerror<\/code>, ...). Use a <code>data-<\/code> attribute instead, e.g. <code>data-onboarding-label<\/code>.<\/p><\/dd>\n<dt id=\"can%20i%20use%20this%20to%20add%20onclick%20or%20javascript%20event%20attributes%3F\"><h3>Can I use this to add onclick or JavaScript event attributes?<\/h3><\/dt>\n<dd><p>No. For security reasons and to strictly comply with WordPress.org guidelines and XSS prevention, inline event handlers starting with <code>on*<\/code> are disallowed.<\/p><\/dd>\n<dt id=\"are%20the%20attributes%20visible%20in%20the%20editor%20canvas%3F\"><h3>Are the attributes visible in the editor canvas?<\/h3><\/dt>\n<dd><p>The block editor builds its markup in JavaScript, so the attributes are applied by PHP at render time: you will see them on the front end, in server-side previews requested through the REST API (where <code>is_admin()<\/code> is false), in feeds and in block templates, but not in the JavaScript editor canvas.<\/p><\/dd>\n<dt id=\"can%20i%20change%20the%20capability%20required%20to%20edit%20attributes%3F\"><h3>Can I change the capability required to edit attributes?<\/h3><\/dt>\n<dd><p>Yes. You can use the <code>mtwdev_custom_attributes_capability<\/code> filter in a custom plugin or your theme functions:<\/p>\n\n<pre><code>add_filter('mtwdev_custom_attributes_capability', function() { return 'edit_posts'; });\n<\/code><\/pre><\/dd>\n<dt id=\"does%20it%20work%20with%20third-party%20blocks%3F\"><h3>Does it work with third-party blocks?<\/h3><\/dt>\n<dd><p>Yes. The plugin applies to all registered WordPress blocks that support block attributes.<\/p><\/dd>\n<dt id=\"in%20which%20languages%20is%20it%20available%3F\"><h3>In which languages is it available?<\/h3><\/dt>\n<dd><p>The source strings are English. Translations are handled by the WordPress.org translation platform (translate.wordpress.org), so any locale with an approved translation is served automatically as a language pack. The plugin itself bundles no <code>.po<\/code>\/<code>.mo<\/code>\/<code>.json<\/code> files.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Fix: Unified text domain across JavaScript and PHP to match the plugin slug for GlotPress language packs compatibility.<\/li>\n<li>i18n: Added Spanish translation support and refreshed the translation template.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Name and slug changed to mtwdev-custom-html-attributes-for-blocks.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Security: attribute validation is now an allow list instead of a deny list; <code>xmlns:*<\/code>, <code>xlink:*<\/code>, <code>href<\/code>, <code>src<\/code> and unknown names no longer reach the markup.<\/li>\n<li>Security: unauthorized saves are sanitized with <code>parse_blocks()<\/code>\/<code>serialize_blocks()<\/code> on <code>content_save_pre<\/code>, replacing the <code>pre_kses<\/code> regex that corrupted the block JSON when a value contained <code>]<\/code>.<\/li>\n<li>Security: the save-time check covers every post type and every editor path (block editor REST, classic editor, XML-RPC, imports), not just posts over REST.<\/li>\n<li>Editor: the dead <code>blocks.registerBlockTypeAttributes<\/code> filter was replaced by the real <code>blocks.registerBlockType<\/code>, so blocks registered only in JavaScript keep their attributes.<\/li>\n<li>Editor: the <code>data-*<\/code>\/<code>aria-*<\/code> presets now report an incomplete name instead of creating a valueless attribute.<\/li>\n<li>Editor: block editor data is passed with <code>wp_add_inline_script()<\/code> + <code>wp_json_encode()<\/code> instead of <code>wp_localize_script()<\/code>.<\/li>\n<li>i18n: translations are delivered as language packs from translate.wordpress.org; bundled <code>.po<\/code>, <code>.mo<\/code> and script <code>.json<\/code> files were removed and <code>load_plugin_textdomain()<\/code> is no longer needed.<\/li>\n<li>Docs: corrected changelog, screenshots section, allow-list documentation and the development\/release workflow.<\/li>\n<li>Compatibility: <code>Requires at least: 6.6<\/code> (the compiled editor bundle loads <code>react-jsx-runtime<\/code>), <code>Tested up to: 7.1<\/code>.<\/li>\n<li>Tests: 11 JavaScript tests and 77 PHP tests.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Optimized injection using native WordPress core <code>WP_HTML_Tag_Processor<\/code> with early bailouts.<\/li>\n<li>Seamless integration into Gutenberg's native Advanced panel.<\/li>\n<li>Quick presets bar and full boolean attribute support.<\/li>\n<li>Full internationalization support with English source strings.<\/li>\n<\/ul>","raw_excerpt":"Easily add custom HTML attributes (data-*, aria-*, boolean, and key-value pairs) to any Gutenberg block with active security and native rendering.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/400898","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=400898"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/mtwdev"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=400898"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=400898"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=400898"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=400898"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=400898"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=400898"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}