Last active
October 20, 2022 12:21
-
-
Save rogerlos/7502541070942e16a1188dd0bb9ac2b9 to your computer and use it in GitHub Desktop.
Allows Gutenberg SelectControl to have its options dynamically populated.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This is an abbreviated "ES5" script (though it has some ES6 language, just not JSX, or dependencies on npm) | |
* demonstrating how to get the WordPress "Gutenberg" SelectControl to allow dynamic options. | |
* | |
* It probably isn't elegant, but neither am I...I included more context than may be necessary. | |
* | |
* (SelectControl pukes on dynamic options because it completely dies, never to be seen again, if it | |
* is sent an empty options array. This prevents that with a placeholder until your results come back.) | |
*/ | |
( function ( BLOCK, ED, COMPS, EL, FETCH ) { | |
const { registerBlockType } = BLOCK; | |
const { SelectControl } = COMPS; | |
const { InspectorControls } = ED; | |
/* Custom route in the rest API; it returns all posts, to be filtered up here. */ | |
const ROUTES = { posts : '/myblocks/v1/all-posts' }; | |
/* In an elegant app, these would be passed to the server, DRY and all that. */ | |
const TYPES = [ 'post', 'page' ]; | |
/* My default empty option */ | |
const DY = { key : 'postnone', label : 'Select a Post', value : 0 }; | |
/* The dynamic store. It needs to be an object so a property can be altered. */ | |
const DYNAMIC = { posts: [] }; | |
/* My 'register block' config array, eliminated for brevity. */ | |
const CFG = { /* sanity */ }; | |
/* Calling 'post_selectors' starts the "fetch"...it might be done by the time someone starts poking at the | |
inspector; but if not, no worries: it will update the select on the 'focus' after info is returned. */ | |
post_selectors(); | |
/* Register the block */ | |
registerBlockType( 'pulling/teeth', { | |
...CFG, | |
edit : function ( props ) { | |
return EL( 'div', {}, | |
EL( InspectorControls, {}, | |
poster( props ) // <-- returns the select control with dynamic options | |
) | |
) | |
}, | |
save : function () { /* ... */ } | |
} ); | |
/* Now you can have dynamic options fetched from whereever... | |
* | |
* 'poster' runs every time the block is focused, so it checks our const 'DYNAMIC' and | |
* eventually substitutes fetched results for the placeholder. Remember, 'DY' is the generic | |
* "Select a Post" option object. | |
* | |
* In my fiddling around, the posts property immediately became undefined rather than | |
* the empty array it was initialized as once the fetch started...hence the test as shown. */ | |
function poster( props ) { | |
return EL( | |
SelectControl, | |
{ | |
key : CFG.itemPost.key, | |
label : CFG.itemPost.label, | |
help : CFG.itemPost.help, | |
options : typeof( DYNAMIC.posts ) === 'undefined' ? [ DY ] : DYNAMIC.posts, | |
value : props.attributes.itemPost, | |
onChange : function ( val ) { | |
props.setAttributes( props.attributes.itemPost = val ) | |
} | |
} | |
) | |
} | |
/* FETCH | |
* I found this chain of three functions was needed, I suspect because I don't quite get promises. | |
* | |
* 'get_posts' fetches the posts...filtering them by types allowed via 'TYPES'. */ | |
function get_posts() { | |
let myTypes = []; | |
return new Promise( | |
function ( resolve ) { | |
FETCH( { path : '/wp/v2/types' } ).then( | |
function ( types ) { | |
TYPES.forEach( | |
function ( el ) { | |
if ( typeof( types[ el ] ) !== 'undefined' ) | |
myTypes.push( el ); | |
} ); | |
} ) | |
.then( | |
FETCH( { path : ROUTES.posts, types : myTypes } ).then( | |
function ( res ) { | |
resolve( res ) | |
} ) ) | |
} ) | |
} | |
/* 'post_selector_opts' takes the posts 'get_posts' and turns them into an options array */ | |
function post_selector_opts() { | |
return new Promise( | |
function ( resolve ) { | |
get_posts().then( function ( posts ) { | |
let opts = [ DY ]; | |
posts.forEach( function ( P ) { | |
opts.push( { key: P.slug, label: P.title, value: P.id } ); | |
} ); | |
resolve( opts ); | |
} | |
) } | |
) | |
} | |
/* For some reason which makes sense to someone, 'post_selector_opts' results in a promise, | |
* not an array. Unless you retrieve it in a promise, the sole reason for 'post_selectors'. | |
* | |
* I plunk the array into 'DYNAMIC.posts` so everyone can enjoy. */ | |
function post_selectors() { | |
post_selector_opts().then( opts => { | |
DYNAMIC.posts = opts; | |
} ); | |
} | |
} )( wp.blocks, wp.editor, wp.components, wp.element.createElement, wp.apiFetch ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
shouldn't we use withSelect for wpapi?