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

Core / ACF -> Essential markup differences for Blocks #470

Closed
CreativeDive opened this issue Mar 5, 2021 · 7 comments
Closed

Core / ACF -> Essential markup differences for Blocks #470

CreativeDive opened this issue Mar 5, 2021 · 7 comments

Comments

@CreativeDive
Copy link
Collaborator

CreativeDive commented Mar 5, 2021

Hey @elliotcondon

As you have already noticed, I am currently working intensively on the output of ACF blocks.

I have already identified essential markup differences for inner blocks: #465

But I have already identified essential markup differences for the general output of ACF blocks.

This basically refers to the output in the block editor.

I will try to describe you this differences.

The core block markup (block editor)

<div data-type="core/cover" data-title="Cover" class="has-background-dim has-pastel-red-background-color wp-block-cover block-editor-block-list__block wp-block is-selected" style="background-color: rgb(241, 126, 126);">
	... block content ...
</div>
1. Level --> The block container (including essential [id / classes / styles])
2. Level ----> Block content

The ACF block markup (block editor)

<div data-type="acf/my-block" data-title="My Block" class="block-editor-block-list__block wp-block is-selected" style="">
	<div class="acf-block-component acf-block-body">
		<div>
			<div class="acf-block-preview">
				[ACF BLOCK CONTAINER - From template file]
					... block content ...
				[/ACF BLOCK CONTAINER - From template file]
			</div>
		</div>
	</div>
</div>
1. Level --> The block container
2. Level ----> [.acf-block-body] container
3. Level ------> [DIV] container
4. Level --------> [.acf-block-body] container
5. Level ----------> The block container (including essential [id / classes / styles]) [second time, from the template file]
6. Level ------------> Block content

The general markup is completely different. In general, this is not a problem, although having the same markup on the core blocks would be better.

What is causing display issues?

For each ACF block we use a template file. Inside this template we define the block parent container. This parent container can contains things like:

  • Alignment [full / wide / left / right / center]
  • Style attribute
  • Class attribute
  • ID attribute
  • other attributes

This works fine in the case of the frontend output. But in the case of the block editor output, this causing display issues.

Because the ACF parent block container will outputted two times with different attributes. But actually it should be only one parent block container.

In the block editor, this looks like this:

1. Level --> [CORE-BLOCK-PARENT-CONTAINER]
2. Level ----> [...]
3. Level ------> [...]
4. Level --------> [...]
5. Level ----------> [ACF-BLOCK-PARENT-CONTAINER]
6. Level ------------> [...]

The [CORE-BLOCK-PARENT-CONTAINER] contains:

  • Alignment [full / wide / left / right / center]

The [ACF-BLOCK-PARENT-CONTAINER] is the container we have defined in our block template and contains other other block definition from the [$block] variable. This contains:

  • Alignment [full / wide / left / right / center] --> A second time!
  • Style attribute
  • Class attribute (maybe "has-text-align-left", ...)
  • ID attribute
  • other attributes

What I mean by that. Actually, all of these attributes of [ACF-BLOCK-PARENT-CONTAINER] should be present in container [CORE-BLOCK-PARENT-CONTAINER]. When we talk about the block editor output.

What issues can this cause?

Since we have two consecutive containers with the same property, the following happens:

1. EXAMPLE:

Frontend

.align-full .my-block {
	...
}

Backend (Block Editor)

.align-full .align-full .my-block {
	...
}

This show, at the moment there are two consecutive classes .align-full in the case of the block editor, but only one in the frontend.

2 EXAMPLE:

Frontend

[class*="wp-block"].align-full > * {
	... // --> effect the block content
}

Backend (Block Editor)

[class*="wp-block"].align-full > * {...} [class*="wp-block"].align-full > * {
	... // --> effect the [.acf-block-body] container and the block content
}

Match to all blocks with alignment "full selected" which using classes like this ".wp-block-cover, .wp-block-group, ..." or if we define it like this example to our ACF blocks ".wp-block-my-acf-block, .my-acf-wp-block, ...".

The selector > * concerns the content directly after the block parent container.

These are only two examples, there are many more that can lead to display issues. Because CSS rules can't work exactly like in the frontend.

The question is how to deal with it and whether a fundamental change is necessary for ACF blocks?

If this were to be reconsidered to avoid such display differences in the future, I would find a solution like this:

The structure of an ACF block template could be like this:

// Incoming "$block" variable from ACF
$block = isset( $block ) ? $block : '';

