 Thank you. Hello, everyone. All right, thanks for waiting. So my name is Leonardo Losovis. I came to give a presentation called Cope with WordPress. I'm going to explain what that means in a second. My Twitter is Losovis, like my surname. My personal blog is leoloso.com. And this presentation is available in slice.com slash leoloso slash cope with WordPress, cope with the hyphen wp. I would encourage you to actually load this URL because there are some links that I'm not going to show here that you might want to see later on. So we start. So cope, what does this mean? It actually means create ones, publish everywhere. So it's a kind of clickbait title. I'm sorry about this. I didn't invent this term, but that's what actually means, okay? So yeah, that's how they promote it. So what is cope? It is a strategy for reducing the amount of work needed to publish your content into different platforms or mediums, like which ones, like websites, email, apps, virtual reality or mental reality, Apple Watch, scoreboards or giant screens, podcasts, home assistants like Amazon Alexa, in-card entertainment systems, or others, you name it. So the idea is you have an application running where? Website, yeah, maybe you have any letter. Maybe you have an app and you don't want to work so much into adapting the content for the different platforms. So the idea is how can we minimize this amount of work that we had to do? So how does it work? It establishes a single source of truth for content which can be used for all the different mediums. If we have only one single source of truth that works everywhere, we don't need to keep working on reformatting it for each platform. So there's a problem, which is that a single piece of content doesn't normally work everywhere. So for instance, you work with HTML for the web, but you cannot use HTML to make an app. Classes you use in HTML, class align center, but if you send an email or new letter, you need to transform that into styles. And then a style, like text center, doesn't make sense for an audio-based medium. What does it mean for Amazon Alexa to place some content on the middle? So not everything works everywhere and we need to pay attention to the things. So how does it work, actually? How can we do this? The key is to separate form from content. So the presentation and the meaning of the content might be the couple. Only the meaning is used as a single source of truth and the presentation can be added in another layer specific to that particular medium. So let's see an example. We have this HTML code, it's pretty simple. It's a paragraph with a type P. It's aligning the text to the center and the content is hello world. So this is where HTML is what it is. If we want to reuse it, we need to convert this into something more agnostic that we can use as independent units of data for other platforms. So this can simply be transformed into this. A simple object, an array, or a JSON object. The type is a paragraph, content is hello world and the placement in this case is center. If I can use the placement property because it's a screen, I use it. If it is audio based device, I ignore it. But now I can because the data is available as a property. So this is what we want to achieve. If we can somehow transform our content from the HTML content that we used to input in into our content management system, WordPress, into something more resembling this structure, we made it. Then we can actually use this content for apps and anything that you can think of. So why WordPress? Why are we talking about WordPress? Is it because we are in World Camp and of course we're going to talk about WordPress? Yes, but not just that. Actually WordPress is quite ideal to implement this strategy. They create one's publisher strategy because it is versatile. First thing is that WordPress allows you to create many different content models. It's not restricted to a specific one but through the use of MetaFills, you can add the properties that you need. So by default, WordPress has this structure in mind. It is very powerful because you can add new features through plugins very easily. It is widespread, everyone knows about WordPress, everyone knows how to use WordPress, not just technical people but also marketers, bloggers, everyone. It is headless. So headless is that you can access the content through APIs and we will actually need to access our content through APIs. And finally, and this is the most important one, it has a blog-based editor called Good Timber. And blogs enable to easily export the post-content metadata. So I'm giving this talk today and not one year ago because of Good Timber. The release of Good Timber is allowing us to implement this strategy. So this is what we are particularly interested about and this is what we're going to actually see in this talk. So let's talk about blogs versus blogs. A blog is a single unit of information stored all together in the database. So if we had this piece of HTML code, what we can actually see is an important piece of information like the content of the paragraph. What is it? Look at this wonderful tango. And the URL, the dimensions and the attributes of the YouTube video, okay, that URL, we can't access it directly. It's not metadata. So if you actually want to extract this information, I need to parse this HTML code, which is expensive. It is doable, but it is expensive. So there's no performance, no optimal solution to do this. So back in the day until WordPress 5.0, we were working with blogs. When you're actually typing content in the tiny MCE, in the content editor, that is a blog, okay? So basically what you had in WordPress until Good Timber was not easily accessible. So now let's talk about blogs. How do they change the situation? A blog conveys its own content and properties as metadata customized to its type, a paragraph blog, a video blog, an audio blog, image blog. And this is how it looks like. So in the previous screen, we have a paragraph and we have an embed of a video. If I represent this as a blog, as the data, it basically an object, an adjacent object or an array with two entities. The first one is a type paragraph and it has a content. The second one is a type embed provider YouTube and it has a URL. So each piece of data, depending on its type, can have its own properties. We can easily use any piece of data on its own and adapt it for the specific medium where it might be displayed. So if we're talking about watching a video on my Apple Watch, I don't need to pay attention to the width and height. Okay, I can ignore it. I just show the URL and that's all I care about. So through Gutenberg, we're talking about blogs. So in this case, you have the tile, a lovely tango and then you have a paragraph and then you have an embed of a video. Those two are blogs. And so its data, it can be accessed independently of everything else. However, Gutenberg blogs, they were not designed to work with code in mind. Whenever they designed it, nobody was thinking of this particular use case. Its representation of the information is different to the one just described. And this is how Gutenberg stores the information. Okay, we will actually make a few observations based on this piece of code. So the first one is, the blogs are all together in the same database entry. So if you actually go to table WP underscore posts, you will see an entry for the post containing all this data, which are the blogs. In this case, all the content for the blogs are all together, which is kind of a pity if you think about it, because if each blog is on its own row, you can go straight fetch it from the database on its own row. So you're not bringing the overhead of everything else. Ideally. This is a situation for all blogs except the global or reusable blogs, which they do have their own entry on the database. However, and this is a good thing, WordPress provides a function called parse blocks that you give it a piece of content in HTML. It parses this content and it gives you an array of all the data in the blogs, basically all the blog data on their own entities. And because of this function, we can work with this. Okay, so no problem. We can actually go to the next step. Next thing that we can see is that the blog type and its attributes are stored through HTML comments. So this is how a blog looks like. You can see that at the top is a WP column paragraph. Then you have a comment and then it closes that HTML comment. Then you have another HTML comment. WP core embers like YouTube and a JSON object encoded into a string with all the property for the blog. So these are HTML comments and it was a wonderful design decision when you're working with the web because now you can store the HTML content on the entry, print it on the page, and it's not visible when you're actually browsing the website for the web. However, this could be a problem if you're not thinking about the web because an HTML comment may still be visible for other mediums, okay? So you need to be aware of this. However, it's not the big deal because as long as you're using the function called parse blocks, you're getting the data from the blocks. You don't need to worry about HTML code anymore in that sense, okay? At least for the structuring of the blocks. So then we can work with this. This is quite all right. Next thing that we can observe, and this one is more tricky one, blocks contain HTML. So if you're paying attention to the first block which is a paragraph block, the content is the p tag, look at the wonderful tango and enclosing the p tag instead of just look at the wonderful tango. So the p tag is web, is HTML. So it works for the web, but I don't know if it works for other platforms, right? I mean, it may or it may not work. I cannot make that assumption. And this is a problem because HTML code is not useful for other mediums. So then the solution to this is that we need to strip those tags, okay? And we can keep only the semantic tags. Like for instance, if you use strong, which is to make a text bold, instead of using B, you can actually do that or using EM instead of using the I for italics because these are semantic representations and being semantic, they can be interpreted for different mediums. So Amazon Alexa, when it's reading the text, if it finds the strong tag, it can actually emphasize that sentence, okay? So then it is okay to keep the semantic tags. Everything else, strip it out. So this is something we have to be careful with. And finally, the last one, and this one is even trickier, is that in this case, the video caption is storing HTML and not as an attribute. So if you see at the second block, you can see there is a caption and exquisite tango performance. And this caption is stored between the fake caption tags, but it is not stored in the attributes of the block. And this is an issue because now to access that piece of information, if I want to show the video caption, I need to extract it from the HTML and it to parse HTML content like in the old days, basically. In this case, the regex, the regular expression to do it, a very simple one, okay? Doing that, we obtain the caption. But the problem is that we need to do this block by block. We need to identify what properties are stored as HTML and say, I need this property. I need to extract it and then you need to create a regular expression to do it. This one was very simple, but other ones are more difficult. So this is something that works, but it could have been better. Yeah. So implement the code. Now, what do we have to do to actually implement the algorithm to produce the metadata from the block? The first thing that we had to do is to simplify the structure of the JSON object returned by function parse blocks. The second step is to extract the pieces of metadata from each block, transforming them into a medium-agnostic format. And the third step is to make this data available through an API, okay? I'm going to show these three steps one by one by one. So the first one. We need to simplify the JSON object that we get back because on one side, it has missing data. If you have a reusable block, it is not fetching the data from that reusable block. And then because it adds data under multiple levels. So it is not easy to browse, which is for the nested and the group blocks. This is how it looks like. I'm going to show you a tiny bit. So this is a simple block here. It shows the data like this. Then it has an empty block divided that is adding between two blocks all the time. And here for instance, you have a reusable block. It's simple as a reference to that destination block, but it doesn't bring the data for that block. So we don't have it yet. And then for the nested blocks, it concatenates them under multiple levels. So this is not something that we can directly work with. So we first need to process this data and transform it into something more convenient. So what we do is to basically iterate through all the data and add it on a first level. In the case of the global block, we fetch the destination content. And in the case of the nested and group ones, we move everything to the first level. I have the functions here. And I need to actually show you in detail, but it's basically four functions. It's very simple. And the result is that all the content here is now in one single level. So now this is something that we can actually work with. And to demonstrate this, we can create an endpoint in the WordPress REST API to access this data, which looks like this. So I have here, oh, that looks very tiny. So I have this WordPress blog post with plenty of blocks. It has a video, image, some images which are missing, a video, audio. Okay, pretty much a tiny bit of everything, a tweet. Okay, so how do I see this data? Here you are, well, maybe you can see. Okay, so this is basically how WordPress gives you this data and then you put it in a format nicer. And you can see this is block by block by block, now that I'm accessing. This is the first block, which is a paragraph. Then I have an image, another paragraph. Then I have a YouTube video, okay? So you're basically transforming from the blog post into a JSON object for which you can actually manipulate and use this data. This is the first step, though. But... Works, no. Hello, hello. I'm still here. Okay, but the good thing that you don't need to worry about is that all the code that I did not show you just now for lack of time is available on a GitHub repo that I just created for this presentation. So once again, if you check the slides, those coms, slasher, also slash cop with WP, click on this link, you can access all the code. The second step, now that we have this initial data from the block, we need to transform that into something that is medium agnostic that we can use for any device. So we have data at this moment that contains HTML code, on which, as we have said, that's not suitable for the credit ones publish everywhere strategy. So we must strip the non-semitic HTML tags for each block, turning them into a medium agnostic format. And then while doing so, we can decide on a block by block basis, depending on the type of the block, what property we want to capture. If it is a paragraph, just the content, if it is the video, the URL, the width and the height, if it is an image, the same, and et cetera. And then finally, also while doing this, we identified the metadata that is not easily available because it's not inside the block attributes. And we had to create a regular expression to extract it from the HTML code. So something very important is that not all block types are suitable for this strategy. Some block types are only working for the specific medium that we have here. Screen device may be only for HTML, so we can't transform them. So for instance, core columns, core column and core cover, I don't know how to represent a cover for an audio device for instance. It just works on the screen, so maybe I will ignore it for the time being. Core HTML makes sense for the work only. Core table, core button, and core media text. All of these are different block types for Gutenberg. They are not easy to represent, medium agnostic, they might not make sense, so I have ignored them for the time being. So that leaves me with all these other blocks that I have migrated. These are all of the default blocks shipped with WordPress. If you install plugins, it will have with extra blocks that then you need to work upon. But for these ones, I have already done it, so as a proof of concept that I'm going to show now, it's all working and everything is nice and working very nice. So to extract the metadata, we get the content that I showed you just now, that it was all the data, and we transformed that. We will create a function called getBlockMetaData for this. Once again, no need to show you the code, but it's not very long. What we do here, just to show this one function, is that on a block-by-block basis, in this case for the paragraph, I extract the content like this. In the case of the image, I extract the content like this. In the case of a YouTube embell, I extract the content like this. So on a block-by-block, I'll say how to extract the data. And finally, we had to make this data available through an API, otherwise what is the whole purpose? You need to have an API, because your app, for instance, will need to access the data through an API. So this is the final step, which is quite important. Three ways in WordPress, so far, that I know of at least. One is REST through the WordPress REST API, which is integrated in core. GraphQL, a very nice API, which is implemented through WP GraphQL. It's a plugin that you can install. And finally, POP, which is my own project. I'm going to show you something about it now, that it's also implemented for WordPress. So let's see how to export the data through each of them. So first, for REST, the REST API is very simple. Once again, no need to show you the code, but it's simply one function that is accessing our newly defined function called code block metadata, and it retrieves that, okay? And after creating this API endpoint, we see the results, okay? So if you remember that I showed you just now, that was a big blog post with a lot of content. And this is how it looks like after I have extracted the metadata. It's blog, in this case, a paragraph, with only the content for the paragraph. Then we have an image, and it only has the source for the image. Paragraph, again, YouTube video, it has the URL, and then it has the caption, quote, it has the quote. And here the site has text, and it has the HTML semantic tab that I can actually keep, okay? For the heading, as you can see, something that I have done. The heading is basically h1, h2, h3, h4, h5, h6, okay? It's an HTML tag, but can I use that in other devices, other formats, other platforms? Maybe, yeah, maybe no. So just to be on the side, I don't format that into small, medium, large, extra large, extra large. So now what we have here in something agnostic for the heading is extra large, which is heading two. Then we have the gallery with all the images and the width and the height for each of the images. The list has all the items. So this is awesome. I mean, basically we got it through this. Because now this is data that is available to any of your devices, and you don't need to actually think about it anymore. You go to your blog post, you create a new entry, and that huge piece of HTML is automatically transformed into something that you can access for every platform. This is magic. Once again, no need to show you the code for this, but all the functions that I just showed you, they're available in another GitHub repo, so you can actually download it. Next one is GraphQL. GraphQL is a tiny bit tricky, and I have not been able to implement it because all of the different responses for each of the blog type is different to each other. And GraphQL is very verbose. So for each type, for each different response structure, you need to create a new type. And if I have like 15 blogs, and I had to create 15 types to represent the information, the structure of the information in each blog, I was like, nah, forget it. So I didn't do it. What I did instead was simply to do a JSON in code of the data, okay? And I return everything that I showed you just now as a string. Once you get it in the client, you have to do a JSON decode, and you have the object again. So you can access this through GraphQL. This is quite awesome. And then finally, we have pop. Pop is a library that I'm working on. This is my own brainchild. And it works at any bit like GraphQL that you can actually define fields and you can fetch the field applied on an entity and it gives you the content for that field. So I created one entity or one field called post-blog metadata. And I'm going to show you how it works. So basically you have here the URL of our endpoint, and you define through fields, the fields that you actually want to fetch from that entity. Okay, and it looks like this. It basically same like GraphQL. I'm asking for properties. In this case, post-blog metadata. It gives me all the metadata inside that blog post, as I showed you just now. So this is very convenient. WordPress REST API, you have to make an endpoint with, and it fetches the data that it wants. So you're always limited and constrained to that piece of data. This way, similar to GraphQL, you can say gimme only this and nothing but this, which is pretty practical. But something even better that I have been able to implement through this API is that you can also filter the blocks by the block type. So one of the implications of working with different devices is that not everything works on every medium. Once again, content like text, I can read on my Apple Watch. Apple Watch, images, audio, and video. Don't give me anything else. So I only want to query for the content in the blog post, but not everything. Just give me the video, nothing else but the video. So this is what it does. It allows to add a block name attribute where you define what type of block you want. If I actually click here once again, now what I have is from a list of posts, only the videos. If they don't have any video, it doesn't give me anything, even though it does have content. Final example, here I'm querying a single post and I'm saying gimme all the images in this post. Ignore everything else, gimme the images. Once again, I want to get the images only for my Apple Watch. Okay, so this is what I get. And the beautiful thing about this is that when you're actually inputting the content through Gutenberg, you're not thinking about this. Okay, you're just adding your blog post, but you can use it for any other device. So once again, I'm not going to share the code here, but there's a GitHub repo. If you are interested, you can check it out here. So what we have after all of this that I have shown you is, we have here the HTML for a blog post as it has been set on the database by Gutenberg. Okay, something that is divided by blocks, but it is not readily accessible. Okay, and after a few steps in our algorithm, we have transformed that into this. This is what we wanted to achieve, so we basically did it. Okay, so conclusion. The code, which means create once publish everywhere strategy, helps create several applications which must run on different platforms or medium, web, email, apps, home assistance, virtual reality, augmented reality, audio, you name it. The way to do this is by creating a single source of truth for our content which separates form from presentation. Because it is block-based, Gutenberg makes all metadata inside the post readily accessible through APIs. And now we can implement this strategy. It is not optimal, as I mentioned just now, we had to parse HTML code, it's not the best, but it works, and it works pretty well. And as a result, the effort needed to release our applications to multiple platforms can be greatly reduced. This is what we wanted to achieve, success. So this is it. Once again, I need to mention this. The slides are available online. Check it out, because all the links are actually pretty useful and I couldn't show everything that I wanted to show here lack of time. Thanks very much. Okay, if you have any questions, you can also direct questions to Leonardo separately because we're running short of time. Okay, anyone? No? Okay, so if you have any questions, that's ready. Thank you, Leonardo.