Display Posts Shortcode – Full Content

The Display Posts Shortcode plugin lets you display a list of posts based on any criteria. By default it displays titles only. The example below makes it display the post’s title and full content.

  • Block Styles in Gutenberg

    Every block type in the WordPress editor can have multiple style options. Some block types already have style options like buttons and quotes.

    I’ll show you how to add and remove style options from blocks.


    Block styles let writers easily change the look of a block without any code. When editing a block with available styles, click the “Transform” icon in the top left to change styles.

    Here are the style options available in my theme for the quote block:

    This is a standard blockquote.

    Citation

    This is a large quote. It has a CSS class of “is-style-large”

    Citation

    They are technically just CSS classes added to the block. By using the Block Styles UI for previewing and selecting different styles, your clients won’t need to remember specific class names.

    You can add block styles to any block type in Gutenberg: core blocks and custom blocks from plugins. See my note at the bottom on finding the block name so you can attach your custom styles to it.

    Adding a script to the editor

    We’ll need to create a JavaScript file in your theme or plugin and load it in the block editor. You can use the enqueue_block_editor_assets hook to load assets into the block editor. It works the same as using wp_enqueue_scripts to load assets into the frontend of the site.

    Create an empty editor.js file in the directory /your-theme/assets/js/. Then add the following to your theme’s functions.php file:

    /**
     * Gutenberg scripts and styles
     * @see https://www.billerickson.net/block-styles-in-gutenberg/
     */
    function be_gutenberg_scripts() {
    
    	wp_enqueue_script(
    		'be-editor', 
    		get_stylesheet_directory_uri() . '/assets/js/editor.js', 
    		array( 'wp-blocks', 'wp-dom' ), 
    		filemtime( get_stylesheet_directory() . '/assets/js/editor.js' ),
    		true
    	);
    }
    add_action( 'enqueue_block_editor_assets', 'be_gutenberg_scripts' );

    Adding Block Styles

    I’m working on a website with two styles of headings.

    In my editor.js file I’m adding “Default” and “Alternate” style options:

    wp.domReady( () => {
    
    	wp.blocks.registerBlockStyle( 'core/heading', {
    		name: 'default',
    		label: 'Default',
    		isDefault: true,
    	} );
    
    	wp.blocks.registerBlockStyle( 'core/heading', {
    		name: 'alt',
    		label: 'Alternate',
    	} );
    
    } );
    

    When a style is selected, a class of .is-style-{name} is applied to the block. So in my stylesheet, the h2 { } has my default styling and h2.is-style-alt { } has my alternate style.

    Why register a default style?

    The block style selector lets you select which style you want applied, but does not let you unselect one after you’ve picked a style. If you register just one style and then select it for a block, there’s no way to unselect that block style option and return back to the default styling.

    I register an extra style option called “Default” or “Regular”, but don’t add any specific styles for that style option. When a user selects the “Default” style for an h2, it uses the h2 {} styling rather than a more specific h2.is-style-default{ }.

    If you add isDefault: true then this style will be marked active on blocks that don’t already have a style specified.

    Removing block styles

    When styling buttons in the Gutenberg block editor, I usually don’t want the style options that come standard with WordPress: rounded, square, and outline.

    You can use unregisterBlockStyle to remove existing block styles from a block. Add the following to the editor.js file described above:

    wp.domReady( () => {
    	wp.blocks.unregisterBlockStyle( 'core/button', 'default' );
    	wp.blocks.unregisterBlockStyle( 'core/button', 'outline' );
    	wp.blocks.unregisterBlockStyle( 'core/button', 'squared' );
    } );

    I’ll often remove the defaults and then load my own button style options:

    wp.domReady( () => {
    	wp.blocks.unregisterBlockStyle( 'core/button', 'default' );
    	wp.blocks.unregisterBlockStyle( 'core/button', 'outline' );
    	wp.blocks.unregisterBlockStyle( 'core/button', 'squared' );
    
    	wp.blocks.registerBlockStyle( 'core/button', {
    		name: 'default',
    		label: 'Default',
    		isDefault: true,
    	});
    
    	wp.blocks.registerBlockStyle( 'core/button', {
    		name: 'full-width',
    		label: 'Full Width',
    	} );
    
    } );
    

    List of block names

    You need to know the full block name in order to attach or remove styles from it. Here’s a list of all the core blocks (excluding all the embed ones):

    • core/paragraph
    • core/image
    • core/heading
    • core/gallery
    • core/list
    • core/quote
    • core/audio
    • core/cover
    • core/file
    • core/video
    • core/preformatted
    • core/code
    • core/freeform
    • core/html
    • core/pullquote
    • core/table
    • core/verse
    • core/button
    • core/columns
    • core/media-text
    • core/more
    • core/nextpage
    • core/separator
    • core/spacer
    • core/shortcode
    • core/archives
    • core/categories
    • core/latest-comments
    • core/latest-posts

    Finding a block’s name

    A simple way to find the block name is to insert the block in a page and then print out an escaped version of post_content to see what’s stored.

    I’m using ea_pp() below (code here) but you could also use print_r().

    /**
     * Display Post Blocks 
     *
     */
    function ea_display_post_blocks() {
    	global $post;
    	ea_pp( esc_html( $post->post_content ) );
    }
    add_action( 'wp_footer', 'ea_display_post_blocks' );
  • Gutenberg Color Palette and Button Styling

    The Editor Color Palette allows content editors to style their blocks using the theme’s color scheme.

    When a custom color palette is registered in your theme, WordPress will use CSS classes for styling elements rather than hardcode the color in the content.

    There are two aspects to setting up your custom color palette:

    1. Register the color palette options in functions.php
    2. Add css for each color option in your stylesheet

    I’ll also show you how I style the button block to use the color palette.

    Registering your colors

    In your theme’s functions.php, add support for the custom color palette by specifying the following for each color option:

    • Name: visible to user
    • Slug: used in CSS class
    • Color: used for rendering elements in the Gutenberg block editor

    Here’s an example from my Genesis starter theme:

    add_theme_support( 'editor-color-palette', array(
    	array(
    		'name'  => __( 'Blue', 'ea_genesis_child' ),
    		'slug'  => 'blue',
    		'color'	=> '#59BACC',
    	),
    	array(
    		'name'  => __( 'Green', 'ea_genesis_child' ),
    		'slug'  => 'green',
    		'color' => '#58AD69',
    	),
    	array(
    		'name'  => __( 'Orange', 'ea_genesis_child' ),
    		'slug'  => 'orange',
    		'color' => '#FFBC49',
    	),
    	array(
    		'name'	=> __( 'Red', 'ea_genesis_child' ),
    		'slug'	=> 'red',
    		'color'	=> '#E2574C',
    	),
    ) );

    After adding that to your theme, you should see the following in the Color Settings panel:

    Naming your color options

    I’m using the actual color as the slug, which I think is the best approach for individual client sites. A few years from now we may build a new theme that looks totally different, but their color scheme for brand colors will remain unchanged.

    An alternative approach is to use generic terms for the colors like primary, secondary, and tertiary. I think this is the best approach for widely distributed themes, like premium themes by StudioPress. When a user changes themes, the actual colors will change to match that theme’s style guide, allowing a seamless transition between themes.

    Remove custom color picker

    WordPress includes a custom color picker after our theme colors. We can disable color picker and limit them to only our color options with this:

    // -- Disable Custom Colors
    add_theme_support( 'disable-custom-colors' );
    

    Your Color Settings panel should now match the screenshot at the top of this article.

    CSS for your color palette

    If you select the blue color as the Background Color for a block, WordPress adds .has-background and .has-blue-background-color to the block.

    If you select blue as the Text Color, WordPress sets the classes to .has-text-color and .has-blue-color.

    Your theme needs to provide styling for these color classes. Example:

    .has-blue-color {
    	color: #59BACC;
    }
    
    .has-blue-background-color {
    	background-color: #59BACC;
    }
    
    .has-green-color {
    	color: #58AD69;
    }
    
    ...

    Using SASS

    You can automate this with SASS by defining an array of colors and looping over it.

    // Gutenberg color options
    // -- see editor-color-palette in functions.php
    $colors: (
    	'blue' 		: #59BACC,
    	'green' 	: #58AD69,
    	'orange' 	: #FFBC49,
    	'red' 		: #E2574C,
    );
    
    @each $name, $color in $colors {
    
    	.has-#{$name}-color {
    		color: $color;
    	}
    
    	.has-#{$name}-background-color {
    		background-color: $color;
    	}
    }

    Button Styling

    Styling the button block can be difficult given all the styling options available to editors. Hopefully soon we’ll be able to reduce the color options for the button block.

    My goals with styling buttons are:

    1. Make the default button block match all other buttons throughout the site
    2. Provide appropriate hover styling based on button background color.
    3. Provide appropriate text color styling if editor hasn’t selected one, based on background color.
    4. Remove button styles that aren’t applicable.

    Here’s the default button styling in WordPress:

    I want all buttons to be square, and the default background to be blue (the first color in my $colors array). On hover, the background should get darker and no underline should appear on the text.

    /* Button block
    --------------------------------------------- */
    
    .wp-block-button__link {
    	border-radius: 0;
    
    	&:hover {
    		text-decoration: none;
    	}
    
    	&:not(.has-text-color) {
    		color: white;
    
    		&:hover {
    			color: white;
    		}
    	}
    
    	&:not(.has-background) {
    		$default: nth( nth( $colors, 1 ), 2 ); // first color in $colors array
    		background-color: $default;
    
    		&:hover,
    		&:focus {
    			background-color: darken( $default, 20% );
    		}
    	}
    
    	@each $name, $color in $colors {
    
    		&.has-#{$name}-color:hover,
    		&.has-#{$name}-color:focus {
    			color: $color;
    		}
    
    		&.has-#{$name}-background-color:hover,
    		&.has-#{$name}-background-color:focus {
    			background-color: darken( $color, 20% );
    		}
    	}
    
    }

    Here’s a summary of what’s happening since it can be a bit hard to read the SASS:

    • Button should be square, not rounded
    • On hover, don’t show an underline
    • If the button doesn’t have a text color selected, set the default and hover text color to white.
    • If the button doesn’t have a background color selected, use the first color listed in the $colors array shown above, and set the hover background to be 20% darker.
    • For each color in our color palette:
      • If the button has this text color, ensure the hover state also has this text color
      • If the button has this background color, set the hover state to 20% darker.

    This is just a starting point. You can tweak it as needed to match your style guide. For instance, if the blue button should have a green background color on hover, you could add:

    .wp-block-button__link:not(.has-background):hover,
    .wp-block-button__link.has-blue-background-color:hover {
    	background-color: $green;
    }

    Remove Button Block Styles

    The button block includes three “Block Styles” – Rounded, Outline, and Squared. You can switch between by clicking the “Change Block Type” button in the top left corner.

    On most of the sites we build, we don’t want different button styles like this. The style guide calls for buttons to be square or rounded – not a mix of both.

    You can unregister these block styles using JavaScript:

    wp.domReady( () => {
    wp.blocks.unregisterBlockStyle( 'core/button', 'default' );
    wp.blocks.unregisterBlockStyle( 'core/button', 'outline' );
    wp.blocks.unregisterBlockStyle( 'core/button', 'squared' );
    } );
    view raw editor.js hosted with ❤ by GitHub
    <?php
    /**
    * Gutenberg scripts and styles
    * @see https://www.billerickson.net/wordpress-color-palette-button-styling-gutenberg
    */
    function be_gutenberg_scripts() {
    wp_enqueue_script( 'be-editor', get_stylesheet_directory_uri() . '/assets/js/editor.js', array( 'wp-blocks', 'wp-dom' ), filemtime( get_stylesheet_directory() . '/assets/js/editor.js' ), true );
    }
    add_action( 'enqueue_block_editor_assets', 'be_gutenberg_scripts' );
    view raw functions.php hosted with ❤ by GitHub

    For more information see Block Styles in Gutenberg.

    Share your tips

    How have you been using the color palette in your theme? Any tips or tricks on styling different blocks? Please share them in the comments below.

  • Full and wide alignment in Gutenberg

    The new WordPress block editor includes two new alignment options.

    To take advantage of the new alignment options, your theme must first support them. Include add_theme_support( 'align-wide' ) in your functions.php file.

    Full Alignment

    The .alignfull option should span the full width of the screen. I typically do this using the following CSS:

    .alignfull {
    	margin: 32px calc(50% - 50vw);
    	max-width: 100vw;
    	width: 100vw;
    }

    The margin property can accept up to 4 values. In this case I provided 2 properties so the first ( 32px) is applied to the top and bottom, and the second (calc( 50% - 50vw)) is applied to the left and right.

    This tells the browser to calculate 50% of the its container’s width (ex: 900px) and subtract from it 50% of the viewport width (ex: 1600px). This results in a negative margin that pulls the element to the edges of the screen.

    Wide Alignment

    You have more flexibility with the .alignwide option. It should be wider than the main content area, but not as wide as the full alignment. There are two approaches I usually take:

    Percentage Width

    This is my default styling option built into my base themes. It copies the full alignment in approach, but instead of stretching the full gap between the browser edge and the content, it only does half.

    .alignwide {
    	margin: 32px calc(25% - 25vw);
    	max-width: 100vw;
    	width: 100vw;
    }

    Max width

    I set a maximum width if there are certain design constraints (like the Recommended Reading floating to the right) or you only want the image to reach a certain size.

    I’ll make .alignwide and .alignfull use the same CSS at first, but at a certain break point I’ll change .alignwide to a fixed max width and margins.

    For the negative left/right margin, I subtract the full page width from the content width and divide by two. Ex: ( 768px – 920px ) / 2

    .alignwide,
    .alignfull {
    	margin: 32px calc(50% - 50vw);
    	max-width: 100vw;
    	width: 100vw;
    }
    
    @media (max-width: 920px) {
    	.alignwide {
    		margin: 32px -76px;
    		max-width: 920px;
    		width: 920px;
    	}
    }

    You can also put the math directly in the CSS using calc()

    .alignwide,
    .alignfull {
    	margin: 32px calc(50% - 50vw);
    	max-width: 100vw;
    	width: 100vw;
    }
    
    @media (max-width: 920px) {
    	.alignwide {
    		margin: 32px calc( ( 767px - 920px ) / 2 );
    		max-width: 920px;
    		width: 920px;
    	}
    }

    With SASS

    I use SASS variables to store common units like the margins, content width, and breakpoints (see here). To implement the above using my SASS variables:

    &.alignwide,
    &.alignfull {
    	margin: calc( 2 * #{$block-margin} ) calc(50% - 50vw);
    	max-width: 100vw;
    	width: 100vw;
    }
    
    @include media(">=medium") {
    	&.alignwide {
    		margin: calc( 2 * #{$block-margin} ) calc( ( #{$content-width} - #{map-get( $breakpoints, 'medium' ) } ) / 2 );
    		max-width: map-get( $breakpoints, 'medium' );
    		width: map-get( $breakpoints, 'medium' );
    	}
    }
    

    If we decide we want the wide images a bit wider, we simply edit the medium breakpoint and all the math automatically updates. Likewise, if we change the block margin, the top/bottom margin also updates.

    Consider Sidebars

    If your site uses sidebars, make sure you test your styles on a page with a sidebar.

    You can either limit the full/wide alignment styles to pages with .full-width-content body class, or use the max-width approach shown above, ensuring the max-width stops before overlapping the sidebar.

    I prefer disabling the full/wide alignment styles on pages with sidebars. The CSS is cleaner, and you don’t end up with two different versions of “wide” and “full” alignments.

  • Recommended Plugins with Gutenberg Blocks

    The new block editor in WordPress includes many core blocks, and you can add additional blocks through plugins. I’ve built quite a few Gutenberg websites, and these are the tools I recommend using.

    For simple features like featuring a team member I like to build my own custom blocks. But for more advanced features, especially if my client will need the flexibility to customize it, I try to use high quality plugins.

    I prefer plugins that focus on a single feature rather than “block library” plugins that include many different blocks. A focused product usually delivers a better solution. You also won’t pollute your block list with many blocks you never plan to use. If you do choose to install a block library, use one of these.

    Many of the plugins I recommend include a premium / paid option. These have actual businesses behind the plugins, will be supported for a long time, and will continue to improve over time.

    Here are my recommended plugins for forms, galleries, sliders, and block libraries. I plan to keep updating this article over time, so be sure to check back.

    Forms

    WPForms

    WPForms is my favorite plugin for building any type of form. It’s incredibly easy to use, has plenty of addons, and can be extended through hooks and filters. I’ve used it on every site I’ve built for the past two years.

    The free version is full-featured enough for most use cases, which is why it has over 1 million active installs. The paid versions include additional features and integrations with services like MailChimp, Aweber, Stripe, and Paypal.

    Use their form builder to create your form (video demo), then embed it in a page using the WPForms block.

    Jetpack Form

    Jetpack is built by Automattic, the company behind WordPress.com. It includes a ton of features, so make sure you only enable those you actually need.

    The Jetpack Form block lets you build your form directly in the Gutenberg block editor, which is unique among the form plugins.

    Block Gallery

    Block Gallery is a free gallery plugin built specifically for Gutenberg. It’s incredibly easy to use, allowing you to build and customize beautiful galleries directly in the Gutenberg block editor.

    This plugin includes three different gallery blocks: Carousel, Masonry, and Stacked.

    Envira Gallery

    Envira Gallery is a premium WordPress gallery plugin. It’s Gutenberg integration is fairly basic currently, but it has the most extensive features and addons to implement almost anything you need.

    For basic galleries, the free Envira Gallery Lite will work great. I built the demo below using the free version of the plugin.

    First build your gallery in the Envira Gallery section of your WordPress site (video demo), then embed the gallery in your content using the Envira Gallery block. You can customize the gallery settings in the block panel on the right and see the gallery update live in Gutenberg.

    Future versions of Envira Gallery will include even deeper Gutenberg integration. Soon you’ll likely be able to build the gallery directly in the Gutenberg editor rather than going to the separate gallery builder.

    Sliders

    Soliloquy

    Soliloquy is premium slider plugin, produced by the same team as Envira. The free version, Soliloquy Lite, works great for most use cases. The premium version can be extended with many addons including image protection, slide scheduling, featured content, and more.

    Go to the Soliloquy section of your backend to create a new slider (video demo). You can add images, then customize the settings for each image (title, alt text, caption, clickthrough URL…). You can also set the slider settings, like the image dimension, transition, and theme.

    Embed the slider using the Soliloquy block. There is no visual preview of the slider, nor any customization options within Gutenberg.

    My only complaint is it doesn’t currently support the block alignment options, so you can’t make a full-width slider block without CSS customizations. Here’s the code I used to make the Soliloquy block match my full width block styling, and override the max-width and max-height attributes Soliloquy adds.

    I expect future updates to include deeper Gutenberg integrations, including full-width blocks and creating sliders from within Gutenberg itself.

    Block Libraries

    Atomic Blocks

    Atomic Blocks is a free collection of page-building blocks. It was built by Array Themes to compliment their Gutenberg-focused theme  and includes blocks for post listings, testimonials, CTAs, and more.

    Both Array Themes and StudioPress (creators of the Genesis theme framework) were recently acquired by WPEngine, which makes me even more interested in building with Atomic Blocks. I expect to see deeper integrations with Genesis, the theme framework I use on most sites.

    Jetpack

    As mentioned above in the Forms section, Jetpack is Automattic’s tool to share functionality they build for WordPress.com with the rest of the WordPress ecosystem.

    Automattic was instrumental in getting Gutenberg built and merged into WordPress core, and I expect to see many high quality blocks released by them through Jetpack.

    Jetpack currently includes blocks for markdown, forms, maps, and payment processing through PayPal. Here’s more information on Jetpack’s blocks.

  • Using Advanced Custom Fields with version control

    ACF lets you build metaboxes, Gutenberg blocks, and more with their easy-to-use interface. These custom fields are stored in the database and then rendered in the WordPress backend for you – no code required.

    This can become an issue if you’re using a modern development workflow: building locally, testing on a development/staging environment, then deploying to production.  Since you likely aren’t overwriting the production database with the development one, any metaboxes created in development will need to be re-created in production.

    ACF has a built-in feature to help called Local JSON. If you create a folder in your theme named acf-json/, ACF will automatically add/update a JSON file for every group of fields. These JSON files can then be version controlled with the rest of your theme.

    After pushing the code changes to production, log into the production site, go to Custom Fields in the backend, and click “Sync available” to manually sync the updated metaboxes.

    Alternative Approach

    I prefer having the metabox changes automatically update on production rather than having to manually sync them. 

    I also prefer using a core functionality plugin for any site-specific functionality that isn’t directly theme related.  If the website owner would expect something to keep working after changing themes, it belongs in a functionality plugin. 

    In my core functionality plugin, I have a acf.php file with the following features:

    1. Store the JSON files in the core functionality plugin, in a acf-json/ folder.
    2. Automatically sync new metaboxes. For performance reasons we limit the sync to new versions of the core functionality plugin, when the CORE_FUNCTIONALITY_VERSION constant has changed.
    3. Only display the ACF field editor if WP_LOCAL_DEV === true. I have this constant defined in wp-config.php locally. This prevents clients from accidentally editing or deleting their metaboxes.
    4. Register an options page. I’ve commented it out, but most sites we build leverage an options page so I can quickly turn it on.
    5. Register new blocks. It’s also commented out but easily accessible so I don’t have to keep referring to my article on building Gutenberg blocks with ACF.
    <?php
    /**
    * Advanced Custom Fields
    *
    * @package CoreFunctionality
    * @version 2.0
    * @author Bill Erickson <[email protected]>
    * @copyright Copyright (c) 2018, Bill Erickson
    * @license GPL-2.0+
    */
    class BE_ACF_Customizations {
    public function __construct() {
    // Only allow fields to be edited on development
    if ( ! defined( 'WP_LOCAL_DEV' ) || ! WP_LOCAL_DEV ) {
    add_filter( 'acf/settings/show_admin', '__return_false' );
    }
    // Save and sync fields in functionality plugin
    add_filter( 'acf/settings/save_json', array( $this, 'get_local_json_path' ) );
    add_filter( 'acf/settings/load_json', array( $this, 'add_local_json_path' ) );
    add_action( 'admin_init', array( $this, 'sync_fields_with_json' ) );
    // Register options page
    //add_action( 'init', array( $this, 'register_options_page' ) );
    // Register Blocks
    //add_action('acf/init', array( $this, 'register_blocks' ) );
    }
    /**
    * Define where the local JSON is saved
    *
    * @return string
    */
    public function get_local_json_path() {
    return EA_DIR . '/acf-json';
    }
    /**
    * Add our path for the local JSON
    *
    * @param array $paths
    *
    * @return array
    */
    public function add_local_json_path( $paths ) {
    $paths[] = EA_DIR . '/acf-json';
    return $paths;
    }
    /**
    * Automatically sync any JSON field configuration.
    */
    public function sync_fields_with_json() {
    if ( defined( 'DOING_AJAX' ) || defined( 'DOING_CRON' ) ) {
    return;
    }
    if ( ! function_exists( 'acf_get_field_groups' ) ) {
    return;
    }
    $version = get_option( 'be_acf_json_version' );
    if( defined( 'CORE_FUNCTIONALITY_VERSION' ) && version_compare( CORE_FUNCTIONALITY_VERSION, $version ) ) {
    update_option( 'be_acf_json_version', CORE_FUNCTIONALITY_VERSION );
    $groups = acf_get_field_groups();
    if ( empty( $groups ) ) {
    return;
    }
    $sync = array();
    foreach ( $groups as $group ) {
    $local = acf_maybe_get( $group, 'local', false );
    $modified = acf_maybe_get( $group, 'modified', 0 );
    $private = acf_maybe_get( $group, 'private', false );
    if ( $local !== 'json' || $private ) {
    // ignore DB / PHP / private field groups
    continue;
    }
    if ( ! $group['ID'] ) {
    $sync[ $group['key'] ] = $group;
    } elseif ( $modified && $modified > get_post_modified_time( 'U', true, $group['ID'], true ) ) {
    $sync[ $group['key'] ] = $group;
    }
    }
    if ( empty( $sync ) ) {
    return;
    }
    foreach ( $sync as $key => $v ) {
    if ( acf_have_local_fields( $key ) ) {
    $sync[ $key ]['fields'] = acf_get_local_fields( $key );
    }
    acf_import_field_group( $sync[ $key ] );
    }
    }
    }
    /**
    * Register Options Page
    *
    */
    function register_options_page() {
    if ( function_exists( 'acf_add_options_page' ) ) {
    acf_add_options_page( array(
    'title' => __( 'Site Options', 'core-functionality' ),
    'capability' => 'manage_options',
    ) );
    }
    }
    /**
    * Register Blocks
    * @see https://www.billerickson.net/building-gutenberg-block-acf/#register-block
    *
    * Categories: common, formatting, layout, widgets, embed
    * Dashicons: https://developer.wordpress.org/resource/dashicons/
    * ACF Settings: https://www.advancedcustomfields.com/resources/acf_register_block/
    */
    function register_blocks() {
    if( ! function_exists('acf_register_block') )
    return;
    acf_register_block( array(
    'name' => 'features',
    'title' => __( 'Features', 'core-functionality' ),
    'render_template' => 'partials/block-features.php',
    'category' => 'formatting',
    'icon' => 'awards',
    'mode' => 'preview',
    'keywords' => array(),
    'align' => 'full',
    ));
    }
    }
    new BE_ACF_Customizations();
    view raw acf.php hosted with ❤ by GitHub
    <?php
    /**
    * Plugin Name: Core Functionality
    *
    */
    define( 'CORE_FUNCTIONALITY_VERSION', '1.0.0' );
    define( 'EA_DIR' , plugin_dir_path( __FILE__ ) );
    <?php
    define( 'WP_LOCAL_DEV', true );
    view raw wp-config.php hosted with ❤ by GitHub
  • Change width of post title in Gutenberg

    I wanted a way to tweak the width of post titles to optimize where it breaks to a new line. 

    I created the metabox with Advanced Custom Fields using the Range field type. I set the maximum value and default value to the current max-width of the post title, and the minimum to something reasonable.

    I then customized my theme to add the max-width CSS if the value is less than 1168px. Since my site is built on Genesis, I leveraged the Markup API by adding this to single.php:

    <?php
    /**
    * Post Title Width
    * @see https://www.billerickson.net/change-width-of-post-title-in-gutenberg/
    */
    function be_single_post_title_width( $attr ) {
    $custom_width = intval( get_post_meta( get_the_ID(), 'ea_post_header_width', true ) );
    if( empty( $custom_width ) || 1168 == $custom_width )
    return $attr;
    $attr['style'] = 'max-width: ' . $custom_width . 'px';
    return $attr;
    }
    add_filter( 'genesis_attr_entry-title', 'be_single_post_title_width' );
    view raw single.php hosted with ❤ by GitHub

    That works great on the frontend, but I wanted live updating in the Gutenberg editor so I know what size to use before publishing the post. I enqueued the following JavaScript in the Gutenberg editor: 

    <?php
    /**
    * Gutenberg scripts and styles
    *
    */
    function ea_gutenberg_scripts() {
    wp_enqueue_script( 'ea-gutenberg', get_stylesheet_directory_uri() . '/assets/js/gutenberg-min.js', array( 'jquery' ), filemtime( get_stylesheet_directory() . '/assets/js/gutenberg-min.js' ), true );
    }
    add_action( 'enqueue_block_editor_assets', 'ea_gutenberg_scripts' );
    view raw functions.php hosted with ❤ by GitHub
    jQuery(function($){
    $(window).load(function(){
    var field = acf.getField('field_5c194bf2f653d'),
    header = $('.editor-post-title__block');
    $(header).css('max-width', field.val() + 'px' );
    field.on('change', function(e) {
    $(header).css('max-width', field.val() + 'px' );
    });
    });
    });
    view raw gutenberg.js hosted with ❤ by GitHub

    You’ll need to change the field key to match whatever your ACF field is named. This code leverages the ACF JavaScript API.

    You also need to make sure your Gutenberg editor styles match the frontend of your site. See my post on Building a Gutenberg website for details.

  • Genesis Archive Settings for Custom Post Types

    The Genesis theme framework includes an Archive Settings box for specifying the page title and introductory content for category and author archives.

    Take a look at my Gutenberg category archive as an example.

    Your Custom Post Types 

    When registering your own custom post types, you can enable this same functionality by including 'genesis-cpt-archives-settings' in the supports array.  For more information, see my article on creating custom post types.

    My Code Snippets post type registration looks like this:

    <?php
    $args = array(
    'labels' => $labels,
    'hierarchical' => false,
    'supports' => array( 'title', 'editor', 'genesis-cpt-archives-settings' ),
    'public' => true,
    'show_ui' => true,
    'show_in_rest' => true,
    'show_in_menu' => true,
    'show_in_nav_menus' => true,
    'publicly_queryable' => true,
    'exclude_from_search' => false,
    'has_archive' => true,
    'query_var' => true,
    'can_export' => true,
    'rewrite' => true,
    'taxonomies' => array( 'category' ),
    'menu_icon' => 'dashicons-media-code',
    );
    register_post_type( 'code', $args );
    view raw functions.php hosted with ❤ by GitHub

    Adding to Plugin CPTs

    What if you’re not the one registering the custom post type? In these situations, you can use add_post_type_support().

    Here’s how to add support to an event post type registered by another plugin. Place the code in your Core Functionality plugin or your theme’s functions.php file.

    <?php
    /**
    * Add Genesis CPT Archive Settings to events
    * @see https://www.billerickson.net/genesis-archive-settings-for-custom-post-types/
    *
    */
    function be_event_archive_settings() {
    add_post_type_support( 'event', 'genesis-cpt-archives-settings' );
    }
    add_action( 'init', 'be_event_archive_settings' );
    view raw functions.php hosted with ❤ by GitHub
  • Using Block Templates with Gutenberg

    Block templates are one of my favorite new features in Gutenberg. You can specify a list of blocks that automatically appear in the content editor, and you can customize what appears in each block by default.

    You can also lock the template so no additional blocks can be added. This is a great replacement for metaboxes in many cases. You can control the content structure without sacrificing the visual editing experience. 

    Block templates are currently set for an entire post type, but you will soon have more granular control to define them in page templates and other contexts.

    Quick tip on implementation

    I first build the page in the Gutenberg block editor. Then I add the code below to the theme, which prints out an escaped version of post_content. This shows me the blocks and parameters I need to build the block template.

    I’m using ea_pp() below (code here) but you could also use print_r().

    /**
     * Display Post Blocks 
     *
     */
    function ea_display_post_blocks() {
    	global $post;
    	ea_pp( esc_html( $post->post_content ) );
    }
    add_action( 'wp_footer', 'ea_display_post_blocks' );

    That helped me build the following block template:

    'template' => array(
    	array( 'core/heading', array( 'level' => '5', 'content' => 'Role' ) ),
    	array( 'core/paragraph' ),
    	array( 'core/heading', array( 'level' => '5', 'content' => 'Responsibilities' ) ),
    	array( 'core/paragraph' ),
    	array( 'core/heading', array( 'level' => '5', 'content' => 'Qualifications' ) ),
    	array( 'core/list' ),
    	array( 'core/heading', array( 'level' => '5', 'content' => 'Highlights' ) ),
    	array( 'core/paragraph' ),
    )
    

    Which looks like this in the editor:

    Post template with ads

    Our client is a publisher who needs at least two ads in each post. There’s a few approaches we’ve used in the past:

    • Automatic insertion after X paragraphs. It’s simple to maintain but the ads often don’t follow the natural breaks in article.
    • Manual insertion using a shortcode. The content editor can ensure the ads work well with the content, but it’s more difficult to manage and easy to forget.

    With Gutenberg, we simply pre-populate the content area with two ad blocks (built with Advanced Custom Fields) and three paragraph blocks. Content editors can then dive right into content creation around the ad units.

    Here’s how you set the block template for posts:

    <?php
    /**
    * Block template for posts
    * @see https://www.billerickson.net/gutenberg-block-templates/
    *
    */
    function be_post_block_template() {
    $post_type_object = get_post_type_object( 'post' );
    $post_type_object->template = array(
    array( 'core/paragraph' ),
    array( 'acf/ad' ),
    array( 'core/paragraph' ),
    array( 'acf/ad' ),
    array( 'core/paragraph' ),
    );
    }
    add_action( 'init', 'be_post_block_template' );
    view raw functions.php hosted with ❤ by GitHub

    Testimonial block template

    We feature testimonials throughout the website, and we have a Testimonial post type for managing them. In the past we would have disabled the editor and added a custom metabox on this post type to collect just the quote and byline.

    With Gutenberg, we can limit the editor to just the “Quote” block. This allows the client to use the same UI for managing their blockquotes site-wide.

    When registering your post type, use the template parameter to specify an array of which blocks should appear.

    Including 'template_lock' => 'all' will prevent any changes to the layout. If you set 'template_lock' => 'insert' it will prevent new blocks from being inserted but still allow the writer re-arrange the existing blocks.

    We’ll be featuring these quotes using the “Large” quote style in the theme, so I’ve added is-style-large to the block attributes.

    <?php
    /**
    * Testimonials
    *
    * @package CoreFunctionality
    * @author Bill Erickson
    * @since 1.0.0
    * @license GPL-2.0+
    **/
    class EA_Testimonials {
    /**
    * Initialize all the things
    *
    * @since 1.2.0
    */
    function __construct() {
    // Actions
    add_action( 'init', array( $this, 'register_cpt' ) );
    add_filter( 'wp_insert_post_data', array( $this, 'set_testimonial_title' ), 99, 2 );
    }
    /**
    * Register the custom post type
    *
    * @since 1.2.0
    */
    function register_cpt() {
    $labels = array(
    'name' => 'Testimonials',
    'singular_name' => 'Testimonial',
    'add_new' => 'Add New',
    'add_new_item' => 'Add New Testimonial',
    'edit_item' => 'Edit Testimonial',
    'new_item' => 'New Testimonial',
    'view_item' => 'View Testimonial',
    'search_items' => 'Search Testimonials',
    'not_found' => 'No Testimonials found',
    'not_found_in_trash' => 'No Testimonials found in Trash',
    'parent_item_colon' => 'Parent Testimonial:',
    'menu_name' => 'Testimonials',
    );
    $args = array(
    'labels' => $labels,
    'hierarchical' => true,
    'supports' => array( 'editor' ),
    'public' => true,
    'show_ui' => true,
    'show_in_rest' => true,
    'publicly_queryable' => false,
    'exclude_from_search' => true,
    'has_archive' => false,
    'query_var' => true,
    'can_export' => true,
    'rewrite' => array( 'slug' => 'testimonial', 'with_front' => false ),
    'menu_icon' => 'dashicons-format-quote',
    'template' => array( array( 'core/quote', array( 'className' => 'is-style-large' ) ) ),
    'template_lock' => 'all',
    );
    register_post_type( 'testimonial', $args );
    }
    /**
    * Set testimonial title
    *
    */
    function set_testimonial_title( $data, $postarr ) {
    if( 'testimonial' == $data['post_type'] ) {
    $title = $this->get_citation( $data['post_content'] );
    if( empty( $title ) )
    $title = 'Testimonial ' . $postarr['ID'];
    $data['post_title'] = $title;
    }
    return $data;
    }
    /**
    * Get Citation
    *
    */
    function get_citation( $content ) {
    $matches = array();
    $regex = '#<cite>(.*?)</cite>#';
    preg_match_all( $regex, $content, $matches );
    if( !empty( $matches ) && !empty( $matches[0] ) && !empty( $matches[0][0] ) )
    return strip_tags( $matches[0][0] );
    }
    }
    new EA_Testimonials();
    view raw cpt-testimonial.php hosted with ❤ by GitHub

    There’s no need for writers to include a post title for these quotes, but WordPress’  auto-generated titles weren’t very descriptive.  I’m using the wp_insert_post_data filter to modify the post title to match the value in <cite>. If there is no byline, it sets the title to “Testimonial {ID}”

    I don’t like parsing HTML for this data, but it works given the simple content structure. For more advanced layouts I recommend using something like Gutenberg Object Plugin to save the Gutenberg data as an array in the database so you can access it easier.

    Nested Templates

    You can create nested block templates using container blocks. For instance, here’s an example from the Templates section of the Gutenberg Handbook.

    <?php
    $template = array(
    array( 'core/paragraph', array(
    'placeholder' => 'Add a root-level paragraph',
    ) ),
    array( 'core/columns', array(), array(
    array( 'core/column', array(), array(
    array( 'core/image', array() ),
    ) ),
    array( 'core/column', array(), array(
    array( 'core/paragraph', array(
    'placeholder' => 'Add a inner paragraph'
    ) ),
    ) ),
    ) )
    );
    view raw functions.php hosted with ❤ by GitHub
  • Building a block with Advanced Custom Fields

    The new block-based editor in WordPress provides a great new content editing experience, and it’s even more powerful with custom blocks.

    The core blocks are built using React and JavaScript. You can build your own Gutenberg blocks with JavaScript as well. If you plan to distribute your block publicly as a plugin, I recommend building it with JavaScript to keep it lean and decrease dependencies on other libraries.

    When building a single website with many unique blocks, you’ll likely find it more effective to use a block-building plugin like Advanced Custom Fields. You can build blocks much faster by leveraging a tool you likely already use. This is especially useful if you’re a PHP developer with little JavaScript experience. ACF lets you build everything using PHP.

    What is Advanced Custom Fields

    Advanced Custom Fields is a plugin for building additional content editing fields throughout the WordPress interface. You can build custom metaboxes, site options, user profile fields, and term metadata.

    For a more detailed walkthrough of ACF and how it compares to similar plugins, see my Introduction to Custom Metaboxes. I plan to write more about ACF in the near future, so keep an eye on my Advanced Custom Fields category page.

    ACF is the first popular metabox plugin to add support for building blocks. Other plugins are working on it as well – see CMB2 and Carbon Fields articles on Gutenberg compatibility – but ACF is leading the way.

    Developer's Guide to Gutenberg

    I walk you through the technical details and code snippets you need as a WordPress developer building a Gutenberg website.

    Read More

    Creating a block

    There are three key parts to building a Gutenberg block with ACF:

    1. Register the block with PHP
    2. Build the block editor with the ACF user interface
    3. Describe how the block is rendered using PHP

    I’ll walk you through each step required to build a simple “Team Member” block.

    I’m storing the block’s markup and styles inside the theme to keep things simple, but you could also place the code in a core functionality plugin.

    Register the block

    We’ll use the acf_register_block() to register our custom block. I’ve provided a summary of the parameters below, and for more information see the ACF documentation.

    <?php
    /**
    * Register Blocks
    * @see https://www.billerickson.net/building-gutenberg-block-acf/#register-block
    *
    */
    function be_register_blocks() {
    if( ! function_exists('acf_register_block') )
    return;
    acf_register_block( array(
    'name' => 'team-member',
    'title' => __( 'Team Member', 'clientname' ),
    'render_template' => 'partials/block-team-member.php',
    'category' => 'formatting',
    'icon' => 'admin-users',
    'mode' => 'preview',
    'keywords' => array( 'profile', 'user', 'author' )
    ));
    }
    add_action('acf/init', 'be_register_blocks' );
    view raw functions.php hosted with ❤ by GitHub
    Name

    This is your unique name for the block. ACF automatically namespaces it for you, so my team-member name becomes acf/team-member in the database.

    Title

    This is the title shown in the Gutenberg block editor.

    Render Template

    The template file used to render the block. The same template file will be used on the frontend and as the “Preview” view in the backend editor. This can either be a relative URL from the current theme, as shown above, or a full path to any file.

    Alternatively, you can use the render_callback parameter to specify a function name that output’s the block’s HTML.

    Category

    This determines in which section of the “Add Block” window it appears. The options provided by WP core are: common, formatting, layout, widgets, and embed.

    Icon

    Specify a dashicons icon to use, or a custom SVG icon.

    Mode

    This lets you control how the block is presented the Gutenberg block editor. If set to “Preview” it will render like the frontend and you can edit content in the sidebar.

    If set to “Edit” it appears like a metabox in the content area. The user can switch the mode by clicking the button in the top right corner, unless you specifically disable it with 'supports' => array( 'mode' => false ).

    Keywords

    Up to three additional terms to use when a user is searching for the block. The name is always indexed so you don’t need to repeat it as a keyword here.

    Build the block editor

    Once the block has been registered, you can now go to Custom Fields in the admin and create your block editor. It works just like a standard metabox built in ACF.

    Under the location rules, select “Block” is equal to “Team Member”.

    Build the block markup

    The final step is to write the markup for the block. I created a template partial in /partials/block-team-member.php , matching the render_template parameter I specified when registering the block. My template partial looks like:

    <?php
    /**
    * Team Member block
    *
    * @package ClientName
    * @author Bill Erickson
    * @since 1.0.0
    * @license GPL-2.0+
    **/
    $name = get_field( 'name' );
    $title = get_field( 'title' );
    $photo = get_field( 'photo' );
    $description = get_field( 'description' );
    echo '<div class="team-member">';
    echo '<div class="team-member--header">';
    if( !empty( $photo ) )
    echo wp_get_attachment_image( $photo['ID'], 'thumbnail', null, array( 'class' => 'team-member--avatar' ) );
    if( !empty( $name ) )
    echo '<h4>' . esc_html( $name ) . '</h4>';
    if( !empty( $title ) )
    echo '<h6 class="alt">' . esc_html( $title ) . '</h6>';
    echo '</div>';
    echo '<div class="team-member--content">' . apply_filters( 'ea_the_content', $description ) . '</div>';
    echo '</div>';

    Use the get_field() function to access the fields set in the block settings. You can then build the markup for your block based on your specific design requirements.

    Building a Table of Contents block

    In my article on Developing a Gutenberg Website I mentioned the Table of Contents block I built for a few clients. It dynamically lists all h2’s within the current article and links to each one.

    I started by forking the WP Anchor Header plugin. My changes include:

    • Limiting it to only h2’s
    • Only running on posts that have the table-of-contents block.
    • Before automatically adding an ID to each heading, check if one exists already. Clients can manually specify the heading’s anchor link in the Gutenberg editor so we should respect that.
    • My ea_table_of_contents() function accepts a $count parameter. We use this to list the first few headings in the article on the homepage

    The block doesn’t have any editable fields so I added a Message field describing how it works:

    Here is the full code for the table of contents block.

  • Building a Gutenberg website

    I have built many websites using WordPress’ new block-based editor, code-named Gutenberg.

    I’ll walk you through the technical details you need as a WordPress developer building a Gutenberg website. I’ll then share how we approach these projects and provide some real-world examples.

    Quick Links
    1. Wide and full block alignment
    2. Editor Font Sizes
    3. Editor Color Palette
    4. Block Style Options
    5. Use SASS
    6. Editor Styles
    7. Set block width in Gutenberg
    8. Creating block templates
    9. Building custom blocks
    10. Simple Gutenberg websites
    11. Custom Gutenberg websites
    12. Is Gutenberg the right choice?

    Building a Gutenberg theme

    For the most part, a Gutenberg-optimized theme is just like any other WordPress theme. Your current WordPress theme will likely work great with Gutenberg.

    Wide/Full Alignment

    add_theme_support( 'align-wide' );

    This adds “wide” and “full” options to the left, right, and center alignment options. This will be used primarily for images, but other blocks also support these alignment options.

    You’ll need to add CSS to your theme for these alignment options to actually work, in the same way you have to style .alignleft for left-aligned images to work.

    See my guide to wide and full image alignment in Gutenberg for CSS examples.

    Editor Font Sizes

    When editing paragraph text, a user can select different sizes in the settings panel on the right. This lets you define what sizes should be available.

    // -- Disable custom font sizes
    add_theme_support( 'disable-custom-font-sizes' );
    
    // -- Editor Font Sizes
    add_theme_support( 'editor-font-sizes', array(
    	array(
    		'name'      => __( 'small', 'ea_genesis_child' ),
    		'shortName' => __( 'S', 'ea_genesis_child' ),
    		'size'      => 12,
    		'slug'      => 'small'
    	),
    	array(
    		'name'      => __( 'regular', 'ea_genesis_child' ),
    		'shortName' => __( 'M', 'ea_genesis_child' ),
    		'size'      => 16,
    		'slug'      => 'regular'
    	),
    	array(
    		'name'      => __( 'large', 'ea_genesis_child' ),
    		'shortName' => __( 'L', 'ea_genesis_child' ),
    		'size'      => 20,
    		'slug'      => 'large'
    	),
    ) );

    You’ll also have to add CSS to your theme for this to work. Rather than hardcoding the font size on the paragraphs, Gutenberg adds a CSS class like .has-small-font-size. This helps keep the content separate from the styling and will simplify redesigns in the future.

    Theme Colors

    // -- Disable Custom Colors
    add_theme_support( 'disable-custom-colors' );
    
    // -- Editor Color Palette
    add_theme_support( 'editor-color-palette', array(
    	array(
    		'name'  => __( 'Blue', 'ea_genesis_child' ),
    		'slug'  => 'blue',
    		'color'	=> '#59BACC',
    	),
    	array(
    		'name'  => __( 'Green', 'ea_genesis_child' ),
    		'slug'  => 'green',
    		'color' => '#58AD69',
    	),
    ) );

    Gutenberg includes a color picker in certain blocks like paragraph and button. Rather than letting clients pick any color they want, we disable the color picker and define a few brand colors.

    Like all the other theme options, these require additional CSS to function properly. When a block has the “Background Color” set to one of your theme colors, it adds a class of .has-{color}-background-color. Likewise, when the “Text Color” is set, it adds a class of .has-{color}-color.

    See my Guide to Color Palettes and Button Styling for more information and code samples.

    Block Style Options

    Each block type can have multiple style options. For instance, the Quote block comes with “Regular” and “Large” styles, while the Button block comes with “Round”, “Square”, and “Outline” styles.

    You can add your own block styles using registerBlockStyle, and you can remove existing style options using unregisterBlockStyle.

    See Block Styles in Gutenberg for code samples and a list of all block names.

    Use SASS

    I can’t imagine building a Gutenberg theme without SASS. You need to generate a frontend stylesheet and editor stylesheet, both with differing amounts of CSS.

    For the Theme Colors feature described above, we use SASS loops to build the styles (see here).

    Editor Styles

    If your theme has defined editor styles, these will not be loaded into Gutenberg by default. The idea is that your original editor-styles.css file was written for the classic editor.

    You can use it to define styles that only apply to the classic editor, and load a different stylesheet for the block editor using the enqueue_block_editor_assets hook:

    /**
     * Gutenbergstyles
     *
     */
    function ea_gutenberg_styles() {
    	wp_enqueue_style( 'ea-gutenberg', get_stylesheet_directory_uri() . '/assets/css/gutenberg.css' );
    }
    add_action( 'enqueue_block_editor_assets', 'ea_gutenberg_scripts' );

    Do not load your entire frontend stylesheet in Gutenberg. You should only load relevant styles, and prepend them all with the .editor-block-list__block class to ensure it only applies to the editor (not the WP backend menu, metaboxes…).

    A simpler approach to editor styles

    Alternatively, you can tell WordPress to load your editor styles into Gutenberg with

    add_theme_support( 'editor-styles' );

    WordPress will automatically prefix your styles for you so you don’t have to worry about targeting the correct elements inside of the editor. You’ll have a single editor stylesheet used for both the block editor and classic editor.

    Here’s more information.

    Set block width in Gutenberg

    Gutenberg already has some base styling applied to blocks, but their max-width doesn’t match the max-width we are using on the site. We use the following in a _gutenberg.scss partial to update the size of normal, wide, and full width blocks in the Gutenberg editor. $content-width is a SASS variable we have defined in _base.scss.

    These styles should match your frontend styles. I’ve also added styles for customizing the post title.

    /* Post title width */
    .editor-post-title__block.wp-block {
    	max-width: $content-width;
    
    	/* Post title styling */
    	.editor-post-title__input {
    	}
    }
    
    /* Main column width */
    .wp-block {
        max-width: $content-width;
    
    	/* Wide column width */
    	&[data-align="wide"] {
    		max-width: none;
    
    		@include media(">=medium") {
    			max-width: none;
    			margin-left: calc(25vw - 25%);
    			margin-right: calc(25vw - 25%);
    		}
    	}
    
    	/* Full column width */
    	&[data-align="full"] {
    		max-width: none;
    	}
    }
    

    Creating block templates

    You can simplify the writing experience by pre-populating the editor with a set of default blocks.

    You can even customize what appears in each block by default. We used this on an attorney’s website so all case summaries had the same overall structure.

    You can decide how strict you want to make the template. You can lock it completely (no new blocks, can’t remove/reorder existing blocks), lock insertions (no new blocks, but current blocks can be re-ordered), or have no locks and used the template as a starting guide.

    Read my article on Using Block Templates with Gutenberg for code examples.

    Building Custom Blocks

    The biggest question most theme developers will have is “Should I build my custom blocks from scratch in JavaScript, or use a plugin like Advanced Custom Fields?”

    I think metaboxes make a great analogy. When I’m building a custom plugin that will be distributed and used by many, like Genesis Title Toggle, I build my metabox from scratch. This removes a plugin dependency (ACF) or a bundled library (CMB2) and keeps the plugin lean.

    When I’m building a bunch of metaboxes for a specific client’s site, it’s better to leverage an existing tool like Advanced Custom Fields, Carbon Fields, or CMB2. I’m able to provide a higher quality result much faster than if I were to build everything from scratch.

    I use the same approach to Gutenberg blocks. For client sites, I’m building my custom blocks with Advanced Custom Fields. When I release a public plugin that includes a block, it will be built from scratch.

    See these articles for more information:

    Types of Gutenberg websites

    There are really two types of Gutenberg websites: simple and custom.

    Simple Gutenberg Websites

    Gutenberg is a huge step forward for simple content sites. Clients can easily build beautiful and engaging pages of content with the core blocks. The theme development process for these sites is mostly CSS. We ensure the core blocks look great, match the client’s brand, and can address all their content requirements.

    This is perfect for non-profits who need a low-cost, high-impact website. We used this approach for CARAS and College Discount Cards.

    We start by designing a style guide featuring all the core blocks. Our designer then works with the client to mock up the key pages using these blocks. Once the designs are approved, I style the blocks and build the pages like legos.

    Custom Gutenberg Websites

    These sites follow our traditional web development process. Rather than letting the technology constrain our design and functionality, we first examine the client’s specific needs and document the desired features and user experience. We then design the user interface, mockup all the blocks (both core and custom), and mockup the page layouts necessary to build the site.

    In addition to styling the core blocks, we build custom blocks to implement features not currently in core. The above example of Free Together includes a “Table of Contents” block that dynamically lists and links to each heading in the article.

    On RCP (soon to launch) we built many custom blocks including a Feature Box, Icon Links, and Downloads.

    Is Gutenberg the right choice?

    You have to consider the value proposition for each project. We use the block editor on all projects unless there’s a compelling reason not to. When we disable Gutenberg, it’s typically on a single template.

    The benefits of Gutenberg include:

    • Building a simple Gutenberg site will save us from building a more complex website that relies heavily on custom metaboxes. We can deliver a better product faster and cheaper.
    • Many websites require complex content elements that are easy to implement as custom blocks but difficult to do with TinyMCE. For instance, the RCP project required 9 custom blocks. Before Gutenberg, these would be a mix of shortcodes with Shortcode UI, custom TinyMCE plugins, and metaboxes.
    • We’d rather future-proof our projects by using the new editor rather than locking clients into outdated technology.

    Here’s the “Feature Box” block we built on RCP. This is a great example of how Gutenberg can make content creation easier. Something like this would be difficult and complicated to insert in TinyMCE. See my article on Building Gutenberg blocks with ACF for more examples.

    Frontend / Backend Preview
    Backend Edit

    Gutenberg is not a page builder

    Gutenberg is a block-based content editor, not a page builder. It’s hard to describe, but it will become more clear as you use it in the real world.

    While the columns block does allow you to nest blocks inside of blocks, it’s fairly primitive and difficult to set up. The editing experience can be painful and you’ll need custom CSS to make it mobile responsive. It works for simple sites, but is not a replacement for true page builders like Beaver Builder or flexible content areas.

    We use Gutenberg for most content pages on the site; it replaces a lot of custom page templates we would have developed previously. But for visually complex pages like the homepage and landing pages, we’ll often disable Gutenberg for those templates and build a true page builder with Carbon Fields or Advanced Custom Fields.

    It’s not that Gutenberg can’t be used for complex pages, it just might not be the easiest interface to use in those instances. As Gutenberg becomes more powerful, this will become less of an issue.

    My website – including the homepage – is built completely with Gutenberg. It can be done.

Bill Erickson

Bill Erickson is a freelance WordPress developer and a contributing developer to the Genesis framework. For the past 14 years he has worked with attorneys, publishers, corporations, and non-profits, building custom websites tailored to their needs and goals.

Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk