Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic editor styles and inline CSS without targetting .editor-styles-wrapper #18571

Closed
jasmussen opened this issue Nov 18, 2019 · 8 comments
Closed
Labels
[Feature] Custom Editor Styles Functionality for adding custom editor styles [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. Needs Technical Feedback Needs testing from a developer perspective. [Type] Question Questions about the design or development of the editor.

Comments

@jasmussen
Copy link
Contributor

Twenty Twenty includes color settings in the Customizer for background color and accent color, and based on these settings, it generates ten different colors that it applies to different elements in the theme. In order to give the user a good idea of how their content will look when published, these colors also need to be applied to style elements in the block editor interface.

This ticket was created after a conversation with @andersnoren who added most of the technical context here.

The add_editor_style() function doesn’t support appending inline styles to the stylesheet.

Because of this, Twenty Twenty uses wp_enqueue_style() and wp_style_add_data() in a function hooked to the enqueue_block_editor_assets action:

function twentytwenty_block_editor_styles() {

	// Enqueue the editor styles.
	wp_enqueue_style( 'twentytwenty-block-editor-styles', get_theme_file_uri( '/assets/css/editor-style-block.css' ), array(), wp_get_theme()->get( 'Version' ), 'all' );
	wp_style_add_data( 'twentytwenty-block-editor-styles', 'rtl', 'replace' );

	// Add inline style from the Customizer.
	wp_add_inline_style( 'twentytwenty-block-editor-styles', twentytwenty_get_customizer_css( 'block-editor' ) );

	// Add inline style for non-latin fonts.
	wp_add_inline_style( 'twentytwenty-block-editor-styles', TwentyTwenty_Non_Latin_Languages::get_non_latin_css( 'block-editor' ) );

	// Enqueue the editor script.
	wp_enqueue_script( 'twentytwenty-block-editor-script', get_theme_file_uri( '/assets/js/editor-script-block.js' ), array( 'wp-blocks', 'wp-dom' ), wp_get_theme()->get( 'Version' ), true );
}

add_action( 'enqueue_block_editor_assets', 'twentytwenty_block_editor_styles', 1, 1 );

(Twenty Twenty also sets different font families depending on which locale is active, as seen in the line beneath ”Add inline style for non-latin fonts.”)

As a result of this, some of those inline styles explicitly target .editor-styles-wrapper, in order to apply to only the right blocks and places.

The primary purpose of add_editor_style is for theme developers to avoid having to write custom CSS just for the editor, or more precisely to avoid having to target .editor-styles-wrapper at all, as that increases specificity unnecessarily and could break in future updates to the block editor structure, for example a change that necessitates a different classname or a new element.

So, ideally, the stylesheet enqueues above could be replaced with add_editor_style. This is currently not possible – at least not while following theme directory guidelines. A workaround could be to write the dynamic colors directly to a CSS file, which is then added using add_editor_style( 'editor-style.css' ), but themes on the WordPress.org theme directory are (fortunately) not allowed to write to files.

There might be a usecase for a function that has the same relationship to add_editor_style() as wp_add_inline_style() has to wp_enqueue_style(), allowing themes to append inline styles to the editor stylesheet. The code block above could then be partially replaced by something like:

function twentytwenty_classic_editor_styles() {

	// Enqueue the editor styles.
	add_editor_style( '/assets/css/editor-style-block.css' );
	
	// Add inline style from the Customizer.
	add_inline_editor_style( '/assets/css/editor-style-block.css', twentytwenty_get_customizer_css( 'block-editor' ) );

	// Add inline style for non-latin fonts.
	add_inline_editor_style( '/assets/css/editor-style-block.css', TwentyTwenty_Non_Latin_Languages::get_non_latin_css( 'block-editor' ) );

}

add_action( 'init', 'twentytwenty_classic_editor_styles' );

...allowing themes to enqueue dynamic block editor styles while still using add_editor_style.

Is there a better way?

For now, the above is posted as an opener for a discussion about how to achieve what TwentyTwenty does with dynamic editor styles. Is there a way to do it today that avoids targetting .editor-styles-wrapper?

Or is there a use case for a new function, like add_editor_style, which accomplishes the same?

Thoughts welcome!

@jasmussen jasmussen added [Type] Question Questions about the design or development of the editor. Needs Design Feedback Needs general design feedback. [Feature] Custom Editor Styles Functionality for adding custom editor styles labels Nov 18, 2019
@karmatosed karmatosed added the [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. label Dec 18, 2019
@richtabor
Copy link
Member

I agree, a purposeful function to allow inline styles for editor styles would be a good addition. I've had to do similar work-arounds with the Gutenberg-optimized themes I've build as well.

@jasmussen jasmussen added the Needs Technical Feedback Needs testing from a developer perspective. label Dec 19, 2019
@ellatrix
Copy link
Member

Thanks for creating this issue! It's important for the work on iframing the content to get this right. The way it is done in Twenty Twenty will be copied over a lot by other theme authors. :/ I will probably have two go through stylesheets in JS, see if the target .editor-styles-wrapper, and then load them in the iframe as well.

@anastis
Copy link

anastis commented Apr 24, 2020

There is a shorter workaround, that should pass TRT guidelines, doesn't write a file, and avoids the need for duplicate CSS with different selectors.
add_editor_style() accepts either a local filename or a URL. In the case of URL, it will initiate a wp_remote_get() to get the contents.

We can short-circuit wp_remote_get() to return a response with our generated inline styles, which will then be processed normally by the block editor, selector rewrites and all.

add_action( 'after_setup_theme', 'my_theme_setup' );
function my_theme_setup() {
	add_theme_support( 'editor-styles' );
	// Trick editor into loading inline styles. See my_theme_pre_http_request_block_editor_customizer_styles()
	add_editor_style( 'https://my-theme-block-editor-customizer-styles' );

}

add_filter( 'pre_http_request', 'my_theme_pre_http_request_block_editor_customizer_styles', 10, 3 );
function my_theme_pre_http_request_block_editor_customizer_styles( $response, $parsed_args, $url ) {
	if ( 'https://my-theme-block-editor-customizer-styles' === $url ) {
		$response = array(
			'body'     => my_theme_get_customizer_css(), // E.g. 'body { background-color: #fbca04; }'
			'headers'  => new Requests_Utility_CaseInsensitiveDictionary(),
			'response' => array(
				'code'    => 200,
				'message' => 'OK',
			),
			'cookies'  => array(),
			'filename' => null,
		);
	}

	return $response;
}

@strarsis
Copy link
Contributor

I add a theme style that is automatically adjusted to match inside the .editor-styles-wrapper,
and an editor theme that is not automatically adjusted with which I can select everything on the editor page.

@ellatrix
Copy link
Member

I think we should make add_editor_style more flexible to allow passing a WP dependency handle. So you could register a style, add inline styles, and then pass the handle to add_editor_style. I don't think we should be adding new APIs.

@wpsoul
Copy link

wpsoul commented Aug 2, 2021

Definitely, we need some universal functionality to load static and dynamic styles to all contexts of the editor.
add_editor_style can load only static files, but we have a lot of dynamic styles which are based on user selection in the customizer.

Additionally, to give more freedom, we need next improvements

  1. Hooks which are exclusive for iframes. Something like admin_iframe_head. This allows us to load special styles and scripts only to iframes with the editor
  2. Improvements to Block API. Currently, it allows setting only one file for editorStyle, editorScript. Must be allowed an array of files
  3. Common wrapper for editor in all contexts (template, widget, post content). We used #editor early, then .editor-styles-wrapper, but now all contexts have different wrappers.

@andreiglingeanu
Copy link
Contributor

andreiglingeanu commented Aug 9, 2023

A very elegant solution to this problem is to use the block_editor_settings_all filter in order to append a dynamic editor style. Then, it is even possible to dynamically alter these styles on the client side without having to locate the <style> tag and mutating it directly by altering the editor settings.

Example:

add_filter(
  'block_editor_settings_all',
  function($settings) {
    $settings['styles'][] = array(
      'css' => ':root {--test: red;}',
      '__unstableType' => 'theme',
      'source' => 'blocksy'
    );

    return $settings;
  }
);
const settings = window.wp.data.select("core/editor").getEditorSettings();

wp.data.dispatch("core/editor").updateEditorSettings({
  ...settings,
  styles: settings.styles.map((s) => {
    if (s.source !== "blocksy") {
      return s;
    }

    return {
      ...s,
      css: ":root {--test: blue;}",
    };
  }),
});

Demo:

CleanShot.2023-08-08.at.19.23.15.mp4

For us in Blocksy, it works wonders.

PR in core where a more general solution for the plugins is being explored: #52767

Props to @ellatrix for the hint.

@jasmussen
Copy link
Contributor Author

I'm going to close this one since #52767 has been merged, and that should ideally cover the use case. Related: #46752

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Custom Editor Styles Functionality for adding custom editor styles [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. Needs Technical Feedback Needs testing from a developer perspective. [Type] Question Questions about the design or development of the editor.
Projects
None yet
Development

No branches or pull requests

8 participants