I’m going through wordpress.org’s build your own block course right now. Making notes here because there’s lots of stuff for me to forget.
Creating the block scaffold
Spin up your site, go to the wp-content/plugins folder and run the following command in a terminal (you need to have installed nodejs):
px @wordpress/create-block multi-columns
This will create the block scaffold for a new plugin called “multi-columns”.
The course notes that the files in the src directory are where you will make most of your changes.
Most of the files are pretty self-explanatory. Just note that “edit.js” controls what is seen in the editor, and “save.js” determines what will be show in the actual post.
Changes to the default
Note: make sure to this run inside the new plugin’s directory:
npm start
so you can see changes made in real time.
Also, make sure the new block is activated in WordPress plugins.
Change where the block appears in the editor
In block.json change category to design, and icon to columns.
Add interactivity in edit.js
Edit.js imports the hook useBlockProps. It’s required.
Change the <p> tag to a built-in gutenburg component called <RichText>. To add any component, follow three steps:
- edit block.json to direct data to the component and define attributes.
- edit edit.js to import the component, add it to the edit() function, and add an event handler
- edit save.js to import the component and add component to the save() function
block.json
add this at the same level as “name”:
"attributes": {
"content": {
"type": "string",
"source": "html",
"selector": "p"
}
}
edit.js
include RichText in the inside the same brackets as “useBlockProps”.
Replace the return statement with:
return (
<RichText
{ ...useBlockProps() }
tagName="p"
onChange={ onChangeContent }
value={ attributes.content }
placeholder="Enter some text here..."
/>
);
Add { attributes, setAttributes } as a parameter to the Edit() function.
And add this const right inside the function:
const onChangeContent = ( val ) => {
setAttributes( { content: val } );
};
save.js
Import RichText. Make the save function look like this:
export default function save( { attributes } ) {
return (
<RichText.Content
{ ...useBlockProps.save() }
tagName="p"
value={ attributes.content }
/>
);
}
Add some options to the block (background color, etc)
Add this to supports in block.json
"color": {},
"spacing": {
"margin": true,
"padding": true
}
Note that you need to fix the the tabs to make it valid JSON.
Add defaults to options
Again in block.json, a a style section to attributes (note that you need to add one, not use the style section that is already there):
"style": {
"type": "object",
"default": {
"color": {
"text": "#3a3a3a",
"background": "#fbf9f4"
},
"spacing": {
"padding": {
"top": "20px",
"right": "20px",
"bottom": "20px",
"left": "20px"
}
}
}
}
Customization options
custom columns
Follow the three step process – block.json, edit.js, save.js
block.js
"columnCount": {
"type": "integer",
"default": 4
}
edit.js
Need to pass columnCount to the useBlockProps
const { columnCount } = attributes;
const columnStyles = { columnCount };
and put it in the return:
{ ...useBlockProps( { style: columnStyles } ) }
Now, make it changeable, but need to limit the number of columns the user can select, so use the RangeControl component. First, import it:
import { RangeControl } from '@wordpress/components';
Then add it to the return statement in edit.js (note adding empty tags to group the two other tags:
<>
<RangeControl
label="Columns"
value={ columnCount }
onChange={ onChangeColumnCount }
min={ 2 }
max={ 6 }
/>
<RichText
.
</>
And add a change handler:
const onChangeColumnCount = ( val ) => {
setAttributes( { columnCount: val } );
};
putting the controls on the side instead of in the block
First, InspectorControls. Import it from block-editor (with richtext and useblockprops), then wrap rangecontrol in it.
Then, import PanelBody from components to make it more beautiful. Wrap rangecontrol with it.
save.js
Just need to unpack the object to get the column number in save.js
export default function save( { attributes } ) {
const { columnCount } = attributes;
const columnStyles = { columnCount}
return (
<RichText.Content
{ ...useBlockProps.save( {style: columnStyles}) }
tagName="p"
value={ attributes.content }
/>
);
}
More practice
adding styling to the columns
width
block.json
"columnWidth": {
"type": "integer",
"default": 200
},
add custom number input component (from the course) in a new folder called compenents. Then import it in
edit.js
import NumberControl from './components/number-control';
add the variables in the edit() function
const { columnCount, columnWidth } = attributes;
const columnStyles = { columnCount, columnWidth
And put width in the return (should be able to figure this part out).
!!! Be sure to cast the number to integer in the onchage functions with Number( val ) inside the function.
Then update the consts in save.js
Group panel controls
add a title to PanelBody:
<PanelBody title="Column Settings">
divider lines
Use SelectControl component
huge block in in return statement (it’s a select component, so you have to code all the options)
keep the panel closed at first:
<PanelBody title="Column Separator" initialOpen={false}>
Course does a pretty good job of making you repeat the process many times.
Inner blocks
Don’t need content section of block.json, because child blocks will handle it.
Get rid of RichText and use InnerBlocks instead.
Replace RichText with a div, it has useBlockProps as an… attribute of some kind. Then put innerblocks inside the div:
return (
<>
<InspectorControls>
.
.
.
.
</InspectorControls>
<div { ...useBlockProps( { style: columnStyles } ) }>
<InnerBlocks />
</div>
</>
);
Be sure to use InnerBlocks.Content in save.js
Control types of blocks allowed
const ALLOWED_BLOCKS = [ 'core/heading', 'core/paragraph', 'core/image' ];
Can also add a template:
<InnerBlocks allowedBlocks={ALLOWED_BLOCKS} template={MC_TEMPLATE} />
Refinements
You can add keywords for easier searching for the block in the editor.
Make it full width by specifying that in block.json.
Make the interface translatable (to other languages) with the __( ) function.
Back in block.json, you can add a list of allowable parents.
Style varations: add in block.json, add in style.scss, create preview.
Custom styles
If you let user costomize a custom style you have created (in style.scss) you have to define the css tag in edit.js:
const columnStyles = {
columnCount,
columnWidth,
columnGap,
columnRuleStyle,
columnRuleWidth,
columnRuleColor,
'--drop-cap-color': dropCapColor,
};
Use something like this to hide things when not needed:
{ attributes.className === 'is-style-drop-cap' && (
) }
Leave a Reply