So this question has been raised many times under different flags, however I'd like to present a unified thread for an ultimate solution to this issue.
In WordPress, by default, when switching back and forth between the HTML and Visual editors in TinyMCE, certain tags are stripped out of content, and other weird functionality occurs. Two known workarounds for writing more efficient HTML code are using removing the wp_auto_p function using filters, and installing TinyMCE Advanced & enabling the "stop removing p & br tags" option.
This only works so well, unfortunately.
Take, for instance, the following example:
<h2>How does it work?</h2>
<p>In order to use jQuery Easy Columns, you must install it as you would any other jQuery plugin. First, download the zip file using the button above. After downloading the file, extract it to a location of your choice, and move the extracted folder to your server using your favorite FTP client. After moving the plugin to your server (and of course calling the jQuery source into your document), call it in on your site using the following snippet of code:</p>
<pre>
<script type="text/javascript" src="/path/to/jquery.easycolumns.js"></script>
</pre>
If I type this code into the HTML editor, with both options listed above already enabled, then when I switch between the two different editors, nothing happens, which is expected. Unfortunately, when saving, the code automatically converts to this:
<h2>How does it work?</h2>
<p>In order to use jQuery Easy Columns, you must install it as you would any other jQuery plugin. First, download the zip file using the button above. After downloading the file, extract it to a location of your choice, and move the extracted folder to your server using your favorite FTP client. After moving the plugin to your server (and of course calling the jQuery source into your document), call it in on your site using the following snippet of code:</p>
<pre>
<script type="text/javascript" src="/path/to/jquery.easycolumns.js"></script>
</pre>
As you can see, all entities inside the pre tag are converted back into actual HTML characters. Then, if I save this same post again, I get something like the following:
<h2>How does it work?</h2>
<p>In order to use jQuery Easy Columns, you must install it as you would any other jQuery plugin. First, download the zip file using the button above. After downloading the file, extract it to a location of your choice, and move the extracted folder to your server using your favorite FTP client. After moving the plugin to your server (and of course calling the jQuery source into your document), call it in on your site using the following snippet of code:</p>
<pre><br />
<script type="text/javascript" src="/path/to/jquery.easycolumns.js"></script><br />
</pre>
Note that Wordpress will actually inject br tags into the post. Needless to say, when this post has been updated a few times, when viewing it on the frontend, the display is nowhere near the intended display.
The only way I've seemed to get rid of all of the added "formatting functionality" has been to disable the Visual editor through my profile.
This is a fine solution for me, considering I'm a professional web developer. For my clients, this solution is far from elegant. My clients will, for the most part, be using the visual editor. A lot of my clients aren't very tech savvy, and sometimes need me to fix their posts when the layout breaks. This limits me to using the visual editor, as I can't change to the HTML editor without fear of breaking the layout.
Mainly, (and I think there's a large community that could benefit from this answer), what explicit steps can I follow to ensure the following:
- A post can be edited from the Visual or HTML editor.
- A post's content is not modified in any way when switching between the two tabs.
- When saving a post from the HTML editor, no extra content is added.
- When saving a post from the HTML editor, no entities are converted.
- BONUS: When saving a post from the HTML editor, any code (HTML for example) that's wrapped inside a pre tag and not already converted to entities will be automatically converted to entities.
Essentially, if we can create the aforementioned behavior in TinyMCE through the use of a third party plugin, we can quell all other questions regarding false formatting through the use of TinyMCE. I feel that many people could benefit from this.
It just seems logical that there is a certain functionality one would expect from a WYSIWIG editor, and this goes against it. According to all logic and reason, Wordpress' built in formatting functions are pretty useless with their current setup. It seems to me that if they want to use these formatting options, their best bet would be to enable one editor or the other, not both.
AND PLEASE: Don't answer this thread with workarounds and downloads for other WYSIWIG editors that 'fix' the problem. This is an underlying problem (although not truly a bug) with the Wordpress core that needs to be corrected.
EDIT: Alright, I've been working on this and I'm thinking reverse engineering will be the best way to solve this issue. So for right now, I've disabled wpautop (which just for clarity is a function that hooks into "the_content" filter to add p and br tags before the text is displayed, not when the text is saved. I think there exists some confusion as to how this function operates. wpautop isn't responsible for the changes you see happening when you switch between editor tabs. That's something entirely different.
Anyway, I've disabled wpautop, as is good practice when you use the HTML editor. From that point, I disabled the visual editor to start first with the html entity errors that are present when saving a post. Thanks to the help of one C. Bavota, I found a snippet to convert any tags in the HTML editor to their equivalent entities before displaying them on the front end of the site (credit: http://bavotasan.com/2012/convert-pre-tag-contents-to-html-entities-in-wordpress/).
#add_filter( 'the_content', 'pre_content_filter', 0 );
/**
* Converts pre tag contents to HTML entities
*
* This function is attached to the 'the_content' filter hook.
*
* @author c.bavota
*/
function pre_content_filter( $content ) {
return preg_replace_callback( '|<pre.*>(.*)</pre|isU' , 'convert_pre_entities', $content );
}
function convert_pre_entities( $matches ) {
return str_replace( $matches[1], htmlentities($matches[1] ), $matches[0] );
}
add_filter( 'the_content', 'pre_content_filter', 10, 2 );
This effectively eliminates issues with Wordpress converting all entities into tags upon save by circumventing it. Now, you can use the HTML editor, and write standard code in between "pre" tags without doing the entity conversion yourself. This takes care of all of the issues with entity conversion in Wordpress, and makes sure everything displays correctly on the front end. Now, we need to figure out what to hook into to modify the behavior experienced when clicking back and forth between tabs. Right now, it would appear that when moving from the HTML to the visual tab, the contents of the HTML tab are interpreted by javascript or something to try to provide a live update of what the content should look like. This causes the tags (which are displayed in non entity form in the HTML tab) to be processed instead of displayed. Then, when switching back to the HTML tab, it would appear that TinyMCE passes the current data along. This means when you switch back, you lose your HTML structure. We need to figure out a way to tell TinyMCE to convert everything in pre tags to it's equivalent entities before loading it into the window (essentially the backend version of what we did on the frontend but with tinymce and javascript instead of php and hooks), so that it's displayed instead of processed. Suggestions?
EDIT 2:
After some more research, converting the entities in the pre tag when they are displayed works fine for content within the pre tag, but say I have a blog post with a line like this:
"Next, we need to add this line to our HTML file: <p>Hello, World!</p>"
Looking at this line, you can tell that the code is supposed to be displayed on the site, and not parsed, however when the post is saved, these entities get decoded on the next post edit load, and on every subsequent save they are saved as raw html tags, which causes them to be parsed on the front end. The only solution I can think of so far would be to write in similar code for the "code" tag as I'm using for the pre, and then just wrap small one liners in the "code" tag, and large chunks in the "pre" tag. Anybody have any other ideas?