|
/** |
|
* 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; |
Something people forget is that when they're building something they get lost in the technical details, and ask about them. They forget that me and other people reading it have no idea what it was they were trying to build in the first place and have to reverse engineer that. it's all the more frustrating when you ask someone why they want an articulating hinge to open more than 60 degrees and they respond with "I needed rotational motion to move the plank of wood, do you know why it won't move to 70 degrees?" when what I actually needed was "I'm trying to build a door for my house"
From what I can tell this is for a workout program post type, and you have a block called
sadc
which you use to say "do Squats, 5 times, at 4 reps". You can then pick an exercise post type ( e.g. the "squats" post ) and it shows some info. For some reason this information iis copied from the squats post and turned into raw content placed inside as nested blocks, but I'm not sure why. Why not create an exercise block that displays info about an exercise post? Or just have a component that displays this information when given an ID ( you don't need to store anything more than the post ID, just fetch the data in JS in the edit component, or render it dynamically on the frontend )