I have created a fairly simple accordion block, and it works great for basic text. The problem is that the control I am using for the accordion content is the RichText, which only allows for basic formatting such as bold.
What if I wanted to create an Unordered List as well as basic text? I am currently using multiline: "p"
, but how can I add additional elements so that I can also have UL elements in there as well?
The only two ideas I can think of, I cannot figure out how to implement. The first is to extend the block toolbar with BlockControls
to include additional formatters for UL, and the second is to use another element instead of RichText - such as Freeform (which might have been renamed to Classic Editor?) - but I cannot find any documentation on these.
Here is an example of my current code:
ATTRIBUTES
attributes: {
title: {
type: 'string',
selector: '.hd-accordion-title',
},
content: {
type: 'array',
source: 'children',
selector: '.hd-accordion-content',
}
},
EDIT
edit: function( props ) {
var title = props.attributes.title;
var content = props.attributes.content;
function onChangeTitle(newTitle) {
props.setAttributes({
title: newTitle
});
}
function onChangeContent(newContent) {
props.setAttributes({
content: newContent
});
}
return [
(
<div className={"hd-accordion"}>
<RichText
tagName="h3"
className= "hd-accordion-title"
value= { title }
onChange= { onChangeTitle }
placeholder = "Title"
keepPlaceholderOnFocus = { true }
multiline= { false }
/>
<RichText
tagName="div"
className="hd-accordion-content"
value={ content }
onChange= { onChangeContent }
placeholder = "content"
multiline="p"
/>
</div>
)
];
},
You can register new formatting options like this-
Adding simple formatting button
registerFormat( 'bold', {
selector: 'strong',
edit( { isActive, toggleFormat } ) {
return (
<Fragment>
<Shortcut
type="primary"
key="b"
onUse={ () => toggleFormat() }
/>
<ToolbarControls>
<ToolbarButton
icon="editor-bold",
title={ __( 'Bold' ) }
isActive ={ isActive }
onClick={ () => toggleFormat() }
/>
</ToolbarControls>
</Fragment>
);
},
} );
Adding A Link Button
registerFormat( 'link', {
selector: 'a',
attributes: {
url: {
source: 'attribute',
attribute: 'href',
},
},
edit( { isActive, removeFormat } ) {
return (
<Fragment>
<Shortcut
type="access"
key="s"
onUse={ () => removeFormat() }
/>
<Shortcut
type="access"
key="a"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<Shortcut
type="primary"
key="k"
onUse={ /* Set state and pass to LinkContainer */ }
/>
<ToolbarControls>
{ isActive && <ToolbarButton
icon="editor-unlink",
title={ __( 'Unlink' ) }
onClick={ () => removeFormat() }
/> }
{ ! isActive && <ToolbarButton
icon="admin-links",
title={ __( 'Link' ) }
onClick={ () => /* Set state and pass to LinkContainer */ }
/> }
</ToolbarControls>
<LinkContainer { ...props } />
</Fragment>
);
},
} );
Adding an Image button
registerFormat( 'image', {
selector: 'img',
attributes: {
url: {
source: 'attribute',
attribute: 'src',
},
},
edit: class ImageFormatEdit extends Component {
constructor() {
super( ...arguments );
this.state = {
modal: false;
};
}
openModal() {
this.setState( { modal: true } )
}
closeModal() {
this.setState( { modal: false } )
}
render() {
const { insertObject } = this.props;
return (
<Fragment>
<InserterItems>
<InserterItem
icon="inline-image",
title={ __( 'Inline Image' ) }
onClick={ openModal }
/>
</InserterItems>
{ this.state.modal && <MediaUpload
type="image"
onSelect={ ( { id, url, alt, width } ) => {
this.closeModal()
insertObject( {
src: url,
alt,
class: `wp-image-${ id }`,
style: `width: ${ Math.min( width, 150 ) }px;`,
} );
} }
onClose={ this.closeModal }
render={ ( { open } ) => {
open();
return null;
} }
/> }
</Fragment>
);
}
},
} );
You might encounter few bugs here and there. Relevant ticket