Adding Custom Styles Dropdown in WordPress TinyMCE Editor

I have been trying out a WordPress plugin called WP Code Prettify to make code snippets on this website look more presentable. Previously, I was simply using <pre> or <code> tags without any styling and it was difficult to read.

Well, WP Code Prettify will automatically style all <pre> or <code> tags specified with the prettyprint CSS class.

Everything’s pretty cool except that I had to manually type in class="prettyprint" in the WordPress text editor, which is going to be somewhat of a hassle in the long run.

Prior to WordPress 3.9, there was a ‘Formats’ dropdown, in which we could add custom styles which the user could then simply select to apply specific CSS classes to elements.

But in 3.9’s TinyMCE 4.0, the Formats dropdown is hidden by default. So the first thing I had to do was to reactivate it. This Formats dropdown “button” in TinyMCE is called styleselect. In functions.php in the theme, enable styleselect like this:

// Callback function to insert 'styleselect' into the $buttons array
function custom_mce_buttons_2( $buttons ) {
    array_unshift( $buttons, 'styleselect' );
    return $buttons;
}
// Register the callback to the appropriate filter
add_filter('mce_buttons_2', 'custom_mce_buttons_2');

Note that ‘_2’ in the mce_buttons_2 filter refers to the second row of the TinyMCE buttons. I could use mce_buttons_3 which would add it to an empty third row but it wouldn’t look as good, sitting there all alone – wasting space as well.

Now I can go on to add custom styles to this Formats dropdown, which will allow me to simply select it from the list and apply it to <pre> elements:

// Callback function to filter the MCE settings
function custom_mce_before_init_insert_formats( $init_array ) {  
    // Define the style_formats array
    $style_formats = array(  
        array(  
            'title' => 'Prettify',  
            'block' => 'pre',  
            'classes' => 'prettyprint',
            'styles' => array(
                'display' => 'block',
                'background' => '#eee',
                'white-space' => 'pre-wrap',
                'padding' => '10px'
            )    
        ),
        array(  
            'title' => 'AnotherOne',  
            'inline' => 'span',  
            'classes' => 'class-a class-b etc'
        ),
        array(  
            'title' => 'AnotherTwo',  
            'selector' => 'p',  
            'classes' => 'class-d'
        )
    );  
    // Insert the array, JSON ENCODED, into 'style_formats'
    $init_array['style_formats'] = json_encode( $style_formats );  
    
    return $init_array;  
} 

// Attach callback to 'tiny_mce_before_init' 
add_filter( 'tiny_mce_before_init', 'custom_mce_before_init_insert_formats' );

The above code will add 3 new style formats titled Prettify, AnotherOne and AnotherTwo to the Formats dropdown.

Selecting Prettify will apply the prettyprint class to an element. Since the block argument was specified as pre, it creates a new <pre> element with the style applied, and will replace the existing block element selected.

When AnotherOne is selected: since the inline argument was specified, it creates a new inline <span> element with the specified classes applied, and will wrap whatever is selected in the editor, not replacing any tags.

When AnotherTwo is selected: since the selector argument was specified, it limits the specified format to a specific HTML tag (in this case, the <p>), and will apply the specified classes to an existing tag instead of creating one.

You can refer to the WP Codex for the full Style Format Arguments specified for $style_formats. Just an additional note regarding ‘styles’ argument – this is used for rendering the style of the element when shown in the editor. I could have added this in editor-style.css instead.

To go further, if I have many other format items to add to the dropdown, I could even categorise multiple format items by creating a nested dropdown by specifying $style_formats like this, :

// Creating nested format/style items with it's own settings
$style_formats = array(  
    array( 
        'title' => 'Category 1',
        'items' => array(
            array(  
                'title' => 'Item 1',  
                'block' => 'div',  
                'classes' => 'class-a'
            ),
            array(  
                'title' => 'Item 1',  
                'block' => 'div',  
                'classes' => 'class-b'
            )
        )
    ),
    array( 
        'title' => 'Category 2',
        'items' => array(
            array(  
                'title' => 'Item 3',  
                'block' => 'div',  
                'classes' => 'class-c'
            ),
            array(  
                'title' => 'Item 4',  
                'block' => 'div',  
                'classes' => 'class-d'
            )
        )
    )    
);

So that’s all, and not too difficult to implement. In my opinion, it is important to consider how you would want your user to use the style formats that you add to the Formats dropdown. So specifying the correct values to the inline | block | selector and wrapper arguments is crucial. For example, if wrapper is set to true for a format, and the user keeps on applying it to a block element without first clearing the formatting, we will end up creating nested block elements unknowingly.

Formats Dropdown
An example of a TinyMCE Formats nested dropdown button

Now, I hope the code snippets are easier to read than before!

Leave a Comment