WordPress.org

Ready to get started?Download WordPress

Forums

[resolved] Custom/Dynamic CSS in TinyMCE (18 posts)

  1. Justin Tadlock
    Member
    Posted 9 months ago #

    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.

  2. Wouldn't admin_head work?

    http://codex.wordpress.org/Plugin_API/Action_Reference/admin_head

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

  3. Jonathan Christopher
    Member
    Posted 9 months ago #

    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?

  4. Zack Tollman
    Member
    Posted 9 months ago #

    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>'
    	)
    );
  5. Justin Tadlock
    Member
    Posted 9 months ago #

    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: http://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.

  6. OriginalEXE
    Member
    Posted 9 months ago #

    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?

  7. Justin Tadlock
    Member
    Posted 9 months ago #

    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.

  8. Justin Tadlock
    Member
    Posted 9 months ago #

    Looks like you beat me to it.

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

    Yep. I'm fine with JS.

  9. OriginalEXE
    Member
    Posted 9 months ago #

    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.

  10. Justin Tadlock
    Member
    Posted 9 months ago #

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

  11. OriginalEXE
    Member
    Posted 9 months ago #

    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');
  12. OriginalEXE
    Member
    Posted 9 months ago #

    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.

  13. OriginalEXE
    Member
    Posted 9 months ago #

    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.

  14. Justin Tadlock
    Member
    Posted 9 months ago #

    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.

  15. OriginalEXE
    Member
    Posted 9 months ago #

    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.

  16. Justin Tadlock
    Member
    Posted 9 months ago #

    Cross-posted this on WPSE too:
    http://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.

  17. OriginalEXE
    Member
    Posted 9 months ago #

    Awesome, the solution you went with is really smart way, no js needed (looks like I was wrong).

  18. Justin Tadlock
    Member
    Posted 9 months ago #

    Just letting everyone that saw this thread that the solution is posted on the WPSE link above. Thanks for the feedback and help.

Reply

You must log in to post.

About this Topic

Tags