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

Cannot access the blocks root element in the editor using JavaScript #55947

Closed
markhowellsmead opened this issue Nov 7, 2023 · 4 comments
Closed
Labels
Needs Technical Feedback Needs testing from a developer perspective. [Type] Bug An existing feature does not function as intended

Comments

@markhowellsmead
Copy link

Description

The Block Editor is loaded in an iframe. The site is empty and has no plugins installed. The theme contains no customisations of any kind to the functionality: it contains nothing but an empty index.html template for the site editor.

I have now enqueued a JavaScript file using the enqueue_block_editor_assets hook, as described in #48286. If I console.log the document.body.classList, this returns the CSS class names of the root element in the post.php file view, not the class names of the root element in the iframe. This would seem to indicate that the script is loading in the context of the window, not the iframe.

(My actual goal is to add a custom CSS class name to the root element of the block editor when selecting a colour option through a custom ToggleGroupControl element provided by registerPlugin. In the same way which the Wabi and Wei themes work: this functionality in those themes is also no longer working, presumably because Rich's scripts use the same logic and don't work in the iframe context.)

Step-by-step reproduction instructions

Enqueue a JavaScript file containing console.log(document.body.classlist); using the enqueue_block_editor_assets hook. Then load the edit page screen in the block editor.

Screenshots, screen recording, code snippet

No response

Environment info

  • WordPress 6.3
  • No plugins and no other theme-based functionality.

Please confirm that you have searched existing issues in the repo.

Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

Yes

@markhowellsmead markhowellsmead added the [Type] Bug An existing feature does not function as intended label Nov 7, 2023
@Mamaduka Mamaduka added the Needs Technical Feedback Needs testing from a developer perspective. label Nov 7, 2023
@Mamaduka
Copy link
Member

Mamaduka commented Nov 8, 2023

The enqueue_block_editor_assets will load assets in the root page element and not the iframe canvas, but that's what you need here. You're adding the new editor settings1.

Since we cannot access iframe's document & window via plugin slot component reference, just like we do in blocks. We're left with good old plain JS.

// A helper method that updates both main and iframed canvas body classes.
function updateBodyClasses( { newClass, prevClass } ) {
    document.body.classList.remove( prevClass );
    document.body.classList.add( newClass );

    const iframe = document.querySelector( '[name="editor-canvas"]' );
    if ( iframe ) {
        iframe.contentDocument.body.classList.remove( prevClass );
        iframe.contentDocument.body.classList.add( newClass );
    }
}

// Example.
updateBodyClasses( { newClass: 'is-quinary-accent', prevClass: 'is-secondary-accent' } );

I assume you would use a similar logic as Wabi and add styles using admin_body_class for the initial load. I would recommend prefixing admin classes with admin-color-, so they're automatically copied into the iframe body.

Cc-ing @richtabor in case he wants to update the code for Wabi 😄

Footnotes

  1. We really need to standardize terminology here and even provide some illustrations to differentiate easily. cc @ndiego, @ryanwelcher

@markhowellsmead
Copy link
Author

Terrific, thanks George. The combination of enqueue_block_editor_assets, iframe.contentDocument.body.classList and the admin-color- prefix work a treat. :D I based my version on Rich's work, but am using useEffect to apply the class names in the editor environment, so I don't need to hook them in using PHP.

const [color, setColor] = usePostMeta('sht_post_accentcolor');

useEffect(() => {
	const iframe = document.querySelector('[name="editor-canvas"]');

	colors.forEach((availableColor) => {
		if (iframe) {
			iframe.contentDocument.body.classList.remove('is-with-accent', `is-${availableColor}-accent`);
		}
		document.body.classList.remove('is-with-accent', `is-${availableColor}-accent`);
	});

	document.body.classList.add(color, 'is-with-accent');

	if (iframe) {
		iframe.contentDocument.body.classList.add(color);
		iframe.contentDocument.body.classList.add(color, 'is-with-accent');
	}
}, [color]);

@markhowellsmead
Copy link
Author

Problem resolved!

@Mamaduka
Copy link
Member

Mamaduka commented Nov 8, 2023

I'm glad my snippet was helpful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Technical Feedback Needs testing from a developer perspective. [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

No branches or pull requests

2 participants