|
/** |
|
* Retrieves the translation of text. |
|
* |
|
* @see https://developer.wordpress.org/block-editor/packages/packages-i18n/ |
|
*/ |
|
import { __ } from '@wordpress/i18n'; |
|
|
|
/** |
|
* React hook that is used to mark the block wrapper element. |
|
* It provides all the necessary props like the class name. |
|
* |
|
* @see https://developer.wordpress.org/block-editor/packages/packages-block-editor/#useBlockProps |
|
*/ |
|
import { |
|
InnerBlocks, |
|
useBlockProps, |
|
InspectorControls, |
|
} from '@wordpress/block-editor'; |
|
|
|
/** |
|
* Other things needed |
|
* |
|
*/ |
|
|
|
import { SelectControl, TextControl } from '@wordpress/components'; |
|
import { Component } from '@wordpress/element'; |
|
import { useDispatch, useSelect } from '@wordpress/data'; |
|
|
|
/** |
|
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files. |
|
* Those files can contain any CSS code that gets applied to the editor. |
|
* |
|
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css |
|
*/ |
|
import './editor.scss'; |
|
|
|
function mySelectPosts({clientId, attributes, setAttributes }) { |
|
|
|
// Used to reset inner blocks if we've changed the selected exercise |
|
const { replaceInnerBlocks } = useDispatch("core/block-editor"); |
|
const { inner_blocks } = useSelect(select => ({ |
|
inner_blocks: select("core/block-editor").getBlocks(clientId) |
|
})); |
|
|
|
/** |
|
* Called when the inspector controls select box is changed |
|
* Saves the value of the selected post to the selectedPost attribute |
|
* and resets the innerblock |
|
**/ |
|
|
|
const onSelectPost = ( post ) => { |
|
|
|
// reset the inner |
|
let inner_blocks_new = []; |
|
|
|
replaceInnerBlocks(clientId, inner_blocks_new, false); |
|
|
|
setAttributes( { |
|
selectedPost: parseInt(post), |
|
} ); |
|
}; |
|
|
|
const posts = useSelect( 'core' ).getEntityRecords( 'postType', 'exercise', { //1 |
|
// *no _embed here |
|
|
|
// This should always be set to avoid duplicates in the post selection dropdown. |
|
// But of course, you can change the value, e.g. to 20 or, the max value - 100. |
|
per_page: 10, |
|
} ); |
|
|
|
const selectedPost = useSelect( select => { //2 |
|
const { getEntityRecord } = select( 'core' ); |
|
|
|
const post_id = attributes.selectedPost; |
|
|
|
// Fetch the post from the REST API, if we have a valid post ID. |
|
return post_id && getEntityRecord( 'postType', 'exercise', post_id, { |
|
// Request featured media along with the standard post data. |
|
_embed: 'wp:featuredmedia', |
|
|
|
// *no per_page here |
|
} ); |
|
// This useSelect callback has one dependency - the selected post ID. |
|
}, [ attributes.selectedPost ] ); |
|
|
|
/* Set of functions for saving out attributes |
|
* reps, sets, notes |
|
*/ |
|
|
|
const onChangeReps = ( reps ) => { |
|
setAttributes( { |
|
reps: Number( reps ), //3 |
|
} ); |
|
} |
|
|
|
const onChangeSets = ( sets ) => { |
|
setAttributes( { |
|
sets: Number( sets ), //4 |
|
} ); |
|
} |
|
|
|
const onChangeNotes = ( notes ) => { |
|
setAttributes( { |
|
notes: notes, |
|
} ); |
|
} |
|
|
|
// will contain the text output for the edit. |
|
let output = ""; |
|
|
|
const blockProps = useBlockProps( { |
|
className: "sandcexercise", |
|
} ); |
|
|
|
// we've selected a post, so grab the bits from that post to put into the html |
|
if (selectedPost) { //5 |
|
|
|
// grab the things we are putting in the innerblock from the post |
|
let mediaID = selectedPost?.featured_media || 0; //6 |
|
let mediaURL = selectedPost?._embedded?.['wp:featuredmedia'][0]?.source_url || ''; //7 |
|
let exerciseLink = selectedPost.link; |
|
|
|
// remove any html content from the excerpt as it explodes the inner block :/ |
|
let strippedContent = selectedPost.excerpt.rendered.replace(/(<([^>]+)>)/gi, ""); |
|
|
|
// create a linked heading |
|
let heading = '<a href="' + exerciseLink + '">' + selectedPost.title.rendered + '</a>'; |
|
|
|
// build the innerblocks template |
|
const MY_TEMPLATE = [ |
|
[ 'core/heading', { content: heading } ], |
|
[ 'core/image', { id: mediaID, url: mediaURL, href: exerciseLink, align: "right", sizeSlug: "medium", caption: "Click for instructions", width: 300 } ], //* |
|
[ 'core/paragraph', { content: strippedContent } ] |
|
]; |
|
output = <InnerBlocks |
|
template={ MY_TEMPLATE } |
|
templateLock="" |
|
/> |
|
|
|
} else { |
|
output = <p>Select an exercise from the right</p> |
|
} |
|
|
|
//8 I changed the SelectControl's options - a "loading" message is shown if "posts" |
|
// is yet filled. |
|
|
|
// return the edit html. |
|
return [ |
|
<div { ...blockProps } key="sandcexercise"> |
|
<InspectorControls> |
|
<div id="sandcexercise-controls"> |
|
<SelectControl |
|
onChange={ onSelectPost } |
|
value={ attributes.selectedPost } |
|
label={ __( 'Select a Post' ) } |
|
options={posts ? [ |
|
...[ { value: 0, label: __( 'Select an exercise' ) } ], |
|
...posts.map( post => ( { |
|
value: post.id, |
|
label: post.title.rendered, |
|
})), |
|
] : [ |
|
{ value: 0, label: __( 'Loading the posts list..' ) }, |
|
]} |
|
/> |
|
</div> |
|
</InspectorControls> |
|
{output} |
|
<TextControl |
|
{ ...blockProps } |
|
label="Reps:" |
|
type="number" |
|
className="thereps" |
|
onChange={ onChangeReps } |
|
value={ attributes.reps } |
|
/> |
|
<TextControl |
|
{ ...blockProps } |
|
label="Sets:" |
|
type="number" |
|
className="thesets" |
|
onChange={ onChangeSets } |
|
value={ attributes.sets } |
|
/> |
|
<TextControl |
|
{ ...blockProps } |
|
label="Notes:" |
|
type="text" |
|
className="thenotes" |
|
onChange={ onChangeNotes } |
|
value={ attributes.notes } |
|
/> |
|
</div> |
|
] |
|
|
|
} |
|
|
|
export default mySelectPosts; |
You're not, you're copying the data into the post as paragraphs/image/heading blocks, no embedding or displaying is occurring. E.g. if the original post changes none of these blocks would change
You don't need to create inner/nested blocks to display a post from a saved ID.
Yes
Yes, the recent posts block does it, and there are many ways to do it, just as there are many ways a shortcode could do it. Maybe you render the block server side in PHP? Maybe you fetch it in JS? Maybe your inner block isn't headings and paragraph blocks but a custom block that represents that exercise? There are lots of ways to do it, very few of them rely on special Gutenberg sauce to do it. Why would it be any different to the way it worked for shortcodes? You could even do a literal embed of the post and use a customized embed HTML via the embed filters for that post type. There are lots and lots of ways to do it.