May 6, 2011

Mastering the TinyMCE Styles Dropdown in the WordPress Visual Editor

TinyMCE Styles dropdown menuI’ll just come out and say it: I write my blog posts in the visual editor. Yes, it may be blasphemy for a developer to do that, but I just don’t care. I like seeing the post I’m writing come to life as I’m writing it. Since I’m such a fan of the visual editor, I’m always looking for new ways to stretch its capabilities without adding a truckload of extra markup to my post. There’s a slightly more detailed story that leads to how I got to writing this particular post,* but that’s not why you’re reading this. You’re reading this because you want to learn about the styles dropdown in the visual editor. Here we go!

Most people know about the “Kitchen Sink” button in the WordPress visual editor—the one that toggles the second row of buttons. On that second row, there’s the familiar Format dropdown menu. Well, there’s another dropdown menu available that isn’t on the toolbar by default: the Styles dropdown. This makes it easy to add custom classes to the visual editor in WordPress (which is particularly great for client websites, when clients need a foolproof way to add HTML to the post).

TinyMCE editor screenshot

The power of the TinyMCE Styles dropdown menu.

Method 1: Comma-separated string of styles

I learned about the Styles dropdown a couple of years ago, and through a few Google searches I found out how to make it show up and list my custom classes. This is what I learned then, and it’s still prevalent in Google search results:

add_filter( 'tiny_mce_before_init', 'my_custom_tinymce' );

function my_custom_tinymce( $init ) {
	$init['theme_advanced_buttons2_add_before'] = 'styleselect';
	$init['theme_advanced_styles'] = 'Button=button,Callout Box=callout';
	return $init;
}

(That code would go in your theme’s functions.php file.)

This is pretty straightforward. We’re adding the Styles dropdown ('styleselect') to the second row of buttons (theme_advanced_buttons2_add) at the beginning of the row (_before). Then we’re adding our own styles to the list.

In the list of styles, the title comes before the equals sign and the CSS class comes afterward. Separate multiple styles with a comma. Violà!

So what’s wrong with that?

This method is 100% okay to use. It’s short and sweet, requires very little code, and gets the job done. However, it’s a little restricting. This will take whatever text is highlighted in the editor and wrap a <span> element around it, applying the CSS class to the span. Here’s what it won’t do:

  • Apply a class to an existing block element
  • Limit a style to a specific HTML tag
  • Wrap multiple block elements in another block element with a custom class
  • Apply inline styles to an element

I definitely want to be able to do all of those things. Don’t you? (Well, maybe not inline styles, but the point is that you can.)

Method 2: Arrays using TinyMCE parameters

Step 1: Add the Styles dropdown to the toolbar

Add this code to functions.php:

add_filter( 'mce_buttons_2', 'my_mce_buttons_2' );

function my_mce_buttons_2( $buttons ) {
    array_unshift( $buttons, 'styleselect' );
    return $buttons;
}

A slightly different way of adding the dropdown. This filter applies only to the buttons, so it feels a little more right.

Step 2: Add KICK-ASS custom styles

After that, add this code:

add_filter( 'tiny_mce_before_init', 'my_mce_before_init' );

function my_mce_before_init( $settings ) {

    $style_formats = array(
    	array(
    		'title' => 'Button',
    		'selector' => 'a',
    		'classes' => 'button'
    	),
        array(
        	'title' => 'Callout Box',
        	'block' => 'div',
        	'classes' => 'callout',
        	'wrapper' => true
        ),
        array(
        	'title' => 'Bold Red Text',
        	'inline' => 'span',
        	'styles' => array(
        		'color' => '#f00',
        		'fontWeight' => 'bold'
        	)
        )
    );

    $settings['style_formats'] = json_encode( $style_formats );

    return $settings;

}

This is also fairly simple once you know the syntax. All we’re doing is defining the formats, then encoding them as JSON so they’re TinyMCE-friendly, then assigning them to the TinyMCE settings.

Let’s break apart the array and look at the different options.

