This is pretty much an exact duplicate of: How to make Wordpress and TinyMCE accept <a> tags wrapping block-level elements as allowed in HTML5? and HTML5, WordPress and Tiny MCE issue - wrapping anchor tag around div results in funky output

My problem is that the suggested solution (tiny_mce_before_init filter) doesn't seem to solve my problem. I have HTML that looks like this:

<a href="#">
    <img src="path/to/file.jpg" />
    <p>Some amazing descriptive text</p>

The is perfectly legal in HTML5. However, the WP editor doesn't like it and transforms it to:

<a href="#">
    <img src="path/to/file.jpg" />
<p>Some amazing descriptive text</p>

This, of course, breaks my layout. Does anyone know of a way I can prevent this behavior? I can't give up the Visual component of the editor and stick to plain text. Any suggestions are welcome.

Just to be clear, when I use the code below (suggested here), the <p> tags are allowed to remain inside the anchors but a lot of extra space is added along with an &nbsp; entity which multiplies every time you switch between Visual and Text mode.

add_filter('tiny_mce_before_init', 'modify_valid_children');

function modify_valid_children($settings){
    return $settings;

2 Answers 2


Regardless of what you have configured as valid children, WordPress handles p tags as well as line breaks in a very unique way. You'll probably notice eventually, if you haven't already, that when switching from the text editor to the visual editor and back that your <p> tags get stripped, similar to what occurs on the frontend. A way to block this from happening is by giving the <p> tags a custom class.

<p class="text">This p tag won't get removed"</p>.

While this will keep your p tag from getting stripped, it won't fix your issue as your markup on the frontend still gets mucked up. You could DISABLE wpautop. If you do that AND have p included in valid children, this WILL FIX YOUR ISSSUE.

OPTION 1 : Disable Autop and Set Valid Children

remove_filter( 'the_content', 'wpautop' );
add_filter('tiny_mce_before_init', 'modify_valid_children', 99);
function modify_valid_children($settings){     
    return $settings;

I should warn you though that the second you switch from the HTML editor back to TinyMCE your HTML will get destroyed. A workaround is to disable TinyMCE altogether for certain post types as in option 2 below.

OPTION 2 : Disable Auto P, TinyMCE, and Set Valid Children

remove_filter( 'the_content', 'wpautop' );
add_filter('tiny_mce_before_init', 'modify_valid_children', 99);
function modify_valid_children($settings){     
    return $settings;
add_filter('user_can_richedit', 'disable_wyswyg_to_preserve_my_markup');
function disable_wyswyg_to_preserve_my_markup( $default ){
  if( get_post_type() === 'post') return false;
  return $default;

For most people though this is not an option.

So what other options are there? One workaround I've noticed works is to use a span tag with a class and make sure there is no white space between your HTML tags. If you do this you can use option one above and avoid having to disable TinyMCE all together. Just remember that you'll also have to add some CSS to your stylesheet to display the span correctly.

OPTION 3: Option 1 + Styled Span Tags


<a href="#"><img src="https://placehold.it/300x200?text=Don%27t+P+On+Me" alt="" /><span class="noautop">Some amazing descriptive text</span></a>

CSS in Stylesheet

.noautop {
    display: block;

Option 4: Use the built in media uploader shortcode

shortcode media uploader

I initially forgot this one, but the [caption] shortcode will look like this:

[caption id="attachment_167" align="alignnone" width="169"]
    <img class="size-medium wp-image-167" src="http://example.com/example.png" alt="" width="169" height="300" />
    awesome caption

The output will look like this:

<figure id="attachment_167" style="width: 169px" class="wp-caption alignnone">
    <img class="size-medium wp-image-167" src="http://example.com/example.png" alt="" width="169" height="300" />
    <figcaption class="wp-caption-text">Some amazing descriptive text</figcaption>

If you don't want figure tags you could use a plugin like custom content shortcode that allows you to do this:

[raw] <p>this content will not get filtered by wordpress</p> [/raw]

Why can't the editor just work how I want though?

I've spent countless hours trying to get this to work well over the past couple years. Occasionally I'll come up with a solution that works perfectly, but then WordPress will push an update that messes everything up again. The only solution I've ever found to completely work how it should, leads me to the best answer I have.

Option 5 : Preserved HTML Editor Markup Plus

So save yourself the headache and just go with this. By default, Preserved HTML Editor Markup Plus only affects new pages. If you want to change pages already created, you have to go to www.example.com/wp-admin/options-writing.php and edit the plugin settings. You'll also be able to change the default newline behavior.

Note: If you do decide to use this make sure you check the support thread when a new WordPress update gets launched. Occasionally, an change will mess things up so it's best to make sure the plugin works on the newer versions.

Extra Credit: Debugging Your Problem / Editing Other TinyMCE Options

If you want to inspect and easily edit your TinyMCE configurations manually, like you do with filters, you can install advanced TinyMCE config. It lets you view ALL of the configured TinyMCE options and edit them from a simple interface. You can also add new options just like you would with the filters. It makes things a whole lot easier to understand.

For example, I have both that and Preserved HTML Editor Markup Plus. The screenshot below is of the Advanced TinyMCE Config admin page. While the screenshot is cutting off 90% of what's really there, you can see it shows the valid children available to edit and which ones Preserved HTML Editor Markup Plus added.

TinyMCE editor

This is an extremely helpful way of not only completely customizing your editor, but also seeing what's going on. You might be even able to figure out what was causing your issue then. After looking over the parameters myself while Preserved HTML Editor Markup was enabled I saw some additional options that could be added to a custom filter.

function fix_tiny_mce_before_init( $in ) {

    // You can actually debug this without actually needing Advanced Tinymce Config enabled:
    // print_r( $in );
    // exit();

    $in[ 'force_p_newlines' ] = FALSE;
    $in[ 'remove_linebreaks' ] = FALSE;
    $in[ 'force_br_newlines' ] = FALSE;
    $in[ 'remove_trailing_nbsp' ] = FALSE;
    $in[ 'apply_source_formatting' ] = FALSE;
    $in[ 'convert_newlines_to_brs' ] = FALSE;
    $in[ 'verify_html' ] = FALSE;
    $in[ 'remove_redundant_brs' ] = FALSE;
    $in[ 'validate_children' ] = FALSE;
    $in[ 'forced_root_block' ]= FALSE;

    return $in;
add_filter( 'tiny_mce_before_init', 'fix_tiny_mce_before_init' );

Unfortunately this method didn't work. There is probably some regex or JavaScript that is happening when updating the post and/or switching between editors. If you take a look at the Preserved HTML Editor source code you can see that it does some JavaScript work on the admin side so my last bit of advice would be to check how the plugin works if you want to add this functionality in your theme.

Anyway, sorry for anyone who has gotten this far in my answer. Just thought I'd share my own experiences dealing with the WordPress editor, so others hopefully won't have to spend hours trying to figure this out like I did!

  • Thanks for catching that typo in my example HTML (I edited the question). Just to be clear, the real HTML in question does not have that issue. I will checkout the plugin you mentioned.
    – Dominic P
    Commented Jan 15, 2016 at 6:05
  • Hope this helps Dominic! One last thing I'd like to mention is that you can add captions in wordpress through the media uploader. Also, I believe that semantically the correct way to be doing this is like this. w3schools.com/tags/tag_figcaption.asp Commented Jan 15, 2016 at 19:45
  • That's an interesting thought. I hadn't considered marking it up as a figure and caption. I'll give that a try.
    – Dominic P
    Commented Jan 16, 2016 at 19:23
  • Just to close this out. I wound up using <span> tags. I hate that my markup is now white-space dependent, but it was the path of least resistance for now. I tried <figcaption> but it's a block level element, and TinyMCE wouldn't allow the <a> tags to wrap it, so I was back at square one. Thanks again for all the ideas.
    – Dominic P
    Commented Jan 16, 2016 at 22:28
  • Dominic, Check out option 4 above if you want to use the <figure>. I totally forgot that the built in caption shortcode does this by default! Commented Jan 19, 2016 at 3:43

First of all: Many thanks for Bryans excellent answer, which documents as well the difficulties he encountered.

Just as a result of own experimenting (including a bit of Bryan's suggestions), I think that the following plugin could vastly aid in consistency when swithing between html and visual editor: Advanced Editor Tools (previously TinyMCE Advanced) - https://wordpress.org/plugins/tinymce-advanced/.

At first sight, the plugin didn't do what I expected it to do. On a second turn, I found a settings parameter "preserve paragraph tags". The visual editor no longer removes <p> and <br> tags from the html editor. Even more: After switching between both editors, I found that almost all empty lines were gone and that instead many <p> and </p> are put in instead. The downside is that the visual representation in the visual editor shows some minor quirks, but that's considered a minor problem. For me counts this: You know exactly where you are with the cursor, because of nearly WYSIWYG. After all: Also without this specific setting, the visual editor has rendering flaws compared to preview/final result.

I feel that I have quite full control over spacing in text now. Even when I hit Return in the visual editor (or shift Return), the extra tags are generated. Again a downside: You only see that in the html view (and the final view) - the visual editor does not show the extra space. So what? It counts is no longer breaking my beautiful HTML!

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.