























Welcome back! We’ve just taken a look at what Gutenberg is and how it operates from the admin side. Gutenberg is certainly going to have a massive impact on the WordPress world. If you are just arriving here and have no idea what we’re talking about, I recommend at least skimming Part 1 to make sure you have the appropriate background.
Let’s create a custom block with a bit of help from a wonderful tool called create-guten-block. Onward!
To create a Gutenberg block, you create a WordPress plugin. Anything that affects *content*, like a Gutenberg block certain will, needs to be a plugin so that it remains active even as you change themes. Something that is very theme-specific or just affects how your site looks can be part of the theme files or functions.php file in your theme. Read more about this distinction in our article about WordPress Functionality Plugins.
That said, the blocks in themes issue is a hot topic. The WordPress Theme Review Team is discussing whether or not to allow blocks in themes at all as part of themes. A post, “Getting Ready for Gutenberg”, on the Theme Review Team’s Make page posed this question, and was met with strong opinions from both sides. The general consensus, however, is that blocks are plugin territory.
WordPress.org is comprised of various teams, each with their own homepage at make.wordpress.org/team-name, channel in the WordPress Slack, and a weekly meeting. If you are interested in getting involved in WordPress or curious about how it operates, I highly recommend browsing through a list of the teams here, joining a Slack channel, and popping into a weekly meeting to see how it all happens.
In the far future, it’s possible that themes will consist of *just a stylesheet*, while all custom functionality and content structure come from blocks in plugins. I’m paraphrasing the words of Tammie Lister, Gutenberg’s design lead, on this episode of Shoptalk Show. Very much worth a listen!
What’s kept me from diving head first into modern JavaScript is the dang configuration. The transpiling, the bundling, the code splitting, the tree shaking… yeesh, I’m busy! I love learning new things, but there’s a limit to my patience and, apparently, configuring a build process for a small test project is my limit.
It’s this sentiment that led to the development of a tool called create-react-app, zero-configuration build setup for, you guessed it, creating React apps. It’s brilliant. Assuming you have a functioning node and npm installation, you can run a single command and you have a project ready for you to start coding in React. The transpiling, bundling, and tree shaking is set up for you.
But wait… can we use create-react-app for Gutenberg blocks? No, but the aforementioned create-guten-block, developed and beautifully documented by Ahmad Awais, does pretty much the same thing for us! That’s what we’ll be using for our block.
create-guten-block is not the only block generating tool at our disposal! You can scaffold a block using WP-CLI, but I have chosen not to because the default setup is for ES5 (for now) and does not give us what we need for our journey into modern JavaScript. That being said, I found it helpful to dig through the ES5 implementation of a block as a way to reinforce the core concepts, so maybe give it a go after you finish here!
Yes, this is a shortcut. We are choosing to avoid understanding the core concepts of a technology by using a tool. We’ll have to learn these concepts someday. But for now, I’m totally fine bypassing this configuration step. My philosophy about using tools such as this: use them, but do so with the understanding that it *probably* won’t save you time or effort in the long run.
It’s worth noting that, like create-react-app, create-guten-block allows you to npm eject your configuration. This means exposing all of the settings the tool has created for us and making them available for customization. Note, however, that this is irreversible; if you eject and then make a mistake, you’re on your own to fix it! Like I said, you’ll have to learn it someday :)
We will first install create-guten-block globally, like so:
npm install -g create-guten-block
In theory this should work no problem, but that’s not realistic. create-guten-block requires a minimum of Node version 8 and npm 5.3, so if you haven’t updated either of them for a while, that’s one possible error (and here’s one possible solution).
I always start by pasting my console error into a search engine and removing line numbers and file names to keep my query general. In the interest of improving this tutorial, however, I am curious to hear about what went wrong so feel free to post your issue in the comments as well.
It’s time! Let’s do it! You know what? I’m not going to tell you how because Ahmad’s documentation is so good and there’s no sense in replicating it.
Go here and follow Ahmad’s instructions to create that guten-block in your command line.

Go to your Plugins screen, activate your new block plugin — it should be called something like test-block — CGB Gutenberg Block Plugin where “test-block” is what you named your block when creating it.

So easy! Now, go to the editor view of a post or page, locate your block, and insert it.

Although I named my block “test”, searching “test” in the block selector yielded the wrong result as you can see in the gif above. The default name of the block is instead “CGB Block” — we will change this very soon!
I’ve found it very helpful to have a specific text editor setup for developing blocks. I use Visual Studio Code for my text editor, but I’m sure you can figure out something similar with whatever editor is your preference.
Here are the key ingredients:

