 Okay, we are live, we are recording. Welcome to everybody joining us today. Apologies for being a few seconds late. I was having some Zoom issues. I think I may have either incorrectly copied a meeting URL or not set something up properly because when I opened up Zoom today, I didn't have a scheduled meeting to trigger. So Alvaro, who's co-hosting with me today was pinging me on Slack to say, hey, where are you? And I'm just going, I don't know. I don't know where I am. All good. So welcome everybody. While you are joining, if you are going to code along with us today, please do get your local environment ready. You will need a local WordPress installation using something like local WP or DevKinster or WPENV or MAMP or WAMP or any of those. You will also need a code editor like VS code or Sublime if you want to code along with me today. And then the part one block code, which we worked on last week, if you haven't got it, we will download it during the course of the Zoom session. So you've got some time to get that set up and then just pop us a message in the chat and let us know where you're joining us from and maybe what part of the world you're joining from. I am going to turn around and pour some water into my coffee because I made my coffee a bit late today. So give me a minute. And Alvaro, why don't you reduce yourself while I'm doing that? Yeah, my name is Alvaro, I'm in Spain. I'm a happiness engineer in the WordPress.com. Where are you all from? Have I been pronouncing your name wrong? Have I been saying it Alvaro and it's Alvaro? Yeah, like it's got an accent mark on the A, but I rarely use it because it messes up the alphabetical order because of things. Yeah. Yeah, so we've got folks from Docker, we've got folks from Munich. Everybody's signing in, this is good. Cool, so yeah, those of you who don't be high from India, those of you who've never seen me before, my name is Jonathan, I'm from Cape Town in South Africa. So I'm way deep into the Southern Hemisphere and it's starting to get lovely and warm here now. I'm an extroverted code instructor, I'm currently sponsored contributor to the training team at Automatic. Hi, Adrian from Anaheim and you can find me for as long as it's around on Twitter at John underscore messenger. It's been an interesting few weeks watching Twitter sort of implode. Okay, so today we are going to be following on from a session that I started last week, we're going to be building some WordPress blocks without using React. And when I say without using React, what I mean is we're not going to be using JSX which is the React sort of syntax for building elements. We're not going to be using the build tools, we're just going to be coding vanilla JavaScript. Last week we built a very simple block which I'm going to just open up the link to here quickly. Let me grab that out and pop that in the chat quickly. My screen just did something weird and an effort affected you all. But if you want to grab that plugin you can do and then I'm just going to save this onto my desktop now. And I'm going to open up my WordPress install. No, that's the wrong one. This is the problem with calling your, naming your things after products that exist. I think I really have it installed. No, I don't. So let me just add it now quickly. If you want to code along you're welcome to install it as well. If you were here last week and you were working through that code and you still have that code from last week you can use that as well. But basically what we built and I'll go through it all in a second was just a very simple block that renders some content to the editor renders some content to the front end. And we're going to basically be building on top of that block today. Before we get started let me get some announcements out of the way. Let me just change this. Welcome everybody. And thank you also to Alvaro for her co-hosting today. Thalma was supposed to be joining us today but she's not feeling well so Alvaro stepped in at the last minute so I appreciate that. We are presenting in focus mode as always but if you would like to please do consider enabling your video. If you would like to react to my workshop you're welcome to, you don't have to it's on a requirement. You are welcome to ask questions as we go through the session. You're welcome to either post those questions in the chat or unmute and ask those questions. The only thing that I do ask is if the question doesn't specifically relate to what we're doing on screen at the time then please hold it. I do have pauses where folks can ask questions that are sort of tangentially related to what we're doing so please try and hold those or just ask them in the chat and Alvaro will see them and if he feels like we need to stop and cover them he'll let me know. Okay, then I'm supposed to be talking about this at the end of my workshop but I often run out of time so I like to cover it first but if you are following the tutorials and the workshops and the things on the Learn WordPress website and you want to share your voice about what you want to get from the platform, what works, what doesn't work please consider taking the Learn WordPress Learner survey. It's basically our sort of process of gathering feedback from the community about what folks think we're doing well, what we need, what new topics we need and we would like to get as much feedback than that as we can while we busy plan out our goals for the training team for 2023. So please do consider taking that after this workshop or whenever you have time. Final reminder, if you are coding along to download that zip file so long or you can do it in a second but it will be handy to have that. And then the last few things if I'm going too fast, please stop me and let me know. I will be posting the session to WordPress TV afterwards sometime during the course of the day tomorrow. So if you want to catch up later, you can do it that way and then for more WordPress focus content please do visit learn.wordpress.org. There have been some awesome block development courses added there recently some block theme development courses. So there's lots of new content coming up all the time. So please do check that out. Okay, our learning outcomes for today. So today we are going to, first of all, have a look at last week's course and just remind us how is what we did. Then I want to dive into some sort of general developer tools, principles for block development. And it's just some of the things that you can use in the browser and some of the processes that you can follow to kind of make your life a little bit easier. Then we're going to add an attribute to the block we built last week and the attribute we want to add is so that we can enable users to edit that block. We're going to make it possible to edit and save the block attributes. We're going to be doing a very simple way of doing it. And then we're going to implement a slightly more advanced way which is to use the rich text component to give a better user experience. So those are the five things we want to try and cover today. Our actual fine detailed objectives is that I want to kind of review browser dev tools and also how to clear the browser cache because those are things that I use a lot when I'm developing blocks because everything is JavaScript based. We're going to change, when we have a look at the code, this will make a bit more sense but one of the first things we're going to do is we're going to change the element, the DOM element for the edit function from a paragraph to a text area so we can make it use editable. We're going to add the string attribute to the block and then we're going to spend a bit of time talking about the difference between the block props and the block props. Now those sound the same but they're kind of not. So we're going to talk about that and make sure we understand what those two things do. And then we're going to use the attributes content in the edit function. So we're going to, I'm going to show you ways that you can access the attributes in multiple different ways and then you can decide which process in which path you want to take. Then we're going to update the save function to use that attribute so that when it saves the block it saves the attribute data and is rendered on the front end. And then we're going to add the unchanged functionality so that when a user makes a change it actually saves it in the right places. And then finally, we'll implement the rich text component just to make it look better. And you'll see what I mean when I say make it look better when we get in there because when we use the text area, it doesn't look great. It's not a great user experience. It doesn't give a lot of functionality but using the rich text component does and it's a way that you can use WordPress packages, WordPress components inside of your block code. Okay. I'm going to pour some more water into my coffee and pour my coffee in my cup. If anybody has any questions or if anybody needs to get set up or get their local environment set up now's a great time to do it. Well, I wasn't used. And usually I have my coffee ready to go before these workshops because of the Zoom issues I had earlier. I didn't do that. So you have to be with me when I move some things around on my desk here. Do I have one question? Yes. So can we get the recording? Yeah, go ahead. Yes. So the recording link, I won't be able to do it at the end of this meeting but I will do it tomorrow. So during the course of my Friday because when I do these workshops they're right at the end of my day. So I basically finish the workshop, close my laptop and I go home. And then first thing tomorrow morning what I do is I download the video from the Zoom account. I upload it to WordPress TV and then I share the link to the meetup group in the comments. So you will definitely get the recording sometime during the course of the day tomorrow and you'll be able to then watch it whenever you want to. So thank you for that question there. Okay. Let's get to some coding. So the first thing I want to do is I want to just review the block code that we worked on last week. If you've downloaded the zip file you should have this in your local WordPress install as well. My Visual Code Studio is not coming up. So let me open this up over here. So in the plugins directory it's the wp-learn-javascript file if you've installed it and activated it. And in that file we created a few files last week. We created the block.json file which contains various information and metadata about the block. It has a title, it has the name of the block. Last week I think when we were doing this we called it basic block. I've updated that to make a JavaScript block today just so that it's easier to work with. So if you're using the code from last week please consider updating yours to match mine to wp-learn-javascript-javascript block. We set the category, we set the icon and we set the editor script file which is basically the block code. We also set some styling so we set the editor style and the main style. Then we worked on the block code itself and this is what the block code looks like and we basically are just using the blocks element and block editor packages from the WordPress global object and passing them into our function. And if you remember that function is a automatically running function or IFFE I can't remember the details of it. I just want to actually, while I think about this I want to, I don't think I had it here in my resources. No, I didn't. I want to share the recording of this workshop from last week. So those of you who want to watch it see what we did last week can do that. So it's going to be around here somewhere. No, it's not. Let's do this. No, I'm not going to find it now, am I? Developing without, there we go, developing without react. That's part one. So if you want to see how we built what we're working on today this is part one. This is what we did last week. You're welcome to watch that and then try this out later but for now we're just going to continue on. So we use this create element function and we basically pass it to a variable and then we use that to create the element in the edit and save functions of the block. Here we are registering the block type, giving it the same name as we specified in the block JSON and then we have edit function which is all the functionality that happens in the editor and then the save function which is the functionality that happens when the block gets saved to the database. And all we did was we had some text. So hello JavaScript world, hello JavaScript world. We implemented the block props which is a special react hook which we're actually going to talk a little bit about more today. So we understand what that does and how it works and you'll see on the front end we'll talk about what that did. And then the other thing we did was we created this block asset file which basically sets up all the dependencies. So it was the blocks dependency, the element dependency, the block editor dependency and that polyfoil which enables all of this non-react stuff for us. And those are the three main files that we needed in terms of creating the block itself. And then lastly, the fourth file was just initializing the block in PHP. So using the register block type PHP function passing at the current directory so it can find the block.json file to start registering things and taking it through from there. So that's everything that we did last week. So Bob says change in the block name also changed the class name that was great to imagine. Yes, good point. I'm getting to the styling now. It's a very good point there. Then the styling we did. So in the block JSON we said there was an editor style which was the editor.css file and the style file which is the style.css file. So in the editor.css we had the class name that was automatically generated which was WP block learn JavaScript JavaScript block. So if yours is basic block and you wanna follow along please change that to JavaScript block today. And we just created a green background white color for the text and 20 pixels of padding. And then for the, I'm going very fast with this I do apologize, we'll stop in a second. And then in the front end styling again learn JavaScript JavaScript block and we gave it a red background white color and 20 pixels of padding or 50 pixels I think we did last week. I'm leaving it at 20 now. So it's a very basic block very simple, very straightforward. If we have a look at that in WordPress we activate this and we go into a post and we add that block. And this is why I renamed it JavaScript block so it comes up easier when I search for it. That's all it does in the editor it's just some text we can move it around at least and that was where block props came in handy the ability to move it up and down the ability to remove it from here. And then if we preview this in the front end it has the red color, there it is in the front end. So that's all we did last week very simple, very straightforward. That's the basis that we're gonna start from today. Does anybody have any questions around everything that I've just gone through very, very quickly if you weren't here last week if you haven't ever built a block from scratch before some of this might be new unfortunately I'm not gonna be able to cover it again but you can watch that recording that I shared earlier but does anybody have any questions around all of that before we get started? If you don't seem to have questions so I think we can get going. We can have a question. Oh, here we go. This is if you could ask the toolbars or not having the upper block that your screen shows but as soon as I add everything was working fine. Oh, yes, I remember you had that problem last week. Excellent, I'm glad you got that worked out. Excellent stuff. Okay, so there don't seem to be any questions so I think we can move forward. So just as a reminder, the documentation that we're working through is in the block editor handbook. So if you go to developer.wordpress.org in a browser and you're welcome to open this up because we're gonna be using some of this code today. On the developer resources page, the third item from the top says block editor or at least in my English version it does if you're using a different language or color it might say something different but it's usually the same icon. And then you've got this link for building of blocks and that takes you through to the block editor handbook and then there are these how to guides. So I'm gonna open that quickly and the first one is accessibility and the second one is blocks. Now, one of the reasons that I'm doing the series of workshops is because the way that the block editor handbook is kind of put together as you can see is alphabetical. So accessibility first then blocks then development platform and then C comes and it's kind of very difficult when you're first building blocks to know where to start. And so what I did when I first started building blocks was I hit this how to guide and I hit this blocks how to guide and it was a tutorial to take me through. But then there's got some links of moving around and build steps and all kinds of other things and I found it very difficult to follow. So the goal of today or at least the goal of this series is we're gonna work through each one of these pages and understand what's going on on the page. Last week we did the create a basic block step. So it was setting up the block JSON file, setting up the block registration, setting up the edit and save functions, adding the dependencies and then making sure it all works. And then the next thing we did was we, the next tutorial was the using styles and style sheets. So we didn't go the inline style route. We discussed it very briefly but we went the block class name route which is what Shabam was mentioning earlier. We implemented use block props and we use the class name that that generates. And then we enqueue the style sheets, the editor.css and the style.css. And that's where we ended up. The next one is attributes and editable fields which is where we're going to start today. So if you have that open up in your browser, please do navigate to that page now. And the very first section is about attributes. So it says there until now the edit and save functions have returned a simple representation of a paragraph element, which is what we saw earlier. We've also learned how these functions are responsible for describing the structure of the block's appearance. If the user changes the block, the structure may need to change. To achieve this, the state of the block is maintained through the editing session as a JavaScript object. And when that update occurs, the edit function is invoked again. So what we need to do now is we need to now figure out how can we maintain the representation of that object to be able to allow folks to edit it. And that's where we could start using block attributes. Okay. Now, if you have a look at this code and if you scroll down or you can just have a look on my screen here, I'm going to scroll down to the bottom where they show the attributes being registered. You'll see that they're registering in this code example. I'm going to switch to the plain version. Why is software trying to update when I'm doing a Zoom call? No, go away. In this example, the attributes are being defined inside the registered block type function. And if you'll remember from our first step, when we created the block JSON, we set those things up in the block JSON form. So when I was working through this documentation the first time and I saw this, I went, but hang on, now my API version, my title, my icon, my category is suddenly in my registered block type. Should I be doing it this way? And the answer is both ways work. You can either register your attributes as an object in the registered block type or you can do it in the block.json file. So one of my goals is going through these workshops is also to get this documentation updated to follow a specific process one or the other with notes on the alternatives. But here it's got attributes being defined inside registered block type, but we can define the same set of attributes inside the block.json file. So all I'm going to do is I'm going to copy out this attribute section here. It's the content type, source and selector, just this part over here. And then I'm going to switch over to my block.json file and it doesn't matter at what point you insert the attributes. Personally, I like to do it after the name field in the block.json file. That's just a personal choice. You could make it first, you could make it second. It's a json object, it doesn't matter. But I like to do it after names. I'm going to pop that in there. And you'll see immediately it starts throwing me some errors because in the block.json file, my field names need to be in quotes. Whereas when you specify them inside the, let me go back to the browser, when you specify them inside the registered block type function, you can just leave them without quotes. So that's the one difference. So back over here, I'm just going to see if I can, this is not going to be allowed me to do this. I'm going to have to do it manually. So I'm going to put attributes in double quotes and then I'm going to put content in double quotes. And then I'm going to put type in double quotes and source and selector. And then it's also giving me the same issue here with strings, I have to do double quotes there as well. And the same for this one and the same for this one. There we go. And then I'm getting some errors on the commas and that's because JSON objects don't like a comma at the end of an object in the last item. So I'm going to remove that and I'm going to remove that. And that's what I end up with. Now, if you just type all of that along with me or if you're looking at that on the screen and you're going, okay, sure, but what does that all mean? That's kind of what we're going to dive in today. But for now, all I want you to do is understand that we're setting an attribute with a name or a title if you will have content. So we're going to be referring to content. So it's the content of the block. It has a type of string, which means it expects some form of string. So not another object or not necessarily something else. It has a source of HTML, which I'm going to explain to you in a second and has a selector of P, which is a paragraph tag as those of you know HTML. Now, what that means is when I apply this attribute to my block, it's going to look for a DOM element or an HTML element, if you will, with the selector of P, in other words, a paragraph tag. And it's going to read the HTML source of that paragraph tag. And that's where the source HTML comes in as the attributes content. And when it updates the content, it's going to update that back to the same place. So that's what all of that means. Now, if you open up, I think I've got this in my resources. So we will grab that now quickly. Here we go, block attribute. So this is the reference guide in the block editor. Let's go ahead and open up that. I'll just pop that in the chat. And it talks about block attributes providing information about data stored by the block. So this is your block's data. So you can have multiple attributes. You can have rich content. You can have a list of images. You can have background colors, button titles, all kinds of things can be attributes of a block. So we can think about them as like variables of a block. It can contain a number of attributes and these are specified by the attributes field. An attribute definition will contain at a minimum either a type or an enum. So what that means is we can actually, if we go back to here, we can actually take all of this out and just specify without the comma, just specify the content attribute as a type of string and then it'll work. But now I'm gonna leave that in, but we could do that if we wanted to. And if we go back to the documentation here, it shows some examples. So you might have a URL attribute, which is a type string and it's going to get the image selector. So the image tag of the block, it's gonna look for the SRC attribute on that selector and then it's gonna get that value and put it into that string and store it and save it for the block. Or you could just have a title that is just a type string or you could have something like a size. So there's multiple different attributes that you can set up. Now, they only really become sort of understandable once you start applying them to some kind of element. So for now, if it's confusing, don't worry, because as soon as we start applying it just now to a text area, you'll start understanding what's going on. Okay. Any questions on setting ups of attributes? Adrian says, yeah, Adrian says, if this is how you could add an ARIA label. I actually think, and we're gonna dive into this in a second. The ARIA label I think is actually set by the block props. So hold on to that question, Adrian, because we're gonna get to that in a second. So what I wanna show you now, and I'm gonna jump back to my slides to remind myself what the next step was because I've forgotten. Oh yes. We wanted to look at the code. We wanted to say, oh yeah. So I've jumped ahead a little bit, but we wanted to first review developer tools and browser cache because I'll get to it in a second and we wanted to change the element for the edit function. I'll get to that in a second. But let's go back to the code and let's just see where those attributes come into play. So if you're coding along with me, open up your block.js file and inside of your edit function, inside of that function, open, close brackets, just put in the word props, okay? You don't have to make it props. You can make it properties as well if you want. Either one would work, but the sort of industry standard is to call it props. And then what I want you to do is I want you to console log props. So console log is a developer tools thing that you can do and it'll output the value of that variable to your browser developer console. But what I also wanna show you is something very cool which is, and this is part of the showing you how DevTools works, is you can actually set up an object by using the curly braces and then give it just as you would a normal JSON object, give it a name or a title or whatever and I'm gonna call this edit props here. And then when it logs to the console, I can actually then see where the code is. So if I've got multiple things that I'm logging I can give them names and I can find them easy. So that's all we're gonna do for now. So in the block.json, we're gonna set up the attributes. We're gonna set up the first attribute called content and we're gonna give it a type string, source HTML and select to P. That's all we're doing there for now, all double quoted, making sure you take out the comma there and the comma there. And in the block.js, we're gonna add props to the function. So basically it's a parameter for the edit function of props and then we're just gonna console log props here and then have this edit props, props notation there. Okay, I'm gonna pour my coffee quickly while I wait for everyone to catch up and then we'll show you what this does when you switch over to the editor. Okay, so hopefully everybody's up to speed with that and they're gonna be able to see what this does in their website. I'm gonna switch back to my browser here and I'm gonna go into my post and I'm going to remove the block and I'm going to turn on developer tools. Now, depending on your browser, depending on which browser you're using, I know this works in Chrome. I know Chrome has developer tools. I know Firefox has developer tools. I know the Windows Edge browser, which is based on Chrome has developer tools. I don't use Safari, but I'm pretty sure Safari has developer tools as well. There's a combination of shortcuts that opens it. Sometimes F12 opens it. In a Mac, if I have a look here, if I go to more tools, developer tools is the, what is that? That's the option command, alt button, whatever it is, but each browser has a developer tool somewhere. It's a very good idea to have developer tools open when you are developing with blocks. The one reason is so that you can log things to the console and you can see what's going on. The other reason is if there are any errors, those errors are going to get logged. And when you start developing with blocks, it's a good idea to open up your dev tools and see what errors are being rendered without you doing anything with your block so that you can differentiate between your errors and WordPress errors. Now here, for example, we've got an API fetch error. This isn't a WordPress error. This is probably my local environment not being able to connect to some external service, but you'll see here, there's a jQuery migrate thing that's been installed and there's the core separator block that's rendering to the console. So this is the kind of stuff. So now I know if I ever see a different type of error, I know it's related to my block. Okay. If I now add my block to the post, I should have seen a console log there because I did that in the code. Now, one of the reasons I might not see that is because you're working in JavaScript. Sometimes the JavaScript gets cached in the browser and there are a few ways around this. One of the ways you can do it is to use something called browser caching where you apply it like a timestamp version number to your scripts and all those kinds of things. But one of the cool things about Chrome specifically, and I'm sure the other browsers do this as well, is if you have DevTools open and you right click on your refresh, reload the page option. So if I right click on here, there's an empty cache and hard to reload option. And that's very cool because now it's gonna clear the cache and things should start working for me. So I always have DevTools open and I always use the empty cache and hard to reload jobs. And you're gonna see me doing that a lot today. Okay, so let's reload that and let's see what happens if we add that JavaScript block. We should see things log into the console. So let's do that and there we go. Now we're seeing the JavaScript log into the console. I'm gonna make my console a little bit bigger here so that folks can see it. So if we look at that object we've set up, there's the edit props that we set and there you'll see it passes the attributes through to the props. It also passes things like a client ID, it passes a context, it passes something insert blocks out, a whole bunch of other things related to the block. Now, Adrian was asking me earlier about an ARIA label. Now, if you don't know what ARIA is, it's related to accessibility. And as far as I understand it, you can set those labels to different properties to make them accessible in a certain way. The use block props that we used last week is where that gets it up. So what I also want you to do and we're gonna kind of dive into the difference between props and use block props here, I want you to copy that line out and I want you to create a second one and we're gonna say this is block props. And then I want you to copy the, in fact we can't do it there because we haven't set it up yet. So let's take this block props var and just put this right at the top here. So that we have it set up and then we're going to log that there. Okay, so now we're just logging the first props parameter, which is the one that's passed to the edit function and the blocks props parameter or variable, which is the one that we set up by calling the use block props react hook. Okay, if I now refresh this, now what I'm going to do is I'm going to remove my block and I'm going to empty cache and hard reload and I'm gonna, as I say, I'm gonna be doing this a lot today. If we then re-add it, we should then see two things being logged to the console. Okay, so there's edit props and there's block props. So let's make that a bit bigger and let's make that a bit bigger. And you'll see at the top of the block props, the ARIA label is being set. So that's automatically created because we're using used block props. And here's where we need to spend a little bit of time understanding the difference between the properties of the block and block props. Okay, now block props is what's known as a react hook. And our react hook is just a special function that does a certain bunch of things automatically. Last week we learned that the one thing that it does is it sets the class name. Now we've learned it also sets the ARIA label. It also sets a data block attribute, it sets a data title, it sets a data type, it sets an ID. And all of these things get applied to the block element, the main block element. So if you right click on your main block element here, this text area here, and you inspect this, this will take you to the element. You'll see that all of those things we just saw in block props, I'm trying to make this so that everybody can see this, things like the ARIA label, things like data block, things like data type, data title. These are all being applied to that paragraph element that is the main container element of the block. So if we changed, for example, this block to be a div, which we can do now. So let's do that quickly. So what I want to do is I want to change this over here to a div element. So that's all I'm doing. I'm changing it from paragraph to a div. Gonna save that. And we're gonna switch here and again we're going to empty cache and hard reload. And then we're going to add that block and we're going to inspect it again. There you'll see now it's a div but it has the same ID, the same ARIA label, the same data block, the same data type, everything from the block props. So to reiterate block props is a special function that does a whole bunch of things automatically and it applies those things to the main container of your block. Whatever your main container is that you set, it applies those things. The props that we pass to the functions are specific properties related to just the block itself. So it doesn't affect things on the outer container but it's how you can pass things like attributes around. It's how you can update attributes and it's important to understand those two different things. Later on in this workshop we're actually going to pass some of the props to block props and we're gonna work with it there but it's good to understand what those two things are and how they are different and how they interact differently and how they do things differently. You'll notice that if we go back to the console edit props, if you have a look the name comes from the block.json exactly as we have it set up in the block.json. It has a client ID. It has the attributes from the block.json. It has other things that it adds or remove or replace but it's specific, sorry, kicking my mic there. It's specific to the block whereas block props is specific to the outer element in that block and you'll see it's already created. It basically runs a whole bunch of things automatically and then applies it to that element. Cool, so we're gonna pause there for a second if anybody has any questions on all of that. Otherwise we will move on. Okay, there don't seem to be questions. So I'm going to move this over here and the first thing that I want to do is I want to make this block editable. Now, if you come from an old school HTML world like I did you'll remember that one of the first form elements that you might have learned on to make something editable was a text area. So text area is basically a default HTML element that has columns and rows and you can then type some data in there. So what we're actually gonna do is we're gonna set up the text area in this block. So I'm going to just comment out these console logs here for a second, we're gonna use them later, so leave them in. And then I'm gonna change the element that we're setting up to be a text area. That's all I'm gonna do. Okay, so I'm setting up a text area and I wanna show you what that does. So again, I'm going to remove, going to hard reload. And if I now add the block in, suddenly it looks different. As you can see, it's not a paragraph tag anymore, it's a text area. But you'll notice I'm suddenly getting some errors and these errors are not the errors that I was seeing earlier. And it's saying, what do you use default value or value on the props and various other things? Okay, so it's starting to give me some problems, which is fine. But a text area I can actually edit and I can do things too, okay? So that's kind of cool, I think, just by changing the element from a paragraph to a text area, I can actually implement text area in the editor and I can then make some changes too. These changes won't save though, because as you will remember from our code, our code in the save function is still returning a paragraph and it's still using the hard coded string. We're gonna get to how we change that in a second, but I just think it's cool to show you how that works. So let me go back to my internal notes and just change this, okay? So we've done the developer tools, we've changed the element, cool. Now we want to get that attribute from the block to JSON into our text area. So there's this cool thing that you can do in the block.json attribute and you can specify a default value. So if you add default here and I'm going to copy out this Hello JavaScript world text and I'm gonna specify that as the default value, okay? So put a comma in there quickly. So now it has a default content and then because we've got this content, we want to render this content somewhere. So let's actually render it over here. So because we've got props, props contains the attributes and I'm gonna show you how to access the attribute. So it's props.attributes and the attribute be called content. So it's dot content, okay? So we're returning the element function. We're saying it's a text area element. It still uses block props and then it passes in the content that we specified in the attributes for the block. So now we should see and let's make it Hello JavaScript world. Let's make it a little bit unique. Let's say hello my JavaScript world just so we verify that this is what's happening. But now notice something else. When we set up the attribute, we said we were working with a P select. However, we've just changed that element to a text area. So we need to tell the attributes to work with the text area as well. And that's where the selector comes in, okay? So here we can just go text area. The source is still the HTML of the text area. That's fine. It's the internal content of the text area, but the selector needs to be the text area. And that's what this error was telling us over here. If we go back here, it was saying use the default value instead of setting the children because we were setting children data instead of the value. Okay. So we've set that to text area. We've set this to text area and we've changed it to the content of props attributes. Let's see if this works. So let's remove this, hard reload and we re-add it. Okay. So now we're still getting an error. So let's see what the error says. Okay, it's still saying use the default value or value props instead of setting children on texture. Okay. Now, I've done something that I shouldn't have done. And I'm gonna have to check my code and figure out what I've done. What have I done wrong? Let me go back to my GitHub for this because I have forgotten something. So give me a second. I made some notes about this yesterday. Now that's the rich text. I think it's because I've still got the source set. Try that, if that takes it away. Nope, still getting an error. Use the default value or value props instead of setting children on text area. Okay. So this is where looks like you do not need props. So you need props to get the content. But I have a feeling it's because I'm passing it in as children and not, oh yes. Oh yes, I remember now. Okay. Let's go back to the documentation because documentation is handy to look at. And let's find there's the plane. Okay, here we go. So when you're specifying something other than a paragraph or a diff so something that is editable like a text area the way it works is you need to pass the content as the value in block props. And this was something that I got stuck with on Tuesday. So I'm surprised I forgot it today. So what we're gonna do then is we're gonna grab this code here. So if you're following along and you've got this plain code open scroll down to the edit function and you'll see it says rich text there which we're not gonna use now but grab this object assigned code here. So object assigned block props all of this down to here and we're going to use that and I'll explain in a second why this is necessary. So we're gonna take that out there and I'm going to make this on a new line just so we can see it. I'm gonna pop that over there. I'm gonna pop that in there and I'm gonna explain what object assigned means in a second. The tag name, we're gonna make text area. We're gonna leave out the unchanged content for now. We'll put that back in a sec and the value will be the props. No, not that one. Props.attributes.content. Okay. So that's what it looks like. So we're updating the element call. We're passing in the text areas, the first variable. And then in the second variable we're doing this object assigned business passing in block props and then a new object which has a tag name which we don't need but I'll show you what it does in a second and then a value. Okay, is this on the attributes page? I don't see this code. Yes, if you have a look on the attributes page. So I'm gonna scroll from the top. So this is the introducing attributes and editable field stock. Not the attributes. So not the attributes in the reference guide but the introducing attributes and editable fields in the how to guide. So the first one that we looked at. I'm gonna copy that out, paste it in the chat so that you have it. And then if you scroll down to the example code and you click on the first example and you make sure the plain option is highlighted and scroll down about halfway you'll see the edit function with the props and then further down you'll see the return element rich text object assigned part. Do you have that? Anybody needs to catch up or so we need to slow down. I'm very lost today. Okay, let's go back a step Adrian. Do you have? No, that's fine. I want you to catch up with us. Do you have this at least? Do you have this in your edit function? You're welcome to unmute if you find it easier to talk. Okay, so you've got that. Okay, then open up the link that I just sent you. You didn't get my errors. Really? Am I the only one getting errors today? Okay, so everybody else did they see did they not see this error on their side? That's interesting. That's interesting. I wonder if this is the version of WordPress that I'm running. What am I running? I cleared the cache. Maybe that 6.1. Yeah, I think I'm running 6.1 as well. That's interesting. I'm seeing, I'm seeing areas that other people aren't seeing. I'm doing six. I'm running 6.1.1. So that might be why it might be an update to 6.1.1. Let's spend some time figuring that out. Let me sort of, how would I downgrade to hang on? There must be a way I can downgrade. I can do this on the command line, but I'm lazy today. It's got a core rollback. It's called core. Yeah, yeah. Is that what you're trying to do? Yeah. Core rollback that one there. It was right there. Yeah, it's taking its time. Yeah. There you go. It's an anti-fragment plugin. Why am I not surprised? That's interesting that nobody else got those errors. So let's activate that. Let's rollback this version of core. Alvaro, we might have uncovered a bug that needs to be logged. Maybe. Okay, let's rollback this one to 6.1. And let's see if I get that error. Install 6.1. Perfect time for a sip of coffee. There's nothing that wakes you up quicker than a cup of coffee in the morning or an error that you didn't expect in a live workshop. No, Angel, it looks like I'm probably a little more lost than anybody today. Let's let this thing finish. It looks like I'm running 6.1. So let's go back to my posts. Let's go back here. Let me switch on DevTools. And let me clear cache. Let me check. That's my old plugin code. That's what I want. Excellent. Let's add the plugin. I'm still getting that error, but other folks aren't getting this error. That's interesting. So those of you who have your DevTools open, you're not seeing this use default value error. I wonder if it's a plugin that I have installed. Let me deactivate all my other plugins. Let's deactivate that one as well while we're here. I'm getting the same error. Okay, so I don't have the Gutenberg plugin installed. So Adrian, those of you who aren't seeing the error, do you have the Gutenberg plugin installed? Maybe disable it and see if you're getting it because you should get errors. It's my understanding of things. I want to make sure we're all... If it takes that amount of time today, I want to make sure we're all on the same page at least. And then we can dive into why the error happens and what's going on. So let's make sure everybody's on the same page. Yeah. You definitely should be getting the error. If you're not, then no extra plugin is still the only one we were making. So that's interesting. Some folks are getting the error and some folks aren't. So I will say this. There should be an error. I wonder if it's because... Let me just check what my debug settings are. So those of you who aren't seeing the error, can you do me a favor and can you go into your WP config file and set the WP debug variable to true and then also include this defined script debug to true. That might be why. That might be why you're not seeing the error. And that might be why I'm seeing it. Because when I develop, I leave debugging on all the time so that I see any possible errors. So those of you who aren't seeing the error, open up your WP-config and then run about line 82. It'll probably be defined. WBT bug would be false. Change that to true and then add this one after that. I'm going to copy this into the chat. And if anybody who's not seeing the error could try that out and report back what you're seeing. While you're doing that, I'm going to turn these things off and see if the error is suppressed. And that might be why some folks are seeing it and some folks aren't. You see, I'm not seeing it now. So the error is possibly being suppressed for some of you. So for those of you who aren't seeing it, if you set up those debug variables or constants and then with quite hard refresh and add the file, you should then see that error. If I do this workshop again, I'm going to make that part of this workshop as well. I'm going to hang around and wait while everybody tries that out. And let me know. Looking forward to getting your feedback. I'll pack a bag of errors. So if you scroll up at the top, you should see the same message that I got. Let's actually remove and hard reload, re-add. So you should see all of these and right at the top of that error, you should see something along the lines of use the default value instead of setting children. So if you're seeing that, yes, give me a same, give me a thumbs up. We're all on the same page. And then we can move on. Excellent. I'm glad folks have asked me that. Okay. So let's actually take a break and talk about that. Whenever you're developing for WordPress, I highly recommend having your debug constants switched on. Because this will, you see, the problem with errors is that there are different levels of error. There are breaking site errors, which you always want to see. But then there are errors that are not going to break your site and functionality might still work, but it's not the recommended way to do things. And that's this one we saw now about using the value instead of the children. And I'll explain what all that means when we get back to the code in a second. But it'll still work. The problem with the problem, and those are more sort of warnings. You also get deprecation errors. So something has changed in either PHP or JavaScript or the framework or whatever. And it still works. But the problem with deprecation errors is that might stop working. So it's better to stop using those things. And the problem with warnings as well is warnings are saying, hey, something that you're doing kind of works, but it really shouldn't. And it could lead to other things you're not aware of. So whenever you're developing with WordPress, always have your WP debug constant set to true and that'll log all PHP errors. And always have your script debug set to true and that'll log all JavaScript related errors. For the PHP related stuff, you could also define the following variables, which I like to do. I like to do WP debug, debug, display as false. And then what that does is that'll log the errors, but it'll suppress them in the browser. And then I said WP debug log to true. And what that does is that'll log them to a file in the WP content directory called debug.log. It'll send them all there. So it means while you're working with the website, if you make a PHP error that can cause your site to break, everything else will still run, but the error will get logged at least. This is also, and I'm sure Alvaro, who's a happiness engineer at WordPress, will appreciate this bit of knowledge. This is also a way to troubleshoot white screens of death and other related issues, is make sure these three things are enabled, run the site and then check the log. Alvaro, am I right? That's probably one of the first things you tell folks to do when they have a support ticket with a white screen. Yeah, we'll start there, yeah. Okay, cool. Right, so we had a little bit of a detail on logging now. Let's get back to what that error means and why the code was wrong. So if we have a look at the error, it says use the default value or value props instead of setting children on text area. Okay, so let's talk about what that means in a second. So what I'm going to do in a second now, let's talk about it now. I'm going to open up a very simple HTML file so we can dive into this because it's important to understand. In fact, let's just do this one here. So this is just the read me in the WordPress install. Now, if you've worked with HTML for a while, HTML.com, the document object model, you will know that you can do things like JavaScript. You can say, get elements by ID, get elements by name, and then you can do things like get children elements. So if we have a look at, for example, this ordered list here, if that is the parent or top level element, the children elements of that elements are all the list elements. But what isn't commonly known is that children of, for example, this H2 is the HTML text inside the H2 is also the children. Now, when you're working with things like text areas, text areas are a special type of element that allow things to be changed. So you don't, let me actually just show you, for example, an input field, you typically have a value in an input field. You don't typically write it like you would an HTML element. It's a value property, and then you update the value property. If we have a look at, let's go to MDN text area, let's go and look at the official documentation on Mozilla network, the text area element. And let's just find an example of a text area. I can show us one here. Yeah, here we go. So a text area, now here's what's getting interesting. A text area in HTML, you would be able to specify children because there's text inside the element. But in the React world or in the JavaScript DOM document object model world, you would rather use the value of the text area. So that's what that area is telling us. And that's why the code still works, because it is acceptable from an HTML point of view, just to say the children of the text area is the text and it'll render that properly. But because you're working in this JavaScript world where you're working with values and attributes and all kinds of other things, you would rather specify the value of the text area objects. And that's something that folks often get confused with when they start working with what's known as the document object model or there's another term called the shadow DOM, all these JavaScript concepts. Sometimes how the elements work in the DOM versus how they work just in a plain HTML file is slightly different. So that's effectively what that error message means. And what it's saying is use either the default value or value props of the text area instead of setting the children. So when we do this over here, let's go back to the code. If you might remember when we looked at this create element function earlier, it said the first parameter is the element that we want to create. The second one is an object of data that we can pass it. And then the third one was the children of that element. And what this code is telling us, what this area is telling us is resetting the children, but it's saying rather use the value. That's the better, more correct way of doing it in this JavaScript React T type framework. That's another thing to note is the titles of these workshops are write blocks without using React. We are actually still using React in the background. The block editor is written using React. Everything that we're working with is using React. We're just interfacing with those React elements and React components in plain JavaScript. But this creates element hook is a React hook. The use block props hook is a React hook. So we're not physically writing React code ourselves, but we are interacting with React, which is why we get these interesting errors about using values versus using children. I hope that explains it. It took me a while to wrap my head around it. If anybody's still not sure about that, I do recommend going and reading about how React DOM works, the document object model versus HTML layouts. But that's basically what the error means. So what we have to do now, if we go back to the documentation that I shared with you earlier, and this is another reason why I'm doing these workshops, because for the first time I saw this code, I was like, what does that mean? What are we doing here? Effectively, what we're doing is object to sign is very similar to the PHP array merge function. It basically says take an object, take another object and merge the two together. So in this case, the first object is the block props that we got from used block props that React hook. Then we're passing in another object and we're sending in a tag name. We're sending in this case on change. We'll talk about that in a second, don't worry. And we're giving it the value, which is what that error is telling us to do. So let's set the value of the element instead of the children. So let's copy this out and let's go back to our code. And let me just make sure that my debugging is on. Yes, my debugging is still on. And just to make this easier to read, I'm going to put text area on its own line. I'm going to put block props on its own line and I'm going to take away the content. What you could also do is you could do something like this. You could say, I think this works. You could do something like that, merge this together into block props and then use it. But the easier way to do is just to basically do it in place of block props. So what I'm going to do is that I'm going to leave out the tag name for now. I'm going to leave out the on change for now. We're just going to pass in the value. And the value that we need to pass is the same content that we passed earlier. So in other words, the props attributes content like that. Exactly the same as we did earlier. And then we'll do a little bit of formatting. Let's format that. So it looks a little bit neater. And this is what you should end up with. Okay. Is everybody up to speed on that? Let me take a break so that folks can catch up if they like. If anybody needs me to stop or whatever, let me know. Otherwise, if you're happy for me to continue, then give me a thumbs up or are you ready to go? Or Adrian says she's still behind. Okay. Are you just catching up with the code? Do you need me to wait? Cool. That's no problem. That's why it's called let's code, not Jonathan codes. But while Adrian's catching up, I will Adrian, sorry, I keep saying that wrong. I will also mention that this whole concept is something that I struggled with a lot when I first got into block development, how to set the attributes, how to pass them around, how to update them, how to change them. And my plan today for today's workshop was actually going to be to assign a whole bunch of attributes and do a whole bunch of things. And then I realized maybe we should just do one. And I'm so glad we did. So we might not actually get to where we want to get to by the end of this workshop and we might take some of it and move it to the next workshop. And that's also okay. Because it's important that we understand how this works and what it does before we can start moving on. Adrian's up to speed now, so that's great. So let's see now what we have on the front end. So let's go back over here. Let's remove this. Let's do another hard refresh. Okay. Let's add the block. Now we should see no errors. I'm still getting an error. Why am I still getting an error? Okay. Aha. The error is a little bit more understandable. So you should see a similar error to that, which is good. We'll get into the on change in a second. But basically that's the only error that I'm seeing at the moment, which is an error that I expect. So that's great. Okay. So I've got my text area. I'm busy passing the content of the attribute to the to the value of the text area. I want to show you, is anybody else seeing the same area that I'm seeing? Because if you are, that's good. That is what we want to see. Is anybody not seeing that? Is everybody happy with what they're seeing? Okay. Same area. That's excellent. That's what we want to see. Everybody's getting the same error by the looks of it. Good. Okay. Now what that error is telling us is that we need to specify an on change handler. So again, in HTML land, let's go back to an HTML file. You might remember that it would have been possible in old days, you had this on change. Event that you could specify on any kind of input value or text area. And then you could pass it a JavaScript function call or a jQuery or whatever. And basically what happened is as soon as the value or the internal HTML of that element change, it would trigger that JavaScript code. Because we have got a text area. And because we're passing it a value. React to saying to us, Hey, you're passing a value. And I'm going to assume you're going to want to do something with this value. So would you mind passing in an on change handler as well? Again, it doesn't cause the block to fail. I can still see my block. I can see my text area with the content. It's just giving me a warning and going, Hey, you know, it's actually being nice. It's being friendly. It's saying, Hey, you might have missing things. So if we have a look at the, the example code from the documentation, we'll see there, the on change handler is specified and look at the difference in regular HTML. The on change is usually all lowercase. I think camel case does work, but it's typically all lowcase. But in, in react land, you need to specify it like this as on and then uppercase C for on change. So we copy that out. And we're going to update that in our object assignment. Let me just make sure, yeah, it's inside the object to sign. Now again, it doesn't matter too much where you put it because this is just an object. So I'm just going to say on change and I'm going to specify an on change content function. I can call it whatever I want, but then I actually need to create that function. So if we pop back over to the code you'll see at the top here, there's a function called on change content. It accepts a new content variable. And then it calls the set attributes, content new content. And you might remember when we echoed the, the props earlier, there was that set attributes value. And that's a cool default value that exists on the blocks props or the properties. And it allows you to update the property. So what that effectively does is when the text area changes, it'll take that new value, pass it to this on change content function, the new content will be there. And then it'll say set the attributes that specifically our content attribute that we want to set. In other words, this one that we specified here. And set the new value of the content to whatever we're passing to it. Okay. This is going to break. And I know why this is going to break and I'll explain why in a second, but for now that's where we want to be. So we've set up the on change event handler. We've told it to trigger on change content. Then we created on change content. Say except the new content and we can call this anything we want. We can call this just new if we want. Or we go new underscore content, whatever. This is just how we define our, our parameters. And then with that new content, we want to say, take the set attributes function from props. And then update the content attributes with the new content. Okay. I'm going to pause there. If anybody needs to catch up. Otherwise we're going to test this out and we're going to see what happens. Okay. So let me show you what happens when I run this. I want to remove it. I want a hard reload. Let's reload that there. And let's add our block. Okay. So now we're not getting errors when we add our block because it's got a value that it's happy with. And it's got an unchanged handler that it's happy with. So that's a good first step. But watch what happens when I change this block. So all I'm going to do is remove the D. Suddenly it changes to this object, object string. And if you're testing this on your side, you should see something similar. If you don't, please let me know. But if you see the same, give me a same error or a thumbs up or whatever in the chat. Let me know that you're seeing. Okay. Good. So we're seeing the same error. Now, the reason this is happening is because the text area is not a specifically react element. It's just a regular HTML element. So when the unchanged handler fires, it passes not the content, but an event. And that's not something that you would necessarily know about the text area element. And it's one of the reasons that you wouldn't use the text area elements. You would use a react component in our example, the rich text component. Okay. So let's take a step back. If we go back to the documentation. You'll see it talks here about components and the rich text component. Okay. So earlier examples, we worked with, use the create element function to create Dom knows, but it's also possible to, to take that functionality and put it into reusable components. And this is one of the very cool things about specifically react, but also about the block editor is instead of just using a text area, which looks awful, we can implement the rich text component. Now the rich text component, if you open up this rich, I struggle with all of these consonants. If you open up the rich text component link, it takes you to the reference guide for rich text. And effectively it's just the component that is rendered when you render a paragraph tag in the block editor. So, sorry, a paragraph block in the block editor. So if I go back to, you move this video out the way here, I'm just going to remove my block. If I just add a regular paragraph, such as a paragraph block, that effectively implements the rich text components, which allows me to do things like type words. If I can spell them, but it also allows me to do things like set bold or set italic or specify a link. That's all happening because the paragraph block implements the rich text component. And that's the perfect block for us to use in our basic JavaScript block. Okay. Because as you'll have agreed with me earlier, the text area that we use, let me just add it quickly. Where's my JavaScript block? Here it is. It doesn't look great at all. It's sitting off to the side somewhere. There's no formatting options. I can just move it up or down. So instead of writing a whole thing, I just reuse a package that WordPress makes available to me. Okay. So the rich text reference let me just find the package. I think it mentions it here. Rich text component is part of the block editor package. Right. And if you remember when we looked at the code, we're already implementing the block editor package because we want to use block props. So that means we don't have to change any dependencies. It's a really part of the block editor. And most of the core components are part of the block editor. So what we can do is we can include the rich text component into R. So we don't have to worry about all this because this is all done already. We can do this over here. So we can say var rich text is block editor rich text. So we can just put this at the top here. Like that. Okay. And that'll make rich text as a component available to this whole function. You'll notice the other thing they're doing is they're moving used block props to the top here as well. That's also one way you can do it. I actually like that. So I'm going to do that now as well. And I'll give you some time to catch up. And what that does is that allows us to take away this here because the block editor variable that we've set up is effectively now available in the global scope. So it's there in there. Okay. So the changes I've made so far, I've added the rich text line. So var rich text is the rich text from the block editor. This needs to be in that same uppercase format as it is because that's what the component is defined as. This can be whatever you want, but I like to keep them the same. And then the same here, this var used block props is also from the block editor. So it's basically putting those objects into my function. And then what I've done is I've changed this line from, instead of saying block editor used block props, I've just said just used block props because it's in the global scope. And then in the save, I've done the same, just used block props set. Those are the changes that I've made so far. The reason I do that is it just makes it easier to work with. I'm specifying the block props in one place and then just calling it wherever I need, specifying rich text wherever I need it and then just calling it wherever I need. Okay. Once you've got there, somebody give me a thumbs up or a same or a good to go before we implement the rich text editor. Okay, works a good to go. Excellent. So now we can implement rich text. So there's a couple of changes we need to make. First change we make is we take out the text area here and we replace it with rich text. Okay. That's the first change. We don't need to necessarily make that change in the save, but I'll show you how you can use rich text in the save in a second, but we can just leave the save as it is for now. The other change we need to make in the block.json is we're no longer using the text area selector. We're using rich text. Now I want to show you what rich text renders so that we can understand what we must change that to. So if I inspect my rich text here, you'll see that scroll up. The rich text just actually renders a paragraph tag. So that's cool because now we can set the source back to whatever it was selected back to P and that'll work. So in the block.json, we can specify this being back to a P for the paragraph tag because rich text is basically just implementing a paragraph tag with all that other cool functionality. Okay. So your content attribute is still a string type because we're still working with string content. Still the P tag. The default is still the same in the block.json. All we've done is we replaced the P tag here with rich text. The rest should all just work. Okay. So let's see what happens. So again, let's remove these extra blocks. Let's do a note, not that one. Let's do a hard refresh. Hard reload as it calls it. And then let's implement our JavaScript block. Okay. So there's our block. It looks the same as it did when we first started. Do you remember? It had the green because it was just a paragraph tag. So the styling also works. The block props are still being used. So it's still the same class name. But to notice, suddenly I can do things like I can set things bold. I can make things italic. So because I'm using rich text instead of a plain paragraph tag, that's all working. I'm going to switch back to my console. There are no errors. So that's excellent. I'm going to move this over to the side so we can see a bit more of a screen. And now if I start making changes, I'm going to start doing some things in the background. Okay. Because I've done the set attributes and all of that. So that's great. There's no errors there. But what happens when I preview? It's still the original content. It's not using the attribute that we specified. So we need to change that. Okay. So if I go back to my code now, we start thinking about, well, how can we get those properties in? Well, we can do it exactly the same way we did with the edit function. We can specify the same props attribute there. And then we'll do that again. And then we'll do that again. And then we'll do that again. So you understand, you're editing your save function, they're always going to receive the properties always. Every single time. So you put them in and they will receive them. Whatever's in them, they will be available. If they are no attributes, if they won't be attributes available, if you set the attributes, they will be available. Okay. We don't need to do things like unchanged content and all of that. So we can just leave it as a paragraph tag if we want to, we can leave the block props if you want to, if you want to, you can leave the block props attributes content. There. Okay. And that should work. So let's see. So again, we remove. And we hard reload. Let's add it. Okay. That's working. Let's update the content so that something actually gets saved. And I'm going to show you just now in the background, how this works. And now let's preview this. Hello, JavaScript world. Yay. It's working. Yeah. So now how can we validate that this is working? And the one thing that I like to do is I like to use this edit props here. And what I like to do whenever I'm developing is I like to just have a very simple console log. Sorry. I'll just recode it. I like to have a very simple console log here. And I just log props attributes. So it's just the attributes of the props. Of the blocks properties. And I like to do it in an object so that I can see whether I'm in the edit or the save. And I like to do this. I like to do edit attributes. Or ATTRs or whatever you want. And then I pass in the attributes. And then I like to have in the save as well. And I have a save ATTRs. And it logs props attributes. And then whenever edit fires and whenever save fires, those functions, I will then see that data in my console. So I'm going to leave that on screen while you catch up if you want to put that in your code as well. When you're ready to go, give me a thumbs up or a good to go. And then we'll go and see what this does on the front end. And I'm so glad I didn't try and do more attributes today because we were at a run out of time. Yeah, Adrian's got it. So I'm going to move on from here. So let us remove this again. And it has hardly loaded again. And I want to show you in the console, every time the edit function and every time the save function edit fires, so you can understand what's happening in the background. So let's add the block and you'll see the edit function fires. And then every time you make a change, you see that every time you make a change edit fires. And so every time edit fires, let's go back to the code. Every time edit fires, the unchanged content fires. It takes the new content runs props attributes, set attributes function and updates the content with the new content every single time. And then you'll notice as well, sort of periodically, when you're working with the edits, the save function will fire. So it's not every time you edit. So if I edit one that's edited, edit, edit, edit an hour wait, then save fires. So you see that saves not happening all the time. It's happening like one or two seconds after the last edit. So it actually waits. However, when you hit preview, it also saves and renders it. And you can actually see those changes get made. And you'll see save and edit just fired again, just by themselves. So there's like a timer in the background that's just checking, do I need to just keep saving, keep saying, and off we go. Okay. So that's how it works. Every time you make a change, edits firing, edits firing, edits firing, it's making those updates, updating the props, and then save fires and writes it to the database. Okay. Cool. I'm going to stop there. If there are any questions around any of that, there's a few other things I do want to cover today. It's just kind of wrap cleaning up a few things, making things a little bit better, a little bit more standardized. But are there any questions around everything we've covered today, the functions that we've implemented, how we've implemented them, that anybody's not sure of. Now's the perfect time to ask before we wrap up for the day. I don't seem to have questions, but if you think of them, please do paste them in the chat while we're going. A couple of other things I want to show you. This props object contains both attributes and the set attributes function. And every time we want to use it, we have to go props.attributes and props.setattributes. There's a nicer way of doing things. And it's called, let me find the document link for you. What I did this week, just by the way, what I did this week was the first resources tab is all the WordPress documentation. And the second resources tab is all the Mozilla stuff that we were talking about. And the first one, there's the object assigned one there. The first one is the destructuring assignment. So let me show you that. So what destructuring assignment does is allows you to destruct or take apart an object and pull out certain pieces of that object and make it available to your function. So let me show you what that means in the code. If I open up an object notation here, and then I just type attributes, comma, set attributes, and you'll see that my code, my code is quite clever. It's actually expecting those things. What that's basically doing is it's basically saying, assign the attributes from the props to this attributes variable in this function, and then assign the set attributes from the props to this set attributes in this function. So now I can just remove that and just echo the attributes. And I can also just change that to set attributes there. And it does the same thing. It just means less code on your screen. And you can destructure any object like this in JavaScript. So if you're passing any object to a function as a parameter, you can destruct it in this way by just specifying the object notation and then the specific items from that object that you need. This is something that has only come to PHP very, very recently, but JavaScript has had it for a long time. And it's one of the things that I like about JavaScript is the fact that as long as you pass objects around, then you can destruct them nicely like this in your functions. So that was the one thing. And then this also changes here because I've already got attributes. I can just change this to attributes. And that's perfect. And then I like to do the same down here. I don't need the set attributes function in the save because I'm never going to update those attributes. So I can just go attributes there and I can just change this to attributes there and do that. It's just nicer and keener and easier to work with. So that's the one thing I want to share with you. The other thing I wanted to mention is that you'll notice that in the save function, we're just returning a p tag. But if you have a look at the example code in the documentation, sorry, my zoom has just taken over my screen and I can't hit my tabs now. So let me wait for it to go away. There we go. Where was it? Yes. You'll notice the save function in the example code uses the rich text content instead of just rich text. And so that's a good recommendation to do. So instead of just the p tag, let's update that to rich text content. And effectively that's just the content of the element, which will be a paragraph tag anyway. So it's effectively the same thing, but because we're using rich text here, we update it to use rich text content here. The other thing you'll see is that it's assigning the value and a tag name. Now the tag name is a... I've got the doc for that. Here it is, the element. The tag name is a specific attribute on an element. And it basically allows you to... There's a JavaScript function called getElementsByTagName. So instead of having to... Those of you who remember we used to do IDs and classes and then we used to say getElementByID or getElementByClass, you can also do getElementByTagName. So that's essentially what that's doing. So it's a good thing to follow. So it's also setting up a tag name in the block prop. So it's a good idea to do that. So let's pop that in there. In fact, we'll just do the same thing over here. Do the same object assignment because it is there. And we can take out the children there. Now what's interesting about this is because we're using the rich text element. The rich text element is effectively a paragraph. So we could just assign the children. But apparently it's better to assign it as the value, not the children. So that's why it's recommended to do it in this format. It all will still work the same. It won't give you any errors as you saw. But if you're using the rich text component, it's recommended to do it in this format. So we don't need on change. We just need the tag name and we just need the value. Okay. And let's just test that it all still works. So let's go back and remove this. And let's do a reload. Let's add it. Okay. So there's my edit attributes. I'm still seeing those, which is great. If I do that, I'm still seeing that it's still doing what it needs to do. The save should fire soon. A couple of seconds. Ooh, save. Are they really? Save is fired. Let's do a preview. Or is it just hello, my JavaScript? Hello, my JavaScript. That's all working. So it's all working great. Okay. So the last few things we did there, which is a little bit of a cleanup, a little bit of a, there's multiple ways to do the same thing in every programming language. This is more the recommended way. So I didn't want to leave you without doing it the recommended way. But that's how we can apply attributes. Now, just as we've done that, we can apply multiple attributes. And next week, that's what we're going to do. So my goal. Okay. So I'm says react create element type is invalid expected a string. Everything is working, but this is coming. React create element type is invalid. So. That sounds like one of these returns where you're using the element function has a bug in it. Um, spectator string. And I just check, is this, do your attributes look like this? So the type of string, the selectors P in the default has the default value. Okay. That's good. Then in your JS, is that what your element, your first element looks like in the edit function? So it's got the rich text. String. Okay. That's good. Okay. Then let's have a look at your, so can you copy out your block JS code? The whole block JS file. Uh, let's see what that looks like. Oh. Um, So what I, what I can say is this. Um, it's always difficult to debug these issues, you know, in a workshop. Um, so it's a little bit of props, props, props, props, I'm changing new content. So that's fine. EL rich text, block props, and P unchanged, unchanged content. It looks good to me. Let me just, um, copy this out, see if there are areas there. Better, better, better. What am I doing? I have the edit function. Easy if I just see it in front of me. Wonder if. Leave it on. I love, I love life coding this kind of stuff. Um, so what I'm going to do is I'm going to comment up my edit function and see if I can get that error with your edit function. And let's grab your save. Let's do the same thing. Save there. And let's pop your saving here. Hey, props, save block props, use block props. Unchanged new content. That looks good. Rich text, block props, tag name, unchanged, unchanged content. Any props attributes content that looks fine. Save props. You say rich text content. Let's just clean this up in props attributes. Okay. So there we go. Let's see what this does. The closed captioning is probably stressing with the fact that I was mumbling under my breath there. Let's reload that. Let's add it. Okay. So I'm not getting any errors with your edits and save code. Um, so it could be something else. It could be that something is not set up correctly up top here. Maybe. Um, so do you want to just confirm that you've got all of these things set up and that your function has all of those things. Um, but the code that you've just sent me works perfectly on my side. So it tells me there's nothing wrong with your code. Um, maybe it should be value. I should be content night. Just copy this out. Have you tried just clearing your cache? That's for no reason. Let me just do this. Attributes. This is fine. Props attributes. Tag name on change. It all looks good to me, my friend. Um, again. Okay. There we go. Often, often that's the problem. And that's why I'm always carrying my cash when I met it. That's great. I'm glad we were able to find that job. I'm not seeing, I'm not. Oh, here we go. Wanting create element type. Here we go. I'm getting this now. Um, so let's see what that says. Expecting a string for building components or a class function for composite components because I'm defined. You'd likely forgot to export your component from the files to find it. This sounds to me like it's a. Error with. Create element itself. I don't think this is a problem with your code. Um, This may or may not be a bug. Um, I just want to see something. The fact that it's a warning, I wouldn't worry too much about. Um, expected a string type isn't better expected a string. That's interesting. Um, I would say that to me, that's not your code. It's the problem. It looks like there's maybe an issue with create element or something like that. But from what I can see, your code is looking good. Uh, so I wouldn't, I wouldn't stress about that too much. I might dig into that after this and see if there's a bug somewhere. Maybe in the block edits or something like that. It could be causing this, but it's a warning, not an error. So I wouldn't stress too much about that. Um, okay. Awesome. Let's us just go back to the code. And. What was I saying something, but I've forgotten now what it was. Um, It's completely something. So I'm going to call it a day there. So. Yes. Oh, yes. That's right. I was talking about what we're going to do next week. We're going to add additional attributes and those attributes. We're going to use to replace the styling. So I'm going to add an attribute for background. For color and for padding. And then what I want to do is I want to actually have, if we look at that block. Um, Click on here. I actually want to have some, let me close DevTools. So we can see what you're talking about. Um, I want to have some settings in the sidebar. In the sidebar for the block where we can actually have a color picker that chooses the color for the background and chooses the color for the text and chooses the, the pattern as a slider for the pattern. Um, so the goal there is to show you how to add additional attributes, how to use existing toolbar components. Um, to apply those things. I was going to try and do that today, but as you can see, we've already gone over the hour and a half. So definitely not enough time to do that. Um, once again, if you are following this afterwards, if you're watching this on WordPress TV, um, this code is available on a repository in my GitHub profile. Um, so every, every step of this workshop that we're doing, I've got set up in a repository. Uh, so you can just go to my, my GitHub and it's this WP learned JavaScript repository. I'm going to copy this link out in the chat so that folks have it. Um, and I'll make sure that I add it to my slides because I don't think I did. Uh, so I'm going to do that now. And then I'll re-upload the slides for the, um, for the recording. Uh, but you can check out every step of the way. So there's the, the first step where we created the basic block, the second step where we added the style sheets, the third step where we now today did the attributes and the rich text. And then as we go through, it'll all be there. Um, that is my bit for today. Thank you all for joining me. I hope that this workshop helps you understand how attributes work, how to pass them around in the block. Um, it is to me, it is one of the most difficult things to learn about block development. So if you didn't get it today, I recommend watching the workshop recording later. I recommend going through the code documentation. I recommend, uh, reviewing the code, using console log to, to output things like, let's go back here, the props, the block props. Um, the new content in this function, you could do a console log for the new content, see that coming through. Um, so that you understand exactly what's happening because it is to me, one of the most difficult things about working with, with blocks, when you're used to PHP, where the state doesn't change much because it's, you know, it's run from top to bottom and then it finishes. And this JavaScript world, the props are moved around, they're updated, they're changed all over the place. So knowing how all this works is very, very important. Um, as I say next week, we're going to do some more attributes because as I say, this is a good concept to cover. We're going to do some colors and some styling and some padding. So I do look forward to doing that with you all next week. Uh, we've gone five minutes over time. So I apologize for that. But thank you all for joining me. Enjoy the rest of your Thursday and the rest of your week. Thank you. Bye everyone.