title [required] label for this dropdown item
selector | block | inline [required]
  • selector limits the style to a specific HTML tag, and will apply the style to an existing tag instead of creating one
  • block creates a new block-level element with the style applied, and will replace the existing block element around the cursor
  • inline creates a new inline element with the style applied, and will wrap whatever is selected in the editor, not replacing any tags
classes [optional] space-separated list of classes to apply to the element
styles [optional] array of inline styles to apply to the element (two-word attributes, like font-weight, are written in Javascript-friendly camel case: fontWeight)
attributes [optional] assigns attributes to the element (same syntax as styles)
wrapper [optional, default = false] if set to true, creates a new block-level element around any selected block-level elements
exact [optional, default = false] disables the “merge similar styles” feature, needed for some CSS inheritance issues

Note that while classes and styles are both optional, one of the two should be present in each array. (Otherwise, why are you adding this to the dropdown anyway?)

Step 3: Add your stylesheet to the visual editor

WordPress made this one easy in version 3.1. Just add this to functions.php:

add_editor_style();

Then put a file in your theme folder named editor-style.css. Any styles in there are applied to the visual editor.

Update 6/11/11: I’ve made a plugin version of this so your customizations will be preserved when updating your theme (especially important if you’re using a regularly updated theme like Twenty Ten). Download it below.

Download the Custom Styles Dropdown plugin

To use it, just unzip the download and put the PHP file in your wp-content/plugins folder, then activate it!

That’s it! For more TinyMCE parameter examples, check out this post at WordPress Answers and this documentation for TinyMCE.

* Here’s the story I mentioned earlier: I am just days away from launching Themejack, where my husband and I will be creating and selling premium WordPress themes based on my Bolts framework. I had a bunch of fancy custom shortcodes defined for things like callout boxes, download links, and buttons, when I happened upon this post by Justin Tadlock. Basically he’s saying that shortcodes are often overused, and replaced only with basic HTML. This has certain disadvantages for the user (read his post for more details on that). I really admire Justin Tadlock’s work—he definitely knows his stuff, and he’s one of the developers that inspires my work in WordPress—so I tend to listen to what he says when he expresses opinions as strongly as he did in that post.

So I did plenty of Google searching and somehow landed on the TinyMCE Styles dropdown. It makes much more sense than shortcodes when you think about it. Changes can be visible immediately in the visual editor (if you’re using a custom editor stylesheet) and if the user switches themes, there aren’t a bunch of useless shortcodes left in the content. I was running into that lack of flexibility, though, and didn’t find these advanced TinyMCE parameters right away. When I did track them down, they were scattered across a few different sites, some of which were on pages 3 & 4 in the search results. Hopefully putting them all in one place will make someone else’s search less exhausting than my own!