In VS Code, I accomplish this using the following features:
Command + ~ on Mac, or from the menu bar with View > Integrated TerminalThis part is optional, and you don’t have to use VS Code. The important thing is having ready access to the command line, your plugin’s source, and the Gutenberg plugin’s source for reference. You can totally reference the source on GitHub if you like, but I enjoy having the files in the same environment for side-by-side comparison and easy searching with Find In Folder.
We are using Gutenberg from the plugin repository for the actual functionality, but that instance only includes the compiled files. We want to reference the source files, so we need to use the codebase directly from GitHub. If you’d like to access updates before they are released in the plugin, you can clone the repository. It would be totally possible to build and work from the GitHub version, but for simplicity’s sake, we are using the plugin version in this tutorial.
Gutenberg itself isn’t a plugin anymore, it’s built into WordPress 5.0+. This article covers where to get/look at that code.
Once you are ready to go, make sure you are cd‘d into your block’s plugin folder and run npm start. You should see a satisfying message indicating the process has started:

npm start in our plugin folder, we are officially “Watching for changes…” (and we didn’t have to touch any config! Cheaters…)I’m using Wes Bos’s theme for Cobalt 2 in VS Code as well as the same theme for ZSH in my Terminal and iTerm. This makes absolutely no difference in how the technology works, but it does make a difference, on a personal level, to customize your workspace and make it feel like your own (or Wes Bos’, in my case).
Now that we are in code mode, let’s take a look at the files we’ll be working with. I’ll borrow this from the create-guten-block Readme for reference:
└── test-block
├── plugin.php
├── package.json
├── README.md
|
├── dist
| ├── blocks.build.js
| ├── blocks.editor.build.css
| └── blocks.style.build.css
|
└── src
├── block
| ├── block.js
| ├── editor.scss
| └── style.scss
|
├── blocks.js
├── common.scss
└── init.php
For the purposes of this tutorial, we are only concerned with what is inside the src directory. We will not touch anything in dist (those are compiled files), plugin.php, or any stragglers such as package.json, package-lock.json, or.eslintignore.
plugin.php officially alerts WordPress of our plugin’s existence. It requires src/init.php, which is where we’ll write any PHP we need for our block(s). In general, we won’t write anything in plugin.php — out of the box, the only code it contains are the comments to register our plugin.
Let’s drill into src:
└── src
├── block
| ├── block.js
| ├── editor.scss
| └── style.scss
|
├── blocks.js
├── common.scss
└── init.php
The block directory contains files for single, individual block. This includes:
block/block.js — All the JavaScript for the individual block.block/editor.scss — Sass partial for styles specific to the editor view,block/style.scss — Sass partial for styles specific to the front-end view, i.e. what you see when you view your page/post.Now, open up src/blocks.js:

I think of src/blocks.js as a table of contents for blocks, similar to the role of an index.scss or main.scss in a Sass project structure. If we wanted to include two blocks in our plugin — let’s say this was a suite of custom blocks — we could, in theory, duplicate the block directory, rename it, and add something like this to src/blocks.js:
import 'new-block/block.js';
Then, whatever create-guten-block has prepared for us behind the scenes would know to include our new block’s block.js in the main script file compiled into dist (now is a good time to take a peek into dist, if you haven’t already).
Not too bad so far, right? We still haven’t really gotten to any JavaScript…
Okay, now it’s time for a challenge! Open up src/block/block.js and take a couple of minutes to read through the author, Ahmad’s, excellent comments.
Then, see if you can figure out how to*:
* You should be able to work through (almost!) all of these in about 10 minutes. ;-)
How was that?
What problems did you run into? Did you get tired of reloading the editor? Did you see the “This block appears to have been modified externally” message more often than you’d like? I sure did, but such is life with new technology — there’s a lot to be desired in the developer experience, but this isn’t a priority for the team at present and will come in the later stages of Gutenberg’s planned development.
Most importantly, did you get #7?
If you did, then you should be writing this tutorial! That one was a gotcha. I hope you felt at least a little confused and curious because that’s how we learn! We’ll get to that in Part 3.
Now that we have our bearings, let’s dig deeper into this notion of a block.
Here is block.js with the comments stripped out — what we might call the skeleton of a static block:
// Stripped down version of src/block/block.js
// PART 1: Import dependencies
import './style.scss';
import './editor.scss';
// PART 2: Setup references to external functions
const { __ } = wp.i18n;
const { registerBlockType } = wp.blocks;
// PART 3: Register the block!
registerBlockType( 'cgb/block-test', {
// Part 3.1: Block settings
title: __( 'test - CGB Block' ),
icon: 'shield',
category: 'common',
keywords: [
__( 'test — CGB Block' ),
__( 'CGB Example' ),
__( 'create-guten-block' ),
],
// PART 3.2: Markup in editor
edit: function( props ) {
return (
<div>You’ll see this in the editor</div>
);
},
// PART 3.3: Markup saved to database
save: function( props ) {
return (
<div>This is saved to the database and returned with the_content();</div>
);
},
} );
Let’s do a side-by-side comparison with another static block, the “Separator” block from the default blocks included in Gutenberg. That file is is located in packages/block-library/src/separator/index.js. If you have the folder open in either VS Code or Sublime, you can use the shortcut Command + Option + 2 on a Mac, or View > Split Editor to get the files side-by-side.
If you are following the text editor setup outlined previously, you should have something like this:

