我有一个自定义块,它在内部块中输出一个核心/图像块。在我尝试发送一个尺寸之前,一切都很顺利。执行此操作时,块验证在重新编辑时失败:
Block validation: Block validation failed for `core/image` ({name: "core/image", icon: {…}, keywords: Array(3), providesContext: {…}, usesContext: Array(0), …}).
Content generated by `save` function:
<figure class="wp-block-image alignright" style="max-width:50%"><a href="https://.../"><img src="https://.../plank-banner.jpg" alt=""/></a></figure>
Content retrieved from post body:
<div class="wp-block-image"><figure class="alignright is-resized"><a href="https://..."><img src="https://.../plank-banner.jpg" alt="" class="wp-image-8687" width="300px"/></a></figure></div>
您可以看到从正文中检索到的内容非常不同。这是两个innerblocks模板之间的区别:
Doesn\'t work:
const MY_TEMPLATE = [
[ \'core/heading\', { content: heading } ],
[ \'core/image\', { id: mediaID, url: mediaURL, href: exerciseLink, align: "right", width: "300px" } ],
[ \'core/paragraph\', { content: strippedContent } ]
];
Works:
const MY_TEMPLATE = [
[ \'core/heading\', { content: heading } ],
[ \'core/image\', { id: mediaID, url: mediaURL, href: exerciseLink, align: "right" } ],
[ \'core/paragraph\', { content: strippedContent } ]
];
我的保存很简单:
save: function( props ) {
const blockProps = useBlockProps.save();
const { attributes } = props;
return (
<div { ...blockProps } key="sandcexercise">
<InnerBlocks.Content />
</div>
);
我四处嗅了嗅,确实发现了这个:
https://github.com/WordPress/gutenberg/issues/21989 这感觉很相关,但对我来说太复杂了,弄不清楚!
--
根据请求添加了更多代码。很抱歉这里的代码质量,我真的是从很多不同的教程中拼凑出来的,其中很多都是为API v1编写的,这是我第一次体验EXNext、React和Gutenberg!
此块显示inspector控件中的下拉列表,该下拉列表由自定义帖子类型(称为练习)填充。选中后,它将在innerblock内的块中呈现摘录、特色图像和标题以及几个其他属性。
当我试图通过宽度属性调整核心/图像块的大小时,它会消失。
我正在访问wp。api使用
wp_enqueue_script( \'wp-api\' );
在我的php文件中。
两个文件:
索引。js公司
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType} from \'@wordpress/blocks\';
import {
InnerBlocks,
useBlockProps,
} from \'@wordpress/block-editor\';
const { __ } = wp.i18n; // Import __() from wp.i18n
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import \'./style.scss\';
/**
* Internal dependencies
*/
import Edit from \'./edit\';
/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType(\'get-coached/sandc\', {
apiVersion: 2,
attributes: {
posts: {
type: \'array\',
default: [],
},
post: {
type: \'object\',
},
selectedPost: {
type: \'number\',
default: 0
},
options: {
type: \'array\',
default: [ { value: 0, label: __( \'Select a Post\' ) } ],
},
reps: {
type: \'number\',
source: \'number\',
selector: \'.thereps\',
default: 15,
},
sets: {
types: \'number\',
source: \'number\',
selector: \'.thesets\',
default: 3,
},
notes: {
types: \'text\',
source: \'text\',
selector: \'.thenotes\',
default: \'\',
},
},
edit: Edit,
save: function( props ) {
const blockProps = useBlockProps.save();
const { attributes } = props;
return (
<div { ...blockProps } key="sandcexercise">
<InnerBlocks.Content />
<div className="repsrow"><div className="repslabel">Reps:</div><div className="thereps">{ attributes.reps }</div></div>
<div className="setsrow"><div className="setslabel">Sets:</div><div className="thesets">{ attributes.sets }</div></div>
<div className="notesrow"><div className="noteslabel">Notes:</div><div className="thenotes">{ attributes.notes }</div></div>
</div>
);
},
});
编辑。js公司
/**
* 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
*
*/
const { SelectControl, TextControl } = wp.components;
const { Component } = wp.element;
const { useDispatch, useSelect } = wp.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),
} );
};
// define the exercise custom post type model so we can get the list of them
const Exercise = wp.api.models.Post.extend( {
urlRoot: wpApiSettings.root + \'wp/v2/exercise\',
defaults: {
type: \'exercise\',
},
} );
// set up the structure for querying for exercises
const Exercises = wp.api.collections.Posts.extend( {
url: wpApiSettings.root + \'wp/v2/exercise?_embed\',
model: Exercise,
} );
const someExercises = new Exercises();
// options will contain our select dropdown options.
let options = attributes.options;
const loadPosts = ( ) => {
// grab the exercise custom post types from the db
someExercises.fetch().then( ( posts ) => {
// clear out the options array just incase something has changed
// and add the default back in then repopulate.
options = [ { value: 0, label: __( \'Select an exercise\' ) } ];
posts.forEach((post) => {
// build out the select dropdown options from the exercises
options.push({value:post.id, label:post.title.rendered});
});
// save both options and posts.
setAttributes( { options: options } );
setAttributes( { posts: posts } );
});
}
/* Set of functions for saving out attributes
* reps, sets, notes
*/
const onChangeReps = ( reps ) => {
setAttributes( {
reps: reps,
} );
}
const onChangeSets = ( sets ) => {
setAttributes( {
sets: sets,
} );
}
const onChangeNotes = ( notes ) => {
setAttributes( {
notes: notes,
} );
}
/* If select post isn\'t, and the posts has nothing in it
* Then we need to go and get some posts!
*/
if (!attributes.selectedPost && attributes.posts.length == 0) {
loadPosts();
}
// will contain the text output for the edit.
let output = "";
// array of returned exercise posts
let posts = attributes.posts;
const blockProps = useBlockProps( {
className: "sandcexercise",
} );
// we\'ve selected a post, so grab the bits from that post to put into the html
if (attributes.selectedPost) {
// grab the post from the posts array using the ID in selectedPosts
const selectedPost = posts.find( ( item ) => { return item.id == parseInt( attributes.selectedPost ) } );
// grab the things we are putting in the innerblock from the post
let mediaID = selectedPost.featured_media;
let mediaURL = selectedPost[\'_embedded\'][\'wp:featuredmedia\'][0]["source_url"];
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" } ],
[ \'core/paragraph\', { content: strippedContent } ]
];
output = <InnerBlocks
template={ MY_TEMPLATE }
templateLock=""
/>
} else {
output = <p>Select an exercise from the right</p>
}
// 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={ options }
/>
</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;
任何改进建议(或指出的明显缺陷)都将受到赞赏。