Le Monde cover sheet with multiple columns

Testing .. 1 . 2 .. erm .. 3 .. Gutenberg Blocks

To Gutenberg blocks and beyond! Well, that was an interesting 48 hours! I was sitting here writing something for someone else (words, lots and lots of words) and while I was looking at it, I thought it would be nice to have more than one column of text to read, like a newspaper or magazine; flowing columns. Of course, a simple enough ask if you’re creating your own HTML/CSS, the ‘column-count’ and ‘column-gap’ styling options work a treat. However, when you’re writing in WordPress paragraphs, there are no such thing.

It seems since the update to 6.3 and the update to the 2023 theme, this is now broken. Please be aware of that, I haven’t had a chance to look at why. If you wanted to have a look and let me know that would save me the effort! Thanks.

Dave

I could have, of course just created a class with my requirements in it, then apply it to every paragraph I create, that would mean that I would be restricted to multiples of multiples, rather than a group of multiples. i.e.. I wanted a block that was columns, but inside those columns I could take advantage of the rest of the already tried and tested editing environment.

Just like this example, a simple little pull-out with multiple columns of flowing text, the ability to add any other block objects inside it and apply all of the containing styles there in.

This is something to give a shit about

Extensa ubi lor emittet sui incipio mallent hos sentire. Et at cogor vapor vocem quare. Quinque ex vestiri de ii pretium. Alteram acquiri in priorem et. Mentemque calescere nul mem subjectum dei. Aliquam ab validas totaque infusus necesse mo ut. Expertus realiter ita uti indiciis occurret age via.

Aliud curam seu venti nihil sed istud volui eae qua. Autho ha falsi fidam tangi ut an tactu. Revera per eandem vox coelum videbo nam virtus. Item olim ei se duas ut. Ut mo ut peccato student adorare et diversa. Praecipuis ad conjunctam me percipitur agnoscerem at perfectius respondere. Horum meo porro uno debeo. Fallacem sentiens ha expertus delapsus dubitare ii. Ex ii efficiente et to perspicuae voluptatem arbitrabar.

Minus patet ac spero at ne serie vi aliud prona. Jam creando dicendo calebat ima quosdam deo attendo sui. Pictores hoc venturum dat sim affectus lus rerumque. Praecipuis conjunctam expectabam ad effecerunt quaerendum si. Praeterea praeterea industria referenda ad ha gi ad abducerem. Conjectus mei continere qua lor inhaereat dem. Usu vix uno retinet saeculi quaenam poterit. De meis ecce et rari alio an tale ideo ac. Ha generali ab ea revocare infinite. Poterit si tacitus ad alteram to praeter at ipsamet erroris.

Minus patet ac spero at ne serie vi aliud prona. Jam creando dicendo calebat ima quosdam deo attendo sui. Pictores hoc venturum dat sim affectus lus rerumque. Praecipuis conjunctam expectabam ad effecerunt quaerendum si. Praeterea praeterea industria referenda ad ha gi ad abducerem. Conjectus mei continere qua lor inhaereat dem. Usu vix uno retinet saeculi quaenam poterit. De meis ecce et rari alio an tale ideo ac. Ha generali ab ea revocare infinite. Poterit si tacitus ad alteram to praeter at ipsamet erroris.

I had been meaning to look at Gutenberg in more detail for ages, but you know how it is, shit happens, work and life get in the way, everything moves on at a pace and all of those little things you wanted to have a look at end up on a never ending to-do list, where the inclination to knock off even one of those things starts to feel “pointless“. Yet here I was, faced with the fact that the ‘columns’ option in the Gutenberg Editor, was not natively what you would call ‘columns’; they were columns, but discreet columns that you had to edit individually. Definitely not what was required.

I could have looked for some third party solution and there are a multitude of third-party plugins out there that create blocks, blocks from templates and more besides. A solution like that is way to much like overkill for my liking and brings ZERO understanding to the problem or solution. So off I set on the path of how to add a block template to the Gutenberg editor.


I feel like there should be some music playing here with the visuals of some sap walking off into the distance instead of me just saying to myself “Well, how hard can it be?”


Off I went, wide eyed and bushy tailed, in search of documentation and examples (I am a visual learner, always have been; it is what is is).

To my surprise, there actually wasn’t that much out there. Well, not much in the way of cohesive help with regards to plain JavaScript, loads of react stuff and using node.js to build blocks, but nothing useful for anyone not particularly interested in React per se.

Let me start by listing the things my solution needed to do.

Requirements:

  1. Create a space where I could have multiple columns, where text could flow automatically across the columns.
  2. Allow for nested blocks as available (paragraphs, headers, etc …)
  3. Allow the number of columns to be specified
  4. Allow for the changing of the background colour of the block rather than relying on the nested blocks to allow overall consistency.

