To start off welcome to the future of editing with wordpress and the gutenberg block system. The goal of this article is to help you get from 0 to block in a few minutes. I’ll give you some principles some code and then the full code. Please also look at the comments for in-context info on what the purpose of that line of code is.

Starting off lets examine the new blocks are actually JSX templates and are written as functions. Inside the context of these functions you can use other functions and have your own context too so that’s exciting. We are going to talk about the two main functions needed to create a block you can see on the frontend: save and edit. These functions benefit from the structure of a block and inherits the attributes that you will use as your store to save data/text to create a frontend block on your site. We will be creating a simple block today with a header, subtitle and a body text area.

To get our block to even be recognized its important we declare it and enqueue it. You can declare this is your theme or even a plugin. This initialization code looks like:


function mheadley_basic_blocks_register() {

   wp_register_script( 'mheadley-basic-layout', get_stylesheet_directory_uri() .'/assets/js/plain-block.js',
    array( 'wp-blocks', 'wp-components', 'wp-element',  'wp-editor', 'wp-i18n' ),  true );

    register_block_type( 'mheadley-blocks/basic-block', array(
    'editor_script' => 'mheadley-basic-layout',
    ) );

 
}

add_action( 'init', 'mheadley_basic_blocks_register' );

So to start off we should create an attributes array to save all our info. Take a look at my declarations below.


      attributes: { // Necessary for saving block content.
        author: {
          type: 'string',
          source: 'meta',
          meta: 'author'
        },
        body:{
          type: 'html',
          source: 'children',
          selector: '.section-content-body-text',
        },
        title: {
          type: 'array',
          source: 'children',
          selector: 'h3'
        },
        subtitle: {
          type: 'array',
          source: 'children',
          selector: 'h5'
        },
      },

The edit function is the first and important one to talk about because this is where all your declared attributes are saved into a structure of your creation. The edit function also creates the structure and UI of the WordPress editor. You are counted on here to return the (main properties as elements if you want). This is the BlockControls, InspectorControls, and the default view. Please see the comments in the code, and that I reserved those places for code later when we make full use of the inspector controls etc. but for now we are going to stay as simple as possible. Please also notice we save the properties anytime it changes:


                   el( editor.RichText, {
                multiline: "p",
                tagName: 'div',  // The tag here is the element output and editable in the admin
                className: 'section-content-body-text', //selector to come back for
                value: attributes.body, // Any existing content, either from the database or an attribute default
                formattingControls: [ 'bold', 'italic', 'link' ], // Allow the content to be made bold or italic, but do not allow other formatting options
                onChange: function( content ) {
                 
                    props.setAttributes( { body: content } ); // Store updated content as a block attribute
                    //console.log(attributes.body);
                },
                placeholder: 'Write content here...', // Display this text before any content has been added by the user
              } )

Nothing will be saved if you do not set the attributes on change. You can also take this chance to allow different formatting controls for your block as well.

The save function is the one that you show on the frontend. It is the function responsible for saving your block HTML to the database. You will construct the HTML code of the frontend part of the block to be shown to users, and cached too. This is achieved using all the data that you have collected in the admin area via the attributes. Obviously the rich text from our body will be output as just HTML but it’s saved in the attributes as rich text. Most of the work actually happens in the edit, as the save is only concerned about placing the values in the final HTML you see on the frontend.

WHEW! That all sounds complicated but take a looks at a completed block with comments:


(function (blocks, editor, components, element){
  var el = element.createElement
  var RichText = editor.RichText 
  var BlockControls = editor.BlockControls
  var InspectorControls = editor.InspectorControls


  blocks.registerBlockType( 'mheadley-blocks/basic-block', {
      title: 'Custom Block',
      icon: 'smiley',
      category: 'common',
      className: "custom-section-container",
      example: {},
      attributes: { // Necessary for saving block content.
        author: {
          type: 'string',
          source: 'meta',
          meta: 'author'
        },
        body:{
          type: 'html',
          source: 'children',
          selector: '.section-content-body-text',
        },
        title: {
          type: 'array',
          source: 'children',
          selector: 'h3'
        },
        subtitle: {
          type: 'array',
          source: 'children',
          selector: 'h5'
        },
      },
      edit: function(props) {

        var attributes = props.attributes

        
          return [el(BlockControls, { key: 'controls' }, // Display controls when the block is clicked on.
           
          ),
          el(InspectorControls, { key: 'inspector' }, // Display the block options in the inspector panel.
           
          ),
          //this is the default view, note not targeting any element or key, plain div
          el('div', { className: props.className },

            el('div', { className: 'section-content-container'},

              el(RichText, {
                key: 'editable',
                tagName: 'h3',
                placeholder: 'Section Title',
                keepPlaceholderOnFocus: true,
                value: attributes.title,
                formattingControls: [],
                onChange: function (newTitle) {
                  props.setAttributes({ title: newTitle })
                }
              }),
              el(RichText, {
                tagName: 'h5',
                placeholder: 'Section Subtitle',
                keepPlaceholderOnFocus: true,
                value: attributes.subtitle,
                formattingControls: [ 'bold', 'italic' ],
                onChange: function (newSubtitle) {
                  props.setAttributes({ subtitle: newSubtitle })
                }
              }),
              el( editor.RichText, {
                multiline: "p",
                tagName: 'div',  // The tag here is the element output and editable in the admin
                className: 'section-content-body-text', //selector to come back for
                value: attributes.body, // Any existing content, either from the database or an attribute default
                formattingControls: [ 'bold', 'italic', 'link' ], // Allow the content to be made bold or italic, but do not allow other formatting options
                onChange: function( content ) {
                 
                    props.setAttributes( { body: content } ); // Store updated content as a block attribute
                    //console.log(attributes.body);
                },
                placeholder: 'Write content here...', // Display this text before any content has been added by the user
              } )
            )
          )
        ]
      },
      save: function(props) {

        var attributes = props.attributes

        return (
            el('div', {
                    className: props.className
                },
                el('div', {
                        className: 'section-content-container',
                    },
                    el(RichText.Content, {
                        tagName: 'h2',
                        value: attributes.title
                    }),
                    el(RichText.Content, {
                        tagName: 'h5',
                        value: attributes.subtitle
                    }),
                    el( RichText.Content, {
                      tagName: 'div',
                      multiline: "p",
                      className: 'section-content-body-text',
                      value: attributes.body 
                    } )
                )
            )
        );
      },
  } );
}(
  window.wp.blocks,
  window.wp.blockEditor,
  window.wp.components,
  window.wp.element
) );

So if you have followed this far, you have a block that can save: title, subtitle, body text and show it on the frontend. This is the most basic block and we will see more complex operations and even a solution to replace ACF fields in my posts in this series of Gutenberg Blocks.

Leave a Reply

Your email address will not be published.