(Possibly) Related Posts

  1. Extended WordPress Settings API Tutorial, Part 1
  • Jeff

    I read Justin’s post too and tend to agree with him. Looks like you came up with a nice compromise…will give it a try on my next theme.

    Are you going to release a stable version of Bolts?

    Good luck with the launch!

    • Alison Barrett

      Yes, I plan on releasing a stable version of Bolts as soon as Themejack launches, which should be tomorrow night or Monday morning. It will still be free and open-source.

      Thanks!

  • Pingback: How to Add Buttons and CSS Classes to TinyMCE : WP Mayor

  • Anonymous

    Thank you for sharing this. I looked into this a few months ago, but since then I’ve had a peak in clients and put it in the back of my mind (a good place to get lost). I’ve been reading up on WP Post Types and somehow found this. It’s just what I needed…..
    Great find and thanks again.

  • http://twitter.com/NiklasHogefjord Niklas Högefjord

    Thank you Alison for your article! I only knew about method 1 before, but this opens up new horizons. You saved my day actually :)

  • Larry

    Warning: newbie posting. New to WordPress. Not a coder but comfortable with HTML and CSS.
    Alison, this seems to be exactly what I am looking for. But is this the sort of customization that prevents one from applying WP and theme updates without first saving the customized files and reapplying them after an update (assuming their still compatible with the update). My apologies if this is a dumb question.

    • http://alisothegeek.com Alison Barrett

      Not a dumb question! You’re absolutely right—the custom code would have to be reapplied after updating the theme (updating WP would be fine, though).

      I’ve updated the post with a downloadable plugin version of the code, so any customizations you make will be preserved through updates. Enjoy!

      • Larry

        Woops. I saw that WP has an option to upload a plugin that is in zip format and will install it. I did that and activated your plug in and am now getting “Fatal error: Call to undefined function is_rtl() in
        /home/content/70/5439370/html/wp-includes/theme.php on line 1714″.

        • http://alisothegeek.com Alison Barrett

          Try uploading the plugin manually into your wp-content/plugins folder and then activating it. I’m not using the is_rtl() function anywhere. Which version of WordPress are you running?

          • Larry

            WordPress 3.1.2
            Ok, I copied “atg-styles-dropdown.php_” to wp-content/plugins manually via FTP and then activated the plugin. And got the same error.

          • Larry

            Did I do something wrong?

          • http://alisothegeek.com Alison Barrett

            I’m not sure what to tell you—I’m not using is_rtl() anywhere, so I don’t know how it can be my plugin causing it. Maybe it’s some conflict between another plugin and your theme? Try using TwentyTen and see if the error is still there.

          • Toddwas

            Darren’s reccomendation to remove “add_editor_style();” from line 10 worked on my theme also. Thank you to both Alison & Darren!

          • Toddwas

            Darren’s reccomendation to remove “add_editor_style();” from line 10 worked on my theme also. Thank you to both Alison & Darren!

          • Darren

            Larry… I’m having the same issue and I’m working on it. If I find a solution, I’ll make sure to post it.

          • http://alisothegeek.com Alison Barrett

            If you do find a solution, I’ll be sure to edit the post to make whatever fixes necessary to the code. Thank you for working on it!

          • Darren

            Hi Alison and Larry… I got it figured out.  The theme Larry and I are using is probably already using “add_editor_style();”…Simply remove that from line 10 and you should be good to go.

          • Larry

            Hi Darren, I was very excited to see your message. Unfortunately I am not finding that string, but I didn’t set up my theme and am just learning about all of this. I’m assuming that the file you are referencing will be found in  /wp-content/themes/magazine/. And the likely candidates seem to be home.php or functions.php, but I’m not finding that string in these files (or others that I’m perusing around in. I see that I also have a /wp-content/themes/magazine_10 folder that appears to have the fav icon and images that are custom to my site; i.e., not where they should be to allow me to update the theme without messing up these customizations. I probably need to hire someone to fix this since the coder I originally used is unavailable now.

          • Darren

            You’ll find it in Alison’s plugin ‘atg-styles-dropdown.php’ file… Using your favorite FTP program,  look inside your wp-content/plugin/ folder in WP and you should see it. Download it to your desktop, open it with Notepad, remove the line I talked about above then re-upload… Should work for ya :)

          • Larry

            Found that file, removed
            add_editor_style();and I can now activate the plugin without getting the error. But I also still do not have a new styles menu. The line { add_editor_style(); } does not appear in the /wp-content/themes/magazine/functions.php file either. I can add the line to this file (does it matter where in the file?) but I still do not get a styles menu. I’ve never coded in PHP…I must be missing something very fundamental.

            Oh, when I used notepad to edit the ‘atg-styles-dropdown.php’ file, I had to first rename the file to .txt, edit and rename it back. Notepad inserted special characters at the beginning of the file that caused an error when I activated the plug-in. I used the CuteFTP editor instead and it saved the file correctly, but then the issues noted above.

          • Darren

            The only other thing I can think of would be that you’re using the plugin “TinyMCE Advanced”

            If so, you need to go to the settings area of that plugin and drag the “style” dropdown to one of the top 2 lines of the editor.

        • http://www.facebook.com/sunnymorgan Sunny Morgan

          The error is with the add_editor_style() function. I am getting the error as well. If I remove this function then the styles do not show up while editing. Now if I move the code from the plugin file into the function.php file then everything work as expected without an error even with add_editor_style() present. Maybe there is a way to call 
          add_editor_style() a moment later.

  • Pingback: Mastering the TinyMCE Styles Dropdown in the WordPress Visual Editor | WpMash - WordPress News

  • James Dickie

    Hi there,

    A really fantastic tutorial, well done! Off to play with this now.

  • James Dickie

    ah my intention was to also add – is there a method of removing the class assigned to an element in this manner?

  • Pingback: What to do about shortcodes? | unhack WP

  • Pingback: Some ways to customise the WordPress Visual Editor and HTML Editor | things with bits - frances d'ath

  • http://action-a-day.com Ken Brucker

    I’ve been playing with this area of WP myself and one concern I have is that this method does not readily extended across plugins.  If multiple plugins attempt to manipulate styles, the coding method used above will allow only the last one to set style_formats to stick.  A quick mod:  when presented with a non-empty style_formats value, convert from JSON format, apply updates and then convert back to JSON.

  • Armand Morin

    Great post, I’ve been trying to figure this out especially using the “wrapper” aspect. You explained it perfectly. 

    A question though, on your buttons. When you do as you listed here on the buttons, does only the text become linked and not the whole button? I’m trying to make the whole text area clickable and it’s driving me crazy. Any ideas?

    • Armand Morin

      Never mind. Doh! I was wrapping it in a div. I changed to selector and everything is perfect.

  • Pingback: Warren Held.com » Add Custom CSS Styles to WordPress Editor

  • http://twitter.com/trishacupra Trisha Cupra

    Can’t wait to try this! I stumbled upon this post just now, after wondering about this ever since Jason Tadlock wrote the post you referred to.

  • Betriebswirtblog.de

    In my blog the plugin didnt worked with wp 3.21. I got error message and had to remove it manually via ssh.

  • knottulf

    Doesnt work with 3.2.1. Activation leaves the screen totally blank.

  • http://www.reinaris.nl Rein

    Perfect solution. Thanks for your clean explanation! Without plugins like TinyMCE Advanced, great post!

  • http://twitter.com/keramch Kera McHugh

    thank you, thank you, thank you! I have been searching everywhere for an easy way to do this… adding the editor-style.css function worked like a charm! no more client-manually-formatted (and thus likely mis-formatted) posts that clients need me to fix!

  • http://www.facebook.com/simon.farla Simon Farla

    Holy crap you are full of WIN! This is the best way to add different types of buttons to the MCE that I’ve found yet (I’ve tried at least 6 other ways). Thank you for the thorough explanation of the available options.

  • Mike

    Lots of great stuff there and lots to learn. Before the fact, how would I go about reducing the size of the text area (or expanding it in editor-style.css? I can make a conditional if is my template theme use the editor-style-css but what parameters do I put in that stylesheet to make, say, the text area only 1 row high (or 20px) or 150 rows high, etc.?
    Thanks, Mike

  • http://twitter.com/paper_leaf Paper Leaf Design

    This is an absolute must for using WordPress as a CMS. Adding the Styles drop-down to tinyMCE makes my client’s lives so much easier. Adding buttons etc – amazing. Thanks so much.

  • DAWSOG

    I tried this but it does not work

  • scdesigns

    This doesn’t seem to work at all. I get the blank screen too. Been trying to solve this exact problem for hours. I must be missing something easy. UGH!

    • http://alisothegeek.com Alison Barrett

      I’m looking into the white screen issue soon—I’ll post an updated script as soon as I find & fix the problem.

  • Cesar

    Thank you very much for this information. Adding the Styles drop-down to tinyMCE have save me a lot of time, and made my client happy.

  • Pingback: Wordpress: utilizziamo stili personalizzati con l’editor visuale predefinito « Il blog di MrDot

  • Mr.DoT

    Thanks aliso!
    It works perfectly on my WordPress 3 (I followed the 2nd method, because the plugin causes crash to the admin area). 

  • http://ptcampbell.me PTcampbell

    Thanks for this article, you saved me. Much prefer to use these custom functions than a dodgy plugin. 

  • X3msnake

    Thanks for the research and collage :)

    Much helpfull.

  • Pingback: WPSmith | How to Add Genesis Custom Columns to the Editor (to Appear in Visual Mode)

  • http://twitter.com/eyesofjeremy Jeremy Carlson

    Alison, this is absolutely perfect. THANK YOU for writing up your findings and sharing them. I can see how, down the road, someone might expand this into a working plugin, but for the moment, just being able to target a *few* key styles, and APPLY THEM TO BLOCK ELEMENTS … well, what more could I want? You made my morning.

  • http://twitter.com/eyesofjeremy Jeremy Carlson

    I wanted to add in the ID attribute. Took me a minute to realize that it needed to be in an array, e.g.:


        $style_formats = array(
             array(
                'title' => 'Respond Block',
                'block' => 'div',
                'attributes' => array(
                    'id' => 'respond'
                ),
                'wrapper' => true
            )
        );

    Hope this helps someone else.

    • Heinrich

      Hellp me tons.. Thanks!

  • http://www.bookclubrecommendations.org/ Ron

    If you guys are worried about your theme being updated then create a child theme for whatever theme you are using. Then add the code into your child theme’s functions file. That’s what child themes are for.

    Alison a quick question.
    I want to add this functionality in my plugin. If whatever theme my customer is using already has the Style Dropdown will this overright, error or add to it?
    Some may be using the Advanced tinymce plugin as well.

    I’m thinking I would need to do an if function exists, but and then what?
    how would I append my codes to the existing styles.

    Great post. I’ve been looking for how to do this.

  • Pingback: TinyMCE Styles Dropdown | Nick Hamze

  • http://www.darfuria.com Darfuria

    I have added the code to my functions file, but the styles don’t seem to be applied to the text in the editor / the code doesn’t change. Any suggestions?

    • Cristian Giordano

      You will need to create a stylesheet in your theme called editor-style.css then put all of your custom styles in there. if you want to use another named style sheet you can simply call it via the method i.e. add_editor_style( ‘custom-editor-style.css’ );

      or if you want to place it in a sub folder : add_editor_style( ‘lib/css/editor-style.css’ );

      Always read the docs: http://codex.wordpress.org/Function_Reference/add_editor_style

      Hope that helps!

  • Pingback: What to do about shortcodes? | Nick Hamze

  • Aesthetic

    Just installed your plugin and the demo arrays included work just fine. I’m trying to create a new style rule and I’ve tried several options and can’t seem to find the right combination. What I want is for the client to be able to select some text, pick the Principal style from the pull down and have the selected text wrapped with

            array(        ‘title’ => ‘Principal’,        ‘selector’ => ‘h3′,        ‘classes’ => ‘principal’,        ‘wrapper’ => true        ),

    I’ve tried it also with block or inline but nothing works. I don’t want them to have to make it an H3 and then style it. Is it possible to do what I’m trying?

  • Lemmonaid

    Man, you rules! I was looking for this for a long time!

  • http://profiles.google.com/sebastianjthomas sebastian thomas

    Any one else tackled the problem of clearing styles? It seems if the user switches between different styles, the plugin will just keep wrapping more and more elements around it, no?

    • https://www.facebook.com/BeerSupporter Jason Taylor

       I’m having problems clearing HR tags. Did you find a solution to this?

  • Brett H

    I’m trying to do column’s with this, but the merge similar styles thing is just lumping them into one . Even when i set ‘exact’ to true. Any ideas? 

    • George

      I am having the same issue. I need to format a large amount of text into a series of divs with the same class. When the divs are applied next to one another, they merge. I also have ‘exact’ set to true.

  • http://www.facebook.com/kszaman Ks Zaman

    Good helpful example.  http://www.shortcodepress.com here I have implemented a tinumce buttonon editor for wordpress shortcode plugin

  • Jason

     Thank you for putting so much time into this! It is truly appreciated :)

  • Jilly

    Wow. That’s what I was desperately looking for. Works perfect on WP 3.3.1. Thank you man.

  • Emerson

    I’m running 3.3.2 and it doesn’t work. Crashes on activation and has to be manually deleted.