In this image, I copy/pasted the above stripped-down version of the block into an empty file to compare it without the comments. That’s optional!
What similarities do you notice? What differences? Open up a few of the other block directories inside gutenberg-master/library/, and take a peek into their files, comparing them to our block skeleton. Spend a few minutes reading the code and see if you can spot some patterns.
Here are a few patterns I noticed:
return statements and often contains made-up tag names (you might recognize these as React components).title, icon , category, etc. In the library blocks, they appear in an export const settings = ... object, whereas in our plugin block, they are part of an argument for registerBlockType.edit and save as part of the settings object.
editand save functions:
edit( { className } ) { ... } in separator/index.jsedit: function(props) { ... } in our block.jsattributes and instead of propsindex.js. Some contain a block.js or other files that appear to contain a definition for a class extending a Component, e.g. class LatestPostsBlock extends Component { ....What did you find? Feel free to contribute in the comments (but don’t stop reading here!).
You probably noticed a statement importing @wordpress/i18n in every index.js and block.js file in the library, as well as a reference to wp.i18n in our plugin’s block.js. i18n stands for internationalization just like a11y stands for accessibility. Internationalization refers to the practice of developing your application to be easily translated to other languages. Since we want to prepare all static text in our blocks for translation, we assign wp.i18n to an alias of __for brevity, very much like we use the $ as an alias for good ‘ol jQuery. Read more about i18n for WordPress here
It’s also worth mentioning where that wp in wp.i18n is coming from and why it’s referenced as @wordpress/i18n in the Gutenberg source. wp is a global object — global meaning a variable available everywhere — containing all of WordPress’ publicly available JavaScript API methods. To demonstrate this, open up the console while on a page within the WordPress admin. Type wp and hit Enter. You should see something like this:

So, anytime we reference something within that wp object, all we are doing is accessing some functionality the WordPress JavaScript API provides us. @wordpress/i18n in the Gutenberg source is doing the same thing, but its importing the functions from an npm module rather than the global object. The functions in the wp global have been intentionally exposed to the public API by the WordPress core developers for use in themes and plugins.
If you are anything like my internal critic, you might be thinking, “Whatever, Lara, I don’t care about those details. Just tell me how to make a cool block with all the JavaScript already!” To which I would reply:
There are so many moving parts and new concepts in this environment that, I’ve found, the more code I take for granted, the more frustrating and time-consuming the process becomes. Approach every line of code with curiosity! If you don’t know what it does, do a Find in Folder in the Gutenberg source and see if you can find a trail to follow. For me, at least, this has been a much more enjoyable way to approach unfamiliar code than trying to build something haphazardly with copy and paste.
Here’s a screencast where I walk Geoff Graham though the concepts we’ve covered in this post.
What? Homework? Heck yes, there is homework! In Part 3, Andy 🍉 will dive into modern JavaScript goodies: React, JSX, and ES6 syntax. Although our series is written for those relatively new to JavaScript, it is helpful to learn the code and the concepts from many different angles and resources.
In an effort to introduce some concepts early on, here is an outline for some “Homework” prior to Part 3:
render method in ReactclassName instead of classRecommended resources:
I’d also recommend reading React State from the Ground Up here on CSS-Tricks, by Kingsley Silas, because it specifically dives into state in React. If you are brand new to React, this will be a lot to digest, but I think it’s worth getting it into your brain ASAP even if it doesn’t make sense quite yet.
Recommended resources:
In a sentence, ternary operators are shorthand for if...else statements. You’ll see these all over the Gutenberg source — find some simple examples that provide a fallback for a string’s value, as well as more robust uses like in blocks/library/paragraph/index.js, for example.
Recommended resources:
Okay! Thank you so much for reading, and see you in Part 3 for React, JSX, and other goodies.
Was there any part of this tutorial that didn’t make sense? Did you get lost anywhere? We’d love to keep making this better, so please let us know if any part of this was hard to follow or if any information is incorrect or out of date.
Thank you, again, and good luck!
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。