I enjoy simplicity, in everything. Unnecessary complexity is evil. Have a look at my WordPress plugins.

Preserve inline JavaScript or HTML in the WP post editor

By default WordPress’ WYSIWYG editor will encode all HTML entities inside your post’s content and convert double line breaks to paragraphs. This normally means that all manually inserted HTML or JavaScript will break and if it doesn’t, it will when you switch between the ‘visual’ and ‘html’ editor in TinyMCE. Luckily, there is a small trick you can do to preserve certain parts of your post’s content just as it is.\

UPDATE (March 2013): Ben Goodyear pointed me to a post of Andy Stratton who raises a few good points on why you should not use this “raw” or “preserve” function inside your theme. Andy is right and luckily, he came up with a better solution which also looses the coupling between your content and your theme. With his plugin “Raw HTML Snippets” you can create HTML and/or JavaScript snippets which you can then easily embed inside your posts content by using a shortcode like [raw_html_snippet id="js-snippet-1"].

By adding a small hack to your theme’s functions.php file we can only call wptexturize() en wpautop() on certain parts of the content. Since there is no way to disable the TinyMCE encoding that happens when switching between ‘Visual’ and ‘HTML’ mode we need to decode the encoded HTML. Let’s say we want to add some inline JavaScript to our post. Since we need to recognize what part of the content needs to be preserved let’s wrap our inline JavaScript with a shortcode.


... post content ...

[preserve]

<script type="text/javascript">

var welcome_string = "Hello. We don't want this snippet to get messed up by wpautop() and wptexturize()";

alert(welcome_string);

</script>

[/preserve]

... some more content...

Now, inside our theme’s functions.php we’re going to remove wpautop() and wptexturize() from the_content filter and add a function of our own to the filter. This function will only call wptexturize() and wpautop() on the parts of the content that are not wrapped in our [preserve] shortcode. Most parts of this snippet come from “disable automatic formatting using a shortcode“, the only thing that has been added is the HTML decoding to revert the encoding that has been done by TinyMCE when switching modes.

function my_preserve_function($content) {
$new_content = '';
$pattern_full = '{(\[preserve\].*?\[/preserve\])}is';
$pattern_contents = '{\[preserve\](.*?)\[/preserve\]}is';
$pieces = preg_split($pattern_full, $content, -1, PREG_SPLIT_DELIM_CAPTURE);

foreach ($pieces as $piece) {
if (preg_match($pattern_contents, $piece, $matches)) {
$new_content .= html_entity_decode($matches[1]);
} else {
$new_content .= wptexturize(wpautop($piece));
}
}

return $new_content;
}

remove_filter('the_content', 'wpautop');
remove_filter('the_content', 'wptexturize');

add_filter('the_content', 'my_preserve_function', 99);

With this snippet inside your functions.php you’ll see that you can effectively insert inline JavaScript or HTML as long as you wrap it in [preserve] and [/preserve]. When switching between Visual and HTML mode TinyMCE will still encode HTML entities but you can just ignore that cause upon generating the content everything will be decoded so that tags etc. will work just fine.

Got a better idea on how to enable inline JavaScript in your posts? Leave it in the comments!

 

Share this post: on Twitter on Facebook

17 Responses to “Preserve inline JavaScript or HTML in the WP post editor”

  1. Hi Danny… thanks for looking at this. I’m not up on php, but I think I added the code correctly at the bottom of my theme’s functions.php file (enclosed in tags), but it doesn’t seem to make a difference.

    Here is an example of code that I’m trying to get to work in a page/post. If I put it into an html widget then it works (image displays, button works), but if I past it in the html tab in tinyMCE enclosed in [preserve][/preserve] I get the result where wp strips out everything it doesn’t like.

    <div class='ecwid-Product'>
    <div style='text-align: center; padding-bottom: 10px;'><script type="text/javascript" src="http://app.ecwid.com/script.js?258128" charset="utf-8"></script><script type="text/javascript">xProductThumbnail('productid=3631040');</script></div>
    <div class='ecwid-productBrowser-head ecwid-ProductBrowser-head' style='text-align: center; padding-bottom: 15px; font: normal 20px tahoma, geneva, verdana, sans-serif'>hCG Homeopathic Oral Drops, 2 oz</div>
    <div class='ecwid-productBrowser-price ecwid-ProductBrowser-price' style='text-align: center; padding-bottom: 15px' id='ecwid-price-3631040'>$50.00</div>
    <table align='center' border='0'><tr><td align='left' class='ecwid'></td></tr></table><div style='text-align: center'><script type="text/javascript" src="http://app.ecwid.com/script.js?258128" charset="utf-8"></script><script type="text/javascript">xAddToBag('productid=3631040');</script></div>
    </div>

    Should result in a image of a bottle and a cart button.

  2. Works fine for me, make sure you’ll paste your snippet when in ‘HTML’ mode cause TinyMCE will try to add hyperlinks to the script’s source etc. when you paste something in Visual mode. You can switch back to Visual mode after pasting though, some encoding will occur but nothing bad.

    When you still can’t get it to work, drop me a line trough my contact form with the URL of the page you’r trying to add it on so I can have a look on what the output is. :-)

  3. Isn’t there a method to use widgets as posts? In my theme e.g. you can choose for pages with only one row. On such page I would like to put one big form of your newsletter-signup plugin in the middle of my page. All traffic going through certain adds would then pass through the signup form because most of the real information is for subscribers only and happens by newsletter.

  4. Thanks for looking at the trouble I’m having with this, Danny. I sent you an email with some login information in case you get some time to investigate further.

    • Hi Norm,

      I just took a look and figured it out. TinyMCE automatically turns the src attributes into links when pasting script tags in Visual mode. When unlinking these links it leaves a " at the end of the src attribute, which should be it’s decoded equivalent: “.

      Hope that helps you, and others experiencing the same!

  5. hi Danny

    i am trying to call tiny mce Editor inside my plugin function and i tried to call this function with ajax and editor not working properly.

    I am getting this error (switchEditors is not defined). but when i tried to call same function without ajax it’s working fine.

    can you help me please?

  6. Hey Danny,
    this worked perfectly but only the super admin can create posts with tags using this..
    can i get the same functionality for the ‘editors,subscribers’ ?

    • Hey Ben, A tad late but as I’m travelling at the moment late is better than never. I’ve read the article and you (and Andy) are totally right – I’ve thus updated the post with a link to his post and the plugin you mentioned. Great catch, thanks!

  7. I came across to your blog here, and i just want a bit of your knowledge. With my limited knowing on php and css, I thought i cannot view the full file code of my wordpress theme/template on html where i can modify it just as what im seeing on firefox browser “inspect elements” of my theme.

    Though i found some javascripts on my wp style.css file, but not the external JS codes. I digged the whole WP php, css, xml files on theme editor but nowhere to find the external JS’s. My point of my problem is, I just want to modify some of “inline” external javascripts codes such as margin, borders, widths, etc.

    Is there any plugins where i can view and modify my theme inline external javascripts?

    would appreciate your support.

    thank you!

    • Hi Jay,

      I’m not sure if I get what you mean but I’ll try.

      If you want to edit margins, borders and paddings just use “right-click > inspect element” and check out the matched CSS rules that apply for the given element. There is also a filename, if you hover it you will see the full file path of the stylesheet where the element gets it styling rules from.

      Hope that helps.

Leave a Reply