Skip to content

Instantly share code, notes, and snippets.

@jasperf
Last active August 26, 2024 11:42
Show Gist options
  • Save jasperf/53aff6872549caf992010f5f7011b868 to your computer and use it in GitHub Desktop.
Save jasperf/53aff6872549caf992010f5f7011b868 to your computer and use it in GitHub Desktop.
Bud style WordPress block Filter (unfinished)
// Import necessary functions from @wordpress/hooks
import { addFilter } from '@wordpress/hooks';
import { createHigherOrderComponent } from '@wordpress/compose';
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody, ToggleControl, TextControl } from '@wordpress/components';
import { Fragment } from '@wordpress/element';
import React from 'react'; // Ensure React is imported for JSX and cloneElement
/**
* @see {@link https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#blocks-registerblocktype}
*/
export const hook = 'blocks.registerBlockType';
/**
* Filter handle
*/
export const name = 'sage/cover';
/**
* Filter callback
*
* @param {Object} settings Block settings.
* @param {string} name
* @returns modified settings
*/
export function callback(settings, name) {
if (name !== 'core/cover') return settings;
return {
...settings,
attributes: {
...settings.attributes,
loopVideo: {
type: 'boolean',
default: false,
},
autoplayVideo: {
type: 'boolean',
default: false,
},
showPlayButton: {
type: 'boolean',
default: true,
},
coverImage: {
type: 'string',
default: '',
},
},
};
}
/**
* Additional cover block modifications
*/
export const editHook = 'editor.BlockEdit';
export const editCallback = createHigherOrderComponent((BlockEdit) => {
return (props) => {
const { attributes, setAttributes, name } = props;
if (name !== 'core/cover') {
return <BlockEdit {...props} />;
}
const { loopVideo, autoplayVideo, showPlayButton, coverImage } = attributes;
return (
<Fragment>
<BlockEdit {...props} />
<InspectorControls>
<PanelBody title="Video Options" initialOpen={true}>
<ToggleControl
label="Loop Video"
checked={loopVideo}
onChange={(value) => setAttributes({ loopVideo: value })}
/>
<ToggleControl
label="Autoplay Video"
checked={autoplayVideo}
onChange={(value) => setAttributes({ autoplayVideo: value })}
/>
<ToggleControl
label="Show Play Button"
checked={showPlayButton}
onChange={(value) => setAttributes({ showPlayButton: value })}
/>
<TextControl
label="Cover Image URL"
value={coverImage}
onChange={(value) => setAttributes({ coverImage: value })}
help="This image will be used as the cover image for the video."
/>
</PanelBody>
</InspectorControls>
</Fragment>
);
};
}, 'withCoverControls');
/**
* Save element modification for the cover block
*/
export const saveHook = 'blocks.getSaveElement';
export const saveCallback = (element, blockType, attributes) => {
if (blockType.name !== 'core/cover') return element;
const { loopVideo, autoplayVideo, showPlayButton, coverImage } = attributes;
const children = Array.isArray(element.props.children) ? element.props.children.filter(Boolean) : [];
console.log('Filtered Children:', children);
const modifiedChildren = children.map((child) => {
console.log('Processing Child:', child);
if (child && child.type === 'video') {
return React.cloneElement(child, {
loop: loopVideo,
autoPlay: autoplayVideo,
poster: coverImage || child.props.poster,
});
}
return child;
});
console.log('Modified Children:', modifiedChildren);
return (
<div {...element.props}>
{modifiedChildren}
{showPlayButton && (
<div className="wp-block-cover__play-button-overlay" style={{ position: 'absolute', zIndex: 10 }}>
<button className="wp-block-cover__play-button" aria-label="Play Video" />
</div>
)}
</div>
);
};
// Register the filters
addFilter(hook, name, callback); // Adds custom attributes to the block
addFilter(editHook, name, editCallback); // Adds the inspector controls in the editor
addFilter(saveHook, name, saveCallback); // Modifies the save element
/**
* @path wp-content/themes/cafejp/resources/scripts/filters/cover.filter.js
* @see {@link https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#blocks-registerblocktype}
*/
import { createHigherOrderComponent } from '@wordpress/compose';
import { addFilter } from '@wordpress/hooks';
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody, ToggleControl, TextControl } from '@wordpress/components';
import { Fragment } from '@wordpress/element';
import React from 'react'; // Ensure React is imported for JSX and cloneElement
// Hook name for registering the block type modification
export const hook = 'blocks.registerBlockType';
// Unique name for the filter namespace
export const name = 'sage/cover';
/**
* Add custom attributes to the core/cover block.
*
* @param {Object} settings Block settings.
* @returns {Object} Modified block settings.
*/
export function addCoverAttributes(settings) {
if (settings.name !== 'core/cover') return settings;
return {
...settings,
attributes: {
...settings.attributes,
loopVideo: {
type: 'boolean',
default: false,
},
autoplayVideo: {
type: 'boolean',
default: false,
},
showPlayButton: {
type: 'boolean',
default: true,
},
coverImage: {
type: 'string',
default: '',
},
},
};
}
/**
* Extend the BlockEdit component to add custom controls in the Inspector.
* This component adds additional settings to the 'core/cover' block in the editor.
*/
export const withCoverControls = createHigherOrderComponent((BlockEdit) => {
return (props) => {
const { attributes, setAttributes, name } = props;
if (name !== 'core/cover') {
return <BlockEdit {...props} />;
}
const { loopVideo, autoplayVideo, showPlayButton, coverImage } = attributes;
return (
<Fragment>
<BlockEdit {...props} />
<InspectorControls>
<PanelBody title="Video Options" initialOpen={true}>
<ToggleControl
label="Loop Video"
checked={loopVideo}
onChange={(value) => setAttributes({ loopVideo: value })}
/>
<ToggleControl
label="Autoplay Video"
checked={autoplayVideo}
onChange={(value) => setAttributes({ autoplayVideo: value })}
/>
<ToggleControl
label="Show Play Button"
checked={showPlayButton}
onChange={(value) => setAttributes({ showPlayButton: value })}
/>
<TextControl
label="Cover Image URL"
value={coverImage}
onChange={(value) => setAttributes({ coverImage: value })}
help="This image will be used as the cover image for the video."
/>
</PanelBody>
</InspectorControls>
</Fragment>
);
};
}, 'withCoverControls');
/**
* Modify the save element for the cover block to add the new video attributes and play button.
*
* @param {Object} element The original save element.
* @param {Object} blockType The block type object.
* @param {Object} attributes The block attributes.
* @returns {Object} The modified save element.
*/
export function modifyCoverSaveElement(element, blockType, attributes) {
if (blockType.name !== 'core/cover') return element;
const { loopVideo, autoplayVideo, showPlayButton, coverImage } = attributes;
// Ensure the original structure is preserved
const children = Array.isArray(element.props.children) ? element.props.children : [element.props.children];
// Clone the video element with modifications
const modifiedChildren = children.map((child) => {
if (child && child.type === 'video') {
return React.cloneElement(child, {
loop: loopVideo,
autoPlay: autoplayVideo,
poster: coverImage || child.props.poster,
});
}
return child;
});
// Create a wrapper element, ensuring that the structure is consistent
return (
<div {...element.props}>
{modifiedChildren}
{showPlayButton && (
<div className="wp-block-cover__play-button-overlay" style={{ position: 'absolute', zIndex: 10 }}>
<button className="wp-block-cover__play-button" aria-label="Play Video" />
</div>
)}
</div>
);
}
// Add filters to the block editor with correct callback functions
addFilter(hook, name, addCoverAttributes); // Filter to add custom attributes to the block
addFilter('editor.BlockEdit', name, withCoverControls); // Filter to extend the BlockEdit component
addFilter('blocks.getSaveElement', name, modifyCoverSaveElement); // Filter to modify the save element
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment