I built a custom Gutenberg block to show ONE post of a custom post type called story
. Most things are finally working fine, story shows up as wanted via ServerSideRendering. To select the story-to-show there is a List of radio buttons in the sidebar.
What I want:
- after choosing a story from the radio buttons, I want the shown story to refresh.
From some examples I believe this gets solved with withSelect
or useSelect
or something like that. But I can't wrap my head around it, I don't understand how to use them for my case.
When the story_id
of the edit function gets updated, the Story object needs to get rendered again with that new story_id
.
Here's the code:
/**
* Story-Block: osf-blocks-story
*
* Gives back a rendered story (list of images with text & title) after selecting from the left block sidebar
*
* based on create-guten-block
*/
import './style.scss';
import './editor.scss';
import { registerBlockType } from '@wordpress/blocks';
import { ServerSideRender, RadioControl, PanelBody } from '@wordpress/components';
import { InspectorControls } from '@wordpress/block-editor';
import { Component, Fragment } from '@wordpress/element';
import { useSelect, withSelect } from '@wordpress/data';
let $ = jQuery;
// short for console.log
function cl(words) { console.log('drx-osf-story, block.js: ' + words); }
// to get more object infos than console.log(obj + 'some comment');
function ol(object, words='') {
cl(words + ': \\/');
console.log(object);
}
// Represents a single story, i.e. a collection of parts with image, short text and possibly a title
class Story extends Component {
constructor(props) {
super(props);
this.state = {
story_id: props.story_id
}
}
render() {
return (
<ServerSideRender
block="osf-blocks/story"
attributes={this.state}
/>
)
}
}
// Represents a list of radiobuttons to select one of all stories
class StoriesListControl extends Component {
constructor(props) {
super(props);
this.state = {
changeHandler: props.changeHandler,
story_id: props.story_id,
options: props.options
};
}
render() {
return (
<InspectorControls>
<PanelBody title='Story auswählen:'>
<RadioControl
label="Wähle, welche Story hier eingefügt werden soll."
help="Die Story muss vorher über das Story-Interface angelegt worden sein."
selected={ this.state.story_id }
options={ this.state.options }
onChange={ this.state.changeHandler }
/>
</PanelBody>
</InspectorControls>
);
}
};
// Registering the block
registerBlockType('osf-blocks/story', {
title: 'Story' ,
icon: 'images-alt2',
category: 'widgets',
attributes: {
story_id: {
type: 'string'
}
},
keywords: [
'osf-blocks-story',
'Story',
'Stories'
],
edit: (props) => {
// what to do with withSelect/useSelect here??
const {
attributes: { story_id },
setAttributes
} = props;
// called, if a radiobutton gets selected
const changeHandler = (new_story_id) => {
setAttributes({ story_id: new_story_id });
};
// fetching the list of all stories (custom post type) from server
const getStoriesList = () => {
let answer;
$.ajax({
url: '/wp-admin/admin-ajax.php',
type: 'POST',
data: {
action: 'stories_list'
},
async: false,
timeout: 3000 // ms
}).done((rspns) => {
// removing trailing 0 - what does it mean?
answer = { status: 'success', result: JSON.parse(rspns.substr(0, rspns.length - 1)) };
}).fail((xhr, status) => {
cl('request failed: ' + status);
ol(xhr);
answer = { status:'fail', log: status }
});
return answer;
};
// tie it all together
let response = getStoriesList();
let output;
if ( 'success' == response.status) {
// AJAX for storieslist succeeded
ol(response, 'response');
output = (
<Fragment>
<StoriesListControl
changeHandler={ changeHandler }
story_id={ story_id }
options={ response.result }
/>
<div className="story-container">
<div id={ "story" + story_id } className="story-preview container">
<Story story_id={ story_id } />
</div>
</div>
</Fragment>
);
}
else if ('fail' == response.status) {
// AJAX failed
output = (
<Fragment>
<div className="story-container">
<p>No connection to the server: { response.log }</p>
</div>
</Fragment>
);
}
return output;
},
save: (props) => {
return null;
}
});