Custom WordPress and WooCommerce Development

Custom styles for TinyMCE 4.0 in WordPress 3.9

The release of WordPress 3.9 saw the update of the included TinyMCE editor to version of 4.0 and this caused no small amount of havoc for people who’d been customizing the text editor. In the past, one was able to define one’s own custom styles and modify the block formats like so:

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

function mce_mod( $init ) {
    $init['theme_advanced_blockformats'] = 'p,h3,h4';
    $init['theme_advanced_styles'] = "Big Header=bigheaderclass; Red Header=redheaderclass";
    return $init;
}
add_filter('tiny_mce_before_init', 'mce_mod');

You’re a Real Button Now

But surprise! With the update this doesn’t work any more. Digging into the TinyMCE scripts, the formats appear to now be a custom tinyMCE button. You can see that the formatselect button is added to mce_buttons_2; in the class-wp-editor.php;. And then I tracked that to tinymce.js :

editor.addButton('formatselect', function() {
    var items = [], blocks = createFormats(editor.settings.block_formats ||
    'Paragraph=p;' +
    'Address=address;' +
    'Pre=pre;' +
    'Heading 1=h1;' +
    'Heading 2=h2;' +
    'Heading 3=h3;' +
    'Heading 4=h4;' +
    'Heading 5=h5;' +
    'Heading 6=h6'
);

With that in mind, it appears that to modify the block formats, we’ll need to change the editor.settings.block_formats. And theme_advanced_syles; has now become style_formats; in the TinyMCE init object.

Putting it All Together

function mce_mod( $init ) {
    $init['block_formats'] = 'Paragraph=p;Heading 3=h3;Heading 4=h4';

    $style_formats = array (
    array( 'title' => 'Bold text', 'inline' => 'b' ),
    array( 'title' => 'Red text', 'inline' => 'span', 'styles' => array( 'color' => '#ff0000' ) ),
    array( 'title' => 'Red header', 'block' => 'h1', 'styles' => array( 'color' => '#ff0000' ) ),
    array( 'title' => 'Example 1', 'inline' => 'span', 'classes' => 'example1' ),
    array( 'title' => 'Example 2', 'inline' => 'span', 'classes' => 'example2' )
);

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

    $init['style_formats_merge'] = false;
    return $init;
}
add_filter('tiny_mce_before_init', 'mce_mod');

function mce_add_buttons( $buttons ){
    array_splice( $buttons, 1, 0, 'styleselect' );
    return $buttons;
}
add_filter( 'mce_buttons_2', 'mce_add_buttons' );

Small caveat: I’m not sure where to add the styles for the drop-down items themselves. In the TinyMCE sample, the “Red Headline“ option is red. I couldn’t figure this out. If you do please let me know in the comments!  


Comments

11 responses to “Custom styles for TinyMCE 4.0 in WordPress 3.9”

  1. Lawrie Avatar
    Lawrie

    Thankyou! I only just realised all of my handy style dropdowns for some 50+ clients magically stopped working overnight, so I’ve got many, many, many updates to look forward to.

    FYI, I posted a link back to this on a ridiculously unhelpful wordpress.org forum post about the same thing (“How do I fix this? Oh, no worries, I figured it out.” Thanks…), as this is actually useful information.

    1. Oh man, that’s a lot of sites to update. Courage friend. And you have no idea how much I hate forum posts like that. To me WordPress is all about sharing. Take some knowledge from one and give some knowledge to another. “I figured it out” doesn’t pay it forward at all.

      1. For the record, that WordPress.org post was mine. I’m sorry it happened like that. For what it’s worth, I had good reason.

        I did go back today and post my solution.

        1. Great! Thanks for going back to post your solution. You never know who that might help in the future.

  2. Have you found a way to change the label on the style_formats menu? (It’s “Formats” by default.)

    1. Nope, sorry. I haven’t even looked at that. I would suggest reading class-wp-editor.php and tinymce.js. If it is possible to do, that’s probably where you’d find the tip off.

      1. Thanks Kathy.

  3. Dalton Avatar
    Dalton

    This is so frustrating, I really need the fonts to display their colors in the formats dropdown. I have multiple heading styles distinguished only by color, and having “Red H2” and “Blue H2” in the dropdown, displayed in black, just doesn’t cut it. It’s interesting that the dropdown pulls in font family, font size, and font weight, but not color from editor-styles.css.

    It’s an ugly hack, but I added a second stylesheet that’s loaded in the admin specifically for the colors. Each element in the dropdown has an ID, like #mce_72, #mce_73, etc, which you can target with CSS to add the color. This is fragile, since adding in additional formats can change the the IDs, but it works as a temporary fix. I’m considering creating a bounty on WP StackExchange for this item, because I think it needs to be fixed in WP core.

    1. That should be possible in the style_formats option, but I couldn’t figure it out. You can see it in action at the TinyMCE demo and I thought I PHP-ified the javascript object (before json_encoding it) but no luck. The styles don’t pull from the editor-style.css they are added to an inline style tag by TinyMCE… in theory anyway if not in practice. Hope to see your question on SE and maybe we’ll find an answer.

      1. Dalton Avatar
        Dalton

        Ah – I found it in an old WPSE thread: http://wordpress.stackexchange.com/a/116790/799

        Add unset($init['preview_styles']); to your function to allow color and other styles to be inherited from the editor stylesheet.

        Thanks very much for your post!

  4. Matthew Trow Avatar
    Matthew Trow

    This was a great post to get me started on figuring this out and ultimately lead me to the wordpress codex entries for this specific issue. I guess the codex entries possibly hadn’t been updated at the time this post was made, however, it ranks highly in google for a specific search for custom wordpress tinymce styles.

    First, the style info on the codex:

    https://codex.wordpress.org/TinyMCE_Custom_Styles

    Secondly, a great resource on configuring tinymce – including toolbars, block formats etc.
    Note, to enable the custom styles, you’ll need ‘styleselect’ as one of the toolbar options.

    Putting it all together:

    // Wysiwyg editor configuration (Tiny MCE)

    function my_format_TinyMCE( $in ) {
    $in['remove_linebreaks'] = false;
    $in['gecko_spellcheck'] = false;
    $in['keep_styles'] = true;
    $in['accessibility_focus'] = true;
    $in['tabfocus_elements'] = 'major-publishing-actions';
    $in['media_strict'] = false;
    $in['paste_remove_styles'] = false;
    $in['paste_remove_spans'] = false;
    $in['paste_strip_class_attributes'] = 'none';
    $in['paste_text_use_dialog'] = true;
    $in['wpeditimage_disable_captions'] = true;
    $in['plugins'] = 'tabfocus,paste,media,fullscreen,wordpress,wpeditimage,wpgallery,wplink,wpdialogs,wpfullscreen';
    $in['content_css'] = get_template_directory_uri() . "/editor-style.css";
    $in['wpautop'] = true;
    $in['apply_source_formatting'] = false;
    $in['block_formats'] = "Paragraph=p; Heading 3=h3; Heading 4=h4";
    $in['toolbar1'] = 'bold,italic,strikethrough,bullist,numlist,blockquote,hr,link,unlink,wp_more,spellchecker,wp_fullscreen,wp_adv ';
    $in['toolbar2'] = 'formatselect,styleselect,underline,pastetext,removeformat,charmap,undo,redo,wp_help ';
    $in['toolbar3'] = '';
    $in['toolbar4'] = '';
    return $in;
    }

    // Callback function to filter the MCE settings
    function my_mce_before_init_insert_formats( $init_array ) {
    // Define the style_formats array
    $style_formats = array(
    // Each array child is a format with it's own settings
    array(
    'title' => '.translation',
    'block' => 'blockquote',
    'classes' => 'translation',
    'wrapper' => true,

    ),
    array(
    'title' => '⇠.rtl',
    'block' => 'blockquote',
    'classes' => 'rtl',
    'wrapper' => true,
    ),
    array(
    'title' => '.ltr⇢',
    'block' => 'blockquote',
    'classes' => 'ltr',
    'wrapper' => true,
    ),
    );
    // Insert the array, JSON ENCODED, into 'style_formats'
    $init_array['style_formats'] = json_encode( $style_formats );
    return $init_array;
    }

    // Add our filters
    add_filter('tiny_mce_before_init', 'my_mce_before_init_insert_formats' );
    add_filter('tiny_mce_before_init', 'my_format_TinyMCE' );