 All right, welcome folks as you are joining. Welcome to today's workshop. I am going to preface today's workshop by saying that I am again a little bit tired this week. Nothing too serious. It's just that my oldest son is quite sporty and in preparation for his sport this year, his school is having early morning practices before school starts. So I've been waking up an extra hour early than what I'm used to. So it's had a little bit of an effect to me. But my co-host today, Mark, who is joining us today seems to also be up really early this morning. So I appreciate the fact that you're joining us this early, Mark, and anybody else who's joining us super early this morning. I have a great respect now for folks who get up early to join these workshops. So welcome, everybody. While you are joining, if you would like to code along with me today, please do download and install the example plugin. This is a combination of the last four weeks of workshops that we've been doing. So if you have those workshops already, if you have that code already, you don't need this version. But if you don't, or if you just want to get the latest version of the code you can do. And then if you don't have it already, this is not a requirement for today, but some of the things that I will be presenting today will be using Postman. So if you would like to download and install that, if you haven't got it already, please do so. Postman is a API testing tool that I use whenever I'm testing endpoints and testing REST APIs. So it's good to get to know how it works and how to use it. And I'll be using it as we go forward with more of these REST API workshops. Okay. While everybody's joining, I'll do the usual introductions. My name is Jonathan, Cape Town, South Africa. I currently work at Automatic. I'm a sponsor, contribute to the training team. And you can find me at my website, which is my name and surname.com. As you're joining, please do let us know in the chat where you're joining us from. It's always fun for me to see where folks are situated in the world. And then I learn new state abbreviations for the U.S. that I didn't know before. So please do let us know where you're joining from while you're getting things going. I'm going to have my usual sip of coffee to keep my brain together. That's the slide I pick as anybody needs it. Okay. So MLWP says from, you're going to have to forgive me if I butcher this name Snohomish, Washington. I hope I've said that correctly. Sergio is from Port Townsend, Washington. So we've got quite a few Washington folks here. My, Mark Andrews in Baja, Mexico. My understanding of American geography is that Washington is on the East Coast, if I'm not mistaken. So that would make sense that folks from the East Coast are here because it's not super, super early. But I assume it is still quite early for you all. So welcome, Washington State. Okay. I don't know the difference. So I apologize, but hopefully I'm right in saying East Coast. I don't know. I need to learn my U.S. geography. West Coast. Okay. Well, then it's even earlier for you, Sergio. Interesting. So Washington State. Oh, so Washington, the city is in the East Coast and Washington State is in the West Coast. Okay. I'm learning about U.S. geography from you folks this morning. So thank you for that. Excellent. Right. So while John says hello from Chicago, Illinois, awesome. My few Chicago, Illinois references are, I think, Wainsworld is something about Chicago, Illinois and Wainsworld. Well, he's from Aurora, Illinois, if I'm mistaken. St. Louis, Missouri. Excellent. Folks from all over. This is really cool. Okay. So today we are going to continue on our REST API journey. The past few weeks, we've been just looking at using the REST API, interacting with the REST API, using the Backbone.js client to send and receive requests to and from the REST API. If you've missed any of those workshops, there are all on WordPress TV. The easy way to find them is to search for Let's Code, which is the tag name of my workshop sessions. And I'm glad I chose that tag name because it's actually a series on WordPress TV now. And if you click on the Let's Code series and click on the newest filter, then the most recent ones are right at the top. And there we had the use in the WordPress REST API interacting with the REST API. And then last week, we dealt with updates, custom fields, and a little bit of authentication. Today we're going to be looking at how we can modify REST API responses. So we're going to specifically be looking at the default routes and endpoints, and how we can add data to them. So we're going to look at the post endpoint, and we're going to add some custom data to the post endpoint, that's the goal for today. As always, a few announcements. So welcome again, and thank you to Mark for co-hosting with me today. It's always a pleasure to have a new co-host. So thank you, Mark, for joining us. We are presenting as always in focus mode, but if you would like to, please feel free to enable your video. If you don't know, focus mode means that I can see all of your videos if you enable them, but you can't see each other, and I should prevent any kind of zoom bombing. We do still have a few incidents of that every now and then. Then a new option I've added to my announcements. Please let me know if you can't see this slide, this announcement slide on your screen right now. A few folks like Sergio and a few others mentioned that when they connect from an Ubuntu or a Linux workstation, they don't see the screen share. And I was able to test that this morning and determine that it seems to be a combination of focus mode and screen sharing before you're admitted to the room. So if you can't see the announcement slide now, if you just see my face talking, please give me a heads up either in the chat or just unmute and say, I can't see the slide, and then I will disable and re-enable the screen sharing, or any of these slides. You should be seeing my slides on screen right now if you're not, please do let me know, and I'll make sure to do that before we actually get started. You're always welcome to ask questions. The only thing that I ask is if your question is not specifically related to what we're doing, please hold it until the pause sessions. You are welcome to ask them in the chat. I do pause for checking of questions, and Mark is also keeping an eye on the question, so you're welcome to post them in the chat as we go along, and then I will read them and reply to them when I have the sections for questions and answers. Then a final reminder, if you would like to work along with me today, or if you're watching this workshop afterwards and you want to use the tools and the code that I'm working with, this is the URL to download the plugin. I'm going to copy this out in the chat just for anybody who's joining late, and this is the URL for the postman download. Just download it for your local environment and your local operating system, should I say. And then finally, as always, if I'm going too fast, please do let me know. Tell me to slow down. I will be posting this session to WordPress TV afterwards, and I link it in the meetup.com chat, which reminds me, some folks couldn't join last week, so I'm just going to check the chat and make sure there's nobody struggling to log in. No, we seem to be all good there. Okay, excellent. And then for more WordPress-focused content, please do visit learn.wordpress.org. You will find all of our work, upcoming workshops there, all of our tutorials, all of our courses, all of our lesson plans. All of these workshops on the REST API, I am also in the process of turning them into tutorials. And the first one will be coming out, I think it's the week of the 10th of February, or the Friday, the 10th of February, which is next week Friday. That's when I plan to publish that one. So if you don't remember all the using of the WordPress API stuff, you can go back and watch that tutorial. And then finally, this is the GitHub issue that I use to track my planning for this workshop. So if you have any questions, either after the session, or if you're watching this workshop afterwards, and you have any questions or feedback about this topic or about the workshop, please do feel free to leave it as a comment on that issue. It's probably going to be the easiest way to get hold of me if you have questions, if you get stuck with anything, or you've got any follow-up questions you want to ask me, you're welcome to ask me those in the GitHub issue on the WordPress Learn repository. Okay, that was a whole bunch of words. So let's get onto our learning outcomes for today. Today we're going to be looking at different ways to add custom fields to the WordPress REST API. We're going to be focusing on the posts end point. So we've been using the posts end point to create posts, update posts, and delete posts over the last few weeks. We're going to look at today how we can add fields to that end point. We've kind of looked at that already when we looked at custom fields last week. We added custom fields, we enabled the custom field on the post route, and then we posted some data to it. So we're going to be revising that today, adding some information on there. Then we're going to look at how you can actually take a custom field or a post meta as it's so known, and actually make it a top level field in your REST API endpoints. And I'll show you how that works. And then we're going to talk a little bit about the pros and cons of both and why you might want to use one over the other. And then while we're there, we're going to talk a little bit about the schema of the REST API endpoints. And we're going to look at how you can add schema to your custom fields and why you might want to add schema. So those are our four goals for today. Our objectives to achieving those goals we're going to set up and review the code so far. I'm not going to go deep into the code today because the code that I'm going to be writing today doesn't rely on the code we've already looked at. We're just going to review the functionality that we've done so far. And then we're going to review the functionality of Postman very quickly. I'm going to create a new collection, again, a couple of new requests, just to allow us to refresh our mind on how Postman works because we're going to be using Postman quite extensively today. Then we're going to enable a custom field using register meta, which we did do last week. We're going to do it again this week. We're going to review that code. And then we're going to use the register rest field method to add a custom field as a field on the rest API endpoint. And I'll show you what I mean when I say that. And then we'll add some schema to that custom field right at the end just to kind of wrap things up nicely. Okay. Any questions on all of that before we get coding? I'm going to leave the objectives on there if anybody has any questions while I refresh my water and then we will kick off. Thank you, Mark, for reminding us that we can save the chat. That's a very handy thing to have there. Okay. Right. So I already have the plugin installed on my local development environment. My local site environment URL is learn pressed up test. It's the one I use for all of these sessions. It just helps me to have to remember what it's called. The version of the plugin you should be working with is version 0.0.4. And you can you can ensure that it's the latest version by hovering over the tools menu in the dashboard and then going down to the WP LearnRest API submenu item. And you should see a screen that looks like this. It has the load posts and clear post button at the top. If you click on load posts, it loads all of your current posts in that text box, just the ID and the title. It has an add post form that you can use to add a post. It has the update post form that you can use to update an existing post. And it has the delete post form. I'm not going to dive into the details of how those work. If you haven't seen this coding in action and we've covered it in the previous sessions, you can you can check those out on WordPress.tv. But that's how you know you have the latest version of the code is you have all of those those forms on the in the WordPress dashboard. If I switch over to my code editor, the other way you can check is right at the top of the plugin PHP, the WP LearnRest API PHP file. There is this register meta code where I'm registering a URL post meta field also known as a custom field. And I'm setting the show in rest argument to true. And what that does is that enables that on the meta which I'll show you in a second in postman. And then I'm going to very quickly go through this code because we're not going to use much of this code today. But this is the admin menu code. This is the admin menu callback which loads all of those form fields that we're using. This is the NQ scripts function which loads the JavaScript file. And that's all that's sitting in the PHP code right now. And then in the JavaScript file, if we open up the WP LearnRest API JavaScript file, there is right at the top, there is a clear fields function which is what fires when you click the clear post button. There is a load post function which loads the post when you click on that button. A submit post function which is what submits the post using the backbone JS client to the rest API. Update, again, it updates. Delete, delete. I keep my function names very obvious and clear. And then right at the bottom, I have all of the event listener registrations. So whenever the click event of the different buttons is activated, it calls the relevant function. This is how I like to kind of layout my JavaScript files. I like to have all of my functions at the top and then all of my event listener registrations at the bottom. There's many other ways to do it. This is just one way. But this is how I've settled this up. We're not going to be doing much in the JavaScript file today. In fact, we're probably not going to be doing anything in the JavaScript file today. So you can close that out if you don't want to have it open and just have the PHP file open. We're not going to be doing anything with the forms today. We're just going to be registering fields and then we're going to be using postman to test those fields. The reason I'm doing that is because it takes a lot of time to create the form in the dashboard to then post the data back and forth. And then you have to inspect the responses. It's a lot easier to test these things using postman. So today is a very postman focused day. If you're finding you're struggling with getting to grips with how postman is used because it's a brand new tool, I'll try and help as much as I can. But it's one of those things where hopefully you can see what I'm doing, hopefully it's self-explanatory enough and you're able to follow along or at least watch the recording later and follow along then. Okay. Then I'm going to open up postman. That wasn't opening up, that was. And postman looks a little something like this. Hopefully you can see my screen. If you can't, please do let me know. I have this work press collection at the top here which I'm going to just actually just steal this quickly and we'll talk about what this URL is in a second. But I'm going to delete this collection because I want it to look kind of like what your screen is going to look like if you just install postman for the first time. So if you install it for the first time, you're not going to see all of this activity because you won't have any activity. But you will have this option on the left here where you have your collections and then there's usually a button to say create collection. The other option is if you do have collections already, you can click on this plus button over here at the top just above the filter option and it says they create new collection. So a collection is effectively just a collection of requests per project. So it's great because you can, you can create collections per site that you might be working on. I'm just deleting some of these things. And then save those collections and it will save it with the app. You can also, I think on the free tier of postman, you can also save your collection to the cloud. So it'll sync it across if you're working on different machines. So I'm going to start by creating a collection and this is what I do as a default process. The first time I'm working with a REST API or any API for a site that I'm working on, I create an empty collection. I add in first request. So there's a button here where you can just say add a request to start working and it creates a default get request. And then I enter the URL that I'm working with. Now, in a WordPress install, the URL to the REST API is always the website URL itself and then appending WP JSON, WPv2 afterwards. So I'm going to copy all of this out and pop this in the chat and you'll just need to change it. If you're working locally, you'll just need to change it to whatever your URL is. And for the purposes of the day, I'm going to work with the posts endpoint. So I'm going to create a get request to the posts endpoint. I like to name my requests based on what they're doing. So I use the get method and I keep it up okay. So it's clear to me. And then I just use the word get posts. So that helps me remember what I'm doing here. And then I pop in the URL and that's all I need to really worry about with a get request to the posts endpoint. So I'm going to save this and then I'm going to click send and it'll make the request to my site and I should get some kind of response. If you're doing this along with me and you don't get a response, please do let me know and we'll see if we can troubleshoot. One common reason why you might not get a response is if you are working in a local WordPress environment that doesn't have settings, permalinks enabled of some kind. So some kind of permalink structure, then the rest API often doesn't work. So if that is the case, check your permalink structure, make sure you've set it to something other than plain. So either post name, day and name, month and name, whatever the case may be. And then your rest API endpoint should work. But this is what you should see. You should see a JSON response of your posts in the response window. What's great about Postman is it has the pretty option installed by default. You can click on the raw tab and see the raw data if you would like to, but the pretty data is a lot easier to read. So I can see there is my first post. Let me make this a little bit bigger and let's actually make the screen a little bit. I can't do it that way. Let's zoom in one more time. There we go. So there's my first post with ID 47. It's got a title. It's got various things that I can just scroll through and I can see all the data related to this post. Okay. Any questions on how to access the rest API for using Postman or anything like that? If you do have any questions, let me know. Otherwise, we will kick off when we'll start talking about modifying responses. Some of the more eagle-eyed of you may have noticed that I have, I generally have two cups. I have my coffee cup and my water cup, and that's because I try and jump between the two. So I'm not just drinking water all afternoon. All right. There don't seem to be any questions. I'm going to continue along. The first thing we need to talk about when we talk about modifying responses is the following. So let me copy this documentation out and pop it in the chat, and then I will open it up in my browser. This is the documentation we will be working off today. And you'll see that the very first thing in that piece of documentation or the very first heading or the very first subheading, shall I say, is that there is an important note about changing responses. And in big yellow text or at least yellow background, it says changing or removing data from call rest API in-point responses can break plugins or WordPress call behavior and should be avoided wherever possible. So when we talk about modifying rest API responses, ideally, we shouldn't ever remove data. We should rather add data. We also shouldn't ever modify fields. We should only add fields. So when I say, let me rephrase that, we should not remove data, remove fields. We shouldn't ever remove fields. We should rather only add them. We shouldn't modify fields. We should add them. If we're working with a rest API in-point and we want to limit the amount of data that is returned, then it's better to use the fields parameter. And if you attended some of the early sessions that I did on the rest API, I'm going to open that one up and pop it in the chat. You remember, I discussed the fields parameter and I said you can filter using the fields parameter and you can filter based on certain fields in the schema. So if I copy this out and I append this to the end of my rest API URL, I can do that because the fields parameter is a global parameter, which means I can apply it to any endpoint. Posts, users, custom post type endpoints, whatever I would like to do. So if I do that and I save this endpoint and I hit send, now you will see that the response just contains the ID, link, title, excerpt, and author fields. So that reduces what's known as the payload. So the payload is the data in the response and it means that I can just get the fields that I need. So I don't need to modify the endpoint to just get the fields that I need. I use the fields global parameter and that is the recommended way to do it. Okay, moving along. However, there are options to add fields and the two options are using register rest field and register meta. So let's talk about register meta. Register meta we actually saw, that wasn't the one that I want, we actually saw in last week's workshop and it's this code over here. So register meta is a function that you may or may not have used before. WordPress posts and custom post types have a related data table called the post meta table. And it stores key value pairs linked to the post. And you can create as many meta fields for a post or post type as you would like to. And in last week's session, we created a URL field. So let me show you two places where you would see that. The one place you will see that is if you look, if you have this plugin installed and active on your site and you open up, excuse me, then you open up a post, you should see if you've got it enabled at the bottom of the screen is this custom field section. And then if I select here, I can select from available custom fields. If you can't see that, depending on the environment you're in, you can either, if you're in the block editor, you can click on options and go down to, I'll just move this window out the way, go down to preferences, hit panels and then enable the custom fields option. In a classic press environment, which I can actually show you, let me just jump straight to one quickly. I need to log in. Don't worry, that's a very simple local password. So nobody will be able to hack it. I never use the username. There is screen options at the top of the screen and then you can enable the custom fields button there. And so basically, when you use this register meta code, you're basically saying, create a meta key called URL on the post object. And then there's certain properties you can assign to it. And it's a single property. It's type as a string. It has a default value. And then finally, and most importantly, show it in the REST API. What that means is if I create a post using the REST API, I can pass that meta data through. So we're just going to review that very quickly. We did cover it in a previous session, but in the postman response, if I take the post endpoint, and I create a, where is it now? It's under new collect, it's when I hover over my collection and I click on the actions button and I say add request. And now I can create a post request to the post endpoint. And I'm not going to do it now because I'm going to need authentication as well. So we'll review that very quickly in a second. I'm just going to call this post posts. And then when I pass in the data that I want to send to my post object, I can then specify a meta key and I can then specify inside of that key value pay. I can specify a URL and then I can give it a value domain.com, whatever the case may be. And if you were in the previous sessions and we can actually see that in the, let's actually have a look at the JavaScript code because you did it in the JavaScript code as well. You will see that in the submit post code that we wrote a couple of weeks ago, we passed that meta property in the post model object and we passed in the URL and the URL value. So that was the one way that you can register custom fields. Just going to hop back over to my slides. Okay, so I'm going to check my notes here. Cover that, cover that. Okay, so this is the most common way to register additional fields on an endpoint. The advantage of it is that the only code that you have to write for this to become available, let me jump back to PHP, is like this. So you register the meta, you give it the post, you give it the meta key that you want and then you give it the array properties, show and rest true and it works. You can then post the metadata to the post endpoint or the resource endpoint. You can receive that data, you can use it in your code. There's no other PHP code that you have to write, it's just all available and there for you. Are there any questions around registering meta, enabling it for the REST API or anything like that? We did cover it last week, so if you're in last week's session, you probably already know how all that works, but anything around that that you want to ask today about registering custom meta, otherwise we'll move on to using specific custom fields. Actually, no, we'll move on to something else first. Okay, there don't seem to be any questions. So the next thing I want to discuss with you, and this is in the documentation, so let's jump there quickly. Is this big orange block or re-ellow block, whatever color it is over here? Where it talks about prior to WordPress 4.9.8, meta field set to show and rest using register meta are registered for all objects of a given type. If one custom post type shows the meta field, all custom post types will show that field. As of WordPress 4.9.8, it's possible to use register meta with the object subtype argument that allows one to reduce the usage of the meta key to a particular post type. Now I want to show you what that means with a very simple example. So let's say that you have registered a custom post type of book. So to do that, I'm going to start writing a little bit of PHP code here. The first thing I'm going to do is I'm going to set up a function in the net action hook. I'm just checking my notes here. Yes. So it will be add action net. This is generally where you would add any kind of initialization code or anything like that. And I'm going to specify a function called wp-learn. I'm trying to call it plug-in in it because I'm going to do all kinds of initialization things in here. Then I'm going to create that function. So below that, I'm going to say function, use the keyword function, and then the function name, exactly the same as I specified it in the action hook. And then I'm going to open up that function. For the purposes of good coding practices, I'm going to move this register meta code into the wp-learn plug-in in it function. This is giving me an error because I forgot a semicolon because it's a good idea to register your meta in a plug-in in it. It's not a good practice to do it outside of some kind of action hook, and it's better to do it in it. You can do it, but it's not recommended. So that's the first thing that I'm going to do. However, before that, what I'm then going to do is I'm going to register what's known as a custom post type. So we're using the registerPostType function, and I'll link you to the docs for that function now. Let's just do a quick search here. I'm in the wrong handbook. It's just searching in the REST API, not globally, so let me do this again. There we go, registerPostType, and let me pop that in the chat. So what this does, if you've never seen custom post types before, basically custom post types are a subset of posts. Pages are actually custom post types, and all it means is it uses the same post table, but you can then register custom post types and it'll create a menu item for it, and you can manage those separately. And so back in the code, what we're going to do is we're going to register a custom post type of type book. So it is, sorry, am I using this correctly? No, I'm not. So it's there. So the first property is the post type's name. So I'm going to say book, and then, or at least the first argument, and then the second argument is an array of arguments for that custom post type. And you can do things like labels and set it public and set it show and recent, all those kinds of things. I'm not going to type that out now because it's going to take some time. So what I'm going to do is I'm going to share this code with you in the chat, and I will have this all available in the slides as well, but this is what the custom, registerCustomPostType looks like. So it's got a name, a base name, or a slug, if you will, and then it has an array with all of the properties. So it has some labels. So it's got the name, the singular name. It's whether or not it's public. So can I view it on the front end, whether it supports archives, whether it is enabled for the REST API, which I want it to be true. Then we can say it supports things like a title, the editor, the thumbnail, except various things that you can set to support. Some of those you can remove if you want to. And then any taxonomies that you want to enable for. So whether you want it to be able to have categories and tags or remove those things to not have categories and tags, but this is generally what registering a custom post type looks like. With this code like this, if you now switch back to your browser, if you are coding along with me and you refresh your dashboard, you will now see a books option in the menu. And that's what's really cool about WordPress. By registering a custom post type like this, it automatically builds the user interface for adding new books, for deleting them, for managing their categories and managing their tags. And if I click on books, I can then start creating books. The other cool thing is, because I have set the book to be showing rest is true, that means I can create rest API requests to it. And the default endpoint will be instead of post, so wp slash v2 slash whatever posts, it'll just be the name of the custom post type. So we can copy out the word book or just remember the word book, switch back to post manner. What I like to do is I like to cheat by duplicating the existing posts request. So if I click on the options next to get posts and I say duplicate this request, it'll make a copy for me. And then I can just do things like change the... Sorry, not post. I don't want the post one. I want the get one. Let's delete that. Sorry, folks. I want the get one. So I'm going to duplicate the get post one. I'm going to then click on it and just rename it. So I'm going to say get books. And then all I need to do is I need to change where it says posts. I need to change it to book. Now, there is a way to change the REST API base name to books, which I'm probably not going to cover today. We're going to cover it in a future session, but that is possible. So if you were wondering whether that's possible or not, yes, it is definitely possible. But for now, it's everything we need. We can leave the filtering in. I'm not too worried about that right now. We can always delete it later. But I'm going to save this request and then I'm going to hit send. And REST no root was found matching the URL. What have I done wrong? Oh, I'm connecting to the wrong website. I'm connecting to WorkPress, not LearnPress. So let me just change that. I've copied the wrong URL for these. That's embarrassing. Let me just make them all LearnPress because that's the one we're working with. Fortunately, I had posts on my WorkPress site. So there we go. So let's save that one. Let's go back to books. Let's save that one and let's send it. And there we go. I get an empty response. So that doesn't mean it doesn't work. It just means there are no books, which is what we expect. So if I pop on over to my book list and I say add new book and let's just give it a title. Let's say there and back again for all of our Tolkien fans. And then we'll just say a Hobbit's Journey. And we will publish this book. And now the book is published. And now if I switch back to Postman and I hit send on this request, I will get my first book. So that's how we can very quickly create the custom post type, enable it for the rest API using the show in rest as true argument. And it'll all just work and we can start posting data to it. Now, why am I doing all of this? What we spoke earlier, as we mentioned in the documentation, I spoke about how show in rest on registering meta fields works. So let me show you what I'm talking about there. Let me go back to Postman and let me take out the fields. And we've got all the fields there. And you will see in the meta field, there is a URL key. And that is because we have registered. Let me go back to the code. We have registered the URL on the post. And the custom post type, which is a child of post, therefore inherits that key. And so that was the default functionality of the rest API before 4.9.8. In 4.9.8 and it's possible to change and add an object subtype. So what is it? What do I mean by that? So in this register meta code, in the array, you can add, and just actually copy that object subtype. And I can specify that it's only available to book. So now if I refresh my post request, sorry, this is books. Let's go back to posts. If I refresh my post request, we will see that I've got all my fields in. So let's just actually, let's actually just add, I think I could just add meta to this list. It'll make it a lot easier to see. There we go. We will see that in the meta, there isn't a URL option. But if we go to books, and let's keep the filtering in because it will make it easier to see the data. If we go to books and add the filtering in, we can see that the URL is available. Okay. So that is the object subtype that you can enable on your register meta function. Now some folks might ask, okay, great, but why not just register your meta like this? Why not just say register meta, and then explicitly say, I want to register this meta on the book type. And then you can use the same information as we've done here. And then we don't have to specify the object subtype. And that's a very good answer because that code is just as valid. If I now document it or comment it out this code or delete it or whatever and left this in, maybe not with that bug, then it would also work. And the answer is simply simplicity. So if you already have a meta field registered that you're using, and then you decide to change things and you've registered for your posts so you're building a site and you registered for posts, and then you realize, you know, what actually I needed for is a custom post type book. It's easier just to add the object subtype to book than to register a whole new meta field. My understanding of object subtype is that let's check the documentation for that. So let's go to the register meta function. Here we go. And let's go down to object subtype. I'm not going to find it. Now am I? There we go, object subtype. If empty, the meta key will be registered on the entire object entity and you can say a subtype or post or book or whatever. So you can then control however you want things to work. Okay, so it's two ways of doing the same thing. Basically, if your code already is registering this meta and already is using things and you just want to move things around, it's quicker and easier just to use the object subtype. If it's a brand new meta field, it's probably easier just to write the whole thing out than assign it to the specific object type that you would prefer to register it to. Okay, I'm going to pause if there are any questions around all that. If there aren't questions, then we will move on to how we can take those custom fields and make them top level fields in our API requests and responses. Yes, user. Sorry, I don't know what your name is. So it just says user there. You're welcome to switch over. Once you do switch over, just let me know that you switched over and I'll then I'll quickly just disable screen sharing and enable it again. So please do feel free to do that. I'm guessing maybe that's Tim because I know Tim and I had a conversation around this on Mastodon earlier. So if you would like to do that, now's a great time to do it. And then I'll just disable and enable screen sharing when you get back. Are you ready? Okay, let's just do a disable and enable. So let me stop my share and then let me start my share again. And you should now see things. Please let me know if you do not. Excellent. Seems to be, we seem to be good to... Oh, it's Sergio. Oh, hi, Sergio. We seem to be good to go. Excellent. Okay, we know that works as well. Yay. Shelly has a question. Yes, Shelly, please. I see your hand there. Please go ahead with your question. You are currently muted, Shelly. So I don't know if you're asking your question or if you're typing it up. It was an error. I apologize. No, not a problem at all. Not a problem. All good. Lovely to hear your voice anyway. Okay. Good. I think we're good to go. Right. So we understand how, how custom fields work, registering meta. It's the simplest way to do it. Your, your, your meta fields are then, are then, or then, sorry, my words, are then enabled on your post or on your book or whatever you're doing. You can post to those fields by using the meta object and specifying the key value pairs. You can then use it in your frontend, whatever you want to do. Okay. The other option that you have to registering fields on your REST API endpoints is you can actually register them as top level fields. Now, what do I mean by top level fields? Well, in this instance, the ID, link, title, excerpt, and meta are the top level fields. In other words, they're right on top of that JSON response. Sometimes it would be nice to have a field as a top level field. Number one, it's easier to access. So when you're looping through posts or when you're using books or whatever, you can just go book.fieldname. It's easier to post data to. So you don't have to do the meta object every time. You can just post the field data to that field. And it just makes life easier. So a field that might make sense on a custom post type like a book, for example, might be, for example, the ISBN number. For those of you who don't know about this, so the next part is not the point of the story, but I once worked on an e-commerce site for one of the biggest school and university book supplies in South Africa. And that's where I learned about the ISBN number. But the ISBN number is basically like the identity number of a book. It is unique to that book. Every book has one. And all of the e-commerce vendors that buy and sell books, they use that ISBN as the unique identifier. So that's why I use the book post type as an example because we know that's a clear example. So it would make sense to register an ISBN as a top-level field because we're going to be probably pushing that data all the time, which means we don't have to worry about whether it's in the meta or not. We just want to have it available. So to do that, the first step you're going to do is you're going to register that meta field in the normal way. So using the register meta function. So I'm going to leave the URL on the post and I'm going to take out this book part here because I want it on posts and books. But I'm going to copy this register meta code out. And I'm going to use it to register a new field specifically on the book custom post type. And we're going to call it ISBN. It can stay a single field. It can stay a string. We can leave it as a default. And I want to remove the show in rest at this point in time because I want this field to not be in the meta. I want it to be a top level field. So for that to work, I'm going to use the register rest field function. So let me show you how that works. So here is the code. It's a function is the most flexible way to add fields to the rest of your objects. It accepts the object type, the attribute and then any associated arguments. Here is the link for that field. I'm going to pop that in the chat. And the easiest way that we can register a field is we can just say register rest field. So let's switch back to the code. So we've registered the meta. So now we can say register rest field. And we can say we want this to be applied to the book custom post type. And the field is called ISBN. Now I want to show you something. I'm going to, just for the sake of displaying how this works, I'm going to comment out the register meta code here. And then I want to show you what happens on the front end. So when we, or at least when we query this in postman. So we've just got the register rest field book ISBN option. I'm going to take out the filtering just for now. We'll put it back in a sec. And I'm going to send this request. And if we scroll down, we should see that it's not there. And the reason for that is you need the combination of the two. So you need the meta field and you need the, sorry, talking nonsense, getting myself confused here. You need the callback functions. So in the objects array, sorry, in the objects array, in the rest field arguments. So this, let me go back to the documentation here. The object type, then there's the attribute, which is the name of the field. And then there's the arguments. It says an array with keys that define the callback functions used to retrieve the value of the field, the get callback, the update, the update callback and the schema. So those are the three things that you need. So in the code, there's the book and ISBN. I'm going to pop these onto a new line to make it a little bit easier to read. And I'm going to scroll up so we can see what's going on here. So it's easier on screen. We then specify an array and we need to pass in the follow, we need to pass in the schema, which I'm just going to set as null for now. And we'll talk about schema in a second. Then we need to set the get callback. And yes, I am checking my notes. And this will be the, this will be a callback function that we will define. So I'm going to leave it as blank for now. And then there is the update callback, update callback, which again, I'm not using my keys correctly today, which I am again just going to leave as an empty string. And there we go. So those are the three things that we need for registering a red field. Then we need to define those callback functions. So just like when we do an action hook, so we set up the action hook and we define the function to call, we need to do that same thing. So over here, I'm going to specify the get callback function as WP learn, I'm going to say get ISBN. And for the update callback, I'm going to say WP learn update ISBN. And then I need to actually define those functions. So in the roots of my code, I'm going to use the function keyword, say WP learn get ISBN, open up a new function. And then just for the purposes of testing, I'm just going to return a number. One, two, three, four, five, six. Just keeping it super simple. And then we'll do the update ISBN function. And it's WP learn update ISBN. We're not going to use this just yet, but we can set it up so long. And I'm not going to do it. I'll return an empty string for now. Okay. With just that code, let's see what happens. So if I switch back to my husband, okay, so Joe says he had to reboot. Can we one second, Sergio? I'm going to stop the share. Going to enable the share. There we go. Okay. I'm just going to switch back to the code, Sergio, for your purposes. So we're registering the rest field using this code. Inside of the, inside of the init action hook, we are registering the rest field. We're registering the schema, the get callback to that function, the update callback to that function. And then we're defining those functions. Let me show you what this does on the front end. If I, every time I move the zoom video window, it goes into places that I don't want it to go. If I hit send now on this request, I want to show you what happens. So there as a top level field, and you'll see it renders it underneath all of the default post fields underneath ID and slug and title and content and all of those things underneath the meta as well. There is my ISPN field with the value we specified in the callback. So that means, and this is the important part, I don't need to have registered the meta field for this to work. So if I just, for example, want to always return some data in a custom field, I can just do register rest field and the get callback and I'm good to go. I don't have to register the meta field. However, if I do want to update that field, I want to be able to save data to that field, I do need to register the meta field. But I just wanted to show you that you can get away if you're just adding a field to all responses for whatever reason, maybe it's a true or false value or something you want to use in your code and you always want to have that value there, you can just register it with the get callback and return some data. Okay, but if we want to update it, then we need to register the meta field because then we need to tell WordPress that that field can be updated. And then in our update callback, we're going to use something like update post meta. So we're basically going to use the internal get post meta function to return the value and the update post meta function to update the value. So these are two functions that you may or may not have seen if you've worked with post meta before. I'm going to grab them from the documentation. So there's get post meta, which basically requires you to give it a post ID or in our case it'll be a book ID. The key that the key name, so in our case it'll be ISBN and then whether it's a single or not. So we can use that for the get callback and then the update post meta is the one we used to save the meta key to the database. So that also requires a post ID, the meta key and the value. So we'll use that one as well. So let me show you what that would look like in the code. So here we can say return get post meta and now it's going to require three things. It's going to require the ID of the custom post type. It's then going to require the meta key, which in our case is ISBN, and then it's going to require whether it is a single or not. Now in the documentation, it tells us if we have a look at, let me go to second here, register a risk field. Oh, there it is, a pretty cool driving. If we have a look at the get callback, it says the callback function is used to retrieve the field value. The default is null and the field will not be returned. We've seen that in action. This the function, in other words the callback function we defined this function will be passed the prepared object data. Now when I was preparing for this workshop, I saw the word object and I assumed this would be an object type. It's not, it's actually an array. So how you access the data in that callback is different from how you access it in the update one. So let me show you the difference. So in your code, your first argument can be, you can either make a post, or in my case I'm going to call it book because I'm working with the book type. Your second one will be the meta key in our case it's ISPN. And note that this is this key here, not this name here. We can change this in the rest field. We can call it something else. We can call it uppercase ISPN and then that's how the display in the rest API but then the actual meta in the post meta table we're calling it ISPN or Logan. So it's that property data there. And then finally whether it's single or not in our case we have set it single, true. So we need to set it here to single as true. So return a single value. So that's what the get the learn, get ISPN can look like. Get post meta based on, sorry, I'm doing this completely wrong, sorry. The book is passed to the function, not the get post meta function. It's passed to the callback function. So their book, book is passed there. Then we can say get the post meta based on the book and we need the book ID. And now because this is an array it needs to be an array notation which is square brackets and then ID like that. If it was an object it would look something like, like that which doesn't work because it's an array, not an object. So just be aware of that. If you're working with your updates, sorry with your get callbacks, it's an array. So you need to access it via using an array notation. So that should work. We'll test that in a second for the update. You don't have to, you could do the same thing. So you can pass the same book argument or at least create the same book argument. But if we have a look at the documentation and again this caught me out, this will be passed the model object which in this case is an object. And this object data I want to look and see if I can get this documentation updated. So it says in the type of an array or something like that. So it's clear. But in this instance it is an object. So now we need to reference it like it's an object which in the code it would be, so when we return we would say return update post meta. So it's going to perform an update. We need to pass the ID. So we go book and then we use the object notation. So it'll be a book and it's uppercase ID in the book object. We use the same key of ISBN. And then we need to pass the value. And the value is passed to this callback function as the first property. So in the get one of the first property is the actual book array. In the update one it's the actual values. In other words the value we're passing to the REST API. So here we could just call it value. We can call the variable anything we want but I call it value. And then we need to pass that value as the third parameter to the update post meta. And what that will then do is when we post data to our REST API endpoint, when we specifically say we want to post data to the ISBN endpoint, it's going to trigger the update callback which will get the value we've posted and the book object. And it will then update the ISBN with that value. That is essentially what this code is doing. So let's test this out using postman. Okay, before we do that, if you haven't set up your postman environment with your local environment yet, to be able to post data, you need to authenticate your postman requests. We did cover this in last week's session. That's one of the reasons we covered it but I'm going to cover it very quickly again. The easiest way to do that is to click on your user list, find your user, and then right at the bottom there is an application password area. I don't think I've saved my application password so I'm going to revoke this one so we can start all over from scratch. But you can add a new application password. I'm going to just call it postman because that's what I'm going to use it for. And then when I add it, it's going to tell me what my password is which I'm going to copy out over here. And then in postman, to be able to authenticate your post requests. So let us just take this one for example. Actually, let's make a copy of postpost and we'll postbook. So let's duplicate that and we'll make it postbooks as posting to book. And then under the authorization section, you say basic authorization. It's there, basic auth. And you give it the admin and then you pass in your password. And you'll notice that postman is very cool. We're not going to cover this today but postman actually says to you, heads up these parameters, hold sensitive data to keep this data secure, working in a collaborative environment we recommend about using variables. So you can specify variables in your postman environments and then it'll use the variable but somebody else may be able to access that data. I'm not going to worry about doing that today but it's an option. So if I save this postbooks request now and I hit send, it's going to try and create a book but it tells me that I'm not passing content and title and it says except as well but I don't actually have to pass except. So at least I know the authentication is working. So now I want to create a book. So I'm going to give it a title. I'm going to give it some content and then I want to pass in the ISBN. So in the body area, I'm going to make sure I click on raw data and I'm going to change this option on the right the dropdown from text to JavaScript and then I can start passing in some information. So I'll start by saying title and let's say my new book and then I'm going to give it a content. It's giving me an error there for some reason which I'm going to have to have a look at for a second. Why is it giving me an error? Semi-colon expected. Really? Okay, that doesn't seem right. Is it because I've done something somewhere wrong? No, it's definitely raw. So I should just take this out and it's on JavaScript. I'm pretty sure it's supposed to be a... Okay, let's have a look. Maybe something has changed. So let's say my new book and then we're going to say content, my new book content and then we're going to pass in the ISBN and I feel like this is all going to go wrong because this is not doing what I expected to do. So let's give it an ISBN of mnb for my new book. One, two, three, four, five, six. Oh, that's why because I've selected JavaScript and not JSON. I'll make sure you select the correct format, folks. My apologies. I knew something was off there. So it should be JSON. If you select on raw for the body, then click on the dropdown and make sure you select JSON, not JavaScript. Clearly, I need to get some sleep. And then for fun, let's add the meta object and let's give it a URL. So meta then needs to be an object and this is why I left the URL on the post. So we can specify the URL and let's just say my new book dot com. So this is using all of the fields that we have set up and let's see what happens when we post this data. So that's what it looks like. My new book, my new book content, we're passing in the ISBN, passing in the meta URL. Let's send this and see what happens. Okay. So we have a successful response. It's returned to 201 created status. Let's have a look at our data. Here we go. There's the book. There's the link. There's the title. There's the content. There is the meta URL. So that's working excellent. And there is the ISBN. So that's working as well. If we switch over to our WordPress sites and we go and have a look at books, there is the new book. You'll notice it's in draft mode because you didn't specify a status, which is fine. We could add the status as published if we want, but it's fine to be in draft right now. And if we click on that, the ISBN is stored as a custom field. So that means it's being stored in the post meta table as well as the URL. So where they're stored is the same, but how we pass the data to the REST API endpoint is different. The other cool thing, and I haven't actually tested this, so I don't know if this is going to work, but we're going to try, is in your book, let's go and get the field to this over here. Because we've specified this as a field, I'm pretty sure that we can also filter using the field global parameter. So I'm pretty sure if I say ISBN here, I hope this works. I haven't tested this. You should never try things. You've never tested it in a live workshop. But there we go. It's got an ISBN field. Now, obviously, the one that we have just created with an actual field isn't published. So let's publish this quickly so we can actually see that data. If we go back to Postman, we can send that. And there's the new book with the ISBN. So you can filter. That's the other nice thing about creating the custom fields as REST fields is you can filter by that data as well. So that's another reason why you might consider using that over just a standard register meta. If you were using register meta, you'd only be able to filter by the meta field and then you would get the whole meta response back, which may or may not be what you're looking for. Okay. That was a whole bunch of stuff. Nobody stopped me. So I'm going to assume that everybody was either following along or planning on catching up later. Does anybody have any questions around everything we've just done, registering a REST field and the pros and cons, before we move on to talking about the schema? Could you share the put request JSON again? Yes, certainly. So let me go back to Postbook. Where was it? Postbooks. So you're looking for the JSON. So here it is. Let me actually just copy this whole thing out. So remember to click on the body tab, raw and change that to JSON. And then that is the data that we're sending to the book endpoint. And the only fields you actually need are title and content. The rest are optional. Okay. We don't seem to have any other questions at this point in time. So I'm going to move on. But if you do have questions, you're welcome to share them in the chat. The other thing that I wanted to talk to you about before we start looking at wrapping up is this thing that I did in the code where we specified the schema for this field. So the schema argument is an array that describes what the field is and what it's doing. It's not a requirement to specify the schema for a field, but it is a good idea. It's encouraged. And the reason it's encouraged is, number one, if somebody is coming and looking at this code, the schema will actually give them a bit of a human readable representation of what's going on. Number one, number two, when you are testing your endpoints and you're writing automated tests, you can use things like the type in the schema to verify that the type that is being sent is correct. And then if you send the incorrect type, it returns an error response. So for example, if you're specifying a string and then you pass in an array, if you set up the schema to say this is a string type, you'll get an error message if you try and pass an array to it. So setting up the schema is as simple as instead of having null, just creating an array. And just to mention, there are two ways of creating arrays in PHP. In PHP 5.3, I think it is an older, you do it this way. The other way is just to use the square brackets. I prefer the old way just because it's clearer to me that this is an array, but everybody does things differently. And then in the schema, the two sort of minimal fields you can do are the description, which you can specify in human readable language, something along the lines of the unique identifier of the book. And then the other thing that's a good idea to specify is the type. And in this case, it is a string. Okay, and so it's recommended to specify your schema for any fields that you do add. There is a whole, let me find, there is a whole section in the REST API around schema and what it does. I'm not going to dive too much into that today, but I'm going to share the link with you here as well as in the chat. I'm pretty sure it's also linked in my other resources slide at the bottom. Yes, at the bottom of my... No, I don't think it actually is. So what let me do is I'm going to add it now and then I'll update the slides, but it's a good idea to read about the schema, how it works and what it's used for. There's a whole document in the handbook about the REST API talking about schema. There's conversations around type juggling, format strings, numbers of rays, all kinds of things. So I do recommend reading that if you're building with REST APIs. It's good to be able to set those things up. I'm not going to dive too much into that today. Okay, so that is my bit. Hopefully you've understood why you might just use show and REST in the register meta to add fields, why you might prefer to use register REST field and under which scenarios one is better than the other. The other nice thing about using register REST field that I just want to mention is you can, if you have a look, you can actually do quite a lot with these functions. You could do validation of the ISBN value when you do the updates. You could check is the value correct? Is it the right type of data? You could do verification on it in the get function. Maybe there's a reason you need to append other data to this field. You could do that here. You can't do that when it's in the meta. So it really depends on how much flexibility you need your field to have, what you needed to do and how much functionality needs to be around that will help you determine which one you follow. Are there any other questions? Anything else anybody can think of that they want to know? As I mentioned, if you do have follow-up questions to this, if you're watching this after the effect, you can send them to this GitHub link, which I'm going to paste in the chat here anyway. You're welcome to ask me further questions if you're working on this offline and you get stuck with any of the co-examples. You're welcome to ask the questions there. Next week, I'm going to share a little teaser of our plans for next week. Next week, we're going to be looking at adding custom endpoints. So we're going to create specific endpoints that we can push until day to two. This is a very good way of replacing admin Ajax requests or custom admin Ajax requests. So I do keep an eye for that one. But otherwise, thank you all for joining me. Thank you again, Mark, for co-hosting with me today. I hope that you've enjoyed your session. Please enjoy the rest of your Thursday and the rest of your week and I will see you all again next week.