向内部块中的核心/映像添加大小会中断保存

时间:2021-08-26 作者:delanthear

我有一个自定义块,它在内部块中输出一个核心/图像块。在我尝试发送一个尺寸之前,一切都很顺利。执行此操作时,块验证在重新编辑时失败:

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;
任何改进建议(或指出的明显缺陷)都将受到赞赏。

1 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

当我试图通过widthattribute调整核心/图像块的大小时,它会消失。

是的,这是因为你使用了错误的值300px 这是一个字符串width 中的属性core/image 块实际使用number 类型事实上,该属性用作width 属性<img> 标记,因此这就是属性类型为number的原因,因为它就是这样-请参见MDN web docs 了解更多详细信息。

因此,在MY_TEMPLATE, 您应该使用width: 300not width: "300px".

请注意,尽管"300" 只包含数字,它实际上是一个字符串,而不是实际数字。因此,当您想要指定一个数字/整数时,不要将该值加引号,这显然是您实际所做的。。。请参见构建脚本中的第383行here. =)

任何改进建议(或指出的明显缺陷)都将受到赞赏。

您的块类型缺少标题-它是必需的,没有它,块类型将不会被注册-但我猜可能只是问题中缺少了标题?

wp-api script 非常棒,但是当谈到块编辑器时,我会使用getEntityRecords() and getEntityRecord() 用于从REST API检索帖子。

  • posts 不应作为属性添加。更糟糕的是,您实际上存储了整个post对象,这样做会使post内容(extremely) huge, 这不好:(

  • 请参见my gist on GitHub 例如posts 还有其他的改变我喜欢改变reps 至“a”;“真实”;数字

    相关推荐