Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm trying to add custom CSS (set via theme options) to the TinyMCE visual editor in WordPress. On the front end, the theme generates this CSS and outputs it on the wp_head hook. The problem I'm running into is being able to add that CSS output to the editor.

This can't be done with add_editor_style( 'editor-style.css' ) because we need to use PHP to access the theme option.

As an example of how it works on the front end:

add_action( 'wp_head', 'my_custom_colors' );

function my_custom_colors() {
    $color_1 = get_theme_mod( 'color_1', 'cc4a00' );

    echo "<style type='text/css'>a { color: #{$color_1}; }";
}

I need a method for getting that custom style into the visual editor. Any help would be greatly appreciated.

share|improve this question
1  
Note: custom post-content CSS is Plugin Territory, and should not be put in a Theme. Otherwise, users will lose their custom CSS when switching to a different Theme. –  Chip Bennett Oct 31 '13 at 19:15
    
@ChipBennett I only partly agree. This highly depends on what you're styling. Aside from that, it doesn't matter where it is (for that question). –  kaiser Oct 31 '13 at 19:18
    
@ChipBennett This has to do with theme styles, not custom post content CSS. This is pretty standard stuff that you can do with the theme customizer. It's just applying these styles that has me stumped. It's meant to compliment editor-style.css, which is theme territory. –  Justin Tadlock Oct 31 '13 at 19:22
    
Wait: are you talking about dynamic custom editor style? As in: make the visual editor (TinyMCE) aware of Theme option-defined styles? If so, disregard my original comment, and +1 for the question. –  Chip Bennett Oct 31 '13 at 19:26
    
Could you file an edit and show an example of a full set for the theme style? Would be easier to test then. –  kaiser Oct 31 '13 at 19:52

5 Answers 5

up vote 6 down vote accepted

Solution 1

This works as javascript solution:

Example:

tinyMCE.activeEditor.dom.addStyle('p {color:red; font-size:28px;}');

just open your js console and paste it for a quick test. To target a specific editor one should use:

tinyMCE.getInstanceById('##editorID##').dom.addStyle('p {color:red; font-size:28px;}');

This will inject the provided string into the editors iframe <head><style id="mceDefaultStyles"></style> ...

Solution 2

Use wp_ajax as callback handler to add dynamic styles on editor init by using a filter

add_filter('tiny_mce_before_init', 'dynamic_editor_styles', 10);

function dynamic_editor_styles($settings){
    // you could use a custom php file as well, I'm using wp_ajax as
    // callback handler for demonstration
    // content_css is a string with several files seperated by a comma
    // e.g. file1, file2, ... extend the string

    $settings['content_css'] .= ",".admin_url('admin-ajax.php') ."/?action=dynamic_styles";

    return $settings;
}

// add wp_ajax callback
add_action('wp_ajax_dynamic_styles', 'dynamic_styles_callback');
function dynamic_styles_callback(){
    echo "p {color:red} h1{font-size:48px;}";
}
share|improve this answer
1  
I'm not entirely sure what to do with that. –  Justin Tadlock Oct 31 '13 at 20:07
    
Solution #2 actually makes a lot of sense to me. I'll give that a test run. –  Justin Tadlock Oct 31 '13 at 20:23
    
I went with solution #2. The difference is that I dropped the first function and used add_editor_style( add_query_arg( 'action', 'my_editor_styles', admin_url( 'admin-ajax.php' ) ) since this is the standard way for themes to add editor styles. –  Justin Tadlock Oct 31 '13 at 20:49
    
Just for my own edification, I'd be curious to know if mce_css worked for you (if you tried it). –  Chip Bennett Oct 31 '13 at 21:18
    
I actually haven't tried it because I knew you could pass a non-CSS file to add_editor_style(), but it should work just fine looking at the code. Using mce_css is actually a better solution in the case that you need to hook in after styles added via add_editor_style(). One such reason in a theme is because full URLs added via add_editor_style() are output first, despite the order they're added. –  Justin Tadlock Oct 31 '13 at 21:40

WordPress provides a mce_css filter, that can be used to add custom stylesheets to the Visual Editor. According to the Codex:

The file can be a .php file, allowing dynamic generation of CSS rules for the content editor.

Example Codex filter callback, modified for a Theme:

function wpse120831_mce_css( $mce_css ) {
    if ( ! empty( $mce_css ) )
        $mce_css .= ',';

    $mce_css .= get_template_directory_uri() . '/dynamic-css.php';

    return $mce_css;
}

add_filter( 'mce_css', 'wpse120831_mce_css' );
share|improve this answer
    
