-
Notifications
You must be signed in to change notification settings - Fork 182
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
Can ACF support the native render callback in block.json? #730
Comments
The upcoming It's not applicable to ACF Blocks, also note:
|
@lgladdy Thanks for the clarification. I thought this might be a way to solve this issue with the extra wp block wrapper div. Too bad it's not like that. |
@CreativeDive reopening this one as it looks like this might not be the case after all from the 6.1 block api changes guide: https://make.wordpress.org/core/2022/10/12/block-api-changes-in-wordpress-6-1/ I’m not sure we’d really get any benefit from supporting it, but we really should take a look at least! |
@lgladdy nice to know. My hope was that we can eliminate the extra div around the ACF block template in the editor based on this example: <div <?php echo get_block_wrapper_attributes(); ?>>
<?php echo $attributes['text']; ?>
</div> If that would work, then it would finally be done and you could do without hacky workarounds for the correct display in the block editor. |
@CreativeDive I'd be very surprised if they've done anything different to us! You might well be able to test this before me - but you'll need to make a standard non-acf block here to see what markup you get back! |
@lgladdy I'm absolutely not familiar with the native react code, but I've tried to test it in this way:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "wphave/non-acf",
"title": "hello",
"icon": "index-card",
"category": "design",
"supports": {
"align": [
"wide",
"full"
]
},
"render": "file:./render.php",
"editorScript": "file:./block.js"
}
( function ( blocks, element, serverSideRender, blockEditor ) {
var el = element.createElement,
registerBlockType = blocks.registerBlockType,
ServerSideRender = serverSideRender,
useBlockProps = blockEditor.useBlockProps;
registerBlockType( 'wphave/non-acf', {
apiVersion: 2,
title: 'Example',
icon: 'megaphone',
category: 'design',
edit: function ( props ) {
var blockProps = useBlockProps();
return el(
'div',
blockProps,
el( ServerSideRender, {
block: 'wphave/non-acf',
attributes: props.attributes,
} )
);
},
} );
} )(
window.wp.blocks,
window.wp.element,
window.wp.serverSideRender,
window.wp.blockEditor
);
<div <?php echo get_block_wrapper_attributes(); ?> id="test">
PHP RENDER
</div> It seems this is NOT 😒 a solution to eliminate the extra div. |
It seems |
Theoretically it works, but practically not! 😅 No way to get this block selectable in this way.
( function ( blocks, element, serverSideRender, blockEditor ) {
var el = element.createElement,
registerBlockType = blocks.registerBlockType,
ServerSideRender = serverSideRender,
useBlockProps = blockEditor.useBlockProps;
registerBlockType( 'wphave/non-acf', {
apiVersion: 2,
title: 'Example',
icon: 'megaphone',
category: 'design',
attributes: {
blockId: {
type: 'string',
default: ''
}
},
edit: function ( props ) {
var blockProps = useBlockProps();
props.attributes.blockId = blockProps.id;
return el( ServerSideRender, {
block: 'wphave/non-acf',
attributes: props.attributes,
} );
},
} );
} )(
window.wp.blocks,
window.wp.element,
window.wp.serverSideRender,
window.wp.blockEditor
);
<div tabindex="0" id="<?php echo $attributes['blockId']; ?>" role="document" aria-label="Block: Example" data-block="<?php echo str_replace('block-', '', $attributes['blockId']); ?>" data-type="wphave/non-acf" data-title="Example" class="block-editor-block-list__block wp-block wp-block-wphave-non-acf">
PHP RENDER
</div> |
@CreativeDive I was playing around with ACF/non-ACF blocks the last few days, and I hit upon a possible way for you to not render the extra inner div in the editor. Mind you, this only works for divs without additional classes, but it could work in some instances for you. In your render template, you could use:
By doing so, you prevent the inner div from displaying in the editor, but can use the same classes on the frontend and backend (e.g. |
@cabrailsford Thanks for that. Yes, I'm playing with that too. It's the only solution I see here to eliminate the extra wrapper div. It's very frustrating when you work with nested blocks like: <WP DIV>
<ACF DIV>
block content
<ACF InnerBlocks DIV>
<WP DIV>
<ACF DIV>
... Practically there is always something that doesn't work properly, like in the frontend when working with alignments, flexbox, ...: <ACF DIV>
block content
<ACF InnerBlocks DIV>
<ACF DIV>
... I've been looking for a way to resolve this different markup for a long time, right @lgladdy 😅 But it is not possible, at least for ACF, to eliminate this extra div. Your mentioned way is basically a good way but there are side effects like, you can't add PHP generated class names to the A |
@cabrailsford Something like this could be working. But this is very limited, because the class names will only outputted to the <?php
$my_acf_block_classes = 'hello world yooo';
$block_id = isset( $block['id'] ) ? $block['id'] : '';
$block_id = str_replace( '_', '-', $block_id );
?>
<script>
(function( $ ) {
function blockClassNames( $block ) {
var block_id = '<?php echo esc_html( $block_id ); ?>';
var wpBlock = $('#' + block_id);
var wpBlockClasses = wpBlock.attr('class');
var acfBlockClasses = '<?php echo esc_html( $my_acf_block_classes ); ?>';
wpBlock.attr('class', '');
wpBlock.addClass( wpBlockClasses + ' ' + acfBlockClasses );
}
// Adds custom JavaScript to the block HTML
var initializeBlock = function( $block ) {
blockClassNames( $block );
}
// Initialize dynamic block preview (editor)
if( window.acf ) {
window.acf.addAction( 'render_block_preview', initializeBlock );
}
})( jQuery );
</script> |
@cabrailsford Here is a modified solution to pass the ACF block classes to the parent
Output a hidden if( is_admin() ) { ?>
<div data-block-classes="acf-block-classes" data-block-acf-class="hello world yoo" style="display: none"></div>
<?php }
function blockClassNames( block ) {
block.each(function() {
var classes = $(this).find('[data-block-classes="acf-block-classes"]');
var block_id = $(this).attr('id');
var wpBlock = $('#' + block_id);
var wpBlockClasses = wpBlock.attr('class');
var acfBlockClasses = classes.attr('data-block-acf-class');
if( ! acfBlockClasses ) {
return false;
}
wpBlock.attr('class', '');
wpBlock.addClass( wpBlockClasses + ' ' + acfBlockClasses );
});
}
$(document).on('click', '.acf-block-body', function() {
blockClassNames( $(this) );
});
// Initialize frontend script AND mobile/tablet preview in block editor
$(document).ready(function() {
blockClassNames( $('.acf-block-body') );
});
// Adds custom JavaScript to the block HTML
var initializeBlock = function( $block ) {
blockClassNames( $block );
}
// Initialize dynamic block preview (editor)
if( window.acf ) {
window.acf.addAction( 'render_block_preview', initializeBlock );
} Technically, it's similar to getting the class name from the @lgladdy is this something ACF can provide for us? |
I don't think so honestly - doing something as custom as this, that modified the actual core output from the block editor in a custom way; not through provided WordPress methods, would mean we'd be building a huge technical debt that we'd have to maintain over every version of WordPress, and risk breaking over even minor version of WordPress. We support such a wide range of WordPress versions, that it's just not viable for something like this to make it into ACF core. |
@lgladdy Yes I can understand that. Can you tell me please what method ACF uses to set the custom class to the |
@CreativeDive ACF turns |
@cabrailsford I've been playing around with react. It seems that using WP React is a more elegant solution here. It's still experimental but looks like a good way to pass ACF block classes to the block wrapper div just using a bit of extra JS here. It works well for this purpose, but could of course be optimized.
<div data-block-acf-class="<?php echo esc_html( $classes ); ?>" style="display: none"></div>
var el = wp.element.createElement;
var hoc = wp.compose.createHigherOrderComponent;
var withMyWrapperProp = hoc( function ( BlockListBlock ) {
return function ( props ) {
var acfBlockClasses = '';
var block_id = 'block-' + props.clientId;
var wpBlock = document.querySelector('#' + block_id);
if( wpBlock ) {
var acfBlockClasses = wpBlock.querySelector('[data-block-acf-class]');
if( acfBlockClasses ) {
acfBlockClasses = acfBlockClasses.getAttribute('data-block-acf-class');
}
}
var newProps = {
...props,
wrapperProps: {
...props.wrapperProps,
'className': acfBlockClasses,
},
};
return el( BlockListBlock, newProps );
};
},
'withMyWrapperProp' );
wp.hooks.addFilter(
'editor.BlockListBlock',
'my-plugin/with-client-id-class-name',
withMyWrapperProp
); EDIT: And you can use the ACF own " EDIT: Some modifications are required to make the JS filter |
I will end my testing here first. One issue is that the block classes are changed before ACF passes them to the template. This means that the first field change that changes a class name only becomes active with the second field change. I can't get any further here. If anyone is interested and has an idea how to solve this, they are welcome to participate here. |
Hi @CreativeDive, I came across this issue by accident, so I will try to write what I know. As far as I know, as long as the In the dynamic blocks of the core, the I don't know how the ACF block is implemented, but if this component is used for rendering on the editor, it would not be easy to rewrite it into JS. This is because the elements within the block can be defined by the user. One suggestion would be to apply the new display:contents to the divs that are not needed. It might be possible to treat the div as if it did not exist. Also, the skipBlockSupportAttributes property of the |
In the meanwhile I have now found a way to synchronize the ACF block template wrapper classes with the wrapper div in the editor. It works very well. This allows you to add and remove classes via ACF fields in the block wrapper div. let addedClasses = {};
const acfSyncBlockWrapperClasses = ( block ) => {
const acfBlockWrapper = block[0];
// Search for an uniqe selector of your ACF block template wrapper
const acfTemplateWrapper = acfBlockWrapper.querySelector('[data-acf-block]');
if( acfTemplateWrapper ) {
// If classes were previously added, remove them
if( addedClasses[acfBlockWrapper] ) {
addedClasses[acfBlockWrapper].forEach(className => {
acfBlockWrapper.classList.remove(className);
});
}
// Update the list of recently added classes for this block
addedClasses[acfBlockWrapper] = Array.from(acfTemplateWrapper.classList);
// Add the classes from the acfTemplateWrapper to the acfBlockWrapper
acfBlockWrapper.classList.add(...addedClasses[acfBlockWrapper]);
}
}
if( window.acf ) {
acf.addAction('render_block_preview', acfSyncBlockWrapperClasses);
}
/***/
var el = wp.element.createElement;
var hoc = wp.compose.createHigherOrderComponent;
var withMyWrapperProp = hoc(function(BlockListBlock) {
return function(props) {
const block_id = 'block-' + props.clientId;
// Aktualisieren Sie die Klassen jedes Mal, wenn der Block neu gerendert wird
var wpBlock = document.querySelector('#' + block_id);
if (wpBlock) {
var acfTemplateWrapper = wpBlock.querySelector('[data-acf-block]');
if (acfTemplateWrapper) {
// Überschreiben Sie den Cache immer, wenn der Block gerendert wird
addedClasses[block_id] = Array.from(acfTemplateWrapper.classList);
}
}
var newProps = {
...props,
wrapperProps: {
...props.wrapperProps,
'className': addedClasses[block_id] ? addedClasses[block_id].join(' ') : '',
},
};
return el(BlockListBlock, newProps);
};
},
'withMyWrapperProp');
wp.hooks.addFilter(
'editor.BlockListBlock',
'my-plugin/with-client-id-class-name',
withMyWrapperProp
); Maybe this will be very helpful for some people. |
Hello @lgladdy,
I read about it here: WordPress/gutenberg#42430
It seems that
block.json
supports a render callback by default.src/block.json
src/render.php
I'm wondering if we can use this render callback instead of ACF's own
"renderTemplate": "index.php"
in the future if ACF supports it?Could this be a solution to make ACF block markup identical in editor and frontend? 👈 👈 👈
Have you ever been able to test whether this can replace the additional block wrapper?
The text was updated successfully, but these errors were encountered: