Starting with version 5 the HTML standard allows <a> tags wrap block-level elements. On a specific page I need to wrap a heading and an image with an <a> tag:

Some intro text.

  <a href="http://somewhere/">
    <h4>Some heading</h4>
    <img src="http://somewhere/some-img.jpg" alt="Some image" />

While I can enter this in the text editor it causes some strange behavior:

The code above will be transformed into this HTML code:

<p>Some intro text.</p>
<a href="http://somewhere/"></p>
<h4>Some heading</h4>
<p><img src="http://somewhere/some-img.jpg" alt="Some image" /><br />

Obviously, the opening <a> followed by a closing </p> for a never opened <p> is plain wrong. Also there's some non-closed <p> tag before the <img> tag.

Since this seems to be a newline-related issue, I tried to remove newlines from my Wordpress code:

Some intro text.

<div><a href="http://somewhere/"><h4>Some heading</h4><img src="http://somewhere/some-img.jpg" alt="Some image" /></a></div>

Interestingly, this results in the following HTML code:

<p>Some intro text.</p>
<div><a href="http://somewhere/"><br />
<h4>Some heading</h4>
<p><img src="http://somewhere/some-img.jpg" alt="Some image" /></a></div>

Now, there's still a closing </p> tag missing after the <img>. (Okay, HTML5 accepts non-closed <p> tags... but I don't think that this behavior is used intentionally here.) Also, Wordpress introduces a <br /> that comes out of nowhere.

So far to the Wordpress-related issues...

Now to the TinyMCE-related issues:

When switching back from the text edit mode in Wordpress to the visual edit mode, the <a>s are still there. However, when switching back to text mode again (or saving the page from visual edit mode) the <a>s get completely removed.

Having this explained, let's come to my main question: How can I make Wordpress and TinyMCE accept <a> tags wrapping block-level elements?

Here's what I've already tried:

I also found the ticket "Block <a> tags are getting stripped from the Editor", but don't really understand if stripping <a> tags is considered intentional behavior there.

  • Your issue is due wpautop
    – cybmeta
    Aug 20, 2014 at 14:11
  • Thanks for the information. So would adding a to wpautop's $allblocks variable help me here? Can I modify this variable somehow in a clean way without actually changing a Wordpress core file, e.g. via hooks?
    – Hauke P.
    Aug 20, 2014 at 15:37

2 Answers 2


A few years down the track, but hopefully someone else will find this solution useful...

Although my issues trying to get this sort of thing to work in Wordpress were slightly different, hopefully this solution will work for you too.

Firstly, the issue with tags not being allowed to contain multiple block level elements was solved by adding the following code from this article to my functions.php file...

function allow_all_tinymce_elements_attributes( $init ) {

    // Allow all elements and all attributes
    $ext = '*[*]';

    // Add to extended_valid_elements if it already exists
    if ( isset( $init['extended_valid_elements'] ) ) {
        $init['extended_valid_elements'] .= ',' . $ext;
    } else {
        $init['extended_valid_elements'] = $ext;

    // return value
    return $init;

add_filter('tiny_mce_before_init', 'allow_all_tinymce_elements_attributes');

... and then making sure that my tag is given a name. This allowed me to enter and successfully save the following in the Text tab...

Some text.
<a href="https://somewhere.com/product/this_prod/" name="link">
Cost efficient Blablabla</a>

For the second issue, of code being stripped when switching from the "text" to the "visual" tab, I simply turned off the visual tab for a particular post type. I adapted the initial code found in this article, which originally targeted a post ID instead of a post type. I added this code to my functions.php file...

add_filter('user_can_richedit', 'disable_wyswyg_to_preserve_my_markup');
function disable_wyswyg_to_preserve_my_markup( $default ){
  if( get_post_type() == 'product') return false;
  return $default;

If this doesn't work for a custom post type, you could try adding the following line above the previous code...

add_theme_support( 'post-formats', 'my_custom_post_type' );

Or, to solve this second issue, you could alternatively try a plugin such as this one.


I’ve always done this via shortcode. Eg...

[b_link url="http://example.com"]<h4>Stuff</h4><p>Yadda yaddas</p>[/b_link]

(Don’t have code to hand and on mobile but can provide tomorrow if required.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.