How to create a custom button for the visual editor that adds 4 non-breaking spaces? (plugin or simple code)

To WordPress’ visual editor (TinyMCE), I would like to add a button that adds four non-breaking spaces when clicked, like this:

    

I found some plugins that add buttons to the HTML editor, but not to the visual editor (this one for e.g).

Read More

or in general, it would be nice to know if there’s a plugin or a codable (but simple) alternative to add custom buttons to the visual tinyMCE editor.

Related posts

Leave a Reply

2 comments

  1. I already demonstrated how you can achieve such thing in this question but I can explain it here again with your request. I have tested this in WordPress 3.5 and it works elegantly. To avoid this answer being the length of a thesis, I have added comments in all codes to help you understand what each function does and I highly recommend that you read and thoroughly understand them.

    Firstly, in your theme folder, add a folder named admin and inside it, create file class.new_tinymce_btn.php with code:

    <?php
    //wpex_37798_christine_cooper
    //class start
    class add_new_tinymce_btn {
    
    public $btn_arr;
    public $js_file;
    /*
     * call the constructor and set class variables
     * From the constructor call the functions via wordpress action/filter
    */
    function __construct($seperator, $btn_name,$javascrip_location){
      $this->btn_arr = array("Seperator"=>$seperator,"Name"=>$btn_name);
      $this->js_file = $javascrip_location;
      add_action('init', array(&$this,'add_tinymce_button'));
      add_filter( 'tiny_mce_version', array(&$this,'refresh_mce_version'));
    
    }
    /*
     * create the buttons only if the user has editing privs.
     * If so we create the button and add it to the tinymce button array
    */
    function add_tinymce_button() {
       if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') )
         return;
       if ( get_user_option('rich_editing') == 'true') {
         //the function that adds the javascript
         add_filter('mce_external_plugins', array(&$this,'add_new_tinymce_plugin'));
         //adds the button to the tinymce button array
         add_filter('mce_buttons', array(&$this,'register_new_button')); 
       }
    }
    /*
     * add the new button to the tinymce array
    */
    function register_new_button($buttons) {
       array_push($buttons, $this->btn_arr["Seperator"],$this->btn_arr["Name"]);
       return $buttons;
    }
    /*
     * Call the javascript file that loads the 
     * instructions for the new button
    */
    function add_new_tinymce_plugin($plugin_array) {
       $plugin_array[$this->btn_arr['Name']] = $this->js_file;
       return $plugin_array;
    }
    /*
     * This function tricks tinymce in thinking 
     * it needs to refresh the buttons
    */
    function refresh_mce_version($ver) {
      $ver += 3;
      return $ver;
    }
    
    }//class end
    ?>
    

    This code will add custom buttons to the visual editor.

    Next, in your theme folder, create these folders adminjs/buttons and inside, create this JS file spacebutton.js with code:

    (function() {
        tinymce.create('tinymce.plugins.nextpage', {
            init : function(ed, url) {
                ed.addButton('nextpage', {
                    title : 'Space Button',
                    image : url+'/images/btn_spacebutton.png',
                    onclick : function() {                    
                        var prompt_text = "&nbsp;&nbsp;&nbsp;&nbsp;";
                        var caret = "caret_pos_holder";
                        var insert = "<p>" + prompt_text + " &nbsp;&nbsp;&nbsp;&nbsp;</p> <span id="+caret+"></span>";
                         ed.execCommand('mceInsertContent', false, insert);
                         ed.selection.select(ed.dom.select('span#caret_pos_holder')[0]); //select the span
                         ed.dom.remove(ed.dom.select('span#caret_pos_holder')[0]); //remove the span
                    }
                });
            },
            createControl : function(n, cm) {
                return null;
            },
        });
        tinymce.PluginManager.add('nextpage', tinymce.plugins.nextpage);
    })(); 
    

    You will need to add an image for the button (/images/btn_spacebutton.png). The above code is a rather simple javascript function for what happens when the button is pressed.

    Now you will need to load this button class by adding this to your functions file:

    //load custom buttons class
    require_once (TEMPLATEPATH . '/admin/class.new_tinymce_btn.php');
    //create an instance of the class
    $t = new add_new_tinymce_btn('|','nextpage',get_bloginfo('template_url').'/adminjs/buttons/spacebutton.js');
    

    That is it. You should find your new custom button in the visual editor. Whenever you want to add more custom buttons, just add a new JS file with the button function and load the button class as demonstrated above.

  2. TL;DR, code is at the bottom.

    OK, this should work for you, but it is a beta. It works for me, but I haven’t done any kind of rigorous testing. One thing, it doesn’t output four consecutive &nbsp; entities; it does a stuttered &nbsp; [space] &nbsp; [space], but at least it keeps them as-is when switching back-and-forth between Visual & Text modes. It only works in Visual mode, I haven’t taken the time to figure out how to make it work in Text mode.

    It comes in two files, name as you see fit. I used the highly imaginative name: 4Spaces. 🙂 The TinyMCE button is on the top-row, far-right, of the editor. It’ll show whatever your flavor of browser shows for non-existent images. That’s easily changed in 4spaces.js, line 8:

    image   : url + '/' + 'YOUR_IMAGE_HERE.png'
    

    Change `YOUR_IMAGE_HERE.png’ to your image file, relative to the two files, or use an absolute URI like so:

    image   : '/path/to/image/YOUR_IMAGE_HERE.png'
    

    or

    image   : 'http://example.com/path/to/image/YOUR_IMAGE_HERE.png'
    

    I’ve commented and/or left some existing comments throughout the PHP, the JavaScript comments are sparse. You’ll see in the PHP header section where the PHP code came from and kind of where the JavaScript originated.

    Two notable credits, both listed in the PHP header: this WordPress.SE Answer that provided the code that stops TinyMCE (or WordPress, not sure which) from stripping out the spaces, and the link provided in the prior answer by @Alexey, which, while not critical, helped me stumble onto the JS solution.

    I couldn’t make the code in that link work, but eventually came back to it and found the nugget that brought it all together (with some tweaking, to be sure).

    I think that about sums everything up. Here’s the code:

    4spaces.php

    <?php
    /* Plugin Name: 4Spaces
     * Version: 0.1.0
     * Author: AK Ted
     * Author URI: http://akted.com
     * License: GPLv2 or later
     *
     *
     * PHP code adapted & refined from the following two sources:
     * WordPress Codex - http://codex.wordpress.org/TinyMCE_Custom_Buttons#Loading_a_TinyMCE__Plugin
     *
     * WordPress Answers (Stack Exchange) - https://wordpress.stackexchange.com/questions/54398/how-can-i-stop-tinymce-from-converting-my-html-entities-to-characters#answer-54480
     *
     *
     * The JavaScript arose from a lot of trial-and-error, with code [beat into submission...er, I mean] inspired by both of the following sources:
     * tinymce wiki - http://www.tinymce.com/wiki.php/Creating_a_plugin
     * &
     * brett terpstra - http://brettterpstra.com/2010/04/17/adding-a-tinymce-button/
     *
     */
    
    new akt_4spaces();
    
    class akt_4spaces {
        function __construct() {
            add_action('admin_init', array($this, 'init'));
        } // function __construct
    
        // callback for init
        // sets all the hooks only if user has capability & rich_editing is true 
        function init() {
            // Don't bother doing this stuff if the current user lacks permissions
            if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') ) {
                return;
            }
    
           // Add only in Rich Editor mode
           if ( get_user_option('rich_editing') == 'true') {
                add_filter('mce_buttons', array($this, 'add_button'));
                add_filter('mce_external_plugins', array($this, 'add_tinymce_plugin'));
                add_filter('tiny_mce_before_init', array($this, 'preserve_entities'));
           }
        } // function init
    
    
        // callback for mce_buttons filter
        // adds button to TinyMCE
        function add_button($buttons) {
            array_push($buttons, 'separator', 'four_spaces');
            return $buttons;
        } // function add_button
    
        // callback for mce_external_plugins filter
        // attaches the JavaScript file to TinyMCE
        function add_tinymce_plugin($plugin_array) {
            $plugin_array['four_spaces'] = plugins_url('/', __FILE__) . '4spaces.js';
            return $plugin_array;
        } // function add_tinymce_plugin
    
    
        // callback for tiny_mce_before_init
        // stops TinyMCE (WordPress?) from automatically converting &nbsp; entities
        function preserve_entities( $initArray ) {
            // The odd entries are the entity *number*, the even entries are the entity *name*. If the entity has no name,
            // use the number, prefixed with a hash (for example, the service mark is "8480,#8480").
            $initArray['entities'] = '160,nbsp,' . $initArray['entities'];
            return $initArray;
        } // function preserve_entities
    
    } // class akt_4spaces
    

    4spaces.js

    (function() {
    
        tinymce.create('tinymce.plugins.four_spaces', {
            init : function(ed, url) {
                // Register four_spaces button
                ed.addButton('four_spaces', {
                    title   : '4Spaces',
                    image   : url + '/' + 'YOUR_IMAGE_HERE.png',
                    onclick : function() {
                        ed.execCommand(
                            "mceInsertContent",
                            false,
                            "&nbsp;&nbsp;&nbsp;&nbsp;"
                        );
                    }
                });
            }
        });
    
        // Register plugin
        tinymce.PluginManager.add('four_spaces', tinymce.plugins.four_spaces);
    
    })();
    

    Edit: I forgot to mention, for those who don’t know, put both of those files into a directory under /wp-content/plugins/ (default path). It should look something like
    /wp-content/plugins/4spaces/
    or whatever name you decide to call it, then activate it in Admin.

    P.S. – I’m relatively new to OOP, so welcome any and all criticisms, advice, etc., from anyone viewing this answer.