So basically, there are a number of mechanisms available for creating a block, but they all require some fudging of the framework, be that in the theme or as a plugin. I didn’t want to create a child theme just for this, so opted for a plain and simple plugin. It you can’t create an empty plugin framework for WordPress then I suggest you stop reading this now and get to reading about doing that, Creating a WordPress Plugin is as good a place to start as any.

So I created a simple plugin called Multicol .. amazing right .. I thought it was a brilliant name obviously 🙂

/** * Plugin Name: MultiCol * Plugin URI: https://webdav.incredulous.org/wordpress-plugin-for-multicolumn-block * Description: This is a plugin which adds a block that supports multiple columns for text and images. * Version: 0.1 * Author: Dave Wise * * @package multicol */

Don’t panic, I will make all of it available to download at the end, it’s not pretty, but it does work. If you choose to download it and use it, let me know in the comments and be sure to credit me as the originator if you decide to pimp it out some more and again, let me know in the comments.

Anyway, so we have a basic plugin framework, installed and made active. We have to enqueue our JavaScript and styles properly, we wouldn’t want WordPress to get upset with our ‘hacking code together‘ ways.

  wp_register_script('multicol-script', plugins_url('/multicol.js', __FILE__), array('wp-blocks', 'wp-element'));  wp_register_style ('multicol-style',  plugins_url('/multicol.css', __FILE__), array( 'wp-edit-blocks' ), filemtime( plugin_dir_path(__FILE__) . 'multicol.css' ));

All that remains to do in PHP is register the new block we want to create, it’s quite straight forward amazingly, but to be fair all of the leg work happens in the JavaScript front end, that is after all where Gutenberg lives (I mentioned React right? Feel free to read all about that in your own time if you want to learn more, Intro to React is again, as good a place to start as any.)

register_block_type( 'multicol/multicol', array( 'editor_script' => 'multicol-script', 'editor_style' => 'multicol-style', 'style' => 'multicol-style') );

Now things started to get complicated, as I said, pretty much all of the documentation around the subject relates to a Node.js build environment, I am not interested in setting up a build environment just to create one block, so everything I do will be in native JavaScript.

So we have to also create/register the block in JavaScript, connecting into the WordPress libraries that are already loaded. We will want a few, we need wp.element.createElement, wp.blockEditor.InspectorControls, wp.blocks.registerBlockType, wp.components, wp.i18n and this one, this one was the hardest to work out when you don’t know what questions you are asking, wp.blockEditor.InnerBlocks.

var el                = wp.element.createElement,    registerBlockType = wp.blocks.registerBlockType,    InspectorControls = wp.blockEditor.InspectorControls,    components        = wp.components,    InnerBlocks       = wp.blockEditor.InnerBlocks,    i18n              = wp.i18n;

Of course, once I had finished I found there was a cleaner way of dealing with this, I will discuss it at the end because I couldn’t be bothered to change it over, what I had was working enough for proof of concept and to get this post written up so someone else can take over.

I used the variables to shorten what I was typing, I am still quintessentially lazy at the end of the day. We have registered the block in the WordPress PHP framework, we have told it that it exists, now we need to let the JavaScript side of things know that the new block exists and is getting ready to rock everyone’s world. We do that with registerBlockType which basically accepts a name and a load of JSON (object) variables, including some embedded functions.

