Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?

Custom Tweet Block for Gutenberg

This is a basic custom Tweet Block for Gutenberg. Files explained below.

  • block.js — We register Custom Gutenberg block here.
  • editor.css _ Block CSS for the editor.
  • style.css — Block CSS for the front end.
  • index.php — Enqueue block's assets for the editor and the front end.
/**
* BLOCK: Tweet
*
* Registering a basic editable block with Gutenberg.
* Introduces the concept of attributes and extracting
* them while processing a completly different output
* for the frontend.
*
* Styles:
* editor.css — Editor styles for the block.
* style.css — Frontend styles for the block.
*/
( function() {
var __ = wp.i18n.__; // The __() for internationalization.
var el = wp.element.createElement; // The wp.element.createElement() function to create elements.
var Editable = wp.blocks.Editable; // Editable component of React.
var children = wp.blocks.query.children; // The childern() function to extract child nodes from a paragraph of rich text.
var registerBlockType = wp.blocks.registerBlockType; // The registerBlockType() to register blocks.
/**
* Register The Block.
*
* Registers a new block provided a unique name and an object defining its
* behavior. Once registered, the block is made available as an option to any
* editor interface where blocks are implemented.
*
* @param {string} name Block name.
* @param {Object} settings Block settings.
* @return {?WPBlock} The block, if it has been successfully
* registered; otherwise `undefined`.
*/
registerBlockType( 'gb/04-tweet', { // Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
title: __( 'Tweet', 'GB' ), // Block title.
icon: 'twitter', // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
category: 'common', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed.
/**
* Attribute matchers!
*
* Attribute matchers are used to define the strategy by which block
* attribute values are extracted from saved post content. They provide
* a mechanism to map from the saved markup to a JavaScript representation
* of a block.
*
* children() — Use children to extract child nodes of the matched element,
* returned as an array of virtual elements. This is most commonly used in
* combination with the Editable component.
*
* Example: Extract child nodes from a paragraph of rich text.
*/
attributes: {
content: children( 'a' ), // Content: Extract child nodes from an anchor tag's content.
},
// The "edit" property must be a valid function.
edit: function( props ) {
var content = props.attributes.content; // Content in our block.
var focus = props.focus; // Focus — should be truthy.
/**
* Update content on change.
*/
function onChangeContent( newContent ) {
// Console Log.
console.log( 'newContent: ', newContent );
console.info( 'NEW: ', {__html: newContent} );
props.setAttributes( { content: newContent } );
}
// The editable content.
return el(
Editable, // Editable React component.
{ // Creates <div class="wp-block-gb-04-tweet"><a></a></div>
tagName: 'a', // <a></a>.
className: props.className, // The class="wp-editor-gb-04-tweet".
onChange: onChangeContent, // Run the onChangeContent() function onChange of content.
value: content, // Content in our block. i.e. props.attributes.content;
focus: null, // Focus — should be truthy. i.e. props.focus; I have set it null to disable the toolbar. Hacky. There must be a better way.
onFocus: props.setFocus,
// placeholder: __( 'Write a tweet…' ), // Commented coz of a CSS issue probably will be fixed in future Gutenberg versions.
}
);
},
// The "save" property must be specified and must be a valid function.
save: function( props ) {
/**
* Remove HTML tags from tweet's content.
*
* @param {mixed} html.
* @return {text}
* @since 1.0.0
*/
var tweetContent = props.attributes.content; // Content in our block.
// Console Log.
console.log( 'tweetContent: ', tweetContent );
var tweetURI = 'https://twitter.com/home?status=' + encodeURIComponent( tweetContent ); // Encodes a Uniform Resource Identifier (URI) component — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent.
var attrs = {
href: tweetURI,
className: props.className, // Class would be → wp-block-gb-04-tweet
target: '_blank',
};
// The frontend content.
return el( 'a', attrs, tweetContent ); // Returns <a href="https://twitter.com/home?status={tweetContent}" class="wp-block-gb-04-tweet" target="_blank">{tweetContent}</a>.
},
} );
} )();
/**
* ----------------------------------------------------------------------------
* #.# Editor CSS
*
* BLOCK: 03-block-editable block CSS for the editor.
* ----------------------------------------------------------------------------
*/
.wp-block-gb-04-tweet {
color: #ffffff !important;
background: #1da1f2;
border: none !important;
padding: 2rem;
}
.wp-block-gb-04-tweet a {
color: #ffffff !important;
border: none !important;
box-shadow: none;
}
<?php
/**
* BLOCK: Tweet
*
* Gutenberg Custom Block assets.
*
* @since 1.0.0
* @package GB
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Hook: Editor assets.
add_action( 'enqueue_block_editor_assets', 'gb_block_04_tweet_editor_assets' );
/**
* Enqueue the block's assets for the editor.
*
* `wp-blocks`: includes block type registration and related functions.
* `wp-element`: includes the WordPress Element abstraction for describing the structure of your blocks.
* `wp-i18n`: To internationalize the block's. text.
*
* @since 1.0.0
*/
function gb_block_04_tweet_editor_assets() {
// Scripts.
wp_enqueue_script(
'gb-block-04-tweet', // Handle.
plugins_url( 'block.js', __FILE__ ), // Block.js: We register the block here.
array( 'wp-blocks', 'wp-i18n', 'wp-element' ), // Dependencies, defined above.
filemtime( plugin_dir_path( __FILE__ ) . 'block.js' ) // filemtime — Gets file modification time.
);
// Styles.
wp_enqueue_style(
'gb-block-04-tweet-editor', // Handle.
plugins_url( 'editor.css', __FILE__ ), // Block editor CSS.
array( 'wp-edit-blocks' ), // Dependency to include the CSS after it — CSS for wp-edit-blocks.
filemtime( plugin_dir_path( __FILE__ ) . 'editor.css' ) // filemtime — Gets file modification time.
);
} // End fucntion gb_block_04_tweet_editor_assets().
// Only frontend.
if ( ! is_admin() ) {
// Hook: Frontend assets.
add_action( 'enqueue_block_assets', 'gb_block_04_tweet_block_assets' );
/**
* Enqueue the block's assets for the frontend.
*
* `wp-blocks`: includes basic styles built out of Gutenberg through `npm build`.
*
* @since 1.0.0
*/
function gb_block_04_tweet_block_assets() {
// Styles.
wp_enqueue_style(
'gb-block-04-tweet-frontend', // Handle.
plugins_url( 'style.css', __FILE__ ), // Block frontend CSS.
array( 'wp-blocks' ), // Dependency to include the CSS after it.
filemtime( plugin_dir_path( __FILE__ ) . 'editor.css' ) // filemtime — Gets file modification time.
);
} // End fucntion gb_block_04_tweet_block_assets().
} // End is_admin().
/**
* ----------------------------------------------------------------------------
* #.# Frontend CSS
*
* BLOCK: 03-block-editable block CSS for the frontend.
* ----------------------------------------------------------------------------
*/
.wp-block-gb-04-tweet {
display: table;
color: #ffffff !important;
background: #1da1f2;
background-image: url(data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTkuMS4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDM0MS4xMTcgMzQxLjExNyIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzQxLjExNyAzNDEuMTE3OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCI+CjxnPgoJPHBhdGggZD0iTTExNS4zOTQsMzA0LjQwN2MtMzMuMDg1LDAtNjUuODYyLTkuMTU4LTk0Ljc3Ny0yNi40NzlMMCwyNjUuNTgybDI0LjAyNCwwLjQwNWMwLjc3OCwwLjAzOSwyLjAzMSwwLjEwMyw0LjAwNCwwLjEwMyAgIGM5LjE0NSwwLDM4LjI3OC0xLjQ3Miw2OC4xNS0xOC4zMjljLTIyLjQ1NS02LjY3Ny00MS4wMS0yNC4wMzYtNDguNjUxLTQ2Ljc2MmwtMy43ODUtMTEuMjUzbDEwLjMwOSwyLjY4ICAgYy0xNi41MjMtMTIuNjkzLTI3LjMzMy0zMi4yMDUtMjguNTE2LTUzLjk1M2wtMC41NjYtMTAuNDExbDkuNTU3LDQuMTcxYzEuNzQyLDAuNzY1LDMuNTE1LDEuNDQsNS4zMTUsMi4wMjQgICBjLTEzLjU3My0xOC45OTgtMjEuNzg3LTQ4LjM1NS00LjY1OS03OS41MzhsNC43MTctOC41OTNsNS45OTYsNy43NTdjMjguNzI4LDM3LjE0MSw3MS4zMjUsNTkuNzg5LDExNy43NzgsNjIuODk5ICAgYy0wLjI4My0yLjg4Ni0wLjQ4Mi01LjU0LTAuNDgyLTYuMzY5YzAtMzQuNDc0LDI2LjIzNC03MC4xMyw3MC4xMy03MC4xM2MxOC40MjYsMCwzNi4xNjQsNy4zMiw0OS4yMywyMC4yMDYgICBjMTcuNTEzLTQuMTEzLDM0LjI0OS0xNC4zMjUsMzQuNDI5LTE0LjQzNWwxNS4xOC05LjM0NWwtNS43MzMsMTYuODgzYy0yLjc1MSw4LjA4NS02Ljk0MSwxNS41MzQtMTIuMzE0LDIyLjAzOCAgIGMyLjkzMS0wLjk1OCw1LjgxLTIuMDU3LDguNzczLTMuMzQ4bDE4LjIzMy04LjkwOGwtNy42NjEsMTYuNDUzYy02LjMyNCwxMy41OTMtMTYuODcsMjQuODA4LTI5Ljk2OCwzMS45OCAgIGMyLjg3OSw0NC45OTQtMTUuNjI0LDk1LjE5NC00OC45MDgsMTMyLjA1OWMtMjQuNzA1LDI3LjM3Mi02OC43MDMsNjAuMDg0LTEzOC4wMTYsNjAuNTI4TDExNS4zOTQsMzA0LjQwN3ogTTQ3Ljg0MSwyNzcuNDcyICAgYzIxLjQyNyw5LjI0OCw0NC40MDksMTQuMDc1LDY3LjU0NiwxNC4wNzVsMS4wOTktMC4wMDZjNjQuNjI4LTAuNDExLDEwNS41ODYtMzAuODM2LDEyOC41NTYtNTYuMjg2ICAgYzMyLjAzMS0zNS40ODMsNDkuMzk3LTgzLjk5OSw0NS4zMDktMTI2LjYyMWwtMC40MzEtNC41MjRsNC4xMTMtMS45MTVjNi41MjMtMy4wNCwxMi4zNjUtNy4yNjIsMTcuMjY5LTEyLjM5NyAgIGMtNS40ODgsMS4zODgtMTEuMzQzLDIuNDIzLTE4LjA5MiwzLjIzOWwtNC45MjksMC41OThsLTMuODQzLTkuNzQzbDQuNDczLTMuNDQ1YzYuMjY2LTMuNjcsMTEuNzI5LTguNDUxLDE2LjE0NC0xNC4wNDkgICBjLTYuOTg2LDIuOTc2LTE1LjIzMiw1Ljg4Ny0yMy40NzcsNy40MjNsLTMuNTIyLDAuNjU2bC0yLjQxLTIuNjQ4Yy0xMC44MzYtMTEuODktMjYuMjU0LTE4LjcwMi00Mi4zMjEtMTguNzAyICAgYy0zNS44NDksMC01Ny4yNzYsMjkuMTItNTcuMjc2LDU3LjI3NmMwLDEuNzAzLDAuODQ4LDkuNDU0LDEuMTUsMTEuNDQ2bDIuOTE4LDguMjk3bC05LjI4LTAuMTk5ICAgYy00OS43NDQtMS4wNzMtOTYuMDIzLTIyLjg3My0xMjguNTExLTYwLjE4MWMtMTIuODU0LDMzLjc1NCw4LjcyOCw2MC43MjEsMTkuMDM2LDY4Ljc5OWwxNS4wNzEsMTEuODE5bC0xOS4xNDYtMC4zMzQgICBjLTUuOTk2LTAuMTAzLTExLjg2NC0wLjkxOS0xNy41NTItMi40MzZjNS4wNTgsMjIuNTU4LDIyLjg4Niw0MC42ODIsNDYuMDQ4LDQ1LjY1NmwyNS4zNTQsNS40NWwtMjQuOTYyLDcuMDI1ICAgYy00LjM1MSwxLjIyMS05LjI4NywxLjgzOC0xNC42NzIsMS44MzhjLTIuNTE5LDAtNC45MjktMC4xMzUtNy4xNTMtMC4zNDFjMTAuMDM5LDE3LjY3NCwyOC43MzQsMjkuNTUxLDQ5LjQxNiwzMC41NmwxOC4wNzIsMC44ODcgICBMMTE3LjI2NCwyNDkuNEM5Mi4yODMsMjY3Ljc3NCw2Ni4zNywyNzQuODUsNDcuODQxLDI3Ny40NzJ6IiBmaWxsPSIjRkZGRkZGIi8+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPGc+CjwvZz4KPC9zdmc+Cg==);
background-repeat: no-repeat;
background-position: 3% 50%;
border: none !important;
padding: 1.5rem 1.5rem 1.5rem 5rem;
text-align: center;
margin: 0 auto;
font-style: oblique;
border-radius: 0.5rem;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment