This Is What You Can Do When WordPress TinyMCE Won't Allow Anchor Around Block Elements
As a WordPress developer, you may have encountered a common issue where the built-in TinyMCE editor won't allow you to wrap block-level elements like <div>
or <p>
inside an <a>
tag. This can be frustrating when you need to create a specific HTML structure for your content.
The error message you might see is something like this:
The HTML you want to create is not valid as block elements (e.g. <div>
) don't go inside inline elements (<a>
). A valid alternative would be:
<a href="#"> <span></span> </a>
While the suggested solution of using a <span>
inside the <a>
tag is a valid workaround, it may not always be the best fit for your design or content requirements. In this article, we'll explore several methods you can use to overcome this limitation and inject custom options into the TinyMCE editor in WordPress.
Understanding the Issue
The reason WordPress TinyMCE doesn't allow you to wrap block-level elements inside <a>
tags is due to the way HTML structure is defined. Inline elements like <a>
are meant to contain other inline elements, while block-level elements like <div>
or <p>
are intended to be used as standalone containers.
Nesting a block element inside an inline element can lead to invalid HTML structure and potentially cause issues with layout, accessibility, and search engine optimization (SEO).
However, there may be cases where you need to create a specific HTML structure that involves wrapping a block element inside an <a>
tag, such as for creating a clickable box or card component.
Method 1: Use a Custom TinyMCE Plugin
One way to overcome the TinyMCE limitations is to create a custom plugin that injects your desired configuration options into the editor. This approach allows you to extend the functionality of TinyMCE and enable the specific HTML structures you need.
Here's an example of how you can create a WordPress plugin to add a new option to TinyMCE that allows wrapping block elements inside <a>
tags:
- Create a new WordPress plugin file, for example,
custom-tinymce.php
.
- Add the following code to the file:
<?php
/*
Plugin Name: Custom TinyMCE Options
Plugin URI: https://flowpoint.ai
Description: Adds custom options to the WordPress TinyMCE editor.
Version: 1.0
Author: Flowpoint
Author URI: https://flowpoint.ai
*/
add_filter('tiny_mce_before_init', 'add_custom_tinymce_options', 1002);
function add_custom_tinymce_options($options) {
$options['valid_children'] = '+a[div|p|h1|h2|h3|img]';
return $options;
}
In this example, the add_custom_tinymce_options
function is hooked to the tiny_mce_before_init
filter, which allows us to modify the default TinyMCE configuration options.
The key part is the $options['valid_children']
setting, which specifies that the <a>
tag can now contain block-level elements like <div>
, <p>
, <h1>
, <h2>
, <h3>
, and <img>
.
- Save the plugin file and activate it in your WordPress dashboard.
After activating the plugin, you should be able to wrap block-level elements inside <a>
tags in the TinyMCE editor without any issues.
Method 2: Use a Custom Content Filter
Another approach to solving this problem is to create a custom content filter that modifies the HTML structure before it's rendered on the front-end of your WordPress site.
Here's an example of how you can create a custom filter to allow wrapping block elements inside <a>
tags:
- Add the following code to your WordPress theme's
functions.php
file or in a custom plugin:
add_filter('the_content', 'allow_block_in_anchor');
function allow_block_in_anchor($content) {
$content = preg_replace(
'/<a([^>]+)>\\s*(<(div|p|h1|h2|h3|img)[^>]*>.*?<\\/\\3>)\\s*<\\/a>/',
'<a$1>$2</a>',
$content
);
return $content;
}
In this example, the allow_block_in_anchor
function uses a regular expression to find any <a>
tags that contain block-level elements and removes the unnecessary wrapping <a>
tags, leaving the block elements as they are.
The regular expression pattern /<a([^>]+)>\\s*(<(div|p|h1|h2|h3|img)[^>]*>.*?<\\/\\3>)\\s*<\\/a>/
looks for:
- An opening
<a>
tag with any attributes
- Whitespace (optional)
- A block-level element (
<div>
, <p>
, <h1>
, <h2>
, <h3>
, or <img>
) with any attributes
- Any content inside the block-level element
- Whitespace (optional)
- A closing
</a>
tag
The $content
variable is then updated with the modified HTML structure, and the filtered content is returned.
- Save the changes to your theme's
functions.php
file or the custom plugin, and the issue should be resolved on the front-end of your WordPress site.
Method 3: Use a JavaScript Solution
If you prefer a more client-side approach, you can use JavaScript to modify the HTML structure as the user types in the TinyMCE editor. This method involves creating a custom TinyMCE plugin that intercepts the HTML content and makes the necessary changes.
Here's an example of how you can create a custom TinyMCE plugin to allow wrapping block elements inside <a>
tags:
- Create a new file, for example,
custom-tinymce-plugin.js
, and add the following code:
(function() {
tinymce.PluginManager.add('allow_block_in_anchor', function(editor, url) {
editor.on('BeforeSetContent', function(event) {
event.content = event.content.replace(
/<a([^>]+)>(\s*<(div|p|h1|h2|h3|img)[^>]*>.*?<\/\3>)\s*<\/a>/g,
'<a$1>$2</a>'
);
});
});
})();
In this example, the custom TinyMCE plugin named allow_block_in_anchor
is registered with the TinyMCE plugin manager. The plugin listens for the BeforeSetContent
event, which is triggered whenever the content is about to be set in the editor.
The regular expression pattern used here is similar to the one in the previous method, but it's implemented in JavaScript to modify the HTML content before it's rendered in the TinyMCE editor.
- Enqueue the custom TinyMCE plugin in your WordPress theme or plugin:
add_action('init', 'enqueue_custom_tinymce_plugin');
function enqueue_custom_tinymce_plugin() {
if (!is_admin()) {
return;
}
add_filter('mce_external_plugins', 'add_custom_tinymce_plugin');
}
function add_custom_tinymce_plugin($plugins) {
$plugins['allow_block_in_anchor'] = plugin_dir_url(__FILE__) . 'custom-tinymce-plugin.js';
return $plugins;
}
In this code, the enqueue_custom_tinymce_plugin
function is hooked to the init
action, which ensures the plugin is only loaded in the WordPress admin area. The add_custom_tinymce_plugin
function then adds the custom TinyMCE plugin to the list of available plugins.
- Save the changes, and the custom TinyMCE plugin should now be active, allowing you to wrap block-level elements inside
<a>
tags in the editor.
Conclusion
In this article, we've explored three different methods to overcome the issue of WordPress TinyMCE not allowing you to wrap block-level elements inside <a>
tags. Each approach has its own advantages and use cases, so choose the one that best fits your project and development workflow.
Whether you opt for a custom TinyMCE plugin, a content filter, or a JavaScript-based solution, the key is to understand the underlying HTML structure and find a way to extend the functionality of the TinyMCE editor to meet your specific requirements.
Remember, the ability to create custom HTML structures can be a powerful tool in your WordPress development arsenal, allowing you to build more dynamic and engaging content experiences for your users. By leveraging the techniques covered in this article, you can unlock new possibilities and enhance the flexibility of your WordPress-powered websites and applications.
If you're looking for a comprehensive solution to optimize your website's conversion rates, consider Flowpoint.ai, a web analytics platform that uses AI to identify technical, UX, and content-related issues impacting your site's performance. Flowpoint can help you pinpoint and resolve the exact problems that are hindering your website's success
Get a Free AI Website Audit
Automatically identify UX and content issues affecting your conversion rates with Flowpoint's comprehensive AI-driven website audit.