I'm looking for a good way to pass data from parent block to childs of InnerBlocks
So basically i have only 1 block now which is tinymce
editor. I also created SectionEdit
Component which I'm gonna use to wrap every block i need.
Note: Every block is rendered dynamically trough php controller that detects if block is using section and wraps it in html.
So i have helper Section.js
where i export:
export const sectionAttributes = {
sectionUse: {
type: 'number'
},
sectionInside: {
type: 'number'
},
... other options that only adds classes to section
}
and SectionEdit
export class SectionEdit extends Component {
constructor () {
super(...arguments)
}
render () {
const { attributes, setAttributes } = this.props._props
// this is needed so php controller knows to wrap block in section
setAttributes({ sectionUse: 1 })
return (
<Fragment>
<InspectorControls>
<PanelBody title={'Section Settings'} initialOpen={false}>
...controls for attributes
</PanelBody>
</InspectorControls>
{this.props.children}
</Fragment>
)
}
}
So now let's take a look on tinymce
block. Main file index.js is where i import sectionAttributes
. and edit
Component. I merge attributes together.
It's literally copy of core Classic block wrapped in my SectionEdit
;
import { sectionAttributes } from '../../helpers/Section'
import icon from './icon'
import edit from './edit'
const wp = window.wp
const { registerBlockType } = wp.blocks
let attributes = {
content: {
type: 'string'
}
}
attributes = { ...sectionAttributes, ...attributes }
registerBlockType('wpbase-blocks/tinymce', {
title: 'TinyMCE Editor',
icon: icon,
description: 'Classic TinyMCE Editor ',
category: 'wpbase',
keywords: ['classic', 'editor'],
supports: {
className: false,
customClassName: false,
reusable: false
},
attributes: attributes,
edit: edit,
save: function (props) {
return null
}
})
inside edit component i wrap tinymce elements in SectionEdit
. You can see i pass all properties to SectionEdit
trough _props
import { SectionEdit } from '../../helpers/Section'
const wp = window.wp
const { Component } = wp.element
export default class ClassicEdit extends Component {
constructor (props) {
super(props)
this.initialize = this.initialize.bind(this)
this.onSetup = this.onSetup.bind(this)
this.focus = this.focus.bind(this)
}
{...}
render () {
const { clientId } = this.props
return (
<SectionEdit _props={this.props}>
<div key="toolbar" id={`toolbar-${clientId}`}
ref={(ref) => { this.ref = ref }}
className="wpbase-tinymce__toolbar"
onClick={this.focus}
data-placeholder={'TinyMCE'}
onKeyDown={this.onToolbarKeyDown}
/>
<div key="editor" id={`editor-${clientId}`}
className="wpbase-tinymce__editor"
/>
</SectionEdit>
)
}
}
Tinymce block works like a charm, php rendering, using SectionEdit
component too BUT
What I'm trying to achieve next is block collapsing-section
where i use InnerBlocks
. I wanna my SectionEdit
to know when its in collapsing-section
so it will render html differently. I allow all blocks except collapsing-section
itself.
const wp = window.wp
const { Fragment } = wp.element
const { Toolbar } = wp.components
const { registerBlockType, getBlockTypes } = wp.blocks
const { InnerBlocks, BlockTitle } = wp.editor
let allowedBlocks = []
getBlockTypes().forEach(function (block) {
allowedBlocks.push(block.name)
})
// allow all blocks except itself
registerBlockType('wpbase-blocks/collapsing-section', {
title: 'Collapsing Header',
icon: 'shield',
description: 'Header wrapper that collapse up on scroll',
category: 'wpbase',
keywords: ['classic', 'editor'],
supports: {
className: false,
customClassName: false,
reusable: false
},
attributes: {
sectionInside: {
type: 'number'
}
},
edit: function (props) {
const { clientId, setAttributes } = props
setAttributes({ sectionInside: 1 })
// this is what i want to pass to childs
return (
<Fragment>
<Toolbar>
<BlockTitle clientId={clientId}/>
</Toolbar>
<InnerBlocks allowedBlocks={allowedBlocks}/>
</Fragment>
)
},
save: function (props) {
return (
<InnerBlocks.Content/>
)
}
})
Inside collapsing-section
I'm gonna have tinymce blocks. From collapsing-section
i wanna pass attribute sectionInside
with value 1
that i can access inside tinymce
block and pass it to `SectionEdit.
PS: I hope this code will help someone out! If You see some bad practice or something that i use badly please let me know! I'm trying to make this work super automatically but I'm learning many concepts thanks to gutenberg like React comonents, es6 and others
PPS: Gutenberg documentation is really really really bad. It feels like it's 20% of what should it be and many things are missing. If You could first make good documentation and than go for phase 2 I'm sure community will be much more welcome to gutenberg and there will be much more contributors to the project.
For anybody having problem like me this is the solution:
in container block edit:
edit: function (props) {
const { clientId } = props
select('core/editor').getBlocksByClientId(clientId)[0].innerBlocks.forEach(function (block) {
dispatch('core/editor').updateBlockAttributes(block.clientId, { sectionTag: 'div' })
})
return (
<Fragment>
<div className="editor-block-list__title">
<BlockTitle clientId={clientId}/>
</div>
<InnerBlocks allowedBlocks={allowedBlocks}/>
</Fragment>
)
},
and in my section i added those:
if (typeof sectionUse === 'undefined')
setAttributes({ sectionUse: 1 })
if (typeof sectionTag === 'undefined')
setAttributes({ sectionTag: 'section' })
if (typeof sectionContainer === 'undefined')
setAttributes({ sectionContainer: 1 })
Awesome! Thanks man, Helps a ton.
There's a very new block context feature that's relevant:
https://github.com/WordPress/gutenberg/blob/master/docs/designers-developers/developers/block-api/block-context.md
It's only available in the Gutenberg plugin at the moment.
Most helpful comment
There's a very new block context feature that's relevant:
https://github.com/WordPress/gutenberg/blob/master/docs/designers-developers/developers/block-api/block-context.md
It's only available in the Gutenberg plugin at the moment.