registerBlockType ( <name>, { JSON } );
registerBlockType( 'multicol/multicol', {  title: "Multicolumn Block",              // Obvious one, the visible title of the new block  name: "multicol/multicol",               // The usable name of the new block   category: "text",                        // Which section the new block will be found in when you view all Blocks  icon: "columns",                         // The icon we want to use, we use a default dash-icon rather than using our own SVG  textdomain: "multicol",                  // In true WordPress style, even our JavaScript has a text domain we can use

Now we need to define our variables that we want to use in the block, I decided not to specify a column gap, I opted for letting the theme and overall styling work that out for me, I was only interested in the fact there are columns. So I needed a number of columns variable (which I called, columns .. shocking I know), a background colour variable and a couple of toggles so I could turn the inset padding and colour on or off. These are added via attributes, again, finding the information out for these is convoluted at best, damn nigh impossible at worst.

attributes: {  columns: {    // Number of columns to have    type: 'string',    default: '1'  },  background: { // Background colour of the column block    type: 'string',    default: 'inherit'  },  usecolours: { // Do we want to use the colours?    type: 'boolean',  },  usepadding: { // Do we want to use padding about the columns?    type: 'boolean',  },},

Now comes the two most important elements, what happens when we edit the block and what happens when we save the block. It is important to remember here that WordPress actually stores html in posts! So the save section needs to see the variables we have created being using on the blocks.

Let’s start with the Edit function, we have to do a couple of things here. First we need to setup the variables in the settings panel to the right, where it says block. These settings let us control how we want our columned block to look and perform. This will be the difference between it working and it looking hot whilst it is working.

I used the code of one of the supplied standard blocks in the end to work out how to use the InspectorControls as I couldn’t find any decent explanations elsewhere.

edit: ( props ) => {/*** Variables to use on the block and in the settings panel on the right*/var columns     = props.attributes.columns,    TextControl = components.TextControl,    CheckboxControl = components.CheckboxControl,    ColourControl = components.ColorPicker,    background = props.attributes.background,    usecolours = props.attributes.usecolours,    usepadding = props.attributes.usepadding,    pd = 'inherit',    bg = 'inherit';// Change the defaults is the settings are chosenif (usecolours == true) bg = background;if (usepadding == true) pd = '1.6rem';return [  el( InspectorControls, {},    el(components.PanelBody, { title: i18n.__('Block Settings', 'multicol'), className: 'block-content', initialOpen: true },      el( TextControl, { style: { maxWidth: '40%', marginLeft: '1.25rem', marginRight: 'auto' }, label: 'Columns', value: props.attributes.columns, onChange: ( value ) => { props.setAttributes( { columns: value } ); } } ),      el( 'h2', {className: 'components-panel__body-title', style: { margin: '-16px -16px 5px auto' } }, i18n.__('Use Background') ),      el(CheckboxControl, { label: i18n.__( 'Use Colours', 'multicol' ), checked: usecolours, onChange:  ( value ) => { props.setAttributes( { usecolours: value } ); } }),      el( 'h2', {className: 'components-panel__body-title', style: { margin: '-16px -16px 5px auto' } }, i18n.__('Background Colour') ),      el( ColourControl, { label: 'Background', color: props.attributes.background, onChange: ( value ) => { props.setAttributes( { background: value } ); } } ),      el( CheckboxControl, { label: i18n.__( 'Add Padding', 'multicol' ), checked: usepadding, onChange:  ( value ) => { props.setAttributes( { usepadding: value } ); } }),    )),  el( 'div', { className: props.className, style: { columnCount: columns, backgroundColor: bg, padding: pd } } , el( InnerBlocks )), ]; // Can't beat a bit of WYSIWYG editing ...},

The important part of the edit function is the return statement. We have to return two things, first of all we need to return the Settings panel, which is done with the InspectorControls element, and secondly we return a container which contains the default block, which is Paragraph. You can of course change this by allowing only certain block types and by using templates. But I had no need to do any of that, well to be quite honest, I didn’t want to do that, I wanted ALL block types to be available, so it is what it is.

The InspectorControls are quite straight forward, it is an array of nested elements that make up the panel and you have to remember, everything is an element, including plain old text. So you have to be pretty comprehensive and explicit. It takes some getting used to, realising it does anything for you is a bit alien to people these days. So we have some headers, along with a couple of checkboxes, a text input and a colour picker. All is a nice little array of elements that sit inside a bodypanel. It also styles the block in the editor to match what will be displayed to the viewer of the page so there can be no confusion at the point of editing.

wysiwyg-editing

So all that is now left is to save our blocks contents, shockingly we use the save function to do that. One thing I forgot to mention is the prop variable passed to the edit and save functions. This where our blocks variables live. This important variable also contains the various information about our plugin, including, but not limited to the class names being used. If you’re really interested dump the contents to the console to have a nosey. So it’s actually quite important to remember it. Now saving is slightly less complicated as we don’t need any inspector or block controls, we just need to save what we have created including the settings. All of you young’un’s will be pleased to know that WordPress then takes care of everything else for us.

save: ( props ) => {  var columns = props.attributes.columns,      background = props.attributes.background,      usepad = props.attributes.usepadding,      padding = '1.6rem',      usecolours = props.attributes.usecolours;  // Change the defaults if the settings are chosen  if (!usecolours) background = 'inherit';  if (!usepad) padding = 'inherit';  // Output the content inside the column framework  return el( 'div', {    className: props.className,    style: { columnCount: columns, backgroundColor: background, padding: padding},    }, el(InnerBlocks.Content) );},

And that’s that, we now have a shiny new block under the Text group called Multicol, which does exactly what it says on the tin. Feel free to download and use it, update it, change it … whatever … just credit me if you use any of it and post a comment about what you’re doing with it!

I almost forgot, yes, simplifying the declaring of loads of wp.xxxx.xxxx variables. I don’t find it particularly cleaner or otherwise, but we all have our preferences I guess and it would have been remiss of me not to mention it.

( function ( blocks, i18n, el, blockEditor ) {  // Well you get the idea, it could be viewed as being  // a neater way of declaring all of the variables you  // are going to need for your shiny new block!} )(	window.wp.blocks,	window.wp.i18n,	window.wp.element,	window.wp.blockEditor);

Happy Gutenberg’ing .. I hope you find this useful on your WordPress development journey.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.