如何为自定义Gutenberg区块中的图片添加srcset属性?
自定义Gutenberg区块图片srcset属性缺失问题解决方案
问题描述
我正在开发自定义Gutenberg区块,用于上传图片和编辑内容,但上传的图片无法生成srcset属性。查资料说WordPress会自动添加srcset,但我用现有代码开发时,内容保存正常,图片却没有srcset,试过很多方法都没解决。
现有代码
block.json
{ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "dt-panphagia/dt-panphagia", "version": "0.1.0", "title": "Panphagia", "category": "widgets", "icon": "admin-site-alt", "description": "", "keywords": [ "dt", "saurus", "archive" ], "supports": { "align": ["full", "wide"] }, "textdomain": "dt-panphagia", "editorScript": "file:./index.js", "editorStyle": "file:./index.css", "style": "file:./style-index.css", "viewScript": "file:./view.js", "attributes": { "content": { "type": "string", "selector": "p" }, "heading": { "type": "string" }, "mediaId": { "type": "number", "default": 0 }, "mediaUrl": { "type": "string", "default": "" } } }
edit.js
import { __ } from '@wordpress/i18n'; import { useBlockProps, RichText, MediaUpload, MediaUploadCheck, InspectorControls } from '@wordpress/block-editor'; import { TextControl, ToggleControl, PanelBody, PanelRow, Button, ResponsiveWrapper, __experimentalHStack as HStack } from '@wordpress/components'; import { Fragment } from '@wordpress/element' import './editor.scss'; export default function Edit({ attributes, setAttributes, className }) { const blockProps = useBlockProps(); const removeMedia = () => { setAttributes({ media: "" }); } return ( <Fragment> <InspectorControls> <PanelBody title={__('Imagem/Achievement', 'dt-panphagia')} initialOpen={ true }> <div className="editor-post-featured-image"> <div className='editor-post-featured-image__container'> <MediaUploadCheck> <MediaUpload onSelect = {(media) => { setAttributes({ mediaId: media['id'], mediaUrl: media['url'], mediaWidth: media['width'], mediaHeight: media['height'] }); }} type = "image" value = {attributes.mediaId} render = {({ open }) => { return ( <Button className = {attributes.mediaId == 0 ? 'editor-post-featured-image__toggle' : 'editor-post-featured-image__preview'} onClick = {open} > {attributes.mediaId == 0 && __('Escolha uma Imagem', 'dt-panphagia')} {attributes.mediaId != 0 && <ResponsiveWrapper naturalWidth={ attributes.mediaWidth } naturalHeight={ attributes.mediaHeight }> <img src={attributes.mediaUrl} /> </ResponsiveWrapper> } </Button> ); }} /> </MediaUploadCheck> {attributes.mediaId != 0 && <HStack className='editor-post-featured-image__actions'> <Button className='editor-post-featured-image__action' onClick={removeMedia}>{__('Remove', 'dt-panphagia')}</Button> <MediaUploadCheck> <MediaUpload title={__('Replace image', 'awp')} value={attributes.mediaId} onSelect = {(media) => { setAttributes({ mediaId: media['id'], mediaUrl: media['url'], mediaWidth: media['width'], mediaHeight: media['height'] }); {console.log(media);} }} type = "image" render = {({open}) => ( <Button className='editor-post-featured-image__action' onClick={open}>{__('Replace', 'dt-panphagia')}</Button> )} /> </MediaUploadCheck> </HStack> } </div> </div> </PanelBody> </InspectorControls> <div {...blockProps} className='achievement'> <div className='achievement-wrap'> <div className='achievement-image'> <img className="eb-feature-list-img" src={attributes.mediaUrl} width="54" alt="" /> </div> <div className='achievement-content'> <RichText tagName="h3" value={ attributes.heading } allowedFormats={ [ 'core/bold', 'core/italic' ] } onChange={ ( heading ) => setAttributes( { heading } ) } placeholder="Enter heading here..." /> <RichText tagName="p" value={ attributes.content } allowedFormats={ [ 'core/bold', 'core/italic' ] } onChange={ ( content ) => setAttributes( { content } ) } placeholder="Button text..." /> </div> </div> </div> </Fragment> ); }
save.js
import { useBlockProps, RichText} from '@wordpress/block-editor'; export default function save( { attributes } ) { const blockProps = useBlockProps.save(); return ( <div {...useBlockProps.save()} className='achievement'> <div className='achievement-wrap'> <div className='achievement-image'> <img className="eb-feature-list-img" src={attributes.mediaUrl} width="54" alt="" /> </div> <div className='achievement-content'> <RichText.Content tagName="h3" value={ attributes.heading } /> <RichText.Content tagName="p" value={ attributes.content } /> </div> </div> </div> ); }
问题原因
你现在直接存储并输出图片URL(mediaUrl),而WordPress自动生成srcset需要依赖图片ID调用内部函数生成响应式属性,仅用URL无法触发这个机制。静态保存的HTML也无法动态生成适配不同屏幕的图片链接。
修复步骤
1. 更新block.json
移除冗余的mediaUrl属性,添加动态渲染指向PHP文件:
{ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "dt-panphagia/dt-panphagia", "version": "0.1.0", "title": "Panphagia", "category": "widgets", "icon": "admin-site-alt", "description": "", "keywords": [ "dt", "saurus", "archive" ], "supports": { "align": ["full", "wide"] }, "textdomain": "dt-panphagia", "editorScript": "file:./index.js", "editorStyle": "file:./index.css", "style": "file:./style-index.css", "viewScript": "file:./view.js", "render": "file:./render.php", "attributes": { "content": { "type": "string", "selector": "p" }, "heading": { "type": "string" }, "mediaId": { "type": "number", "default": 0 } } }
2. 创建render.php动态渲染文件
用PHP调用WordPress内置函数生成带srcset的图片标签:
<?php /** * 区块动态渲染模板 */ $attributes = $block['attributes']; $media_id = $attributes['mediaId']; $heading = $attributes['heading']; $content = $attributes['content']; // 获取图片响应式属性 $image_src = wp_get_attachment_image_url( $media_id, 'medium' ); $image_srcset = wp_get_attachment_image_srcset( $media_id, 'medium' ); $image_alt = get_post_meta( $media_id, '_wp_attachment_image_alt', true ); ?> <div <?php echo get_block_wrapper_attributes( array( 'class' => 'achievement' ) ); ?>> <div class='achievement-wrap'> <div class='achievement-image'> <?php if ( $media_id ) : ?> <img class="eb-feature-list-img" src="<?php echo esc_url( $image_src ); ?>" width="54" alt="<?php echo esc_attr( $image_alt ?: '' ); ?>" srcset="<?php echo esc_attr( $image_srcset ); ?>" sizes="(max-width: 768px) 100vw, 54px" /> <?php endif; ?> </div> <div class='achievement-content'> <?php if ( $heading ) : ?> <h3><?php echo wp_kses_post( $heading ); ?></h3> <?php endif; ?> <?php if ( $content ) : ?> <p><?php echo wp_kses_post( $content ); ?></p> <?php endif; ?> </div> </div> </div>
3. 修改save.js返回null
动态区块不需要静态保存HTML内容:
export default function save() { return null; }
4. 优化edit.js(可选)
移除冗余的属性存储逻辑,仅保留mediaId:
import { __ } from '@wordpress/i18n'; import { useBlockProps, RichText, MediaUpload, MediaUploadCheck, InspectorControls } from '@wordpress/block-editor'; import { PanelBody, Button, ResponsiveWrapper, __experimentalHStack as HStack } from '@wordpress/components'; import { Fragment } from '@wordpress/element' import './editor.scss'; export default function Edit({ attributes, setAttributes }) { const blockProps = useBlockProps(); const removeMedia = () => { setAttributes({ mediaId: 0 }); } return ( <Fragment> <InspectorControls> <PanelBody title={__('图片/成就', 'dt-panphagia')} initialOpen={true}> <div className="editor-post-featured-image"> <div className='editor-post-featured-image__container'> <MediaUploadCheck> <MediaUpload onSelect={(media) => { setAttributes({ mediaId: media.id }); }} type="image" value={attributes.mediaId} render={({ open }) => ( <Button className={attributes.mediaId === 0 ? 'editor-post-featured-image__toggle' : 'editor-post-featured-image__preview'} onClick={open} > {attributes.mediaId === 0 && __('选择图片', 'dt-panphagia')} {attributes.mediaId !== 0 && ( <ResponsiveWrapper naturalWidth={media.width} naturalHeight={media.height}> <img src={media.url} alt={media.alt || ''} /> </ResponsiveWrapper> )} </Button> )} /> </MediaUploadCheck> {attributes.mediaId !== 0 && ( <HStack className='editor-post-featured-image__actions'> <Button className='editor-post-featured-image__action' onClick={removeMedia}>{__('移除', 'dt-panphagia')}</Button> <MediaUploadCheck> <MediaUpload title={__('替换图片', 'dt-panphagia')} value={attributes.mediaId} onSelect={(media) => { setAttributes({ mediaId: media.id }); }} type="image" render={({ open }) => ( <Button className='editor-post-featured-image__action' onClick={open}>{__('替换', 'dt-panphagia')}</Button> )} /> </MediaUploadCheck> </HStack> )} </div> </div> </PanelBody> </InspectorControls> <div {...blockProps} className='achievement'> <div className='achievement-wrap'> <div className='achievement-image'> {attributes.mediaId !== 0 && ( <img className="eb-feature-list-img" src={media.url} width="54" alt={media.alt || ''} /> )} </div> <div className='achievement-content'> <RichText tagName="h3" value={attributes.heading} allowedFormats={['core/bold', 'core/italic']} onChange={(heading) => setAttributes({ heading })} placeholder="输入标题..." /> <RichText tagName="p" value={attributes.content} allowedFormats={['core/bold', 'core/italic']} onChange={(content) => setAttributes({ content })} placeholder="输入内容..." /> </div> </div> </div> </Fragment> ); }
原理说明
WordPress的wp_get_attachment_image_srcset()函数会根据图片ID自动生成适配不同屏幕分辨率的图片链接集合,静态保存的URL无法触发这个逻辑,因此必须将区块改为动态渲染模式,通过PHP调用内置函数生成完整的响应式图片属性。
内容的提问来源于stack exchange,提问作者Giovanna Penna Eirada
相关产品推荐
相关产品推荐

