 How big and booming is my voice? Can you hear me all the way in the back? No, how about now? Hello, hello. Welcome back after lunch, everybody. My name is Brian, which you already learned about at the beginning. And I'm going to teach you how to create your very first Gutenberg block, which will look not too dissimilar to this perfect lifelike illustration, in fact. Before I dive right in, we are now in the practical application portion of the workshop. So is there anybody who wants to follow along with code, who still has a local setup that is like, eh. Perfect. Yes, Zach will help you. I will walk back and give Zach. If you need help getting your local environment set up. It's local for Windows and PC. Zach is going to help out with that. Windows and Mac. Sweet. And for those of you who are already set up, if you've already cloned the plugin that I set up for sort of our follow along working thing, you probably need to update it. So just get into the directory where it's installed and run get pull. And it'll pull down the newest version. If you haven't gotten it already, it's at the URL that's all the way at the top. In fact, look at this. I can point from way down here. So just head over to github.com slash brichards slash goot and dev. And you can pull down the plugin that we'll be working inside of. If your local doesn't work out, if things blow up during the afternoon, don't fret, because you can always come back to this code later. In fact, Zach has some pretty brilliant courses, lessons already recorded that go into this in much clearer detail than I'll probably be able to articulate today. And the second plugin is the one that Joss will use for his talk. But I'm pointing out that it exists now, if you want to just clone it while we're here. This is at slash caldera hyphen learn slash alert block. And you can pull that down. It's also linked in the readme that exists here. So when the slide changes, all you need to remember is github.com slash brichards slash goot and dev that has a link to all of our slides, a link to all of this code, and lots of other instruction. And then we'll get updated even more after today is done. So you don't have to feel like, oh, no, I missed a bunch of stuff while I was hacking on a thing, and I didn't catch what he said. It'll all get documented. All of those resources will be available to you forever after this. So just be Richards with no numbers, because some punk got there before me and took Risen, which is my name everywhere else. So there you go. I'll leave this up for just another second. And some updates from where we left off this morning. Everything you learned is now useless, because it's all changed while we were at lunch. There's a brand new version of Gutenberg, and everything is different. I'm kidding, of course. That hasn't happened. But it could, because there's a lot of things that are going to change between now and when it eventually merges into core. So take what we're learning today in stride. The concepts that we're covering today will probably be the same forever. But specific syntax might change. Ideally, things will get easier as time progresses and things get simplified. But they will change. In fact, some of the code that was in my original demo changed between when I wrote it and when I updated it yesterday for today. So that's fun. Now, the very first thing we're going to have to do for creating our block is set up some required files. There aren't that many to create if you're working inside of my companion plugin. But basically, we need a PHP file, just like every plugin, in order to register all of our assets. We already talked about in the morning sessions that we need to enqueue our JavaScript. We need to include our style sheets. And then we also have to register the block itself to attach those assets so that it can use them. We need the JavaScript file for actually powering the block, because right now that can only be written in JavaScript. And then, optionally, depending on what you're building, you'll have CSS for rendering things on the front end, perhaps some additional CSS for changing that a bit on the admin area. Because as we said, ideally, what you're building and providing in the admin area matches what people see on the front end. So it's a one-to-one experience. Actually, what you see is what you get. What a novel concept. But perhaps, that'll be confusing as somebody comes to edit it, and they just see text on the page and they're like, I don't know what part of this is actually editable. And so to help them, you may have some additional admin styles that draw a box around click here to edit or change the background slightly. Something to indicate, like, you're currently in edit mode. So everything is sort of green. And then when you're in the front end, that green background goes away. Or perhaps other things. You need to register a few additional controls or show some sample content. Because things get rendered dynamically and you don't want to constantly be pulling in that dynamic content as people are editing their content. There's a lot of reasons why you might want to have admin styles that are slightly different from the front end styles. And so the basic architecture that we're going to look at for this first block, if you're inside of my companion file, we're starting out in the 01 static directory. And inside of there, there should already be an assets directory. And inside of that directory, we're going to create block.js for housing all of our JavaScript. We're going to create editor.css for including our admin only styles. And we're going to create style.css for registering all of our front end styles that also get shared with the admin. So put another way, styles that you put down here in style.css will appear in both places. And then styles that go into editor.css will only appear in the admin area. And there's nothing magic about these names. This is just what I chose to call them. And we'll be referencing them by this name in the code that we write. So you could call them whatever you want. You could name your style sheet Bob if you wanted to. And then index that PHP, the one all the way down here at the bottom behind my head, is just the PHP file that's going to prop things up. That's going to register the scripts so that we can enqueue them and attach them to the block that we're making. So I'm going to head, go ahead, and pop over to my code editor. And we'll go ahead and do that right now. So inside of this 01 static directory, we just have a blank index that PHP, basically, and a totally empty assets directory. Now in my code editor, this is really tiny on the right hand side. Don't worry about what it says on the sidebar. I could right click and do new file. I like doing this in the terminal. So I'm going to change directory into 01 static and change directory into assets. And then I'm going to touch block.js to create that and editor.css to create that. And style.css to create that. And then list all of those. And we can see that we have block.js, editor.css, and style.css. We'll go back a directory and list all of that. We already have index.php. If I come into my code editor, they're all there and they're empty. And that's wonderful. Perfect. So let me go back to our slides. And so this is what we have. We've just created these three files because this fourth one was already made for us. And this is where we're going to put all of our code for this demo. Before I go any further, I should explain a bit of the nuances in this plugin. You are operating with a safety net. So you don't have to worry about blowing things up and getting stuck here in this first exercise and not being able to progress to the other ones that we're doing today. So you should be working for now inside of the O1 static directory. If you want to cheat and skip ahead and see how it all looks in the end, there is this O1 static complete directory. Let me see if I can make this sidebar. I've got to find my mouse. Ready to go. If I can zoom in on that at all. I think that's a preference change that I can't to. I can't remember what it is. Oh, I know. I have it in Finder. So everything we're doing right now to experiment is in O1 static. In this O1 static complete are all of the finished versions. So you can see essentially what we're going to be striving for. And then we'll move on to the next example, which has some boilerplate code for you already. So if you get stuck and break what we're experimenting with here, or if you accidentally break what's in this complete file, that's OK because the next one still has fresh code to hopefully help things move along quickly. And then similarly, we also have a completed version of that. So feel free to change code however you want and experiment and learn in whatever way is most convenient to you. So now that we've got our files, the very next thing we have to do is actually register all of the assets that we're going to be loading. We've got the files. Now we need to do something with them. So we need two functions that should be familiar to you if you've been creating themes or plugins for a while. We've got WPRegisterScript and WPRegisterStyle that tells WordPress, hey, I have these CSS and JavaScript files that I want to use in some context. I want you to know about them so that later I can include them wherever I need them. And then we're going to use a brand new function that only exists right now with Gutenberg installed, which is register block type. And we are essentially declaring that our block exists in PHP and then telling it, here are where the assets are that you need in order to operate. And I just remembered, I had a couple of notes that I can't have on screen. Otherwise, I don't look very magical. So I'm going to put them here so you don't even know that they're there. And I'll look like a genius. That was inner monologue, right? And so essentially what we're going to write is going to look like this. So we're going to register script for our JavaScript file. We're going to register style for our editor. We're going to register style for our front end. And then we're going to call register block type and say, I need to use this file for the JavaScript and these two files for the CSS. And we'll do it a little bit differently than it looks in here because when I made the screenshot, I neglected to make sure that that register block type function exists. So inside of our index.php, we need to call wp register script. And I'm going to put this on multilines because, hang on, scratch this. Always work inside of a function. I call it Gutendev01 register block. There we go. And I'm going to add this via add action to init. So it loads up as soon as WordPress is ready for it. And then inside here, we're going to register the JS, register admin CSS, register front end CSS, and then register the block itself. And because this function only exists sometimes, we want to make sure that it actually exists before we call it so that if someone tries to activate our plugin and they don't have Gutenberg installed or years from now when they try to activate it on WordPress, but they're still running WordPress 4.4 that doesn't have Gutenberg, we don't want their site to blow up just because they turned on our plugin. So we're going to do if function exists, register block type. And then in here, we'll call register block type. That way, this won't fire unless it exists. And the first thing we need to put in here is our block name, which I'll fill in in just a second. And then here, we have to declare the assets. So we've got an array. And we'll have our editor style. And that will equal something. And we'll have our normal style. And that will equal something else. And we'll have our editor script. And that will also equal something. And I'm just going to move this to the top because that makes more sense. So we're going to declare the script that we're using, then the editor style that we're using, and then the front end style that we're using. And so before we can actually use those, we need to define them. And before I do that, I'm just going to name my block so I don't forget to do it later. And then I go to show you a demo when it doesn't actually work, which is something I'm notoriously good at. So naming blocks in Gutenberg is a lot like naming a short code or naming a widget. Or you have to come up with a unique name that identifies whatever your block is. There's one important difference. And that's blocks have to be namespaced. JavaScript supports namespacing. PHP has supported naming spacing for a very long time. In the WordPress world, many of us don't use namespacing for declaring our functions. We're very used to doing something like I just did here while I had a prefix to all my functions. Namespacing is pretty cool. And if you're not familiar with what it is, you should look it up because it might make your development experience more pleasant. But in this context, what it really means is we've got some base name, our namespace, then a forward slash, and then whatever this particular block is named. So I'm working inside of the Guten dev namespace that I just made up. And I'm calling this one Guten dev hyphen 01 hyphen static hyphen block. So I've got my static block that lives inside of the Guten dev namespace. And this way, if you were to come up with your own namespace and also have a block that was named static block for some reason, our two blocks wouldn't collide. And if you forget to do this, you'll see a nice JavaScript error when you try to load up your block. And it's going to say, hey, this block should be namespaced. We haven't included it because you're not following the rules. And that is the basic example there. We'll have to fill in each of these blanks in just a minute after we register our scripts and our styles so that we can give them a name to automatically be enqueued. And thanks to my linter, I just noticed that I have a semicolon in the wrong spot there. That would have been embarrassing. Glad nobody saw that. One of the cool things about how register block type works is we don't have to actually call WP in queue script or WP in queue style on our own. Register block type does that for us. So it knows, OK, I'm in the context of Gutenberg. I need to show this block. I mean, I need to bring all of these assets with me. You don't have to worry about where they show up. Unlike when you created a short code or a widget, you'd have to manually call WP in queue script yourself to make sure that all of your assets come with you. It's one nice city that I really enjoy. So to register a JavaScript file, we're going to use WP register script. And I'm going to call this one Gutendev01StaticBlockJS for good measure. The extra verb here. And then the source for this is going to be plugins URL. And a quick aside, it's always bothered me that core has been this way, that there's plugin path, which only accepts one parameter, which is the current file that you're using. And then you append whatever path you want on after it. Whereas plugins URL is precisely backwards. You can tell it, here's where my file lives relative to the file that we're currently in, which is fun. So this is going to exist inside of assets, and it's going to be block.js. And this will automatically create for us the full-long URL of where this file is. And I'm going to pause here to point out that we have a leading slash here. So it's going to be whatever the root is for this current PHP file, slash assets slash block.js, which should load this file right here. And if it doesn't, well, we'll come back and fix that when it comes time to show off the code working. That's my model. Pretend that it works, and then fix it when it doesn't. So we've got a few other parameters here. We don't have to worry about setting in footer that gets taken care of for us. I also don't have to worry about setting the version in this example. You probably do want to set a version number for your assets in the real world so that they can break a static cache every time you release a new version. And that's as easy as just calling it. My go-to is just to type in the date. So 2018.0316, and it is currently 12.40 PM. You can type in whatever string you want in here, and it will automatically append that as a query string at the end of the URL, which is a really good job of breaking caches from CDNs and things like that, that hosts are kind enough to give us this day and age. And there's an example we'll look at a little later that shows how to dynamically generate that based on the time stamp of the last time the file was saved, which is a pretty cool sort of code style. All right, so we are on setting the dependencies for this JavaScript, and this requires quite a few. Actually, it requires precisely a few. The query is three. So this depends on WP blocks. We want to have that available to us. Hyphen, thank you. WP-blocks, we want WP-I18n for internationalization, and we also want WP-element. These are all of the globals that exist that Zach was showing off so that we can do things like register our block in JavaScript or internationalize our text strings or create an element. And if you're not familiar with WP-register script, this just makes sure that these three JavaScript files are loaded before ours so that when we reference them, the sky doesn't come crashing down. And then, oops, I have a trailing comma here that shouldn't be there. So very simple. We've got a name for our script. We've got the file URL for where the script exists, and then the other scripts that ours depends on. And we're going to do basically the same thing for our CSS, WP-register style. And this one I'll call Gutendev01, static block admin. And I'm just going to copy and paste this and change it from block.js to editor.css. And we're going to make sure that it includes support for WP-blocks just to make sure that the rest of the block styles are in before ours so that we could override them if we wanted. And then our frontend style is basically the same, but instead, oops, I shouldn't be coming it out, this one will be called front for frontend, and it will load style.css. And that should be everything we need there. So we've got our JavaScript registered at the top, followed by our admin CSS, followed by our frontend CSS. And now we just need to feed these names to our register block function down here. So there's that one. And we add in our editor style. And then we add in our frontend style. And now WordPress knows all of the things that it needs to bring along for our block to work. If we were to load up the admin area and refresh things, nothing would be different because we haven't actually created a block at all. So there's no representation. We just have a bunch of empty files. But now we can start throwing things into these and Lord willing, they'll all work perfectly the first time. If not, I've got the ready-made cake in the oven that I can just pull out and show you all that I'm such a great baker. So this stuff, this part here should be pretty common fare for anybody who's written a plugin before. Nothing new or scary or exciting just yet. And that's when we change everything. Before that, let me jump back into presentation mode because I think I have some ideas written down about this. So there's what we just made. Now, step three, let's create the block. Draw your circles, do the rest of it. And unfortunately, that's basically how this is going to go. So we've got a few things that we need to do in order for this block to work. And before I begin, how many people have created a widget before? And of you, how many found that to be a somewhat frustrating experience for the very first time you made one? Yeah, how about a short code? Anybody create short codes? Similar frustration, is that easier? I find this more analogous to creating a short code. You just need to learn a bit more. But then it starts to become more fluid, unlike the sentence that I was trying to articulate. So the very first thing we're going to do in our JavaScript file is include all of the external dependencies that we rely on, the same ones that we declared in PHP. We need WP blocks, so we can use register block type. We need elements, so we can create an element. We need I18n, so we can do our internationalization. We have to now reference all of those in our JavaScript file, give them a shorter name so our fingers don't fall off while we're typing the mile-long name that they have otherwise. We have to give it a title so that it can actually be represented somewhere with a name that people can recognize. We should give it an icon and have an asterisk here so I don't forget about the next slide where I talk about icons. We have to set a category. As we talked about this morning, there are five predefined categories, and those are the only categories that you can use today. Soon you can create your own categories. So as you're creating a whole suite of plugins, you can create a category that's unique to your brand, and all of the blocks that you're registering can go inside that category if you want. But right now you can put them in five, and really it's just four. One of them is embeds, like O embeds stuff. And it's unlikely you're going to make a block for that. Maybe you will. But we've got a few to choose from. Most of the blocks that I anticipate most people making are going to be for formatting, so that text content appears in a very specific format. Or another one, we'll look at what all the categories are in just a second. Optionally, you can register keywords for your blocks. One thing that I really like about the block inserting portion of Gutenberg is it has a search field, and you can just start typing whatever block you want to insert. And it filters this gigantic list that, let's be honest, will be mile long in a year when everybody and their brother has created a block. And you can just start typing a string to represent what block you want to find. It filters it down, and ta-da, here's the one that you want. So we're going to add a keyword so that all of ours can be found by searching for Gutendev, even though Gutendev won't show up anywhere relative to the block itself. Then we're going to define some edit functionality so that it shows up in the editor, and you can change aspects of it. And then we're going to define some save functionality so that those changes you make actually continue, and they're not just for pretend and make believe. And for icons, natively, Gutenberg supports dash icons because they're built into WordPress Core. And I feel important to mention these because there are a lot of icons that Core ships with that it doesn't even use that are just free for you to use for your own purposes, specifically for that purpose. And you can go to developer.wordpress.org slash resources slash dash icons and see a full list. If you don't like any of these, which is also fairly common because some of them don't have a lot of different opportunities for use, you can bring in your own icon. And there's a few ways you can do that, including just providing reference to an SVG file. So if you've got an SVG vector artwork that represents an icon that you want to use, you just tell Gutenberg, load up this SVG file and you've got your own nice new icon just for you. So back to code demo. This is where we write the rest of the block. So buckle in because we've got a lot of new code to learn. I'm going to go back to my code editor and I am inside of block.js. And before I go any further, let me just load up the main plugin file and point this out. I mentioned that we have all of these directories that have the directory in right now where we're making things up. And then the completed version. And then the next one that has some base code that we'll hack on and the completed version of that. This doesn't exist, it's its own plugin now. If you want to load up any of these, you just uncomment this line and now we can have the version we're building and the final result side by side. And I thought I had to namespace them separately so you can have them in queue at the same time and not blow up your installation. But I'm just going to have our working example set up now so it's not confusing as I start to show things off. And I'm going to open up block.js and this is where we're going to write the entirety of our block functionality. And as you may have guessed, we're starting out with a nice simple hello world example just to find our sea legs and make it all work. So the very first thing we need, as I mentioned, are our dependencies. So we're going to need to get register block type, which we can call whatever we want. We're also going to need our underscore underscore from I-18N so we can have translatable strings, which is important. And we're also going to need EL for creating elements. I'm actually going to uncomment these. Actually, I'll leave them commented and I'll just write it on it. I'm also going to write this in ES5. Josh is going to show up and blow all of your minds with a much nicer way of doing this. But that requires having some additional build tools and I want to just get us up and running as quickly as possible. So we're using the old and crusty JavaScript version so you can learn the hard way first and really appreciate those build tools when Josh comes to show them off. So we're going to say var register block type equals WP dot blocks dot, that's the same thing. Whoops, register block type. So now we can type it in 12 characters instead of 100. Similarly, we're going to have var underscore underscore equals, and this one's coming from WP dot I18n dot underscore underscore. And then L is EL equals WP dot element dot create element. And so now we can use all of these functions at our discretion. And from here, we do the rest. So we're going to call register block type, and this function is going to accept two parameters. The first parameter is our block name, which I'll come in and write in in just a second. And the second is an object that has everything else. So I'm going to get our block name from here in PHP because it's very important that these two things match, otherwise all of these assets that we registered don't go anywhere. And so our block is gtndev slash gtndev 01 static block. And so Now WordPress can wire all of our assets over to us and we'll be ready to accept them. And so we need to create a title for our block. I already mentioned that. And that'll equal something, we need to have an icon and that'll equal something else. A category and that'll equal something else. I skipped one and I'll talk about this in a minute when we come to write it, but supports value. And that's going to be an object actually. And then we've got our keywords that I mentioned. That's going to be an array. And then we've got our edit property, which will be a function. And our save property, which is also going to be a function. And this is everything you need to make a simple block. You create it, you give it a title, an icon, category, keywords, edit and save. In fact, we could skip supports right now if we wanted, but I'll leave it there and teach it to you now. And so I'm going to call this one static block. Nope, I'm not going to do that, it's too lame. I'm actually going to call it hello block, which is equally lame, but more fun. And I'm going to wrap this in the underscore underscore function that we brought along, which will allow us to do all of our internationalization. So if someone in Italy, nope, I don't speak Italian, if somebody in France wants to translate this into their own language, they can write bonjour block. And it will work automatically without us having to change a thing, which is nice. Oh, it is a hard requirement now, huh? The text domain. The text domain. So I'm going to give this the text domain of Gutendev. That's a good call. Prior to last week, I think, was it, was that when they finally brought, before they brought in support for the underscore underscore function, but they didn't bring along name spacing just since I started talking. Yeah, that's perfect. And so now it works identically to how it works in PHP, which is fantastic. I wrote up all my original examples like this and then was pointed out like, well, it doesn't actually support the text domain yet. So you don't really need that in there. Now I feel vindicated. The icon that I want to use is actually smiley because that's a fun way to greet people. And the category for this is going to be common. So there, I can't remember them off the top of my head. We'll look at the next example where I have it all already documented and we'll walk through the different categories that exist. And I'm also just going to be a bit fastidious here and put some nice line breaks in each of these. Maybe make this a little bit bigger, so it's easier to read. So we've got our title, we've got our icon, we've got our category. This supports declaration here. There are a few features that you can explicitly declare support for or against with each individual block that you register. For now, you're really just declaring, you are denying support for different things. So I want to say that we do not support HTML without this here. By default, every block supports an HTML edit mode. So somebody inserts a block and then they don't like some particular thing about it. They can click on the little advanced menu and choose view as HTML and just start editing away as HTML, just like you do in the normal editor in WordPress right now where you can change from visual to text mode. You probably don't want to allow that in most of the blocks that you're registering, generally. There may be some cases where you do want that because sometimes you need to make just a minor tweak to one implementation of the block and you want to have the freedom and flexibility to modify the HTML. In this example, I don't want that. I don't want anybody touching the HTML from this. And so I'm declaring explicit support against HTML editing. There are a few other ones. I can't remember the thought top of my head. That's why Google exists and why code documentation exists and I just look those up when I need them. Keywords for this, I'm just going to add GutenDev as a keyword. You could add up to three keywords. So that is also a thing that I really like to make sure that plugin authors aren't just stuffing tons of keywords into their block. So when you go to search for something, how many people have tried to search for a stock photo ever, just like an iStock photo? And you search for something like fireman and then you find like a pile of flowers and you're like, why did this person add the keyword fireman to this photo that's clearly a floral bouquet? And then you look at the description as like a floral bouquet that could be great for a fireman. Like this is not what I want. These are not why these keywords exist. Do you want to hear a good one? Yes, I do. Okay, client who is a tennis pro? Yeah, I want to know. Goes to show you. Keywords can be a dangerous thing. And the dev behind Gutenberg had a very good head on the shoulders when they said, we're going to allow three keywords per block. I was expecting that story to end a bit more explicitly. I'm glad that it didn't. You know what happens when you search Nasrallah? I don't. We are not going to do a live demo of that just in case. Cool, so the basics are all taken care of. We've got a title and icon, a category, some keywords. Now we can do some stuff that we want to inject in the editor when someone adds this block. And I'm going to pass props along to this function. So the properties that exist for this block can be fed into the edit function so that we can reference them and get things that we might need later back out of them. And the only thing that edit is technically responsible for is returning the markup that needs to appear in the editor. So we just have a return statement. And in here, we're going to put some HTML that gets put in the editor. Similarly, the save function, the only thing it's responsible for is returning some HTML that gets saved by default into the post content so that when someone hits save or update, all of the changes that they've made get brought along with the post content. You can bring in other things into this. Like it's not exclusively restricted to a return statement, but it must have one, just like filters in WordPress. I've heard, I've never done this myself, but I've heard that some people forget to put a return statement when they've added a filter. And sometimes the post title disappears instead of applying whatever additional stuff they wanted to add to the post title. So they tell me that it's very important to always end your filter functions in WordPress with a return statement, otherwise nothing shows up. I've never had that problem. Your miles may vary. I've also never told a lie while speaking in front of a large group of people. I have massaged the truth a bit. So in this case, I'm going to use the EL function that we brought in up here for create element. I don't have to do this, but I'm going to do it because it'll be necessary later. And the EL function, the create element function, accepts three basic parameters. The first one is the type of element that you're creating. So in this case, we're going to create a paragraph. The second is an object of all the different properties or attributes that you want to pass along to the element. So if this were an anchor tag, you'd want to pass the href or an image, you'd want to pass the source. In this case, I'd like to pass along the class name. And in this case, it's going to be props.classname, because that's fed to us. And this is one of the few cases where you have to slightly change what the attribute is. We can't just use class, which is how this is going to be rendered in HTML because class is a reserved keyword and things will break if you try to name your object class. So because of that, the common convention is to use class name, and then we can pass in whatever CSS classes we want to use and everything is okay. But if we wanted to set, like I said, with an anchor tag, we could set href exactly as you would expect to write in HTML, just href. And then the third parameter that it accepts is the content. So this is hello block. And this is what we'll get, whoops, I forgot a comma. This is why code linters are nice. They show you they have an error before you try to load it in the browser. So we're creating a paragraph element. We are passing along just one parameter to it. We're giving it a class name, which will be inherited from this block dynamically. And then we're giving it just a little bit of output, which is hello block. And we could be proper in here and also namespace this so that this can also be translated. Yes. Oh, props, yeah. So props are automatically available to us in the background, courtesy of React and other stuff that's for us. We could call this whatever we want here, but when we call the edit function, WordPress is feeding to us props and some other things as well. Magic. So let's scroll over. Oh, yeah, yeah. Can you get class names? I'll repeat it. Josh is trying his darn just to make sure all this gets documented. Oh, sorry about that. So the question was where is this class name coming from? It's getting dynamically injected, but sort of what is setting this class name? How's it getting there? And then Zach had a great answer. Which is after the namespace where you see GutenDev 01 static block, that's going to be the class name that it assigned. So every block will automatically get a unique class based on its unique name. Yeah, WP-block dash whatever. Yeah, so it'll look like this. So it'll be WP-block-your namespace- whatever the actual name is. And this is all just built for us dynamically behind the scenes by all the other infrastructure that's powering Gutenberg. There are a few other props that come along for free for the ride. And the best way to find out about those is to take a look through the documentation that exists for Gutenberg or to go spelunking through the code and just sort of find things that way. So I had a question about the namespace. What is the namespace and why do you include them in the underscore functions? That is great. So I keep saying namespace here and underscore functions. What I mean is text domain. So a quick aside. Translation is very important when we're building things for a global audience. If we want our plugins to be adopted by people who don't speak our language, we want every text string that we're using for titles, for buttons, for links to be internationalized so that someone can translate it. So WordPress core has a few helper functions for this. One of them is underscore underscore. There are a few other variants specifically for when you want to inject something into an HTML attribute. For instance, there's one that will automatically escape it for you. It's ESC underscore ATTR underscore underscore. So it's like applying escape attribute with the underscore underscore function. So this does not actually do any translating itself. There's no magic here, but this declares this string as a translatable string. And then there are tools like PoEdit. Basically we'll generate a file that has all these strings that someone who speaks another language who is bilingual can say ah, instead of hello block it should say bonjour block. And they'll write the translation. And then some other magic that is baked into WordPress will do the text string substitution for you. And then to get to the point of your question, this text domain helps to differentiate between your hello block and my hello block, which might be translated completely differently. This is a bad example, because those would probably always be translated the same, but you might have one set of words that means something contextually different than another set of words, because our language is very imprecise and stupid like that. The English language, I mean. Did that sort of get at the heart of what you wanted? Yeah, so you get to declare, the question is when you're defining this, this is sort of for the entire thing. And yes, you'll want to pick a text domain and use that throughout your entire plugin. So WooCommerce, for example, has a text domain that is WooCommerce. That way, everything that they build inside of WooCommerce can all be included in the same translation file and then be all translated the exact same way. See, let's see. So we've got all of our stuff here. We now should have enough written that we could go into the editor and see what it looks like. But before we do that, I'm going to add some editor CSS just to make sure that it shows up really fancily. So before I do that, did I keep that? Did I delete it? I already typed it up once, so I'm going to save myself some time. The class name that gets dynamically generated here, we already talked about, is always prefixed with wp-block, hyphen whatever your namespace is, hyphen whatever the rest of your block is. So it's just taking this whole thing and hyphenating it all. And so in my editor.css, if I make this declaration and say background and we'll just pick a nice shade of green, that one's pretty good, I think. And we'll set the color to be white and padding of 1M, all for good measure. So now if we come into our code editor, let me make sure I actually have local running. Good, we'll pop up in the admin, type in my super secure and unique passer that you couldn't possibly guess. There's four characters that I can type left-handed. So we're going to go to our posts and we're going to create a new post. And this will be called a static block test. We get a bunch of text in there. And so now let's add ourselves. I'll just go down here at the bottom. We'll add a new block and under blocks, under common blocks, look at that. Hello block, what do you know? Ta-da, and we add that and look. I'll drag it up so you can see it, so it's not at the bottom of the screen. Or we'll do it like this. Dragging things under pressure is hard. There, ta-da. And now we can publish this. And our post is published and we can go view it on the front end. And here we see, oh, there's no hello block here. It's not there. Anybody guess why? We didn't put anything in the save spot. Yes, good job. So now we can come down here and we can save something. So we can do the exact same deal, basically. And we can do return L. We don't actually have to pass in our class name. Greg taught me this because this is automatically injected for us. Greg, is that true in the admin area too? Is it automatically passed through? No, okay, yeah, so it's a little awkward here. In the admin area, if you want that class name available, you do have to pass it in. But on the front end, Gutenberg has your back and they automatically merge in properties like class name. So you don't have to do it. And we will automatically inherit that class name when we go to look at things in the front end. And in fact, we'll save here. Refreshing will not change anything. When this loads, it's still gone because that only gets put in the post content when we save, excuse me. So if I refresh this, the block has changed, which means we've destroyed it. So we have to add a new one for good measure. So let me, there we go. This is one UI change that sort of backslid. There used to be a much more obvious introduction of these ad blocks. And it's sort of less intuitive at the moment. I have full faith that it'll come back and be intuitive again before it actually ships. But you just click in between a couple of blocks and then you get this nice insert block interface. So I'm going to add in our hello block again. I'm going to hit update. And now I'm going to come back here and we're going to refresh our post. And now it says hello block, yay. And if we right click and inspect on this, oh cool Chrome updated in the background. Love when that happens. Zach, what was the slick trick you used to increase this? So I have to click in here, yep. And then command plus. So we can still see that we have WP-block, hyphen-goot and dev, blah, blah, blah, blah, for days. This class is automatically injected just like Greg promised it would be. He's a truthful guy. I knew we could trust him. And so we can duplicate these styles. But instead of it being green, we could make it red. And if we refresh this admin area now that we've changed our styles, I thought I did, let's go look here. Did I type it wrong? Asset slash style, I registered it. We've got goot and dev one and I've got it there. It was magic the last time I ran this test. There it is. Just have to hit refresh one more time. Now we have a nice red block. And if we go back to the admin area and do a hard refresh here, which was the trick, it's still green because our admin CSS is overriding because it loads our front end CSS. And then our admin CSS. And then to the magic of the cascade, the admin overrides the front end without having to increase specificity at all, which is wonderful. So we have just created our very first block. Give yourself a round of applause. Now, back to the previously scheduled content here. Now, for something you'll really enjoy. It seems like an awful lot of work to just register a paragraph tag, right? We had, I didn't count all the lines, but there were quite a few lines just to get a paragraph tag into the content. Well, good news. WPCLI can generate everything that we just wrote in two commands. So you call WPCScaffoldPlugin and you make your plugin. And you can have a plugin. You call WPCScaffoldBlock and you give it a slug, you give it a title, you can declare the icon that you wanna use, the category you want to use, what plugin this block belongs to. And it creates that. And then one line of PHP in your main plugin file, you call requireOnce and then whatever name of block you just created. And you have everything that we just wrote plus dozens of lines of inline documentation. In fact, not to make myself seem any less important or awesome, the version here, the complete version, was generated from WPCLI. And then I just stripped everything else out and worked backwards to show you how we got here. So their version is 104 lines long, but that's because we've got all sorts of nice inline docs here that explain what each of these properties are and how to use them and why they exist. And if I go to this category one, I can now read to you the five core categories are common, embed, formatting, layout and widgets, which correspond to what you see here. If we go to add a new block, we've got common, formatting, layout, widgets and then embeds are kicked off to their own isolated island over here. So those are the five categories that you can use by default. And just to prove that there are no rabbits up my sleeve, we'll back up. Nope, I'm going to do this in SSH. Oh geez, darn UI colliding. Well here, do that. There we go. I can do WP scaffold plugin and I have to hit enter because I can't ever remember what the things are. So we'll call this my block demo. And I think that's all I need based on how I created things. Yep, perfect. And then WP scaffold block. And what does it need? So it needs a slug. We'll call this hello block. It needs a title. Hello block. We'll call it WP CLI block. And we need a dash icon and we'll use the same smiley as before category. We'll put in common. And then plugin needs to be that same plugin that I just created. What did I call it? My block demo. There we go, spelled block wrong. That happens, happens a lot. So we've got my block demo. It should already be active here in our plugins. We'll leave this. I don't need to save that. Oh, didn't activate, forgot to do that. So we activate my block demo. We go back to our post editor. We edit our static block test. We'll click in down here and we'll add a new block. Forgot the line of PHP. Let's, I gotta go back. My block demo. So running WP scaffold plugin generated all of the stuff here. I could have added hyphen, hyphen skip tests to not include any of the testing stuff. And then doing scaffold block generated this blocks directory here. And inside the hello block.php you can see that we've registered our script and both of our styles and we call register block type and pass it along all of those assets. Here you can also see that slick trick that I mentioned where it uses the file time of the actual asset to set the version number for the script. So every time we save our JavaScript this file time gets updated and therefore the cache busts. So we don't have to fight with it if you're working on a site that has really aggressive caching. Which is what you want except when you're developing things and nothing works you can't figure out why and it'll write it's the cache. Which cache? Static page cache. Object cache. CDN cache. There's a bunch of caches. Clear them all. Oh my gosh, the site collapsed. What are we? Sorry, falling into a tangent. So we've registered all of this stuff and then in this directory we've got all of our assets with everything that we wrote plus way more content in nice inline documentation. So it's pretty slick. There's another tool called create gluten block. Are you showing that off at all? I'll pull that up real quick. I don't have it in my notes but I will add it. If anybody is familiar with Create React app if you're in the React world and writing lots of JavaScript you've probably heard of Create React app to automatically generate some boilerplate for you for working with React. This is an awesome zero config library by Ahmad Awais that will generate a Gutenberg block for you as well as all of the additional build tooling that you'll need to do some pretty fancy stuff like Joss is showing off. So you just type create gluten block and you give the block a name and poof, it creates an entire plugin with the block with your package.json set with your webpack config set and it's magic. It's beautiful. It'd be way overkill for this block that we just made that's only adding a paragraph tag but when you go to create things in the real world this might be pretty cool. In fact, I'm going to add this live here in person to a new slide. We'll say this one. Now it's a link and now it's also white. This is a pretty cool thing that you may also enjoy. And now, suddenly things don't look so bad. We can get our boilerplate up and running in just one or two command line commands or after you've already written it copying and pasting it across the board as you need it for every new block that you create so you don't have to write the same boring stuff over and over again. And then we can focus on just making cool neat things. So, now we can make the static block editable and actually dive in and make it useful because while having an uneditable block may be useful for inserting things like ad placeholders. If you're working with a publisher who has to have an ad block that shows up after the first paragraph or after the second paragraph they could drop that in. They have no reason to configure any of that. Ta-da, you've got a static block. They can just drop it where they need. You may have other things like that too. Business requirements for the site where they just need to have a way to insert a thing and you don't want them to have any control over changing that thing. A static block is perfect for that. But usually people want to be able to change some infinitesimally small part of whatever it is that you've just made for them. And now you're gonna be like, ah, they need to change the salutation before the author's name in the author bio block that they're using. Let's make it editable. Let's make that text string something that we can change. And so there are only a few things that we have to change from our basic static example to make it a fully editable block. First, we need to bring in one new element which is called rich text. We don't need this strictly speaking, but this is nice because it does a lot of work for us that we don't have to do. So we can just say, I want to insert this rich text component and it figures out everything else it needs to be editable and bring in other cool things if you want them. We need to add an attributes property to our block. So we have a place to save this configurable message that people are writing, or at least a place to store it so that when we save the content, we can get what they typed and put it into our post content. We need to register a handler to watch for these changes in the data because now we have a property that exists that can change. So we have to do something when that happens. We don't get that for free. And I didn't do this prior because we didn't need it, but we have to pass props through our save function as well so that we can access props and then do something with them. So I go right back to being in our code demo. And if your sample block that you wrote, we'll close this, did not come out functional on the other end, sorry about that. We are here to help you with that, but don't worry that shouldn't stop you from participating in this next section because PrestoChangio, we have a brand new editable directory that you can work in that has a working version of what we just built plus some documentation to explain what we just built. And now we can start hacking on this. So before I dive into editing this and making it fancy, I need to remember to include it. So we are going to include our editable block and now we can start mashing on it and making it cool. So I'm going to collapse my static complete example and I'm going to dig into block.js because this is where we're going to start making our most important changes. And as I mentioned, the very first thing we have to do in here is include support for that rich text editor element. So I'm going to add var, we're going to call it rich text. And this is from wp.blocks just like our register block type and it's simply called rich text. Now we have a rich text function and we can stuff that wherever we want it. Or the rich text editor. If you have poor text, I'm afraid there's no support for that. We only support rich text. Middle class text is actually considered a subclass of rich text and you can use rich text for that. All right, so we are going to add, we're going to change the icon here because smiley doesn't make sense for what we're about to do. I'm going to change this from just being hello world. I'm not going to make it say hello, my name which is where you probably thought I was going. We're going to make this into sort of a notice, an alert block. So we can add some more noticeable text to the front end to sort of call out some very important thing that a person needs to know. Like this post was edited and you'll want to scroll down to the bottom to see the new paragraphs, for instance. So I'm going to use warning for this so we get a nice big exclamation point in the admin area as the icon. I'm also going to change it from the common category to the formatting category because what we're doing is we're applying a specific kind of formatting to the text that people are typing in. It's sort of the mental model I worked through for picking that category. We don't need to change supports because I still don't want to support HTML mode. Although we could take this off and allow people to edit this in HTML. That's your choice. I'm also not going to add any other keywords to this. And I realized that I, yeah, that's fine. So we're going to get right into our editor here and instead of returning a paragraph tag, we're going to return rich text. And this has a whole bunch of properties that come along with it. I'll fill those in in just a second. And then the content that it's going to use is props.attributes. Hang on, my notes are failing me here. No, just kidding. We don't have to pass anything along. That gets said as a property. So we're using rich text. We're going to set a bunch of attributes here, a bunch of properties. I have this problem. I don't know if the rest of you do when you're learning things on your own online. I use a lot of words interchangeably that aren't actually interchangeable. And I don't realize that I'm wrong until I'm talking to another developer and they go, sorry, what was that thing? Case in point, the interchange of, what was I saying, text domain and namespace earlier, those are not the same thing and it's very bad to conflate them. So we're going to set a bunch of properties on our rich text element. And that will include things like the tag name that it's going to use because it can morph into whatever we want. I'm going to make this a div in this case. We're also going to set the class name, just like before. And this is coming from props, just like before. Next, we're going to set the placeholder. So this is what it will say before somebody types something in. And we want this to be internationalized so that people can change it. And it needs to go into the Guten-Dev namespace and type something important as what I'm going to use for my placeholder. You can put whatever you want there. We're going to set the value and I realize that I put single quotes around the placeholder. That's a force of habit, you don't need those. Value is going to be where we pass through the value of our attribute. So this is props.attributes.message. And now you might be wondering where the heck is this message coming from and what are these attributes that we haven't talked about before? We have to define those. Another question is, how do I know what all of these things are and what to set for these properties? I'm just really smart and I can, I have an index that has all of this information in it. You could ask me about anything. That index is called Google. It doesn't actually work in this context because everything is new and shifting. So I know what these are because I looked at the documentation. There's already quite a good deal of documentation that exists for Gutenberg. It's almost as though the people who are building it want us to start using it as quickly as possible. So a note to all of you developers who are building things for other developers, consider writing your documentation first or immediately so that when you release your thing it can explain itself to the people who you want to use it. Because you're just like, I made this thing and there's no docs. I'm probably not going to use it. You, I'm probably not going to use my library if I push it out like that. But if you have documentation people can read it and figure things out. We could go spelunking through the code and if we go to, do I have this linked? I may have forgotten to actually link that. Where did I put my notes here? I did. So let's go very quick on a virtual field trip to GitHub slash WordPress slash Gutenberg. And in here, there's lots of docs, like I said, which is wonderful. I know that we want to go into blocks and then we want to go down to rich text, which is the one that we just imported and look at all of these properties that they've documented for us. So we can track the value when things change, what the tag name should be, what placeholder we want to use, if we want it to be multi-line or not. A whole bunch of other things that we're not even going to use because we don't need them for this demo, but this one component is really handy for a lot of cases. Most likely it's going to be your go-to anytime you have some editable aspect of any block that you're creating. There are bunches of others, right? I scrolled through a bunch of stuff. There's a bunch of different components that exist and I would encourage you to click around here and see what kinds of cool things you can find. Good question, Zach. So we've got a tag name, we've got a class name, we've got a placeholder, we've got a value, but right now we have no idea where this value is coming from. We know that it's going to be a message and it's going to be some sub-property of attributes, but we have no idea how we got there or what that is. We have to define those attributes. And so we can define that up here. We could define it at the bottom too if we wanted, but I'm going to put it here in our object. And attributes is an object. And here we can stuff in all of the sort of attributes that we care about, all of the different configurable aspects of our block. And in this case, we have one called message. And this is also going to be an object. And here we are describing two WordPress, essentially, where we're going to try and find this value when the admin editor loads. The nice thing about this is you can stuff this data anywhere you want. So as I mentioned by default, this goes into the post content. If you were replacing a meta box, you have a custom meta box in the admin interface and you want to make that into a block, but you don't want to have to risk transporting every single person's data from being post meta to being stuffed in the post content, you can continue to keep that in the post meta table. In fact, you may want that for a lot of things. If you're making a dynamic block that's fetching posts from some API, and then you want to find out where all of the posts that are using this API call, because I need to update those, instead of trying to parse the post content for a thousand posts, which would be a nightmare, you can just query post meta, like you've already been doing, and find all the values that are in post meta that have this and change them there. Which is really nice. In this example, we're just gonna stick to stuffing things in the post content, and then we'll learn how to change that later on. But because of the versatility here, we have to describe explicitly, this is what kind of data we're working with, this is where that data exists, and then depending on where it exists, some additional parameters to be very precise. So our message, I'm going to declare the type to be an array. And you may be wondering why are we making this an array, because it's just going to be a string, it's going to be a message. Well, I don't want to limit people to a single sentence, maybe they want to have a couple of sentences, which means that we've got a couple of paragraphs. So then instead of having a text string, we have a few text strings, because we have multiple paragraphs. When we extract those, we get an array of objects. So our data type is going to be an array. The source, this is also going to be confusing for you, I apologize, is children. And then we need to specify one more thing, which is the selector, and I need both of these here so I can explain them in tandem. This is going to be Gutendev-notice. So what's going on here? So we have a selector, which is a CSS based selector, which is going to be this container that I've created that has a class name of Gutendev-notice. So when this instantiates, WordPress is going to be like, ah, I've selected this object. What part of this object do you actually want to use for parsing this value? And I want to say all of the children elements that exist inside of it. So we've selected a div, and inside that div are two, three, four paragraph tags. And in JavaScript, all of those are objects, right? We have the div object and then each of those paragraph objects. So those are the children. If we were working with an anchor tag, for example, we might want to pull out the link text as one editable value and the link href as another one. So instead of saying source children, we might say source href, or no, it would be attribute href. I'm going to stop trying to show this off live because I didn't rehearse that part. But basically you give it a selector and then you tell it what attribute you want to use. And so you can rebuild an anchor tag in your save function without having to risk somebody editing an anchor tag as HTML to change the link text or to change the href. Similarly for an image, right? You want to have them insert a full width image and they need to be able to change the source of the image and the alt text for the image. You can give them just a couple of inputs for changing those. On the front end, it gets written. When on save, it gets written as an image tag and we've jumped those values in. When we come back here, we pull out just those values rather than pulling out the whole HTML and trying to parse it ourselves. But in our example, we have a div container that we're about to make. And inside that div container is whatever people want to put in there. Maybe it's just a couple of words. Those words are going to get wrapped in a paragraph tag at which point they will be a child of the div that we've selected. Clear? Murky? Yes? Bingo. So the statement as a question is, doing this, we can also then sanitize what values were typed in and that's exactly right. So we don't have to necessarily blindly trust that what somebody put in the editor is safe. If somebody wanted to inject some malicious scripts in here and we didn't have these advanced techniques for getting the data out and working with it, they totally could do that and then we've got a compromised site and somebody might not know about it. And so by doing this, we can both, we can sanitize it when it's being output and we can escape it when it's going into the database. I mean, practice good code security. Excellent question that I was totally going to skip past and now I get to explain. Okay, so back down into our edit function, we now know that this message attribute is one that we defined as a property of the attributes. Attributes, plural, that's important. If you typed it exactly as I wrote it, you wrote it wrong, shame on you. Attributes is plural because it can be many different attributes, always, even if only specifying one. And as a habit, I like to, except when I'm talking apparently, always end in a trailing comma so I don't cause a breakage when I go to add another one and I forgot this comma and it throws an error like, hey, I was expecting a comma here, what happened? I don't know, man, you put the comma there then. Sweet, so the next thing we need to do after we've set our value is we need to also set on change, focus and on focus. So on change is where we declare what should we do whenever something inside this element changes? Well, we want to capture that and save it. So we are going to create a function for doing that and I know that I'm going to call it on change message and we'll come back and write that in just a second. And then for handling focus, I can tell you, because I cheated and looked ahead, we want to set props.focus when this element gets focused and on focus, which means when this is focused, during that focused state, we want to do, or during that focusing action, we want to set props.setfocus. Now I got to cheat, because I can't remember if it is capitalized the way I wrote it. It is good. So back to our blackout. Real quick, props.focus is deprecated. Oh, good. Props.isSelected. It'll work, but like it's going to throw a notice. So, okay, props.isSelected. Is, or sorry, here. Yeah. Good to know. This is why I have co-teachers. So props.focus doesn't exist anymore. In the last 15 minutes, we've pushed a new version. So props.focus. Brian, this happened like, oh, two weeks ago. Two weeks. I'm way behind. That's ancient. So props.isSelected is storing whether or not this element is selected. And so we want to know that and pass it along to the element so that it can properly represent its focused state. And onFocus, so when someone clicks on it, we want to setFocus to true so that that change propagates elsewhere everywhere that it needs to be known. And this should be everything that we need for now to have a nice editable text field. The exclamation point icon for a warning that I wanted. And uh-oh, it has encountered an error. So what do we do? Well, when this happens, we right click and inspect and we bring up the console. And we can see, if I scroll back here, onChangeMessage is not defined. So I referenced this for handling the change, but we didn't actually define what onChangeMessage is or what it does. So let's go back to our edit function here. And I'm just going to declare it as a function. I'm going to call it onChangeMessage and it's going to get a value. And I know that because I tested it. But during onChange, we're sent the value of whatever came across during the change. And so now we want to take this value and we want to set it to be whatever our message value is and our attributes. So there are a few ways we can do this, but the best way is going to be to call setAttributes. So we do props, which we're getting from here passing along, dot setAttributes. And inside of this, we specify which attributes we want to change and what value we want to change them to. So we want to change our message attribute and we want to change it to match whatever the value was blindly. We're just going to let people type in whatever they want here. It's important that we type that correctly or it won't work. And so now, anytime somebody changes the text, it gets sent to this onChangeMessage function and then it gets passed to setAttributes where we update our message attribute with the new value. And now, if we come back here and we refresh and reload and close this for a second and we add our block and this time I'm just going to use the shortcut that they gave me. Look at this. We've got something. It's not quite editable. Oh, I know why, because that's not actually the one I wanted. Hello, editable block. Wait, it's still broken here. Search text name, class name, placeholder. Pay no attention to the man behind the curtain here. I also didn't quite do it the same. Yeah. I think you might be right. Let's, real quick, let's make sure that the working example is actually working there just in case. Okay, so that part works. So that's not true. No, you didn't break it, but I did. So let's debug in real time here. So we've got a couple changes here. In the working version, I forgot that actually wrapped rich text in a div for good measure. So we've got a div and we're passing along, oh, I know why, props.classname and we're setting classname to that. And then the content of that div is this element which is going to be rich text and it's gonna have all these properties. We give it a tag name, we give it a class name, we give it our placeholder, we set our value, we set on change, we set focus, we set on focus. I might still be running an older version of Gutenberg and I might not have it selected, let's see. So these should match and we'll come back and do a refresh and reload and it'll be gone and then we'll add it again let's see if it was Josh's fault. By the way, this is what a lot of Gutenberg development is, making a change, refreshing the browser, starting again. Nope, it's not Josh's fault, it's something that I did. So we'll just go ahead and paste the working example in there. Ta-da! This is why it's good when you do live demos to already have the thing written and within reach. Somewhere, I perhaps missed a comma or typed a value wrong and there's a dumb typo and that's really frustrating. It takes a long time to debug and you wanna waste everybody's life doing that when you're in front of them. Okay, so we have now this editable text thing and if we refresh this, did I actually save it? I did. And we add one more time and we insert this. There's an important text message and blah, blah, blah, blah, blah, blah, blah, blah. That's good. But it's not gonna save because we haven't updated the save method to match. So we need to change what's going on here during save so that all of this text that we're writing comes along for the ride. And in order to do that, save also needs to know what the props are because we have to access those in order to get the message attribute. So we've got that and in this case, I'm going to output a div and in this div we're going to have a class name and what did I call it? Guten dev hyphen notice. And I name spaced or rather I prefixed my class name because notice is already used by WordPress in the admin area for a completely different thing. We don't wanna inherit those styles. And then the content of this div is just going to be our props dot attributes, rebutes dot message. And so now we've got this editable version and then when we save, we just dump in this div with a class name of Guten dev notice with these additional custom content into it. And so if we save this and if I update this as is, it's still using the older version because I didn't refresh. And it'll say post updated, view post, great. And then we'll go to refresh and oh no, it's broken. Because I didn't refresh first. So don't be alarmed. We'll remove the broken version, we'll add a working version and now I'll type this is an important message. Really important. Can't even hit all the exclamation points. And now we update this and it says post updated, view post and if we refresh, good news. The message is still there exactly as we typed it. And if we come to the front end and refresh, good news. The message is still there exactly as we typed it. How neat. But this doesn't really capture my attention that well. It looks kind of dumpy in fact. So let's also change our styles. We're not gonna keep any of these, those are kind of lame. Instead, I'm gonna set the background to a nice yellow. I think ffc is what I want. We're gonna set the border to a slightly darker solid ffa, nope, ff7, the color just to make sure we've got a nice almost black. We'll put some padding back in there. We'll make it 1.5 Ms all the way around. And then we'll add a box shadow because we can. And it'll be zero pixels, three pixels, five pixels. RGBA, 0, 0, 0.15. So nice soft shadow. And now if we come back here to the front end and we refresh, that gets my attention. Let's make it a little bit better. We'll add a margin of two, nope. And auto, we can even add a max width of 720 pixels if we wanted. And we refresh this and now we've got this nice noticeable thing here. And then we can delete the editor styles. We could delete the entire file if we wanted, it doesn't need to be there. But I like saving it just in case I wanna come back and add some custom styles. And now we've got this. Look at that, that's nice. And we can even make it multiple paragraphs and update and we refresh. Indeed, it's still multiple paragraphs. And if we come over here, indeed it's also multiple paragraphs because WordPress, thanks to the rich text editor, makes this experience really rich. And if we expand our div, whoop. Well, pay no attention to the man behind the curtain. I promise it brings along all the markup with it. And that is basically all we need to make our block editable. So let's recap real quick and then I'll ask if anybody has any questions here. Make sure I did all my edits in the right space first. Good, good, good. Okay, good. So all we added here to make this an editable block is we brought in this rich text function which creates a whole bunch of stuff for us. We changed the icon just because we could. We changed the title because we should. Moved it into the formatting category. This is important. We added our attributes so that we can capture the state of whatever that message is while someone is editing their content. We passed in our rich text element through the editor adding a new on change message handler for this value that we're changing. And then on save, we capture that message and pump it into a div that we gave the name GutenDev notice. And that GutenDev notice class is important. You can pick whatever class you want, but it's important here because that's how we're selecting it when we come back to the editor and it takes that HTML that was generated and makes it into an editable block again. So we select the GutenDev notice. We get all of the children that exist nested inside of that which makes it an array. And that's what we need in order to have a nice simple editable block. So question time, because I covered a lot of stuff and Josh is going to come out with the microphone. All right, so I make. Don't mind me. Man down. So recently I got into theme development. Okay. So my question is what prerequisites as far as understanding I guess ES6 or React, would you recommend for learning how to build blocks? I know very, very little ES6. Turns out I actually know quite a bit. I didn't realize this because I just started gradually writing it as I've been learning JavaScript stuff and I realized like, oh, this is the newer stuff. This is what ES6 is. Okay. So if you're learning modern JavaScript today, it will only help you. It's not a hard requirement. Basically, anytime you encounter like, what the heck is this doing? What does this mean? You just research whatever that thing is and learn that new thing. If you want to learn JavaScript basically soup to nuts, I know a guy named Zach who has a very, very good JavaScript for WordPress course that's super detailed, has lots of stuff and his Gutenberg.courses course, that's the URL, covers all the important stuff you need to know specifically in the context of Gutenberg in order to make the most of your experience working with Gutenberg. In terms of creating themes with it, not super important because right now for the most part, Gutenberg is just saving content either to the post content or to post meta and then you're still just interacting with it via PHP and HTML and CSS like you always have. It does make way for it to be somewhat easier to start creating full react apps working with the same Gutenberg data and if you want to start doing that then you definitely need to learn React and ES6 or ESnext actually and all the stuff after that. Yep, no problem. Sorry. There we go. What about if I want to be like custom-deam? Like right now we see it as a plugin. It's better doing it as a plugin or we can apply the same principle in a custom-deam. Yes, this is a great question that I'm surprised we didn't actually talk about already. Anytime you're creating a block, you definitely want to register that block as a plugin because if you register it as part of the theme and somebody wants to change their theme, poof, all of the support for all the custom blocks that you've just made are gone. They change their theme and they go to look at a blog post and everything is just broken when they go to edit it because there's no declared support for that block. So always, always, always register your blocks as plugins. Now declaring styles for your blocks that you'll probably want to do more heavily in the theme. Like you should always have at least some baseline style in the block in the plugin so that someone who's using your plugin but not your theme still has something that looks nice but if you want to get like really precise and specific for matching the elements of the theme that styling should go in the theme. Similar to when you're creating say a widget as a plugin. You'd have the widget all declared in a plugin but then all the custom styling that needs to match the design of the theme goes into the theme rather than in the widget. Question for you, right here. In Gutenberg is it possible to filter blocks only for certain post types? Yes, that's another good one. So yes, does it already do that? Yeah, yeah, okay. Wait, do you say no? Give the microphone to Greg. He's gonna have the much more precise answer here because he's actually building Gutenberg. So the thing is that at the moment you have every blocks registered by default. You can specify which blocks are not provided for the CPT but what happens like all the blocks are still there but in the inserter and everywhere else where you would pick, they don't show up. But we of course are working on the way of providing completely customized set of blocks for every CPT so then you can lock everyone to whatever you want. Cool, so it'd be similar to the supports thing where you're saying I don't want these blocks at the moment. Yeah, more or less because it's still... Yeah, so this part's in flex. Experimental, I would say. Yeah, the direction where this is going is going to be really awesome because you'll be able to declare entire templates for instance. Like one of the most promising thing about the current layout builders that exist like Beaver Builder, which is my favorite, they have pre-configured templates. So you say, I want to start from this and it jumps in with all these modules already done for you. That is where Gutenberg is going to go. That works now, it just can't... Okay, cool, so you already can declare templates but people can fully modify them and eventually you'll be able to restrict it and say like, I only want these five modules in this order for this post type. Yeah, so for you who are watching live stream and for the video, right now you can't exclude other ones from existing. That's the part that's still sort of changing, which is why Greg's answer was sort of hard to deliver at the moment. Yeah, also I want to circle back to the focus and on focus because this one has changed and we checked that in between and on focus is happening for you behind the scenes on the moment so you don't need those two lines. Oh yeah, perfect, I was hoping for that. This is one of the things I'm like, this doesn't seem super necessary if I'm just feeding it what it should already know and Greg confirmed, we don't need to do that. It does that for us and by the time Josh is done talking, we'll probably already have support for things being excluded in the editor. Wouldn't that be amazing if it moved that quick? If you wanted it to move that quick you should contribute because I know everybody would like more contributors. So you registered the block in PHP. You can also add attributes there, I believe, right? In PHP instead of JavaScript? Yes, so in the PHP where we registered the block all I'm doing right now is passing along the assets that we want but we could also pass along some attributes here for the moment and you basically can define them in all of the same way. I don't like doing that because in the context that I've been playing with Gutenberg most it's been for replacing things like a short code which this doesn't really save me anything. I need to have the attributes defined here in the JavaScript because I like my code to be expressive and I wanna be able to interact with it and make it work. So I want it here and then in the PHP where I'm say replacing a short code I still also have to declare short code attributes inside of that for backwards compatibility and so this is one more place for me to define the attributes instead of eliminating a different place. But yes, you can declare all of the attributes here in PHP along with the assets and that gives you a bit more control for making them accessible server side for setting things like defaults for say a particular post ID or doing other neat things and then long term as Greg mentioned eventually all of the stuff that we're doing in straight JavaScript should be also possible in the PHP so you could theoretically write it only in PHP. Yeah, I'd add there three good cases right now to use PHP registration like by default I'd use JavaScript but if you're doing a server side rendered block which at the end of my example code I switch from JavaScript to PHP attributes because I'm going to do server side rendering and so you need the attributes to be known in PHP land. The other one that is if you're going to do something where the attributes are created on the fly based on like database queries or some sort of configuration file or you've created some sort of more object oriented approach it might be easier to dynamically generate blocks or attributes from PHP code especially because you can do like database queries more easily or just not have certain blocks based on certain news like that kind of weird stuff that's going to be more tricky to do it might be better to do it all on the server side especially if it involves permissions. In the back I think, did you have a question? I think guys it's tricky to walk like a week we need to have the shisher in order to speak. In response to what you were just saying why would you prefer PHP for dynamically generated data as opposed to a front end JavaScript model or like an async await? So I would prefer that in the case of it's easier sometimes. For example if I'm adding a block that does what a shortcode also does right because a shortcode pre-exists or we need backwards compatibility you know 4.9 can use the shortcode 5 can use the block that callback is super similar to a shortcode callback so in my everyday life this is one of the things I do is register a render callback and then plug in the exact same function that the shortcode callback is wrapping. So that's a very easy migration path. The other thing is that sometimes it's not worth doing that extra HTTP request right like what point is it like oh I can write a two line PHP function and avoid all the complication of front end JavaScript versus like okay well this is a complex app that might need front end JavaScript. Does that make sense? Cool, any other questions for this? I just, maybe this is just a simple question here but in your first example in the key words part of things in the block.js file I didn't see you do any internationalization is that possible through the key words and when it, when you do the internationalization and somebody searches it does it actually work with that language? That is a great question, I believe it is possible. Yeah, so Greg gave me the thumbs up. Yes, you can internationalize it in thick. I think I did that in the later example without even thinking about it. Let me look at my first example. I did not and then in the second example, I did. Yeah, so you can internationalize it so that someone can translate it to be whatever that keyword is for their language which is just slick. Sweet. One question up front. Can I get Josh to run? How do you say block? How do you say block in French? Le bloc. Je parle français un peu mais je ne parle pas très bien which is the best thing I know how to say in French which is I can speak French a little but I don't speak very well. The very important thing to know I can also say je voudrais aller au cinéma. I wanna go to the movies. That's it, that's two years of French in high school. Sweet, I think this is a perfect time to segue then and take a five minute break. Round of applause for Brian. Okay.