• Resolved Justin Tadlock

    (@greenshady)


    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' ). It’s output via PHP.

    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 inserting that into the visual editor. Any help would be greatly appreciated.

Viewing 15 replies - 1 through 15 (of 17 total)
  • Moderator Ipstenu (Mika Epstein)

    (@ipstenu)

    ?????? Advisor and Activist

    Wouldn’t admin_head work?

    https://codex.www.ads-software.com/Plugin_API/Action_Reference/admin_head

    You could check if you’re on the edit page too.

    Jon Christopher

    (@jchristopher)

    I know it’s not an ideal suggestion, but what if a static CSS file got generated via WP_Filesystem so it does in fact exist on the hard drive somewhere and then you could use add_editor_style()? Is that out of the question?

    The third parameter of wp_editor takes editor settings. If you send a “editor_css” value, it will apply to the editor:

    wp_editor(
    	$content,
    	$editor_id,
    	array(
    		'editor_css' => '<style type="text/css" scoped>.whatever{display:none;}</style>'
    	)
    );
    Thread Starter Justin Tadlock

    (@greenshady)

    Wouldn’t admin_head work?

    No, that wouldn’t work. The editor is in an <iframe>, so styles from the admin head wouldn’t touch it. Not to mention, the editor can be loaded anywhere on the site.

    I know it’s not an ideal suggestion, but what if a static CSS file got generated via WP_Filesystem so it does in fact exist on the hard drive somewhere and then you could use add_editor_style()? Is that out of the question?

    That’s out of the question. Mostly, for the reasons Otto says here: https://ottopress.com/2011/tutorial-using-the-wp_filesystem/

    The third parameter of wp_editor takes editor settings. If you send a “editor_css” value, it will apply to the editor:

    That looks like something worth investigating. Let me check it out.

    OriginalEXE

    (@originalexe)

    The third parameter of wp_editor takes editor settings. If you send a “editor_css” value, it will apply to the editor:

    That won’t help, that is for printing css outside of iframe, you can’t use it for printing inside actual TinyMce iframe.

    @justin are you ok with JS based solution for this?

    Thread Starter Justin Tadlock

    (@greenshady)

    It looks like Zack’s solution does indeed add the styles, but it doesn’t add them within the generated iframe. From what I can see, it allows you to add some custom CSS when the editor is called, but it’s not specific to the editor content.

    Thread Starter Justin Tadlock

    (@greenshady)

    Looks like you beat me to it.

    @justin are you ok with JS based solution for this?

    Yep. I’m fine with JS.

    OriginalEXE

    (@originalexe)

    Actually there is no other way around this but to use custom JS.

    Only way you could print this in the iframe with only using PHP is either to use solution suggested above (creating actual css, which is not that great) or to hook into ‘the_editor_content’ and print ‘<style>’ there, but that would be bad solution because it could be deleted in text editor mode.

    Thread Starter Justin Tadlock

    (@greenshady)

    I was thinking that JS would be the only method. Now, I just got to figure out how to do that with JS.

    OriginalEXE

    (@originalexe)

    I managed to do it, it might need some more optimisation and checks but it works now:

    function my_custom_editor_stylesheet( $editor_id ){
    
    	if ( 'content' !== $editor_id )
    		return;
    
    	$bg_color = '#000';
    
    	echo '<div id="my_unique_stylesheet_id" style="display: none !important;">body { background: ' . $bg_color . '; }</div>';
    	echo '
    	<script type="text/javascript">
    		(function(){
    
    			var checkInterval = setInterval( function() {
    
    				if ( typeof(tinyMCE) !== "undefined" ) {
    					if ( tinyMCE.activeEditor && ! tinyMCE.activeEditor.isHidden() ) {
    
    						jQuery( "#content_ifr" ).contents().find( "head" ).append( "<style type=\'text/css\'>" + jQuery( "#my_unique_stylesheet_id" ).text() + "</style>" );
    
    						clearInterval( checkInterval );
    
    					}
    				}
    
    			}, 500);
    
    		}());
    	</script>';
    
    }
    
    add_action('media_buttons', 'my_custom_editor_stylesheet');
    OriginalEXE

    (@originalexe)

    Note that you should prefix your all css rules with #tinymce since stylesheet is printed outside of iframe to.

    There is a way around it though, give me a minute.

    OriginalEXE

    (@originalexe)

    Ok edited and replaced with much better version, it prints in head instead of body (which was stupid of me) and you don’t have to prefix rules.

    One more note, I check for editor id up there and bail out of id is not “content”, id used by default editor appearing on post edit screen.

    You mentioned using wp_editor on frontend too so you might want to tweak that.

    Thread Starter Justin Tadlock

    (@greenshady)

    Awesome work! I tried to simplify that just a bit and hook into before_wp_tiny_mce.

    add_action( 'before_wp_tiny_mce', 'stargazer_tinymce_callback' );
    
    function stargazer_tinymce_callback() { ?>
    
    	<script type="text/javascript">
    		(function(){
    
    			var my_style = "p { color: red; }";
    
    			var checkInterval = setInterval( function() {
    
    				if ( typeof(tinyMCE) !== "undefined" ) {
    					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 }

    I’m going to play around with this and see what I can do to break it down even more if possible.

    OriginalEXE

    (@originalexe)

    Yup awesome, definitely a lot cleaner.

    It could even be done via external theme js file and wp_localize_script.

    One more suggestion, instead of targeting iframe with id jQuery( "#content_ifr" ) which will be different depending on editor id (scheme is $editor_id + ‘_ifr’), it would probably be better to use jQuery( '.mceContentBody' ) class targeting, since it’s applied to all instances of TinyMCE.

    Also, maybe it would be worth thinking how to allow plugin developers to “opt-out” of your styling (if you will use class for targeting). That could either be done via exclusivity or (better) inclusivity (to target only default content editor and your own custom editors).

    For example, you could only target iframes who have $editor_id either ‘content’ or ‘stargazer’ inside of it.

    Such check would have to be inside js and would be pretty simple to accomplish.

    Thread Starter Justin Tadlock

    (@greenshady)

    Cross-posted this on WPSE too:
    https://wordpress.stackexchange.com/questions/120831/how-to-add-custom-css-theme-option-to-tinymce/

    Now, I’m overwhelmed with solutions when I had none to start with. If you’re interested in other ideas, definitely check that out.

Viewing 15 replies - 1 through 15 (of 17 total)
  • The topic ‘Custom/Dynamic CSS in TinyMCE’ is closed to new replies.