I am trying to enable video thumbnails for posts in my theme. I created a custom post thumbnail media uploader in an editor plugin as follows (This is necessary, because the default uploader can't display videos):
Enqueuing the script in PHP:
function ernst_enqueue_custom_post_meta_plugin() {
wp_enqueue_script(
'ernst_custom-post-meta-plugin',
get_stylesheet_directory_uri() . '/assets/js/editor/custom-post-meta-plugin.js',
array( 'wp-plugins', 'wp-element', 'wp-edit-post', 'wp-components', 'wp-block-editor', 'wp-data', 'wp-core-data', 'wp-i18n' ),
time(),
false
);
}
add_action( 'enqueue_block_editor_assets', 'ernst_enqueue_custom_post_meta_plugin' );
Adding plugin and media uploader in JS:
( function( plugins, element, editPost, components, blockEditor, data, coreData, i18n ) {
// Get required dependencies
const { registerPlugin } = plugins;
const { PluginDocumentSettingPanel } = editPost;
const { Fragment } = element;
const { Button, DropZone, ResponsiveWrapper } = components;
const { MediaUploadCheck, MediaUpload } = blockEditor;
const { useSelect } = data;
const { useEntityProp } = coreData;
const el = element.createElement;
const { __ } = i18n;
// Register custom post meta plugin
registerPlugin( 'ernst-custom-post-meta-plugin', {
render: () => {
// Get current post type
const postType = useSelect( ( select ) => {
return( select( 'core/editor' ).getCurrentPostType() );
}, [] );
// Get Featured media
const [ featuredMedia, setFeaturedMedia ] = useEntityProp( 'postType', postType, 'featured_media' );
// Get meta information for featured media
const featuredMediaMeta = useSelect( ( select ) => {
return( featuredMedia ? select( 'core' ).getMedia( featuredMedia ) : undefined );
} );
// Prevent component render if featured media meta is not resolved yet:
if( featuredMedia && typeof( featuredMediaMeta ) === 'undefined' ) {
return;
}
// Check if featured media is video file
const featuredMediaIsVideo = featuredMedia && featuredMediaMeta.mime_type.includes( 'video' );
// Check for specific size in featured media meta
const featuredMediaHasSize = ( size ) => ( featuredMedia && !featuredMediaIsVideo && 'sizes' in featuredMediaMeta.media_details && size in featuredMediaMeta.media_details.sizes );
console.log( featuredMediaMeta );
// Render components
return(
el( PluginDocumentSettingPanel, {
title: __( 'Featured media', 'ernst' ),
initialOpen: false
}, el( 'div', {
className: 'editor-post-featured-image'
}, el( Fragment, {}, featuredMedia != 0 && el( 'div', {
id: 'editor-post-featured-image-' + featuredMediaMeta.id + '-describedby',
className: 'hidden'
}, featuredMediaMeta.alt_text === '' ? __( 'The current media has no alternative text. The file name is:', 'ernst' ) + ' ' + featuredMediaMeta.media_details.file.split( '/' ).reverse()[0] : __( 'Current media:', 'ernst' ) + ' ' + featuredMediaMeta.alt_text ), el( 'div', {
className: 'editor-post-featured-image__container'
}, el( Fragment, {}, el( MediaUploadCheck, {}, el( MediaUpload, {
title: __( 'Featured media', 'ernst' ),
allowedTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'video/mp4'],
render: ( { open } ) => el( Button, {
className: 'editor-post-featured-image__' + ( featuredMedia ? 'preview' : 'toggle' ),
label: featuredMedia ? 'Edit or update featured media' : null,
'aria-describedby': featuredMedia ? 'editor-post-featured-image-' + featuredMediaMeta.id + '-describedby' : null,
onClick: open
}, featuredMedia ? el( ResponsiveWrapper, {
isInline: true,
naturalWidth: featuredMediaMeta.media_details.width,
naturalHeight: featuredMediaMeta.media_details.height
}, featuredMediaIsVideo ? el( 'video', {}, el( 'source', {
src: featuredMediaMeta.source_url
} ) ) : el( 'img', {
src: featuredMediaHasSize( 'large' ) ? featuredMediaMeta.media_details.sizes.large.source_url : featuredMediaMeta.source_url
} ) ) : __( 'Set featured media', 'ernst' ) ),
onSelect: ( newFeaturedMedia ) => setFeaturedMedia( newFeaturedMedia.id )
} ) ), el( DropZone, {} ) ) ), featuredMedia != 0 && el( MediaUploadCheck, {}, el( MediaUpload, {
title: __( 'Featured media', 'ernst' ),
allowedTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'video/mp4'],
render: ( { open } ) => el( Button, {
variant: 'secondary',
onClick: open
}, __( 'Replace Media', 'ernst' ) ),
onSelect: ( newFeaturedMedia ) => setFeaturedMedia( newFeaturedMedia.id )
} ) ), el( Button, {
variant: 'link',
isDestructive: true,
onClick: () => setFeaturedMedia( 0 )
}, __( 'Remove featured media', 'ernst' ) ) ) ) )
);
}
} );
} )(
window.wp.plugins,
window.wp.element,
window.wp.editPost,
window.wp.components,
window.wp.blockEditor,
window.wp.data,
window.wp.coreData,
window.wp.i18n
);
This works great so far, but every time i save the post, the thumbnail gets deleted (if it's a video). Is it possible to change that sanitization behavior? I'd like to hook into post_thumbnail_html
and adjust the returned html if a post thumbnail is a video. This way I'd be able to keep all the functionality of the_post_thumbnail
and could just continue working on my theme.
The current workaround is to register a new post meta for my featured media and display this instead of the default thumbnail which isn't that elegant in my opinion, especially, because it creates a whole lot of additional metadata entries in the database.
Thanks for your help!