Last active
December 21, 2021 00:38
-
-
Save davidwebca/efe3bb9f69df0a0f007179c59872054a to your computer and use it in GitHub Desktop.
Block style locations for ACF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
THIS IS NOW A FULL GITHUB REPO: https://github.com/davidwebca/acf-block-style-location | |
*/ | |
add_filter('acf/location/rule_values/acf_block_style', function ($choices) { | |
$block_styles_cache = get_transient('acf_block_styles'); | |
if(!$block_styles_cache) { | |
return $choices; | |
} | |
foreach ($block_styles_cache as $blockname => $styles) { | |
foreach ($styles as $stylename => $style) { | |
$stylekey = $blockname . ':' . $stylename; | |
$stylefullname = $blockname . ' : ' . $style['name']; | |
$choices[$stylekey] = $stylefullname; | |
} | |
} | |
return $choices; | |
}); | |
add_filter('acf/location/rule_match/acf_block_style', function ($match, $rule, $screen, $field_group) { | |
if (!empty($screen['block']) && isset($_REQUEST['block'])){ | |
$block = $_REQUEST['block']; | |
$block = wp_unslash( $block ); | |
$block = json_decode( $block, true ); | |
$className = isset($block['className']) ? $block['className'] : 'is-style-default'; | |
$style = get_block_style_from_class($className); | |
$stylekey = $block['name'] . ':' . $style; | |
$match = $rule['value'] == $stylekey; | |
if($rule['operator'] == '!=') { | |
$match = !$match; | |
} | |
} | |
return $match; | |
}, 10, 4); | |
/** | |
* Sometimes, ACF doesn't use location rule match for blocks because it doesn't need to | |
* (no other location rules exist for blocks as of now) | |
* so we need to use load_field_groups to remove them if they don't match | |
* | |
* Note: I think this is the part that doesn't work. Ajax does execute correctly | |
* but the React Component doesn't force update its dom at every call for the form. | |
* This must be something that we can do with ACF JS API somewhere, but can't fin it. | |
*/ | |
add_filter('acf/load_field_groups', function($field_groups = []) { | |
if(isset($_REQUEST['block'])) { | |
$block = $_REQUEST['block']; | |
$block = wp_unslash( $block ); | |
$block = json_decode( $block, true ); | |
$className = isset($block['className']) ? $block['className'] : 'is-style-default'; | |
$style = get_block_style_from_class($className); | |
$stylekey = $block['name'] . ':' . $style; | |
foreach ($field_groups as $groupkey => $group) { | |
foreach ($group['location'] as $locationskey => $locs) { | |
foreach ($locs as $lockey => $loc) { | |
if($loc['param'] == 'acf_block_style') { | |
$result = $loc['value'] == $stylekey; | |
if($loc['operator'] == '!=') { | |
$result = !$result; | |
} | |
if(!$result) { | |
unset($field_groups[$groupkey]); | |
} | |
} | |
} | |
} | |
} | |
} | |
return $field_groups; | |
}, 10, 1); | |
add_action('admin_enqueue_scripts', function(){ | |
// This cache can only get built in the gutenberg editor since block styles don't get registered otherwise... bug? | |
// Make sure to visit a page that contains the gutenberg editor first | |
// before assigning the location | |
if(is_gutenberg_page()) { | |
$block_types = acf_get_block_types(); | |
$block_styles_registry = \WP_Block_Styles_Registry::get_instance(); | |
$acf_block_styles = []; | |
foreach($block_types as $blockname => $block_data) { | |
$styles_for_block = $block_styles_registry->get_registered_styles_for_block($blockname); | |
if(!empty($styles_for_block)) { | |
$acf_block_styles[$blockname] = $styles_for_block; | |
} | |
} | |
set_transient('acf_block_styles', $acf_block_styles); | |
} | |
}); | |
add_action('admin_footer', function( $hook ) { | |
$block_styles_cache = get_transient('acf_block_styles'); | |
if(!$block_styles_cache) { | |
// bail early if we didn't get block style cache | |
return; | |
} | |
?> | |
<script> | |
/** | |
* https://stackoverflow.com/questions/29321742/react-getting-a-component-from-a-dom-element-for-debugging | |
*/ | |
function FindReact(dom, traverseUp = 0) { | |
const key = Object.keys(dom).find(key=>{ | |
return key.startsWith("__reactFiber$") // react 17+ | |
|| key.startsWith("__reactInternalInstance$"); // react <17 | |
}); | |
const domFiber = dom[key]; | |
if (domFiber == null) return null; | |
// react <16 | |
if (domFiber._currentElement) { | |
let compFiber = domFiber._currentElement._owner; | |
for (let i = 0; i < traverseUp; i++) { | |
compFiber = compFiber._currentElement._owner; | |
} | |
return compFiber._instance; | |
} | |
// react 16+ | |
const GetCompFiber = fiber=>{ | |
//return fiber._debugOwner; // this also works, but is __DEV__ only | |
let parentFiber = fiber.return; | |
while (typeof parentFiber.type == "string") { | |
parentFiber = parentFiber.return; | |
} | |
return parentFiber; | |
}; | |
let compFiber = GetCompFiber(domFiber); | |
for (let i = 0; i < traverseUp; i++) { | |
compFiber = GetCompFiber(compFiber); | |
} | |
return compFiber.stateNode; | |
} | |
// call fetch when we change block style to update the form | |
jQuery(document).on('click', '.block-editor-block-styles__item', function() { | |
// preview mode selector | |
let selector = '.block-editor-block-inspector .acf-block-component.acf-block-panel > div'; | |
let currentBlock = wp.data.select('core/block-editor').getSelectedBlock(); | |
if(currentBlock) { | |
if(currentBlock.attributes.mode == 'edit') { | |
selector = '[data-block="' + wp.data.select('core/block-editor').getSelectedBlockClientId() + '"] .acf-block-component > div'; | |
} | |
// get the BlockForm react instance | |
let blockFormInstance = FindReact(document.querySelector(selector)); | |
blockFormInstance.fetch(); | |
} | |
}) | |
</script> | |
<?php | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment