首页 > 解决方案 > 在 Gutenberg InspectorControls 中使用 ajax 数据

问题描述

我正在创建自定义 Gutenberg 编辑器块以将 YouTube 视频 ID 设置为<button>属性data-video=""

更新 - 在下面添加了工作代码

我的function.php代码

// Include Css and js block files
function designa_youtube_block() {
    // Scripts
    wp_register_script(
        'youtube-block-script', // Handle.
         '/wp-content/themes/twentyfifteen/init/block.js',
        array( 'wp-blocks', 'wp-element', 'wp-i18n' ),
        time()
    );
    // Styles
    wp_register_style(
        'youtube-block-editor-style', // Handle.
        '/wp-content/themes/twentyfifteen/init/editor.css',
        array( 'wp-edit-blocks' ),
        time()
    );
    // Register the block with WP using our namespacing
    register_block_type( 'designa/youtube-block', array(
        'editor_script' => 'youtube-block-script',
        'editor_style' => 'youtube-block-editor-style',
    ) );

}
add_action( 'init', 'designa_youtube_block' );

我的 block.js 代码

( function( editor, components, element ) {
	const el = element.createElement;
	const registerBlockType = wp.blocks.registerBlockType;

    const RichText = wp.editor.RichText;
	const BlockControls = wp.editor.BlockControls;
	const InspectorControls = wp.editor.InspectorControls;
    const AlignmentToolbar = wp.editor.AlignmentToolbar;
	const UrlInput = wp.editor.URLInput;


    function getVideoId(url) {
        if (url) {
            let match = url.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/);
            
            if (match && match[2].length == 11)
                 return match[2];
            else
                return false;
        } else {
            return false;
        }
    }


	registerBlockType( 'designa/youtube-block', {
		title: 'YouTube',
		description: 'Видео в всплывающем окне.',
		icon: 'video-alt3',
		category: 'common',
		
		attributes: {
            content: {
    			type: 'string',
            },
            url: {
                type: 'string',
            },
			alignment: {
				type: 'string',
			},
		},


		edit: function( props, isSelected ) {

			let attributes = props.attributes,
                url = props.attributes.url,
                alignment = props.attributes.alignment;
                
			function onChangeAlignment( newAlignment ) {
				props.setAttributes( { alignment: newAlignment } );
			}
            
            if (url)
                videoTitle();
            
            async function videoTitle(){
                    
                    let id = getVideoId(url);

                    const response = await fetch( `https://www.googleapis.com/youtube/v3/videos?id=${ id }&key=AIzaSyBUqaVKkqdXzPQnfuuP8VPa-yqOQlJwV-w&fields=items(snippet(title))&part=snippet`, {
                        cache: 'no-cache',
                        headers: {
                            'user-agent': 'WP Block',
                            'content-type': 'application/json'
                          },
                        method: 'GET',
                        redirect: 'follow', 
                        referrer: 'no-referrer', 
                    })
                    .then(
                        returned => {
                            if (returned.ok) return returned;
                            throw new Error('Network response was not ok.');
                        }
                    );
            
                    let data = await response.json();
            
                    props.setAttributes( { title: data.items[0].snippet.title} );
            
            };


			return [
				el( BlockControls, { key: 'controls' },
					el( AlignmentToolbar, {
						value: alignment,
						onChange: onChangeAlignment,
					} )
				),
				
				el( InspectorControls, { key: 'inspector' },
					el( components.PanelBody, {
						title: 'Превью видео',
						className: 'youtube-preview-block',
						initialOpen: true,
					},
					
					el( 'div', {
					    className: 'youtube-preview',
					    },
						el( 'iframe', {
                            frameborder: '0',
                            allowfullscreen: 'allowfullscreen',
                            src: url ? 'https://www.youtube.com/embed/'+getVideoId(url)+'?rel=0&amp;showinfo=0' : ''
                            },
                        ),
                        
					),
					
						el( 'div', { className: !props.attributes.title ? 'sceleton-youtube-title' : '' },
						    props.attributes.title ? props.attributes.title : ''
                        ),
					
					),
				),

				el( 'div', { className: alignment ? props.className+' justify-content-'+alignment : props.className },

                    el( 'svg', { className: 'play-icon', width: '50', height: '50', viewBox: '0 0 70 70' },
						el( 'path', { fill: '#f6155e', d: "M35 70C54.33 70 70 54.33 70 35C70 15.67 54.33 0 35 0C15.67 0 0 15.67 0 35C0 54.33 15.67 70 35 70Z" } ),
						el( 'path', { fill: '#fff', d: "M48.2988 35L28.6988 44.1L28.6988 25.9L48.2988 35Z" } ),
					),

                    el( 'div', { className: 'youtube-wrap' },
						el( RichText, {
                                tagName: 'div',
                                placeholder: 'Введите текст кнопки',
                                keepPlaceholderOnFocus: true,
                                isSelected: false,
                                value: props.attributes.content,
                    			onChange: function( content ) {
                    				props.setAttributes( {
                    				    content: content,
                    				} );
                    			}
                            }
					    ),
                        
                        el( 'div', { className: 'youtube-link-wrap' },
                            
                            el( 'svg', { className: 'dashicon dashicons-admin-links', width: '20', height: '20' },
                                el( 'path', { d: "M17.74 2.76c1.68 1.69 1.68 4.41 0 6.1l-1.53 1.52c-1.12 1.12-2.7 1.47-4.14 1.09l2.62-2.61.76-.77.76-.76c.84-.84.84-2.2 0-3.04-.84-.85-2.2-.85-3.04 0l-.77.76-3.38 3.38c-.37-1.44-.02-3.02 1.1-4.14l1.52-1.53c1.69-1.68 4.42-1.68 6.1 0zM8.59 13.43l5.34-5.34c.42-.42.42-1.1 0-1.52-.44-.43-1.13-.39-1.53 0l-5.33 5.34c-.42.42-.42 1.1 0 1.52.44.43 1.13.39 1.52 0zm-.76 2.29l4.14-4.15c.38 1.44.03 3.02-1.09 4.14l-1.52 1.53c-1.69 1.68-4.41 1.68-6.1 0-1.68-1.68-1.68-4.42 0-6.1l1.53-1.52c1.12-1.12 2.7-1.47 4.14-1.1l-4.14 4.15c-.85.84-.85 2.2 0 3.05.84.84 2.2.84 3.04 0z" } ),
                            ),
                            
    						el( UrlInput, {
                                    tagName: 'div',
                                    value: url,
                                    autoFocus: false,
                                    onChange: function( url ) {
                                        props.setAttributes({
                                            url: url,
                                            title: ''
                                        });
                                    }
                                }
    					    ),
    					    
    					    
    					),
                    ),
                    

				),
				
			];
			
		},


		save: function( props ) {
			let attributes = props.attributes;
            
			return (
				el( 'div', {
					className: (attributes.alignment) ? 'justify-content-'+attributes.alignment : '',
				},
				
					el( 'button', {
					        className: 'video-btn',
						    'data-video': getVideoId(attributes.url),
						}, attributes.content,
					),

				)
			);
		},
		
	} );

} )(
	window.wp.editor,
	window.wp.components,
	window.wp.element,
);

我的 editor.css 代码

.youtube-wrap {
    width: calc(80% - 70px);
}
.wp-block-designa-youtube-block {
    display: flex;
    align-items: center;
}
.youtube-link-wrap {
    display: flex;
    align-items: center;
}
.youtube-link-wrap svg {
    margin-right: 10px;
    fill: #8f98a1;
}
.youtube-wrap {
    padding: 0 20px;
}
.youtube-preview {
	position: relative;
	padding-bottom: 56.25%;
	height: 0;
    background: #e1e9ee;
    margin-bottom: 14px;
}
.gutenberg__editor .youtube-preview iframe {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
}
.justify-content-center {
    justify-content: center;
}
.justify-content-left {
    justify-content: flex-start;
}
.justify-content-right {
    justify-content: flex-end;
}
.sceleton-youtube-title:before, .sceleton-youtube-title:after {
    content: "";
    display: block;
    height: 18px;
    width: 100%;
    background-color: #f0f4f6;
    margin-bottom: 10px;
}
.sceleton-youtube-title:after {
    width: 40%;
}
.components-panel__body.youtube-preview-block {
    font-weight: bold;
    color: #5a5e61;
    letter-spacing: 0.015em;
    line-height: 22px;
}

在后端我得到了这个结果: 在此处输入图像描述

一切正常,但现在我需要通过 ID 从 YouTube 获取视频的标题和持续时间getId(attributes.url)并插入到 InspectorControls 块。

如果我尝试使用 Ajax 获取标题和持续时间,首先将所有块字段呈现给 InspectorControls,然后执行我的 ajax 请求。我在ajax成功时需要类似的东西push( el( 'p', {}, '**YouTube Title**') )

告诉我如何在渲染和更改后将使用 Ajax 获得的信息添加到 InspectorControls?

标签: jsonwordpressreactjswordpress-gutenberg

解决方案


推荐阅读