// Modify $block attributes
if( $block ) {
	$block['classes'] = 'my-block-container-class-name';
	$block['attributes'] = array(
		'data-align' = 'alignfull',
		'data-id' = 'my-id',
		...
	);
	$block['styles'] = array(
		'color' = 'red',
		'position' = 'relative',
		...
	);
}

do_action('before_acf_block_template', $block); // <-- This outputs the wrapper container for the frontend, but not for the block editor

// Custom user template content for this ACF block follows here

$my_field = get_field('my_field');

if( $my_field ) {
	...
}

do_action('after_acf_block_template', $block); // <-- Output the closing tag

This is just an example. It certainly needs a little more ideas on how to improve the method.

But this would be solve the main issue, that we have a parent block container two times nested in the block editor.

What do you think about this topic @elliotcondon ?

I know this would only be possible with a switch so that old templates would continue to work fine. Lately, however, a lot has changed in the structure of the Gutenberg editor. Maybe it makes sense to reconsider here?

@CreativeDive
Copy link
Collaborator Author

@elliotcondon Have you already thought about it?

@elliotcondon
Copy link
Contributor

Hi @CreativeDive

Thanks for the topic. This is an interesting problem, and one that we will need to investigate into the future along with the Block API 2.0 suggestions from your precious ticket.

With regards to the .acf-block-body and .acf-block-preview elements, these are necessary structural elements needed for our dynamic block framework to function. I don't see a way in which we can remove these.

It is important to remember that ACF Blocks are fundamentally different to "native blocks" because they deal with dynamically generated HTML from AJAX requests which can then be modified via JS libraries such as Select2, datepicker, etc and still work within React components that are constantly unmounting and remounting from the DOM.

Because of the constantly changing DOM structure within a React App, we need these "parent" elements to remain so that we can retain a jQuery element in existence at all times.

At this stage, I'm not sure what the "solution" is for front-end and back-end CSS compatibility. When we first designed ACF Blocks, we were under the impression that developers such as yourself would add HTML classes and IDs to the block HTML dynamically (within the PHP). We didn't think that developers would rely on the Block editor elements, because they are constantly changing. Is this something that you would consider for your ACF Blocks integration?

@CreativeDive
Copy link
Collaborator Author

Hey @elliotcondon,

sorry for the delay. I was already expecting that some containers would be very important for the functionality of ACF.

Are you suggesting a particular method to solve the problem, or am I getting it wrong? I am currently using my own HTML templates with dynamic classes in PHP.

The main issue here is in the first parent container. As a result, certain block specifications are duplicated and can incorrectly influence the output in the block editor.

Do you have a suggestion on how to solve this better at the moment?

@elliotcondon
Copy link
Contributor

Hi @CreativeDive

Would it be possible for you to take a short screen recording to demonstrate how the difference in markup structure is causing styling issues on the back-end? I think you've done a great job at describing the difference between core and ACF block markup, but I'm not sure that I understand how this represents a real-world problem yet for CSS rules.

A screen recording will be a great way to demonstrate this issue. I suggest using Loom for these kinds of recordings 👍.

@simonseddon
Copy link

simonseddon commented Mar 29, 2021

@elliotcondon just jumping in with an example of how this can be problematic with CSS. If we take a CSS grid layout as an example, and imagine we have a couple of ACF options which control the cols/rows which each grid-item (innerBlocks) will span, this is completely thrown off (in the back-end) due to the surrounding divs which great-great-great...-grandchild your grid-item from the grid layout, making it hard for a content editor to visualise how the layout will flow on the front-end.

Edit: I have found that setting all those container divs (there's 5-6 of them...) to display: contents; gets the grid layout working in the back-end, but also loses the Gutenberg popover (floating UI when a block is selected). Therefor, you can't delete an innerBlock, etc. I've since added a Preview button (B/E only) which toggles display: contents; on and off. This is my current fix to allow content editors to have full control over innerBlocks and preview the layout but ofc it's not ideal.

@elliotcondon
Copy link
Contributor

@simonseddon That's a great point I hadn't thought of. When working with display: grid;, the parent > child DOM relationship is extremely important. Please leave this with me, and we'll do our best to investigate the block API 2.0 shortly.

@CreativeDive
Copy link
Collaborator Author

@elliotcondon A real world problem is a good point. On the first level it is not as drastic as on the child level when properties are inherited (inner blocks). As I have already shown here #465.

I am not a friend of workarounds. Therefore, the best practice would be to have the same markup for the frontend and backend. But I also know that ACF blocks have a limitation so I'm not sure how this can work on the first level.

@simonseddon Thanks for the support with an excellent example.

I'm curious what a solution can look like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants