Posting source code in WordPress: escaping and syntax highlighting the inserted code
November 4, 2007
I have already mentioned that I had difficulty in finding a suitable solution to post source code in my blog. However good the workaround presented in my previous post is functioning, I was not satisfied with it. I noticed two annoying things. The first was that I had to escape HTML special chars “manually” in the inserted code, which was a pain in the ass. My second problem was (I like to indent my code with TAB) that indentation was too wide, which looked not really nice out (and was impractical when your code has multiple nested control structures). After a little JavaScript hacking and playing with GeSHi and CSS I solved both of them.
A little side note: I found that the built-in rich text editor is almost absolutely useless, so I turned it off, and I suggest it to every WordPress user.
Escaping the inserted code
When you want to put some source code to the post, you usually simply enclose it in code or pre tags. The problem is, that the source code may contain characters which have special meaning in the HTML language, so they should be escaped. These characters are: <, >, &, &qout; and they should be converted to: <, >, &, &qout;. I would like to have some kind of automation for this task, which could be run when we insert the text to the post.
When you insert a code (and use a syntax highlighter) you should specify the language of that code. For example if you use the WP-Syntax plugin you should enclose your code in pre tags and use the lang attribute to specify the language. In addition you can mark if you want line numbers to appear. Enclosing the copy-pasted text is another repetitive and tedious task so it is another good candidate for automation
It would be great if we could do this two task in one step, so I thought I extend the toolbar above the textarea to provide this functionality by adding a new sourcecode button to it:

The sourcecode button works similar as the others button on the toolbar, if no text is selected on the first click it inserts the open tag, on the second click it inserts the close tag. If text is selected it encloses the text in pre tags when you activate it. The button can be accessed via Ctrl-F keyboard shortcut too. Before it ads the open tag to the editor it prompts for the syntax highlighting parameters and generates the proper open tag to them. When text is selected the special characters will be replaced to HTML entities in it. This way adding source code to your post will be very straightforward:
1. Select the text in te editor:

2. Select the inserted text and press Ctrl-F:

3. Type the syntax highlighting information:

4. The resulted text is:

