Gutenberg Dev
Follwing along Zac Gordons Gutenberg Development Course.
Insert:
The Gutenbergs JS libraries
- wp.element: Abstraction Layer on top of React and React Dom. Used for creating elements inside blocks.
- wp.blocks: Components and functions for building blocks.
- wp.components: Components that can be used for building interfaces within the editor (tooltips, buttons … )
- wp.i18n: For translations, similar to the
__() methods in php
All of these libs are accessible globaly (e.g. through the console or other scripts)
To access them within code, use something like
const { __ } = wp.i18n; // using deconstruction
Basic block architecture
Default roadmap:
- Enque block JS in main plugin/theme file [php]
- Register block using
registerBlockType() [js] - Opt. break up block code in components [js]
- Enque block css [php]
Enque block js + css
enque_block_edtior_assets: hook for enquing block js+css in the editor (not the frontend). Used to enque the main block js file, or editor-only styles.enque_block_assets : hook to enque (mostly) css (and js) for both, the editor and the front end. User for main block styles. Use !is_admin()for front-end-only styles/scripts
Building blocks
registerBlockType()
wp.blocks.registerBlockType(
'plugin-name/block-name',
{
title: wp.i18n.__('Blocktitle', 'textdomain),
description: '...',
category: 'common',
icon: 'wordpress-alt',
keywords: [wp.i18n.__('Demo', 'textdomain)],
supports: { html: false },
attributes: {} ,
edit: () => {},
save: () => {}
}
);
attributes
Which information to (re-)store and manipulate
attributes {
message: {
type: "array",
source: "children",
selector: ".classname-of-element"
},
}
edit
Controls how the block is rendered (and updated) in the editor.
Usualy constists of a return method as well as a method that handles what hapens onChange (e.g. text editing). props ( React, anyone?) are passed on automatically from WP.
edit: props => {
const {
attributes: { message },
className,
setAttributes
} = props;
const onChangeMessage = message => {
setAttributes({ message });
};
return {
<div className={className}>
<RichText
tagName="div"
multiline="p"
placeholder={__("Type something ...", "textdomain")}
onChange={onChangeMessage}
value={message}
/>
</div>
}
}
save
How to save the post – for displaying on the front end and restoring for the editor.
save: props => {
const {
attributes: { message }
} = props;
return (
<div>
<div class="output-feld">{message}</div>
</div>
);
}
Update attributes on change
attributes: {
content: {
...
}
}
edit: props => {
const { attributes: { content }, setAttributes } = props;
...
return (
<RichText
...
onChange={ content => { setAttributes( { content } ) } }
value={ content }
>
);
Data API
wp.data.<STORE_NAME> (stores: „core/editor“, „core/blocks“, „core/editor“ …, to check them out log wp.data.select("<STORE_NAME>") [or dispatch instead of select])
(import: const { <STORE_NAME> } = wp.data)
select
=> get data
select("core/editor").getBlockCount();
subscribe
=> subscribe/listen to status change
subscribe(() => {
// updated every time the block count changes
const blockCount = select("core/editor").getBlockCount();
});
Note: subscribe returns a unsubscribe function
const unsubscribe = subscribe(()=>{ /* ... */ });
unsubscribe();
Advanced
Subscribe Class to controll the state handling (otherwise you might want to use withSelect) – more Reactish, less WP abstraction
const { Component } = wp.element;
const { select, subscribe } = wp.data;
export default class SubscribeDemo extends Component{
state = {
blockCount: "",
}
componentDidMount() {
const unsubscribe = subscribe( () => {
const blockCount = select("core/editor").getBlockCount();
this.setState({blockCount});
} );
}
render() {
return <p>Block count: {this.state.blockCount}</p>
}
}
Key-Points:
- Extend the Component class (imported from wp.element)
- Manage
state object ( => React )- call with
this.state - update with
this.setState() [see: React]
- uses
componentDidMount()method [see: React] - use Reacts
render() function
withSelect
=> HOC [?] for select, similar to subscribe it will update everytime its values changes
As component:
const WithSelectDemo = ({ blockCount }) => (
<p>Block Count: {blockCount}</p>
)
export default withSelect( (select, ownProps) => {
return {
blockCount: select("core/editor").getBlockCount()
}
} )(WithSelectDemo);
Explanation / How to read
First code block: Create <WithSelectDemo /> component that takes the current block count as an argument (and prints it)
Second code block: Export withSelect()(WithSelectDemo):
- when
<WithSelectDemo />is exported/used … - it will wrapp everything inside of
withSelect()… - call
select() (getting the block count) … - create / asign it to a new variable
blockCount… - and make that variable available to the
<WithSelectDemo /> component (which takes it as its argument)
ownProps
Notice the ownProps parameter for the withSelect()above. It will get all props (think: attributes) passed into the component (and can be passed on to the component, of course)
<WithSelectDemo text="blah" />
export default withSelect( (select, ownProps) => {
console.log(ownProps) // logs: {text: "blah"}
return {
...
}
...
dispatch
=> calling an action
dispatch( "core/editor" ).removeBlock( clientID ) // clientID = BlockID
withDispatch
=> HOC [?] for dispatch
//TODO
compose
=> HOC [?] for combining multiple HOC’s (Takes an array of HOCs and returns a new component)
// Todo