Adding Quicktags to WordPress and to the TinyMCE Editor for WP Plugin Authors in Many Easy Steps

A while back I wrote a WordPress plugin that adds popup images to the blog. The way the plugin works is that you add in fake HTML-ish <popim> tags and the plugin filters those and changes them to the actual HTML required to create the popup image.

That wasn’t the hard part. The hard part was when I decided to add a UI that automatically generated thumbnails for the plugin. Moreover, I decided to add a button to the WordPress editor as part of that UI. Surely that would be no problem. After all, there should be documentation for adding editor buttons, right?

Ha! I say to you, and ha! again. Clearly you are new to computers.

It took a lot of digging for me to figure out what all I needed to do. I decided to collate the information I found and present it here for other WordPress plugin authors. If you’re in a real hurry, at the end of the article you can grab files with all of the code that is shown in this article.

What the Hey Are You Talking About?

Open up your WordPress admin panel and go to the Write tab. See the part where you write your post? That’s the editor. WordPress has two different editors. One is the visual rich editor, which is a modified version of the javascript-based TinyMCE editor. It hides all of that nasty HTML markup from you and formats your posts nicely. The other is the regular editor, which shows you all of the HTML markup you could ever want and is the editor that real blog writers use. To switch between the two, go to the Users tab and look at the bottom of your profile, in the Personal Options section. The checkbox there toggles whether or not you use the visual rich editor.

If you’re using the regular editor, above the edit panel is a row of buttons. Those are called the Quicktags. They’re a fast way to add HTML tags to your post, similar in spirit to the tag buttons a lot of bulletin board systems have. The TinyMCE editor has a row of pretty graphical buttons that do similar things.

Before We Begin, a Brief Note on Coding Standards

If you’re writing a plugin and you’re not encapsulating your code in an object, you should preface your function names and global variables with a prefix that’s specific to your plugin. That makes it less likely that your function names will be the same as those of another plugin or WordPress itself, since PHP doesn’t have proper namespace support. In this post, I’ll use the prefix “pluggy”.

Adding a Quicktag

Adding a button to the Quicktag bar requires a bit of javascript. What we’re going to do is add some code to the bottom of every page that contains the editor. The javascript code will create the button element and append it to the Quicktags.

First of all, let’s write a function that will (eventually) add our specialized javascript to all editor pages. In your plugin’s .php file, add the following:


// Add javascript to generate a quicktag button. If the quicktag bar
// isn't available, instead put a link below the posting field entry.
function pluggy_quicktag_like_button() {
  // Only add the javascript to post.php, post-new.php, page-new.php, or
  // bookmarklet.php pages
  if (strpos($_SERVER['REQUEST_URI'], 'post.php') ||
      strpos($_SERVER['REQUEST_URI'], 'post-new.php') ||
      strpos($_SERVER['REQUEST_URI'], 'page-new.php') ||
      strpos($_SERVER['REQUEST_URI'], 'bookmarklet.php')) {
    // Print out the HTML/Javascript to add the button
?>


Now we need to add the javascript to create our button. Quicktags' javascript code come from the file wp-includes/js/quicktags.js. If you look in that file, you'll discover that the <div> element that holds the Quicktags has an HTML ID of "ed_toolbar" and that each button has a class of "ed_button". So we need some javascript to create a button of class "ed_button" and append it to the "ed_toolbar" div. This next bit of code replaces the "JAVASCRIPT WILL GO HERE" comment above.


var pluggy_toolbar = document.getElementById("ed_toolbar");

if (pluggy_toolbar) {
  var theButton = document.createElement('input');
  theButton.type = 'button';
  theButton.value = 'Pluggy';
  theButton.onclick = pluggy_button;
  theButton.className = 'ed_button';
  theButton.title = 'Pluggy!';
  theButton.id = 'ed_Pluggy';
  pluggy_toolbar.appendChild(theButton);
}

If you add all of that code to your plugin and then visit the Write Post page, you'll see a button called "Pluggy!", assuming that you're using the regular editor. Success! Except that the button doesn't do anything yet. Thanks to the onclick value it wants to call the function pluggy_button(), but that doesn't exist. We need to write that function. Add this snippet of javascript after the above bit:


function pluggy_button(querystr) {
  alert("Pluggy button pressed!");
  return false;
}

and that will make the button pop up an alertbox when you push it. If this were a more complicated plugin, we could use the pluggy_button() javascript function to pop open a new window or insert code into the editor window. I'll leave those as an exercise for the reader, though you can see an example of popping open a UI window in my Simple Popup Images plugin.

Adding a Button to the Visual Rich Editor

The visual rich editor has pretty graphical buttons for you to push. You really don't want to add a new one of those.

I mean it. For full functionality, you'll have to write a TinyMCE plugin, and that's a process that's even more sketchily documented than that of writing WP plugins, plus you have to write your plugin in javascript.

If you're determined to write a TinyMCE plugin, all I can do is point you to the TinyMCE documentation; mention the tinymce_before_init, tinymce_plugins, and tinymce_buttons filters that WordPress has made available; show you other TinyMCE plugins, and wish you the best.

There are other, easier options than creating a graphical button and writing a new plugin. WordPress 2.1 introduced the Code tab in the visual rich editor. If you open the Code tab, you'll see the usual array of Quicktags...including our new one. But what if you want to support the WP 2.0 branch? You can't easily add a button, but you can add a nice link just below the editor that will do the same thing as the button. We'll add an invisible <div> to every post page and, if the Quicktags aren't available, make that div visible and move it into position.

Above the <script type="text/javascript"> in your code, add the following:



(Note that, for code-posting reasons, I have changed the <a> in the code snippet to [a]. Change the []s to angle brackets for it to work.) After the "if {}" block of javascript code that creates the Quicktag button, add:


else {
  var pluggyLink = document.getElementById("pluggy_link");
  var pingBack = document.getElementById("pingback");
  if (pingBack == null)
    var pingBack = document.getElementById("post_pingback");
  if (pingBack == null) {
    var pingBack = document.getElementById("savepage");
    pingBack = pingBack.parentNode;
  }
  pingBack.parentNode.insertBefore(pluggyLink, pingBack);
  pluggyLink.style.display = 'block';
}

That bit of javascript makes the <div> with our link visible and moves it to just before the secret hidden pingback input elements that come right after the editor. Tah-dah!

Bonus Topic 1: Inserting Text in the Editor

Your plugin, like mine, may pop up a window, do some processing, and return, inserting some text into the editor window. You can do that with two javascript functions:


// Insert myValue into an editor window
function insertHtml(myValue) {
        if(window.tinyMCE)
                window.opener.tinyMCE.execCommand("mceInsertContent",true,myVal\
ue);
        else
                insertAtCursor(window.opener.document.post.content, myValue);
        window.close();
}

// Insert text into the WP regular editor window
function insertAtCursor(myField, myValue) {
        //IE support
        if (document.selection && !window.opera) {
                myField.focus();
                sel = window.opener.document.selection.createRange();
                sel.text = myValue;
        }
        //MOZILLA/NETSCAPE/OPERA support
        else if (myField.selectionStart || myField.selectionStart == '0') {
                var startPos = myField.selectionStart;
                var endPos = myField.selectionEnd;
                myField.value = myField.value.substring(0, startPos)
                + myValue
                + myField.value.substring(endPos, myField.value.length);
        } else {
                myField.value += myValue;
        }
}

Calling insertHtml('some text') will paste that text in the editor window.

Bonus Topic 2: Adding HTML-Like Tags to the Visual Rich Editor

For your plugin, you may end up inventing an HTML-like tag to be filtered later. For example, the WP-FLV plugin adds an <flv> tag that, when a post is displayed, is converted to a flash-embedded object.

TinyMCE won't like that. It strips out tags it doesn't know anything about. To make TinyMCE like your new tag, you need to add it to TinyMCE's list of valid elements. WordPress gives you a filter for doing that: mce_valid_elements. Define your tag using the TinyMCE format for valid elements and then add it to the valid elements list using the mce_valid_elements filter.

You know what? Let me show you an example. Let's say you've defined a new <pluggy> tag for your plugin. It can have two attributes called "width" and "height". To get the visual rich editor to leave your tag alone, do the following:


add_filter('mce_valid_elements', 'pluggy_mce_valid_elements', 0);

function pluggy_mce_valid_elements($valid_elements) {
  $valid_elements .= 'pluggy[width|height]';
  return $valid_elements;
}

The "pluggy[width|height]" is the TinyMCE valid element string. Now TinyMCE won't get rid of any <pluggy> tags when your users are writing their posts.

One other note. When I used this trick, I used a single self-closing tag, like <pluggy />. TinyMCE automatically turns this into <pluggy></pluggy>, and there's nothing you can do short of hacking the editor's javascript. Just a word of advice.

Conclusion and Downloads

That's it. I hope you found this article helpful. If you'd rather not type in all of the code above, you can get two files that have the code already entered for you.

22 thoughts on “Adding Quicktags to WordPress and to the TinyMCE Editor for WP Plugin Authors in Many Easy Steps

  1. Wow… that’s a lot of stuff to digest. As you’re aware, I don’t use WordPress for blogging. I guess it boils down to am I ready to try and tackle yet another language? If I ever do, I know where to come look for doing really cool things.

  2. Oh, goodness, you don’t have to know all of that to use WordPress. The only reason I needed to know it is because I decided to write a WP plugin. Using WP is much easier.

  3. The other is the regular editor, which shows you all of the HTML markup you could ever want and is the editor that real blog writers use.

    I love it when you talk nerdy to me.

    [GIVE ME HTML OR GIVE ME DEATH!]

  4. hey bud, you might want to link to a PHPS file instead of a PHP file, as you may know, you can’t download that!

  5. I thought I’d fixed the MIME types to take care of it, but changing its extension to .phps works just as well. Thanks for the suggestion.

  6. Nicely done, I think it’s pretty lame that WP doesn’t offer guides for this sort of thing.

    Thank you for doing a great job 🙂

  7. This is an amazing post. Now to go and implement this into a not-so-complete podcasting plugin with a non-functional “send to editor” button 😉

  8. You just saved me a lot of time. I have been planning on adding a button for my SFV plugin to the editor but I as not sure how to go about doing it. I will give this a shot. Thank you!

  9. Excellent, thanks, this was the article that finally got me unscrewed. This was the key:
    add_filter(‘admin_footer’, ‘pluggy_quicktag_like_button’);

    Working on a writeup of my experience, will be linking here.

  10. Owen strikes again with a “comment quickags” plugin for WordPress. This adds the ability of commenters to use little clickable buttons to format XHTML in their comments. Thanks BloggingPro

Comments are closed.