Extending the toolbar is quite easy, only the wp-includes/js/quicktags.js file should be slightly modified (you can download the fully modified version from here, all the modifications are commented). To add a new button to the toolbar you should add the following code:
127 128 129 130 131 132 133 | edButtons[edButtons.length] = new edButton('ed_pre' ,'pre' ,'<pre>' ,'</pre>' ,'f' ); |
After then we should modify the edInsertTag function, and we are ready:
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | //------<code modification>------- // Prompts for syntax highlighting parameter, and return the appropriate start tag. // TODO: l10n support. function edGetPreStartTag() { var syntaxInfo = prompt('Please insert syntax highlighting information:'+&qout;\n&qout;+'language[, line number]!', 'php,1').split(','); return '<pre lang=&qout;'+syntaxInfo[0]+'&qout;'+(syntaxInfo[1] != undefined ? ' line=&qout;'+syntaxInfo[1]+'&qout;' : '')+'>'+&qout;\n&qout;; } // It converts all HTML special chars to HTML entites function edHtmlSpecialChars(string) { return string.replace(/&/g, '&').replace(/</g, '<'). replace(/>/g, '>').replace(/&qout;/g, '&qout;'). replace(/'/g, '''); } //------</code modification>------- // insertion code function edInsertTag(myField, i) { //IE support if (document.selection) { myField.focus(); sel = document.selection.createRange(); if (sel.text.length > 0) { //------<code modification>------- if (edButtons[i].id == 'ed_pre') { sel.text = edHtmlSpecialChars(sel.text); edButtons[i].tagStart = edGetPreStartTag(); } //------</code modification>------- sel.text = edButtons[i].tagStart + sel.text + edButtons[i].tagEnd; } else { if (!edCheckOpenTags(i) || edButtons[i].tagEnd == '') { //------<code modification>------- if (edButtons[i].id == 'ed_pre') { edButtons[i].tagStart = edGetPreStartTag(); } //------</code modification>------- sel.text = edButtons[i].tagStart; edAddTag(i); } else { sel.text = edButtons[i].tagEnd; edRemoveTag(i); } } myField.focus(); } //MOZILLA/NETSCAPE support else if (myField.selectionStart || myField.selectionStart == '0') { var startPos = myField.selectionStart; var endPos = myField.selectionEnd; var cursorPos = endPos; var scrollTop = myField.scrollTop; if (startPos != endPos) { //------<code modification>------- var selectedText = myField.value.substring(startPos, endPos); var selectedTextLengthGrowth = 0; if (edButtons[i].id == 'ed_pre') { edButtons[i].tagStart = edGetPreStartTag(); selectedTextLengthGrowth = selectedText.length; selectedText = edHtmlSpecialChars(selectedText); selectedTextLengthGrowth = selectedText.length - selectedTextLengthGrowth; } myField.value = myField.value.substring(0, startPos) + edButtons[i].tagStart + selectedText + edButtons[i].tagEnd + myField.value.substring(endPos, myField.value.length); cursorPos += edButtons[i].tagStart.length + edButtons[i].tagEnd.length + selectedTextLengthGrowth; //------</code modification>------- } else { if (!edCheckOpenTags(i) || edButtons[i].tagEnd == '') { //------<code modification>------- if (edButtons[i].id == 'ed_pre') { edButtons[i].tagStart = edGetPreStartTag(); } //------</code modification>------- myField.value = myField.value.substring(0, startPos) + edButtons[i].tagStart + myField.value.substring(endPos, myField.value.length); edAddTag(i); cursorPos = startPos + edButtons[i].tagStart.length; } else { myField.value = myField.value.substring(0, startPos) + edButtons[i].tagEnd + myField.value.substring(endPos, myField.value.length); edRemoveTag(i); cursorPos = startPos + edButtons[i].tagEnd.length; } } myField.focus(); myField.selectionStart = cursorPos; myField.selectionEnd = cursorPos; myField.scrollTop = scrollTop; } else { if (!edCheckOpenTags(i) || edButtons[i].tagEnd == '') { //------<code modification>------- if (edButtons[i].id == 'ed_pre') { edButtons[i].tagStart = edGetPreStartTag(); } //------</code modification>------- myField.value += edButtons[i].tagStart; edAddTag(i); } else { myField.value += edButtons[i].tagEnd; edRemoveTag(i); } myField.focus(); } } |
Controlling the indentation
The WP-Syntax plugin uses GeSHi with default settings, which means that GeSHi wraps code blocks in pre tags. In this mode GeSHi doesn’t replace TAB characters with spaces, so we can’t control the appearance of the indentation. But if we instruct GeSHi to use div tags instead of pre, it will replace leading TAB characters to spaces, and you can set the number of spaces. If we want to use 4 spaces we should modify the plugin accordingly to the following:
79 80 81 82 | $geshi = new GeSHi(htmlspecialchars_decode($code), $language); $geshi->enable_keyword_links(false); $geshi->set_header_type(GESHI_HEADER_DIV); $geshi->set_tab_width(4); |
After this modification you should probably modify your CSS. I use now the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /***** SYNTAX HIGHLIGHTER *****/ .wp_syntax { color: #100; background-color: #f9f9f9; border: 1px solid silver; margin: 0 0 1.5em 0; overflow: auto; } /* IE FIX */ .wp_syntax { overflow-x: auto; overflow-y: hidden; padding-bottom: expression(this.scrollWidth > this.offsetWidth ? 15 : 0); width: 100%; } .wp_syntax table { border-collapse: collapse; } .wp_syntax div, .wp_syntax td { vertical-align: top; padding: 2px 4px; white-space: nowrap; } .wp_syntax .line_numbers { text-align: right; background-color: #e8e9dc; color: gray; overflow: visible; } td.code div { padding-top: 0px; } |
I think these modifications would be interesting in the official WordPress version too, I found them useful, now I can insert source code to the post in a very convenient way.
Posted in
content rss

November 9th, 2007 at 9:41 pm
Nice post, well explained.
I particularly like your
/* IE FIX */in the stylesheet, I’ve been looking for a way around that scrollbar problem for some time.November 10th, 2007 at 10:39 pm
[...] the text from the clipboard to the attribute. This is a repetitive and tedious task, so like in the previous case I automate [...]
November 14th, 2007 at 6:03 pm
[...] Lesz fejlesztési rovat, ehhez jól jön majd kódmutogatásnál egy rendes kódszÃnezÅ‘, tippek itt. [...]
November 16th, 2007 at 3:22 pm
[...] che i caratteri vengano interpretati da Wordpress. Dopo diverse ricerche ho trovato una soluzione molto elegante grazie a questo blog.. Se avete il mio stesso problema, vi consiglio di darci [...]
November 29th, 2007 at 8:57 am
[...] alguien (Posting source code in WordPress: escaping and syntax highlighting the inserted code) ya se ha tomado la molestia de resolver este problema, y de paso, agregando magnificas [...]
January 18th, 2008 at 3:43 pm
[...] wie von Felho beschrieben modifizieren um GeSHi auf die Verwendung von div-Tags umzuschalten [...]
March 21st, 2008 at 3:27 pm
Thank you, really very good thing.
April 18th, 2008 at 8:26 pm
Very very good post! There is only one mistake in your javascript: you replace the quotation mark with &qout; but (becarful!) the right code is "!
April 18th, 2008 at 8:29 pm
Mmm…. In the previous comment the page encoded what I have written….
The right code is "
April 18th, 2008 at 9:42 pm
[...] trovato un articolo che spiega in modo preciso come creare un nuovo pulsante per la barra degli strumenti [...]
August 1st, 2008 at 8:49 pm
Hmm.. thank you so much, usefull information
August 4th, 2008 at 12:19 pm
Thanks! Really interesting. I wish i could spend my time on writing articles…just have no time for it.
October 28th, 2008 at 6:43 pm
[...] e in questo utile articolo: http://blog.felho.hu/posting-source-code-in-wordpress-escaping-and-syntax-highlighting-the-inserted-... [...]
February 10th, 2009 at 7:43 am
Thanks for posting this! I am brand new to word press, but I can’t figure this posting code issue. I have tried about every plugin on Word Press, no love for any of them! I upload the GeSHI to the plugin folder, but it does not do the trick either, yikes I feel so stupid that I can’t get this.
I have a post here:
http://blog.meleana.info/?p=82
Can you offer any help to me?
Thanks so much
Johnny`-`
By the way great post, I am going to to over this again and hopefully I can finally fix this issue.
February 19th, 2009 at 9:12 am
[...] il semble qu’il y ait un problème associé (sécurité ? sans doute) car l’auteur propose une solution plus élégante … à tester ! Je ne vous garantit donc pas la sécurité de ce [...]
September 26th, 2009 at 3:38 pm
[...] Resultat im Artikel den HTML-Code angezeigt bekommt. Um dieses Problem zu umgehen, habe ich eine Lösung von Gergely Hodicska gefunden, die es zudem ermöglicht, den Quellcode noch komfortabler einzugeben. Im ersten Schritt [...]