Mr.Bennett was faster, just added that to my answer below as well :), but slightly different. –  ungestaltbar Oct 31 '13 at 20:13
    
@ungestaltbar we're actually using two entirely different filters. :) –  Chip Bennett Oct 31 '13 at 20:22
    
with the same result :) –  ungestaltbar Oct 31 '13 at 20:25

I accepted the solution above by @ungestaltbar. However, I wanted to expand on this answer a bit with the full solution that I am using so that others could see how it works.

add_action( 'after_setup_theme', 'my_theme_setup' );

function my_theme_setup() {

    add_editor_style(
        array(
            'editor-style.css',
            add_query_arg( 'action', 'my_editor_styles', admin_url( 'admin-ajax.php' ) ),
        )
    );
}

add_action( 'wp_ajax_my_editor_styles', 'my_editor_styles_callback' );
add_action( 'wp_ajax_nopriv_my_editor_styles', 'my_editor_styles_callback' );

function my_editor_styles_callback() {

    // @todo sanitize
    $color_1 = get_theme_mod( 'color_1', 'cc4a00' );

    echo "a { color: #{$color_1}; }";

    die();
}

I'm hoping it's okay to post another answer here like this. I didn't see a way to post this in direct reply to my accepted solution. I'm still learning how to use WPSE.

share|improve this answer
    
Maybe you should add add_action( 'wp_ajax_nopriv_my_editor_styles', 'my_editor_styles_callback' ); if editor is used on the frontend (for non logged-in users). –  OriginalEXE Oct 31 '13 at 21:06
    
Yes, answer with significant changes/tweaks is perfectly fine. :) FYI if it was over some issue to be fixed in original answer then submitting edit to it would be way to go. –  Rarst Oct 31 '13 at 21:11
    
@OriginalEXE - Yep. I'll update it. –  Justin Tadlock Oct 31 '13 at 21:23
    
@Rarst - Thanks for clarifying. –  Justin Tadlock Oct 31 '13 at 21:24
    
Just a tip for anyone else who finds this later, I was unable to get this to work properly, as it's presented. I finally figured out that I had to include header information in the callback, so it would be seen as css. header("Content-type: text/css; charset: UTF-8"); Not sure if this is something different in my .htaccess or what. –  Aargh-a-Knot Nov 18 at 15:29

I am probably late to this party but after using the above solution, I soon realized that page load speed of the editor had severely been crippled! Taking a keen look at the code, I realized that the code keeps executing long after tinyMCE.activeEditor has been initialized. The code uses The setInterval() method which evaluates an expression at specified intervals, I believe that was because you couldn't determine at what point during code execution "activeEditor" will be available. This is what brought the page speed down to its knees.

A much better solution I am using to build a plugin is this

   /**
     * Extend TinyMCE config with a setup function.
     * See http://www.tinymce.com/wiki.php/API3:event.tinymce.Editor.onInit

     */
    function custom_tinymce_css($init) {

      $css = get_option('some_css'); 

     ?>

        <script type="text/javascript">            

            function addTempCSS( ed ) {
                ed.onInit.add( function() {
                    tinyMCE.activeEditor.dom.addStyle(<?php echo json_encode($css) ?>);
                } );
            };
        </script>

        <?php
        if (wp_default_editor() == 'tinymce')
            $init['setup'] = 'addTempCSS';

        return $init;
    }
    add_filter('tiny_mce_before_init', 'custom_tinymce_css');

Here a native TinyMCE listener is used to execute the code after the active editor is initialized. I hope this will help someone out there. Kind regards.

share|improve this answer

This is a modified solution posted on the WordPress.org forums for this question: http://wordpress.org/support/topic/customdynamic-css-in-tinymce?replies=14#post-4827573

This definitely works. I'm no JS guru though, so I'm not entirely sure if this is the best solution.

add_action( 'before_wp_tiny_mce', 'my_tinymce_callback' );

function my_tinymce_callback() {

    $color_1 = get_theme_mod( 'color_1', 'cc4a00' ); ?>

    <script type="text/javascript">
    jQuery( document ).ready(

        function() {
            var my_style = 'a { color: #<?php echo $color_1; ?>; }';

            var checkInterval = setInterval(
                function() {

                    if ( 'undefined' !== typeof( tinyMCE ) ) {
                        if ( tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden() ) {

                            jQuery( '#content_ifr' ).contents().find( 'head' ).append( '<style type="text/css">' + my_style + '</style>' );

                            clearInterval( checkInterval );
                        }
                    }
                }, 
                500 
            );
        }
    );
    </script>
<?php }

This could also be added to a JS file. You could easily pass variables via wp_localize_script() with that.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.