Fortunately there is a hook that we can use to customize what component is used to render the taxonomy panels called editor.PostTaxonomyType
.
Gutenberg renders taxonomy panels with a component called PostTaxonomies
, which really just checks whether the taxonomy is heirarchical or not, and passes the props along to either the HierarchicalTermSelector
or FlatTermSelector
components accordingly. Normally, these two components don’t appear to be exposed in the Gutenberg API, except for within the editor.PostTaxonomyType
hook, which passes the relevant component as the 1st argument.
From there, all we have to do is extend the component, override the renderTerms
method to change the input type from checkbox
to radio
, and override the onChange
method to only return one selected term.
Unfortunately, extending the class within the hook seemed to cause a noticable performance hit, but storing the extended class in the window
seemed to mitigate that.
/**
* External dependencies
*/
import { unescape as unescapeString } from 'lodash';
function customizeTaxonomySelector( OriginalComponent ) {
return function( props ) {
if ( props.slug === 'my_taxonomy') {
if ( ! window.HierarchicalTermRadioSelector ) {
window.HierarchicalTermRadioSelector = class HierarchicalTermRadioSelector extends OriginalComponent {
// Return only the selected term ID
onChange( event ) {
const { onUpdateTerms, taxonomy } = this.props;
const termId = parseInt( event.target.value, 10 );
onUpdateTerms( [ termId ], taxonomy.rest_base );
}
// Copied from HierarchicalTermSelector, changed input type to radio
renderTerms( renderedTerms ) {
const { terms = [] } = this.props;
return renderedTerms.map( ( term ) => {
const id = `editor-post-taxonomies-hierarchical-term-${ term.id }`;
return (
<div key={ term.id } className="editor-post-taxonomies__hierarchical-terms-choice">
<input
id={ id }
className="editor-post-taxonomies__hierarchical-terms-input"
type="radio"
checked={ terms.indexOf( term.id ) !== -1 }
value={ term.id }
onChange={ this.onChange }
/>
<label htmlFor={ id }>{ unescapeString( term.name ) }</label>
{ !! term.children.length && <div className="editor-post-taxonomies__hierarchical-terms-subchoices">{ this.renderTerms( term.children ) }</div> }
</div>
);
} );
}
};
}
return <window.HierarchicalTermRadioSelector { ...props } />;
}
return <OriginalComponent { ...props } />;
};
}
wp.hooks.addFilter( 'editor.PostTaxonomyType', 'my-custom-plugin', customizeTaxonomySelector );