Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: wordpress

  • Blocks: Another Way to Adjust Settings

    Blocks: Another Way to Adjust Settings

    As I’ve mentioned a few times, one of the ways you can adjust settings on a block in Gutenberg is via the sidebar. In fact, this is the default way most people will interact with block settings.

    If you make a paragraph today, you can see it like this:

    This is the default paragraph sidebar from Gutenberg. No customizations.

    But. I don’t actually like it very much. I appreciate that I have it, and I love that I can get it out of the way. But sometimes I like settings to be a little more contextual.

    It’s Easy to Add Sidebar Settings

    One of the reasons we all use sidebar settings is that, well, they’re easy. When I built out my listicles plugin, I could use the inspector controls and automagically I have my own settings.

    This:

    <InspectorControls>
    	<PanelBody title={ 'Listicle Settings' }>
    		<RangeControl
    			label={ 'Items' }
    			value={ items }
    			onChange={ ( value ) => setAttributes( { items: value } ) }
    			min={ 1 }
    			max={ MAX_ITEMS }
    		/>
    		<ToggleControl
    			label={ 'Reversed' }
    			help={ ( checked ) => checked ? 'Reversed order (10 - 1)' : 'Numerical order (1 - 10)' }
    			checked={ props.attributes.reversed }
    			onChange={ () => props.setAttributes( { reversed: ! props.attributes.reversed } ) }
    		/>
    	</PanelBody>
    </InspectorControls>

    Looks like this:

    A screenshot of the listicle settings, which are a slider for the items and a toggle to reverse the order display.

    But like I said, I don’t like it very much. It’s clunky, it’s touchy, if you delete the number and type in a new one it’ll wipe all your data. And worst of all, my partner in crime, Tracy, hates it. If your work partners hate a tool, then it’s serious problem. I’ll put up with annoyances to me, but I’ll learn new code for the team.

    Think About What’s Easier

    Before I get into the code I used to solve the issue, I want to take a moment to talk about theory and understanding usage.

    One of the critiques about Gutenberg is that it’s changing too much too quickly, and it’s not listening to users. The problem with that complaint is it lacks context. I’m big on context because I believe that only with understanding the usage and context can we as a whole make the correct decisions going forward. What changes, when, and why depends entirely on what’s being used, for what, and why.

    It’s much more direct to understand this when I look at my little listicles block. You see, we use it for one thing: to make lists with a specific format. And we have few requirements.

    • Add and remove items
    • Add content of myriad types to each item
    • Be able to reverse the item count (1 to 10 or 10 to 1)

    That’s really it. Except now I’m adding one more thing:

    • An easier, inline, way to add/remove/toggle items.

    So I sat and I thought about what would be the easiest to use, and I came up with a simple solution. Three buttons, one to add an item, one to remove, and one to toggle the order. Have those show perpetually at the bottom of the list, and you could easily add and remove as needed.

    It’s Actually Easy To Add Buttons

    Once I knew what I wanted, I took a page from some work Yoast is doing and sketched my idea to look like this:

    Three buttons: Add item, remove item, and toggle order

    In order to do this, I needed to add some code to the bottom of my <dl> code:

    <div className='listicles-buttons'>
    	<IconButton
    		icon='insert'
    		onClick={ () => setAttributes( { items: parseInt(`${ items }`)+1 } ) }
    		className='editor-inserter__toggle'
    	>Add Item</IconButton>
    
    	<IconButton
    		icon='dismiss'
    		onClick={ () => setAttributes( { items: parseInt(`${ items }`)-1 } ) }
    		className='editor-inserter__toggle'
    	>Remove Item</IconButton>
    
    	<IconButton
    		icon='controls-repeat'
    		onClick={ () => setAttributes( { reversed: ! reversed } ) }
    		className='editor-inserter__toggle'
    	>Toggle Order</IconButton>
    </div>

    This sits inside the <dl> and just below my <InnerBlocks...> insert. It generates the buttons, which change when you hover by default.

    Now it’s not perfect. If you deleted all the items and pressed delete again, it would sure try to delete. I didn’t put in checks to make sure we didn’t go below 0 or above 18 (which is my current limits). But this is the start to make sure we can keep improving and iterating.

  • Shortcodes Aren’t Leaving Us

    Shortcodes Aren’t Leaving Us

    In a recent post, someone asked:

    We have this scenario a lot:

    Lorem ipsum some text [shortcode]affected text[/shortcode] more text, all within one parapgraph.

    How can this be solved with Gutenberg?

    Quick answer? It won’t.

    Just like [shortcode] that outputs a single content, or [shortcode text="affected text"], there will remain a need for singe, inline, in context, shortcode for a while.

    I know it’s confusing. This is because there are different kinds of shortcodes for different purposes. Some, yes, will no longer be needed as much.

    Shortcodes for Inline Content

    This is the easiest one to understand. Think about videos. Or my example of inline editable blocks. Those are a very clear one to one. If you’re inserting a shortcode (or an embed) on it’s own line today, that will be ‘replaced’ in time with a block.

    Embeds are already supported, by the way. If you create your own embeds, they too are automatically blocked.

    Shortcodes for Layout

    This is harder to understand, since it’s not fully ready yet. But if you’ve used a plugin or a theme that told you to use a lot of shortcodes to make a two column layout, guess what you’re not going to be doing anymore in the future? That’s right, using shortcodes. Instead, we’re creating listicles, tables, how-to directions and more.

    Example of Yoast SEO’s How To Block — coming soon. (Credit: Yoast.com)

    Their looks a lot better than my basic blocks, but it shows you what we can do and how great we can do it. Those simple and complex layouts will become blocks, where we will be able to actually see what it’s supposed to look like. This includes the Gallery shortcode we all know and love.

    Shortcodes for Text Insertion

    And finally we have the ‘classic’ block. This is the sort the poster was asking me about. Guess what? Nothing’s going to change with those any time soon. Oh, I’m sure eventually someone will take my inline-editable-block concept and make it so when we add the shortcode, it’ll adjust the text accordingly right before our eyes.

    And really, if we look at the concept of [shortcode]affected text[/shortcode] we realize how much more we can do already with Gutenberg. What are we affecting the text with? We can already make it bold. But can we make it blue? Not yet. But I can see this coming soon.

    But right now? Those inline shortcodes, in the middle of your block, are staying put.

  • Show Feedback in “Right Now”

    Show Feedback in “Right Now”

    The “Right Now” section of the WordPress dashboard is a great way to get an overview of the goings on of your site. But it doesn’t quite list everything. What if you could add things like ‘messages’ to the the “At a Glance” section like this:

    The "At a Glance" section, with messages added in.

    Guess what? You can!

    The Code

    Presmuing you’re using Jetpack’s contact form module, you automatically get a new kind of post called ‘Feedback.’ In order to make it display it’s count in “At a Glance,” there are two parts. First we add the CSS, which does the styling. Then we add the PHP that counts and displays the number of posts in feedback.

    add_action( 'dashboard_glance_items', 'helf_dashboard_glance' );
    add_action( 'admin_head', 'helf_dashboard_glance_css' );
    
    /*
     * Show Feedback in "Right Now"
     */
    function helf_dashboard_glance() {
    	if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'contact-form' ) ) {
    		foreach ( array( 'feedback' ) as $post_type ) {
    			$num_posts   = wp_count_posts( $post_type );
    			$count_posts = ( isset( $num_posts->publish ) ) ? $num_posts->publish : '0';
    			if ( 0 !== $count_posts ) {
    				if ( 'feedback' === $post_type ) {
    					// translators: %s is the number of messages
    					$text = _n( '%s Message', '%s Messages', $count_posts );
    				}
    				$text = sprintf( $text, number_format_i18n( $count_posts ) );
    				printf( '<li class="%1$s-count"><a href="edit.php?post_type=%1$s">%2$s</a></li>', esc_attr( $post_type ), wp_kses_post( $text ) );
    			}
    		}
    	}
    }
    
    /*
     * Custom Icon for Feedback in "Right Now"
     */
    function helf_dashboard_glance_css() {
    	if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'contact-form' ) ) {
    		?>
    		<style type='text/css'>
    			#adminmenu #menu-posts-feedback div.wp-menu-image:before, #dashboard_right_now li.feedback-count a:before {
    				content: '\f466';
    				margin-left: -1px;
    			}
    		</style>
    		<?php
    	}
    }
  • Selective DeGutenberging

    Selective DeGutenberging

    Okay let’s be honest, friends. Not everything is ready for Gutenberg. In fact, I myself have certain sites that aren’t ready for it today. That’s why there exists an excellent plugin known as the Classic Editor. This allows you to decide it you want to block Gutenberg (which is the default option) or if you want to allow users to chose between Gutenberg and Classic editors.

    The settings page for the Classic editor.

    But what if you want to go a step further?

    What if you want to have Gutenberg on by default for posts and pages, but not for a custom post type?

    Don’t worry. We can do that.

    The Code

    The basic idea is that if WP is 5.0 or higher, make sure that the Classic Editor is installed. If it’s less than 5.0, make sure Gutenberg is installed. Then block the code as needed:

    class HELF_Gutenberg {
    
    	public $gutenfree = array();
    
    	public function __construct() {
    		$this->gutenfree = array( 'post_type_ONE', 'post_type_TWO', 'post_type_THREE' );
    		add_action( 'current_screen', array( $this, 'gutenberg_removal' ) );
    	}
    
    	public function gutenberg_removal() {
    
    		// WP 5.0+ requires Classic Editor
    		// WP 4.9- requires Gutenberg
    		if ( ( version_compare( get_bloginfo( 'version' ), 5.0, '<=' ) && ! is_plugin_active( 'gutenberg/gutenberg.php' ) ) || ( version_compare( get_bloginfo( 'version' ), 5.0, '=>' ) && ! is_plugin_active( 'classic-editor/classic-editor.php' ) ) ) {
    			return;
    		}
    
    		// Intercept Post Type
    		$current_screen    = get_current_screen();
    		$current_post_type = $current_screen->post_type;
    
    		// If this is one of our custom post types, we don't gutenize
    		if ( in_array( $current_post_type, $this->gutenfree, true ) ) {
    			remove_filter( 'replace_editor', 'gutenberg_init' );
    			remove_action( 'load-post.php', 'gutenberg_intercept_edit_post' );
    			remove_action( 'load-post-new.php', 'gutenberg_intercept_post_new' );
    			remove_action( 'admin_init', 'gutenberg_add_edit_link_filters' );
    			remove_filter( 'admin_url', 'gutenberg_modify_add_new_button_url' );
    			remove_action( 'admin_print_scripts-edit.php', 'gutenberg_replace_default_add_new_button' );
    			remove_action( 'admin_enqueue_scripts', 'gutenberg_editor_scripts_and_styles' );
    			remove_filter( 'screen_options_show_screen', '__return_false' );
    		}
    	}
    
    }
    
    new HELF_Gutenberg();
  • Shortcodes vs Blocks

    Shortcodes vs Blocks

    One of the things that Gutenberg changes for everyone is the concept of shortcodes not being absolutely necessary anymore. 

    Shortcodes Today

    One of the nice things about WordPress is that we can use shortcodes to insert dynamic content into our posts. For example, I could use [ copyright ] and have it echo © 2025. And when you have inline dynamism, that works great.

    One of the other cool things you can do is to have an embed like [ embed height="400" width="600"]...[/embed ] to embed a video:

    Yes, you could just paste in the video URL, but this is a demonstration of a shortcode as a sort of block. And speaking of blocks…

    Blocks Tomorrow

    In Gutenberg (which this post was written with), you can keep using in-line shortcodes and even add a shortcode as a block:

    An example of the Shortcode block.

    To a degree, that works well. But there are other options with Gutenberg.

    First, you can see this in a normal paragraph block. Adding options to the sidebar:

    An example of the sidebar editor, with options and the empty additional css class.

    This allows you to edit the various options on the right sidebar and, thus, change the customizable aspects of the block. For many shortcodes, you can keep that interface and have everything be perfectly functional. Have a block that shows user information? Put a dropdown for the users on the sidebar, and so on.

    Inline Edits

    The other options is an integrated block. For example, here’s my example of a review block, with text fields and dropdowns to allow you to edit in situ.

    An example of a block with dropdowns in the block itself.

    In my opinion, this is a more fluid interface, as you can see example what you’re doing and what it’s going to look like.

    How Will You Use The Future?

    There are still hurdles to overcome with Gutenberg, but as we step forward, we’re getting a better look at an integrated editor that gives you a lot of that desired ‘What you see is what you get’ experience.

  • Gutenberg Spoiler Blocks Redux

    Gutenberg Spoiler Blocks Redux

    While I did write up Spoiler Blocks for Gutenberg one way, I also sat down recently and rewrote it a little cleaner. The primary difference here is how I’m properly using defaults:

    The Code

    ( function( blocks, element, editor, components ) {
    
    	const { registerBlockType } = blocks;
    	const { RichText } = editor;
    	const { createElement } = element;
    	const { InspectorControls } = editor;
    	const { SelectControl, ToggleControl } = components;
    
    	registerBlockType( 'library/spoilers', {
    		title: __( 'Spoiler Warning' ),
    		icon: 'vault',
    		category: 'halfelf',
    		customClassName: false,
    		className: false,
    		attributes: {
    			content: {
    				source: 'children',
    				selector: 'div',
    				default: 'Warning: This post contains spoilers!'
    			}
    		},
    
    		save: function( props ) {
    			const content = props.attributes.content;
    			const container = createElement(
    				'div', { className: 'alert alert-danger' },
    				React.createElement( RichText.Content, { value: content })
    			);
    			return container;
    		},
    
    		edit: function( props ) {
    			const content = props.attributes.content;
    			const focus = props.focus;
    
    			function onChangeSpoiler( newContent ) {
    				props.setAttributes( { content: newContent } );
    			}
    
    			const editSpoiler = createElement(
    				RichText,
    				{
    					tagName: 'div',
    					className: props.className,
    					onChange: onChangeSpoiler,
    					value: content,
    					focus: focus,
    					onFocus: props.setFocus,
    				}
    			);
    
    			return createElement(
    				'div', { className: 'alert alert-danger' },
    				editSpoiler
    			);
    		},
    
    	});
    
    })(
    	window.wp.blocks,
    	window.wp.element,
    	window.wp.editor,
    	window.wp.components,
    	window.wp.i18n
    );
    

    Learning more and more about Gutenberg, and javascript, I’ve been able to iterate on the existing code and keep improving.