Gutenberg - markhowellsmead/helpers GitHub Wiki
- https://github.com/WordPress/gutenberg/tree/master/docs/designers-developers/developers
- Block Styles in Gutenberg
- Learning Gutenberg: Setting up a Custom webpack Config
- Building a block with Advanced Custom Fields
- How to extend existing Gutenberg blocks in WordPress
- Managing WordPress Metadata in Gutenberg Using a Sidebar Plugin
- WordPress (React) Storybook
- Stackable live demo
- Stackable source code
- Core Blocks
- Core playground
- Add Polylang support to WordPress Customizer
23.5.2022: this error was caused when trying to use a component using withSelect
from within the save function of a custom block. It's not possible to use async calls within the save function; the HTML generated here has to be generated synchronously.
Run wp.blocks.getBlockTypes().forEach(function (data) {console.log(data.name);});
in the browser console when the editor is open.
Run wp.data.select('core/editor').getBlocks()
in the browser console when the editor is open.
Run wp.data.select('core/block-editor').getBlock('d8cbffe7-d7f1-48cf-ba30-fea9426e2903')
(where d8cbffe7-d7f1-48cf-ba30-fea9426e2903 is the block ID) in the browser console when the editor is open.
To force a block to only be available with full or wide alignment…
- don't add any
align
options to the block component configuration - add the appropriate CSS class to the block wrapper's HTML
- dynamically apply the appropriate
data-align
attribute in thecomponentDidMount
class function.
const {Component} = wp.element;
…
edit: class extends Component {
constructor(props) {
super(...arguments);
this.props = props;
}
componentDidMount(){
document.querySelector('#block-' + this.props.clientId).setAttribute('data-align', 'wide');
}
render() {
return …
…
wp.hooks.addFilter(
'blocks.registerBlockType',
'my-theme/namespace',
function( settings, name ) {
if ( name === 'core/paragraph' ) {
return lodash.assign( {}, settings, {
supports: lodash.assign( {}, settings.supports, {
align: ['medium','wide','full'],
} ),
} );
}
return settings;
}
);
<?php
register_block_type('shb/demo', [
'attributes' => [
'align' => [
'type' => 'string',
'enum' => ['wide', 'full'],
]
],
…
if (!empty($align = $attributes['align'] ?? '')) {
$align = "align{$align}";
}
<div <?php echo get_block_wrapper_attributes(['class' => $align]); ?>>
…
Get all attributes of the specified innerBlocks
object.
wp.data.select('core/block-editor').getBlock('87711d0c-b1f5-4609-bbb0-f3a78b275620').innerBlocks
componentDidUpdate(prevProps){
if(prevProps.attributes.align !== this.props.attributes.align){
// do something
// this.props.setAttributes({title: `RE-ALIGNED: ${this.props.attributes.align}`});
}
}
Get the block's selected style in the save
function.
const { className } = props.attributes;
const isStyle = RegExp(/is-style-/);
const styleName = isStyle.test(className) ? className.replace(isStyle, '') : null;
componentDidUpdate(prevProps){
if(prevProps.attributes.align !== this.props.attributes.align){
// You have to use a local variable here. Using this.props.attributes.imagesize
// to determine the imagesize doesn't work
let imagesize = this.props.attributes.align === 'wide' ? 'panorama' : 'full';
this.props.setAttributes({imagesize: imagesize});
getLazySrcs(this.props.attributes.image.id, imagesize).then(image => this.props.setAttributes({image}));
}
}
- Post Selector (Search and select)
- Post Selector (Single-select dropdown of all (custom) posts, ordered by title.
- Add post type and post slug class name in Editor (for custom editor styling by post type and/or slug)
- Customize Block Styles
- Enqueue Block Editor Assets (Plugin)
- Implement Block Styles
- Hello Gutenberg by Say Hello
- How to build a Block WordPress Plugin (Zac Gordon)
- Post List Block
- How to make an editable WordPress Gutenberg block with Inspector Controls on the sidebar (May 2018)
Patterns are groups of Blocks, which can be inserted by an author in one action (e.g. clicking on a button or preview image). Gutenberg Patterns
- Register a Gutenberg Template, which contains a pre-defined set of other Blocks. e.g. if the user often creates the same content for a specific type of Post.
JavaScript translations are read in from enqueued scripts, not from source files. Because the built scripts are JS and minified by Webpack, the regular __
and _x
function names are replaced.
Create the POT file with relevant exclusions via the command line. Only the generated client-facing JavaScript files in e.g. assets/dist should be scanned.
wp i18n make-pot . languages/shp_flatcare_redirect.pot --exclude="assets/src,assets/gulp,gulpfile.babel.js"
Example for a simple plugin implementation, April 2024. The priority 100 appears to be essential for scripts loaded in the editor using block.json.
// Load editor (JS) translations
// Caution, different path definition than for the frontend
function shp_block_editor_set_script_translations()
{
$script_handle = generate_block_asset_handle('shp/my-block', 'editorScript');
wp_set_script_translations($script_handle, 'shp_my_block', plugin_dir_path(__FILE__) . 'languages');
}
add_action('init', 'shp_block_editor_set_script_translations', 100);
- Core ref.
- The enqueued source file path is used in order to generate an MD5 hash within the file name. (e.g. assets/dist/blocks/blocks.js. WordPress core always uses the unminified path.) If the file is created correctly, check the MD5 hash and the path being used. A double-slash in the path will cause the wrong MD5 path to be used.
- Make sure
wp-i18n
is a dependency of your Gutenberg script. - Call
wp_set_script_translations
on theinit
hook. (This is already in my base Theme.) - Make a new POT file using
wp i18n make-pot . languages/sht.pot
in the Theme directory. - Make a new PO file using
cp sht.pot sht-fr_FR.po
. - Call
wp i18n make-json sht-fr_FR.po --no-purge
in the languages folder to parse the PO file.
_ "Uncaught Error: Maximum function nesting level of '256' reached, aborting"_
Solution: If using Local By Flywheel (with xdebug), increase xdebug.max_nesting_level
to 512 or 1024. Change this in e.g. conf/php/php.ini.hbs and then restart the server.
- Internationalization in WordPress 5.0 (Pascal Birchler)
- Learning Gutenberg - Custom Card Block (CSS Tricks)
-
Creating an advanced block for Gutenberg (with
PostSelector
andPostList
components)
add_filter('render_block', function ($block_content, $block) {
// Target core/* and core-embed/* blocks.
if (preg_match('~^core/|core-embed/~', $block['blockName'])) {
$block_content = sprintf('<div class="some__class">%s</div>', $block_content);
}
return $block_content;
}, PHP_INT_MAX - 1, 2);
To get the WordPress Options from within the Editor (e.g. for use in a Block), use the following.
import api from '@wordpress/api';
…
api.loadPromise.then(() => {
settings = new api.models.Settings();
settings.fetch().then(response => {
console.log(response);
});
});
To add a custom field to the REST response, use the register_setting
function. The option key
is usually e.g. sht_myfield
but must be prefixed if the field is registered using ACF's
acf_add_local_field_group
function.
add_action('init', [$this, 'registerPublicOptions']);
public function registerPublicOptions()
{
// Field registered using WP
register_setting('options', 'sht_my_acf_field', [
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'show_in_rest' => true,
'default' => ''
]);
// Field registered using ACF
register_setting('options', 'options_sht_my_acf_field', [
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'show_in_rest' => true,
'default' => ''
]);
}
if (wp.data) {
wp.data.select( "core/edit-post" ).isFeatureActive( "fullscreenMode" ) && wp.data.dispatch( "core/edit-post" ).toggleFeature( "fullscreenMode" );
}
e.g. if you want to show a list of all the headings in the block editor within a custom Table of Contents block.
import { _x } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import { getBlockDefaultClassName, registerBlockType } from '@wordpress/blocks';
import { Disabled } from '@wordpress/components';
import { select, subscribe } from '@wordpress/data';
import { useState } from '@wordpress/element';
import block_json from '../../../../block.json';
const { name: block_name } = block_json;
const classNameBase = getBlockDefaultClassName(block_name);
registerBlockType(block_name, {
edit: () => {
const blockProps = useBlockProps();
const [headings, setHeadings] = useState([]);
// Watch for changes to the block list and update the headings list
subscribe(() => {
const selected_blocks = select('core/block-editor')
.getBlocks()
.filter(function (block) {
return block.name === 'core/heading';
});
setHeadings(selected_blocks);
});
// Create the list of headings from the list of blocks
const headingsList = headings.map((heading, index) => (
<li key={index} className={`${classNameBase}__entry`}>
<a dangerouslySetInnerHTML={{ __html: heading.attributes.content }} />
</li>
));
return (
<div {...blockProps}>
<Disabled>
<ul className={`${classNameBase}__entries`}>{headingsList}</ul>
</Disabled>
</div>
);
},
});