Switching Visual/HTML Modes With TinyMCE

One of the greatest parts of the WordPress interface is the flexibility it gives us from within the editing screen. As a user, I can write this post using the rich-editor (TinyMCE), or switch to HTML mode to edit the markup directly. I've received a handful of comments on my previous post regarding TinyMCE in WordPress Plugins asking how to go about incorporating this flexibility into plugins.

TinyMCE has a few built-in methods that allow you to turn the editor on and off; essentially this is all you have to do to switch between the two modes. It is not, however, a second interface. The WordPress editor actually has two rich-editors: one for Visual, and one for HTML. Instead of turning  off TinyMCE, WordPress merely switches the rich-editors. That's why you see those nice formatting buttons even through, you're in HTML mode. Accomplishing that type of functionality is difficult. You can see the complexity of the custom switchEditors method in editor.dev.js.

Too much to cover. For now, I will simply show you how to turn the rich-editor on and off. First, set up a basic TinyMCE editor. This code builds of my other post. There you can find a more complete description of what's going on. In short, though, wptinymce() does all the initialization for you, and queues it on the page. This example could exist on a plugin options page, the profile editor, a post metabox, or really anywhere you want users to rich-edit.

wp_tiny_mce(false, // true makes the editor "teeny"
    array(
    "editor_selector" => "foo",
    "height" => 150
    )
);
<textarea class="foo" id="foo" name="foo"></textarea>

Although you must setup the editor for your plugin using wptinymce(), the regular TinyMCE methods are all available to call from some custom JavaScript. The ones you want to be concerned with are mceAddControl and mceRemoveControl. If you spent any time digging through editor.dev.js, you would notice that the complex WordPress switcher still uses these methods.

Above the textarea, stick some links that will act as our switchboard:

<p align="right">
    <a class="button toggleVisual">Visual</a>
    <a class="button toggleHTML">HTML</a>
</p>
<textarea class="foo" id="foo" name="foo"></textarea>

Now, write some simple jQuery that adds the switching functionality. You could enqueue this as a separate file, or place it with the textarea.

var id = 'foo';

$('a.toggleVisual').click(
    function() {
        tinyMCE.execCommand(‘mceAddControl’, false, id);
    }
);

$('a.toggleHTML').click(
    function() {
        tinyMCE.execCommand(‘mceRemoveControl’, false, id);
    }
);

The buttons now add or remove the rich-editor respectively. You will notice that, when in HTML mode, the textarea resolves to a very small box. To combat this problem, simply give it some rows and cols markup, or style it with CSS.

Another route in you could take  is a single button that toggles the editor on or off. I use this in my TinyMCE Signature plugin. It's not terribly different; just add some logic.

$('a.toggleEditor').click(
    function() {
        var id = 'foo';
        if (tinyMCE.get(id)) {
            tinyMCE.execCommand('mceRemoveControl', false, id); }
        else {
            tinyMCE.execCommand('mceAddControl', false, id);
        }
    }
);

Nonce and AJAX

In the WordPress plugin API, Nonce is a way to verify that data passed to/from a plugin is from a trusted source. Mark Jaquith can explain this better than I can:

"A nonce is a number used once, and it is used for intention verification purposes in WordPress. Think of it as a password that changes each time it is used. [...] The idea is simple: we verify that user’s request is intentional by verifying that the request originates from within the WordPress admin."

WordPress ships with a handful of convenient functions that help you create and verify Nonces. They are chiefly designed for synchronous use, or where data is passed from one web page to another using an HTTP request. You create a nonce in your initial form using wpnoncefield() and then verify that nonce is correct in the method that handles the form with checkadminreferer(). It's fairly straight forward and well documented.

However, what if you want to secure your AJAX (asynchronous) transaction with Nonce? With a simple glance at the code, an evil-doer could still send some irresponsible data to your plugin. You can approach the problem with the same theoretical mindset as a normal nonce: pass a code, check it, carry on. The main difference here is how we pass the nonce code.

Let's imagine we have a very simple bulletin plugin that allows a registered user to type a note and post it without a page refresh. First, set up the basic plugin stuff.

$QuickNotes = new QuickNotes();

class QuickNotes {

  function QuickNotes() {
    add_action('admin_menu', array(&$this, 'add_note_page'));
    add_action("admin_print_scripts", array(&$this, 'js_libs'));
    add_action('wp_ajax_quicknotes_add', array(&$this, 'add'));
  }

  function add_note_page() {
    add_theme_page('Quick Notes', 'Quick Notes', 'administrator', 'quick_notes', array(&$this, 'notes'));
  }

  function js_libs() {
    wp_enqueue_script('jquery');
  }

  function notes() {

    if ( function_exists('wp_nonce_field'))
      wp_nonce_field('quicknotes_nonce', 'quicknotes_nonce');

    ?>
    
    <div class="wrap">
      <h2>Quick Notes</h2>
      <ul id="note_board"></ul>
      <p>
        <textarea id="note"></textarea>
        <a class="button" id="add_note">Add Note</a>
      </p>
    </div>

    <?php

  }

  function add() {

  }

}

As a quick overview, here's what has happened so far:

  • We added an option page under Appearance that returns the 'form' held in the notes() method.
  • Queued the jQuery library (good for AJAXing)
  • Mapped an AJAX request using wpajax (action => quicknotes_add(), callback => add())
    • This allows us to use a method within our plugin to handle the AJAX request, as opposed to a separate web page.
  • Created a Nonce to use called quicknotes_nonce.

Now let's set up the actual AJAX request with jQuery so the user can add the note without a page refresh. Using the $.post method, we'll send the values for both the note and the nonce when the 'Add' button is clicked. Finally, the note is pasted back to note board.

<?php function notes() { ?>
jQuery(document).ready(function($) {
  $('#add_note').live('click',
    function () {
      note = $("#note").val();
      nonce = $("input#quicknotes_nonce").val();
      $.post(
        "/wp-admin/admin-ajax.php",
        {
          action:"quicknotes_add",
          note : note,
          nonce : nonce
        },
        function (str) {
          $('ul#note_board').html(str);
        }
      );
    }
  );
});
<?php } // notes() ?>

So, the nonce is now being passed as a $_POST parameter just like standard operating procedure. Next, assert the validity of the nonce in the add() method. If the nonce is correct, move on to inserting the note into the database, or just echo it back to the list.

  
function add() {

  if (!wp_verify_nonce($_POST['nonce'], 'quicknotes_nonce'))
    exit();

  echo '<li>' . $_POST['note'] . '</li>';
  exit();

}

That's it! Download the entire example.

Fork me on GitHub