Categories
Software Development

WordPress Blocks: React Context Cuts Clutter

Using Reacts’ Context in WordPress blocks passes parameters painlessly. Attributes carried by context keep coupling minimal.

Reacts’ Context feature facilitates distributing data down a component tree to any descendant component. Instead of passing attributes between your components manually (e.g. <FooComponent attrib={ attrib }>), which tightly couples the current attributes and components, using a block-level context makes it easy to update and manage attributes (and their changes).

WordPress Blocks (a.k.a. Gutenberg) supports a similar concept called Block Context, but it’s for communicating and sharing attributes between discrete blocks (those registered using registerBlockType).

To someone familiar with React the following is probably obvious and straight-forward, but I found implementing it non-trivial, and also not covered in the WordPress documentation. Regardless, this appears to be so functional it should be a best practice.

Example:

A WordPress block has at minimum 2 top-level components, an Edit and a Save. Each component is passed the block attributes in the first argument. Typically the save component is less-interesting as it specifies the block data saved in the post-content, but if required it would function identically to the following example used with the edit component.

For this example let’s examine a block with 1 attribute, passed to both the toolbar and the sidebar.

export default function Edit( props ) {
	const { foo = '' } = props.attributes;
	const blockProps = useBlockProps();

	const updateFoo = useCallback(
		( _foo ) => {
			props.setAttributes( { foo: _foo } );
		},
		[ foo ]
	);

	return (
		<div { ...blockProps }>
			<MyPluginBlockControls foo={foo} onFooChange={updateFoo}></MyPluginBlockControls>
			<MyPluginInspectorControls foo={foo} onFooChange={updateFoo}></MyPluginInspectorControls>
			...
		</div>
	);
}

While this example is a bit contrived (with only one attribute it is probably not necessary to create subcomponents managing our controls), it should be evident that adding additional attributes cascades changes through the tree. Using a Context instead would resemble code like (differences are highlighted):

import { FooContext } from './context';

export default function Edit( props ) {
	const { foo = '' } = props.attributes;
	const blockProps = useBlockProps();

	const updateFoo = useCallback(
		( _foo ) => {
			props.setAttributes( { foo: _foo } );
		},
		[ foo ]
	);

	const blockContext = {
		foo,
		updateFoo,
	};

	return (
		<FooContext.Provider value={ blockContext }>
			<div { ...blockProps }>
				<MyPluginBlockControls></MyPluginBlockControls>
				<MyPluginInspectorControls></MyPluginInspectorControls>
				...
			</div>
		<FooContext.Provider/>
	);
}

The Context

Creating the context itself is pretty simple:

import { createContext, useContext } from '@wordpress/element';

export const FooContext = createContext( {
	foo: undefined,
	updateFoo: () => {},
} );

export const useFooContext = () => useContext( FooContext );

Using the Context in a sub-component

import { useFooContext } from './context';

export function MyPluginBlockControls() {
	// Use `foo` as normal.  If you need to write it, you can also add `updateFoo`.
	const { foo } = useFooContext();
}

Adding additional attributes

If you modify your block.json to have additional attributes it’s simple to add them to the context (use the property attribute and create a write function at the top-level for every attribute ), then it’s trivial to change the components to import the attribute with the const {foo,bar} = useFooContext() syntax.

Conclusion

This pattern appears to be a good way to decouple attributes within a WordPress block that need to be passed either to re-usable components or just to simplify what code should change when adding/updating the attributes being used. I’m still a React novice and I would love to know if there’s a problem or if it could be improved any way — let me know in the comments!

Categories
Software Development

MermaidJS & WordPress

I get confused by a lot of words. The combination of complex ideas and large walls of text short-circuit and crash my brain. I’ll have to read and re-read a text-only passage multiple times to understand exactly what’s being described. Speaking presentations exacerbate the issue.

However the adage “A picture is worth a thousand words” definitely applies to me. Given graphical clues demonstrating the principle helps me begin to make connections and jumpstarting my understanding.

graph TD
   start(Explain an idea) -->|with words|start
   start --> |with pictures| understanding

One of the tools I’ve found very helpful (if only for myself) is MermaidJS. This software lets you create several different types of charts using a markdown-ish syntax. For instance, the above chart was created with:

graph TD
   start(Explain an idea) --> |with words| start
   start --> |with pictures| understanding

This grants other benefits in addition to the quicker comprehension. Quick edits to the text automatically recreates the chart without requiring any manual intervention/tweaking to the rest of the diagram.

MermaidJS supports flowcharts, sequence diagrams, class diagrams, state diagrams, ERD (entity-relationship diagrams), Gantt charts, pie charts, requirement diagrams and User Journey diagrams.

On my last post I actually used it to show the sequence of flows between WordPress, WooCommerce and webhooks.

WordPress Plugins

Working at Automattic, all our internal documentation and institutional knowledge is recorded using WordPress (you should really checkout using p2’s — it’s an awesome tool). Using Mermaid in this environment has been fantastic — Mermaid can be supported anywhere you have HTML (and I can be exported to SVG too), but as WordPress is running 40% of the web, this seems like a pretty good place to start.

In fact MermaidJS has a page dedicated to integrations of their software and mention a couple plugins:

  • WordPress Markdown Editor (seems to have been rebranded to WP Githuber-MD — see below)
  • WP-ReliableMD: The page was in a different language than I understand and I made a snap decision to avoid it 😢. Should I revisit this decision?

Here is my un-asked for 2¢ about some different WordPress plugins supporting MermaidJS.

WP Mermaid (and WP Githuber-MD)

These plugins are both created & maintained by Terry Lin. I think they’re both great. They support Gutenberg blocks. They display the Mermaid text. Give them a shot and see if they float your boat.

Personally, I didn’t need the full markdown editor, and WP Mermaid had a couple small annoyances that I couldn’t solve. I submitted a couple PR’s, but decided I could use something a little simpler, which brings me to my own plugin…

MerPress

I can’t take full credit for this plugin. My coworker Michael Pretty actually did most of the work on this iteration and I submitted it to WordPress.org. I’m giving him full-credit. He did an awesome job with it.

A couple features I really like:

  • MerPress keeps the wptexturize functionality. Posts preserve the capability to convert simple characters like quotes and dashes into the nice curly quotes and dashes (e.g. “”, –, —).
  • In the Gutenberg editor, the block is encased in a code block letting you edit the code with a monotype font.

Some features I would like to see:

  • Ability to change the theme site-wide and per block
  • Add other configuration parameters to the block
  • Support 3rd party CDN (something that WP Mermaid already does)

Conclusion

If you learned nothing else, you now know I need pictures in order to comprehend complex concepts. Hopefully it’s also obvious that Mermaid is a neat tool and can be used to quickly share intention and purpose and thoughts without all the words.

graph TD
  ad(all done) --> te(the end)

Please let me know if I’m missing a plugin that I should try or if there is something you would like to see added to MerPress…