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

Allow themes to dynamically add CSS class names to the editor wrapper #26494

Closed
Aljullu opened this issue Oct 27, 2020 · 10 comments
Closed

Allow themes to dynamically add CSS class names to the editor wrapper #26494

Aljullu opened this issue Oct 27, 2020 · 10 comments
Labels
[Feature] Custom Editor Styles Functionality for adding custom editor styles [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. [Type] Enhancement A suggestion for improvement.

Comments

@Aljullu
Copy link
Contributor

Aljullu commented Oct 27, 2020

Is your feature request related to a problem? Please describe.
WordPress themes might have several page templates that might have different styles (different background colors, widths, etc.). Currently there is no easy way for themes to apply those styles in the editor when the user changes the active template.

Our specific use-case: In Storefront, we have a 'default' template and a 'full width' template, which have a narrow and wide content area respectively. Until now, when the user changed the page template, Storefront added a class to .block-editor-writing-flow. That class was used to apply narrow/wide styles appropriately. While the solution is very fragile because it directly modifies the DOM, it used to work fine until WP 5.6, when it stopped working because we are relying on .block-editor-writing-flow existing on wp.domReady(), but that seems to be no longer the case: .block-editor-writing-flow is appended later.

Peek 2020-10-21 17-22

I'm working on a solution to the issue (woocommerce/storefront#1520) which relies on a mutation observer to detect when .block-editor-writing-flow is added to the DOM, but that solution is far from ideal because it relies on editor markup not changing in future versions.

Describe the solution you'd like
Themes should have an easy way to load styles in the editor based on the selected template.

Some proposed solutions:

  • Allow an easy way for themes to dynamically add classes to the editor wrapper. That would allow the theme to change the editor wrapper class name after a template change occurs. Ideally, this would be an API so themes don't need to modify the DOM directly.
  • Another option would be to directly add a class to the editor wrapper based on the active template. So if the user selects a template named Full width, the editor wrapper would have a .page-template-fullwidth class.

Related issues
This issue is quite similar to #17854, but in our case, we want to modify the CSS class names dynamically (in JS) instead of only doing it on page load (in PHP).

@Aljullu Aljullu added [Feature] Custom Editor Styles Functionality for adding custom editor styles [Feature] Themes Questions or issues with incorporating or styling blocks in a theme. labels Oct 27, 2020
@stefanfisk
Copy link
Contributor

I've needed this in several project for stuff like selecting color schemes per post. So far I've just given up on getting it to work while using add_editor_style() without resorting to hacks that modify the DOM behind React's back 😿

@mrwweb
Copy link

mrwweb commented Nov 19, 2021

My experience matches those of others here. I'll add that any class added would hopefully be on a wrapper that includes the editor title field which I also frequently need to style based on post options or context.

@fatesallow
Copy link

I'm looking to do this too. I have a hybrid theme, with a page template that changes the body background color. The problem is my client can't see how to style block background colors because the editor shows the background color I set in theme.json. All I need is a class that's added to .editor-styles-wrapper depending on the template used. There doesn't seem to be a way to hook into it.

It's hard to explain to my client why some pages match the frontend and some don't.

@stefanfisk
Copy link
Contributor

stefanfisk commented Aug 8, 2022

This hack seems to work for me, but since React owns the element it is far from koscher.

const SET_INTERVAL = 100;

let theme = 'blue';

// Update `theme` by some other means

const update = () => {
    const root = document.querySelector(
        '.block-editor-block-list__layout.is-root-container'
    );

    ['blue', 'yellow', 'green', 'red'].forEach((t) =>
        root?.classList.toggle(`theme-${t}`, t === theme)
    );
};

setInterval(update, SET_INTERVAL);

@ndiego ndiego added the [Type] Enhancement A suggestion for improvement. label Feb 10, 2023
@aut0poietic
Copy link

Know this is an old issue, but I've got a off-the-cuff solution that seems to be working pretty well as a block-editor plugin.

import domReady from '@wordpress/dom-ready';
import {useState} from '@wordpress/element';
import {registerPlugin} from '@wordpress/plugins';
import {useSelect} from '@wordpress/data'

function getTemplateSlug(name) {
	let sanitized = name.replace('.php', '');
	sanitized = sanitized.replace(/%[a-fA-F0-9][a-fA-F0-9]/, '');
	return 'template-' + sanitized.replace('/[^A-Za-z0-9_-]/', '');
}

function TemplateChangeHandler() {
	const [templateName, setTemplateName] = useState('');
	const template = useSelect(select => select('core/editor').getEditedPostAttribute('template'));
	if (template !== templateName) {
		if (templateName) {
			const prevClassName = getTemplateSlug(templateName);
			if (prevClassName) {
				document.body.classList.remove(prevClassName);
			}
		}
		const newClass = getTemplateSlug(template);
		if (newClass) {
			document.body.classList.add(newClass);
		}
		setTemplateName(template);
	}
	return (<></>);
}

domReady(() => {
	registerPlugin('ufo-template-change-handler', {render: TemplateChangeHandler});
});

It does require that the theme implements a admin_body_class filter that replicates the same behavior as the getTemplateSlug() method. Don't love that I'm rendering nothing -- there's probably a better way to install a one-off feature -- but it gets the job done.

@ellatrix
Copy link
Member

Duplicate of #17854.

@ellatrix
Copy link
Member

Whatever solution we implement, yes, it should reflect the front-end and dynamically change as you change templates etc.

@sammyaxe
Copy link

sammyaxe commented Jan 5, 2024

this is actually really needed, I use tailwind prose on the frontend, and I want to add prose classes to the wrapper.

@stefanfisk
Copy link
Contributor

this is actually really needed, I use tailwind prose on the frontend, and I want to add prose classes to the wrapper.

@sammyaxe have you tried .editor-styles-wrapper { @apply prose; }?

@sammyaxe
Copy link

sammyaxe commented Jan 6, 2024

this is actually really needed, I use tailwind prose on the frontend, and I want to add prose classes to the wrapper.

@sammyaxe have you tried .editor-styles-wrapper { @apply prose; }?

At first this didn't work, but I must have had some other error in my code, as I retired and it worked well. Thank you!

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. [Type] Enhancement A suggestion for improvement.
Projects
None yet
Development

No branches or pull requests

8 participants