Video Tour of Wagtail 8.0
Published August 26, 2026
This video is from Wagtail CMS 2019 .
Wagtails RichText editor, Draftail, is very minimal out of the box. There are times when you need to extend it's functionality. Luckily for backend developers, we can extend the Draftail editor by writing a Wagtail Hook in Python. No JavaScript needed! We're create an inline HTML code and a centered text feature in this tutorial.
In this lesson we'll learn how to create 2 types of Draftail Extensions.
Full Tutorial: https://learnwagtail.com/tutorials/extending-draftail-richtext-editor/
Git Commit: https://github.com/CodingForEverybody/learn-wagtail/commit/281f08524c183284672141b4b57ac335601e350b
Learn Wagtail from scratch with the official Wagtail for Beginners Course
https://learnwagtail.com/wagtail-for-beginners/
Used in this video: Wagtail 2.4, Python 3.7, Django 2.1.5 #Wagtail #Django #Python
Automatically transcribed, so expect mistakes in names and technical terms.
Hello and welcome back to another lesson on learning Wagtail. In this video, we are going to be talking about rich text plugins. Or in other terms, we're going to be creating We're actually going to create two different extensions for the draft tail rich text editor. Now before we get started, I want to show you what we're talking about here. So I'm going to CD into my website and I'm going to CD into my site. Pip env shell just to get in there. Python three manage. py run server This is gonna complain on me. Yep. So let's do run server 8001. Switch it up for this video So let's go ahead and open up localhost
port thousand eight thousand and one uh da da da da let's type in our credentials And let's edit an article blog page because this one will probably have da da da da da da da some rich text somewhere. Rich text and title. So we've got title. No, that's not right. That was just title. I read that far too fast. Let's get rid of that one too. Let's go ahead and find some rich text. Full rich text. So in our reg text page here and because this is at the bottom, this is gonna be tricky to see. Maybe I'll make another stream field so I can move this up. There we go. This is our draft tail editor. So we've got bold italic h23 four ordered list, unordered list, horizontal rule, new line, video embed, link embed, document embed, and image embed
But what if you want more? What if, for example, you're writing a uh a website where you want to share code snippets with people And you want to be able to format the code inside of here. Just just inline code. So like you want to be able to highlight a variable name, for instance We're going to cover that. And what if you wanted to center your text? Because a lot of the times people actually want to center their text, but they don't have the option to do that. Well, I'm going to show you how exactly we can add center text as well. So we're going to be working with this thing called a hook. And Wagtail actually has several different types of hooks. We're just going to be working with one of them. Now hooks are not a new idea. In JavaScript they're called callbacks.
React finally has hooks. Stripe even has a notion of web hooks. Hooks are not a new idea. And all it is is when your site runs some code and then it's done running some code, it's just a function and it's a callback to say, hey, run a little bit more code. So we need to create a file called wagtail underscore hooks. py. Now, because I don't want to create a brand new app just for this one file, just because we're registering a couple rich text Hooks. Uh I don't think we should create a new app. If you disagree with me, feel free to create a new app and throw this new file in there. What I'm going to do, because I'm actually going to be a little bit lazy here, is under streams, I'm going to create a new file. I'm going to call it Wagtail.
hooks. py. Now I had mentioned that we're going to be creating a code, which is going to look like this. And if you remember old HTML, we're going to create something like this, not using this tag. We're going to use a proper CSS style for this one. So this one that we're going to register here, this one is an inline style, and this one is going to be a block style. So center is going to center an entire paragraph and code is going to, uh it's just going to wrap the code element around a few words. So let's go ahead and create our first plugin or our first uh custom rich text styling feature if you want to call it that. Now I'm going to ignore I'm going to ignore the imports for now and I'm going to come back to them in just a little bit.
Now the reason I'm doing that is because by importing at the end, my Flake 8 linter will say, oh, actually you have a function or you have a class or something that's being instantiated that isn't loaded in this file, you need to import it. And that keeps your imports nice and minimal. So what I want to do is at hooks. dot register and in here I'm going to put register rich text features And it would help if I could spell that, right? Register rich text features. This is our hook. And because you see this at sign, it's a decorator, so we need a function to decorate. So let's create a function. Register. Code styling and it takes one parameter features and then we can do our customization in here
Okay, so I just gave us some room to work there. I just closed up that side menu. And let's create a doc string. And this one is going to be our code. So we're going to add the code. To the rich text editor. Lovely. Okay, so now we have a few different things that we need to add here We're going to add a couple variables. We're actually going to add a few variables. So the first one's going to be a feature name. Second one's going to be a type And the third one is going to be a tag. Now in this example, they're all going to look the same, well, or very similar, but in the following example, they're going to be different. So there's a reason that they all sort of look the same in this situation, but in our center text one, the one we're going to create after this, they're going to look different.
So just bear with me on this one. So this one is going to be called code, because that's what our feature name is. The type that we want, we're gonna call this code. This is for mapping to uh to the database and out of the database. And the tag that we want to use, the HTML tag, is code. So next we need to configure how uh how DraftTail handles this feature in the toolbar and what that means. How is this being handled? So when you put your your mouse over, does it say heading to? Or in here does it say italic? Does it even have an eye? Does it have an icon? Does it have some sort of text in there? That's what we're going to tackle right now. So we're going to call this one control.
This is not content. Troll. And this is simply a dictionary. So this dictionary is going to have a type. And the type is going to be what we told it to be. It's code. And we're using this because we're going to reference this variable a little bit later. Next we have a label. Label. And this is what we want it to say in here. What we want it to show up with, maybe it's an icon, maybe it's just some text. I think we're just gonna stick with something that looks like code. It seems pretty similar And then we want to add a description. Description. And what is this going to be called? We can call it code or code style or anything like that. Let's just call it code.
Okay, so we've got a control variable in here, but nothing's actually happening because we're in a function and well there's nothing you can really do with a variable in a function unless it calls another function. So that's what we're going to do. So step three is we're going to call another function, actually it's a method, to basically register everything that we've said here, the type, label, and description. to draft tail. So we're saying draft tail take this stuff and throw it in your nav bar. Throw it in your throw it in your bar here. So this one takes features dot Register, editor, plugin, and the first parameter it's going to take is a draft tail, draft, Tail
1T is going to take our feature name and this one is going to take draft tail Features dot inline. Is this going to do it for me? Nope. Maybe it's because of this. Maybe it's not going to do it at all. Who knows? Yep, it's not going to inline style feature. And this one's going to take control. So basically we're just saying features, what we take from up here Let's actually move that over. So we have features as our first parameter. Features comes with a method called register editor plugin. We're saying register it with draft tail. The feature name is code. And how it's going to handle it is an inline style feature. So that was
step three. And this one is step two, and our variables are step one. Alright, next step is we need a database conversion. So basically, the way that things are saved in the database is not the way that you think they would be. We don't save raw HTML in the database just because If you're linking to a Wagtail image or another Wagtail page and that page ID changes or or that page just goes away entirely. Or an image source changes, say you upload an image, select it in your rich text editor, and then you decide, oh, actually I want to go and change that image. So you upload a different image with the same image ID. DraftTail will recognize all of that for you.
And so it stores it in a special format. And for us to work within that format, we need some sort of database conversion in and out of the database So let's create another variable here and we're gonna call this one db conversion. And this one is going to be a dictionary and this one takes two keys. From database format takes some stuff in here and to database format and it takes some stuff in here So this first one, let's get rid of this. This one's going to take a dictionary. Again, this one is going to be a tag. And we're going to say this tag needs to be an inline style.
Element handler. It's quite the name. Type. I'm just gonna close that off. We'll make sure all of our brackets match here so our brackets look good And then down in the to database format, we want to again create another dictionary in here. This one's going to be called style style map. And I did that first one wrong too, actually. So, style map. And this one's going to be a dictionary. This one's going to take our type Nope, I actually got ahead of myself here. So this one is not the name of that one. This one is going to be the actual tag that we're registering here. So this one's going to register our tag in the database. So
It's going to say from database format, whatever our tag is, that is our code. Handle this as an inline element basically. Then we want to map our styling. So our type is going to be again, this one's another dictionary. So this one's a few dictionaries inside of dictionaries. And this one's going to be an element and this one's going to be the tag. So basically what we're saying is through all this complexity here, when it's coming from the database, you're going to have your tag. That's code, which is going to be Code. When you have that, you want to map it to this type. Code. And to your database format basically does the exact opposite.
So now we have a dictionary for db conversion. Now again, this is just a variable. We actually have to register this with DraftTale, with Wagtail as well. So let's go ahead and create. Features. register converter rule and this one's going to take a content state because we're changing the state of our content This one's going to be a feature name. That maps here. That's what our feature name is. Not the tag. It is different. feature name and we're going to say when you're working with this feature name use the db conversion dictionary as your set of rules And then lastly, and this one is technically optional, but if you wanted to append this to all rich text editors across your entire site by default, you could do this.
So let's say this will register. This feature with all rich text editors by default. And It goes features dot default default features dot append Feature name, feature name, feature name, feature name. Okay, so we have a bunch of stuff in here. Okay, so here's the thing. When we open up our terminal. We don't see any errors, despite the fact that we know that there's supposed to be errors in here. Now what's the deal with this? Wagtail hooks get loaded when Wagtail loads.
So if we just simply restart our server. There we go. Now we're actually seeing some errors in here. It says names. Name hooks is not defined. So this basically says, oh, you don't have any of your imports. So let's go ahead and add our imports. Let's add our hooks first. So let's do from Wagtail. core import hooks. It's a core feature. Let's also import Uh what's the next one that we have to add? You saw that takes care of hooks. We need draft tail features and inline style element handler. Okay, so let's import. Import Wagtail dot admin dot rich underscore text dot editors dot draft tail dot features
as draft tail Features. So we're actually just importing feature, but we want to rename it because feature is uh it's sort of ambiguous. You're going to be using it a lot in your hooks, in your in your rich text hooks. So let's just call it DraftTail Features. And then uh let's import our inline style element handler. And that one comes from wagtail. admin dot richtext. converters. html That was the wrong one. HTML to content state import and this one wants to be an inline style element handler Alright, so we have our imports. I don't think there's anything else that's missing in here. Let's go ahead
open up this. Is this actually going to complain? Yep, same complaint. No module named Wagtail Admin Rich Text Editor. Okay, so I probably have a typo in there. Yep, editors. So we'll just save that. Okay, one more little typo. It's supposed to be features. I know better. This probably should not be happening. Alrighty, so let's go ahead and open up our browser and let's refresh this page and let's see what happens. So yep, let's leave the page. We have a new element in here for code. So test, test, test, test, test, test, a bunch of stuff in here. And select that. Oh, hello. Let me zoom in on that.
Sorry, this made Wagtail really ugly. But as you can see, there is some actual code styling in here. So let's Let's preview this. And let's inspect our elements because I want to make sure this is code. Look at that. There it is. Code. So that's inline elements So that's all the that's all it took. You can add delete, strike, span, anything else. You anything else that you want you can add now. This is To me, this is a really important feature because I work with uh sites that need to display code and sometimes I need to display inline code. So this is really, really nice. I mean the styling of it is not nice. I would style it differently, not not the way that this theme has it, but we can see that it is actually working.
So that's fantastic news. Go ahead and save draft. Now you can see when we put our mouse over it, it says code. That's our little description. We have our label in there and it actually creates all the code for us. So the next one we want to do is uh we're gonna move down to the bottom here. We want center text. Now this one is a little bit different, and at the same time it's a little bit the same. So we're going to follow the same sort of rules here, step Uh three, let's do this. Step four, and then we register it. Step five, and this one is step six, but it's optional.
Okay, so now when we want to register a new hook, we can do the same thing. So again, we're still in wagdelhooks. py, so let's create a decorator. Hooks. register. Register rich text features. And because it's a decorator, we need something to decorate. So let's decorate a function. Let's call it register. Uh nope. Let's register center text feature. And again, it just takes features as a parameter and creates centered text in our website or in our rich text I guess So the way we're going to do this one is we're actually going to use a div
and we're going to basically say div style is equal to text align center. And we're gonna put our content between that div and we're gonna close that div. That's how this one's going to work. So it's a little bit different. A div is a block element, so it's gonna take up the entire width from left to right. Whereas the code one, the one that we just worked on, is an inline style, so it works with text beside it. So they are technically different, and that's why we're doing two examples in this video. So let's go ahead and create a feature name. And this feature name is uh let's just call it center. Let's create a type. The type is equal to center text, I guess. Tag is equal to a div
Step two is we need to add some control in here. So let's add a dictionary. We have our type that takes something. Just copy that over a few times. Then we have a label, and then we have a description, and then we have one that we didn't use last time, and this one is style. So our type is simply our type. Our label is yeah, just call it center, center text. Call it whatever you really want. The description is going to be center text. Very simple. And uh the styling is going to take another dictionary, and in this dictionary, we're going to give it display
and text align. So this is our CSS at this point. So this is our style attribute and this is the actual CSS that we're going to put in there. So display is going to be block and text align is going to be center. And that just makes sure that our div always acts as a block and so that our text can always be centered. Next, we need to register this. So features dot register editor plugin And this one's going to be draft tail. This one's going to take the feature name again. Draft Tail Features. dot inline style feature and this one's going to be a control. It's going to take control.
It's what we just wrote. That's our dictionary up there with the styling in it. Next, we need some sort of funky db conversion in here. So let's do some db conversion is equal to it's a dictionary. It's going to take from database format and it's going to do a bunch of stuff in here and it's also going to take to database format And it's also going to take a bunch of stuff in here. So let's do the from database format first. This one is going to be again a Dictionary, it's gonna take our tag, so it's gonna map whatever our tag currently is to an inline style element handler and let's take Let's give it a type. Now the two database format, this is where this one gets a little bit trickier, I guess.
And I'm going to show you a cool little thing that we can do. So to database format, let's give this one a dictionary as well. This one has a style map. And let's use the style map a little bit differently. So that one's also a dictionary. And this one's going to take the type. Because that's what we're mapping here. So we're mapping our type in and out of the database. That was going to take a dictionary. And in here we're going to be able to give it an element and some props. So let's give it an element, and that's going to be whatever our tag is. So it's now mapping the type to our tag. And let's give it props. And this one's going to be a dictionary as well, although this one could probably be in one line.
And let's give it a class. So these are the properties of your HTML element. So this div can have a specific class. And if we wanted to, we could put anything in here. So because we're using bootstrap, we could use d block. But let's also put ZZZZZZZZZ test Z Z Z Z Z Z Z so we can clearly see that this is going to work. Alright, and then uh just like last time we need to register this. So This dictionary is nice. It's a well-formatted dictionary. It's totally useless until we actually register it. So we do features dot register converter rule. Content state, feature name, and we'll give this one dbconversion.
And if we wanted to, we could optionally append it to every rich text editor on our website by default. And we give it default features dot append and the feature name. All right, let's see. If there are any complaints. No complaints. Alright, look at that. Okay. Refresh the moments we are waiting for. Oh, hello, center text! This is an announcement. We are centering text. Okay. Let's grab that, center it. And yeah, let's preview. Alright, let's take a look here. So Alright, this is an announcement. We are centering text. The text actually is not centered.
It's because I actually misled you on just one small little detail here. But before I get into that, we can see that we have a div in here. We have d block. with bold in the middle. This is for the most part working, just our text is not centered. Now to test center our text we can simply add a class Let's add the class text center and I just want to explain one thing here. So this is our control styling. This is when we are inside of draft tail So when you see this, this is being centered in here, this is what it's doing. Display block, text align center. It is saying this is a block element, so take up this entire width, don't let things be side by side
and also center that text. That's what this one is saying. So this one is not what is going to be output. This is what is controlled in your rich text editor And to actually make that text center, we add a class in here. Although if you wanted to, you could add your own class. I'm sure you could probably do something like this where it says style, and then you could have. Text align center if you wanted to. I've never actually tried that one, uh, just because I always prefer to do things in classes. And so we're going to stick with text-center, and things are looking good Now as a summary, here's what we did. We wrote some text, we selected some of it, and we said this has to be the code styling. So it looks like this code.
This element here. And then we said, okay, well, what if we want to do something a little bit bigger? What if we wanted a full block element And so what we did was we added some centering in here. So you can now center text in your rich text editor, and you can also make some stuff be styled with the code element in HTML. And if we wanted to, we could further extend this by quite a bit. We could add all sorts of additional things. In fact, you could even add React components in here. so that you can do advanced things like uh like getting stock numbers. So you can just like select a little section and you can basically create uh where where's a good menu A little menu like this, you type in your stock, and then it'll go look up your stock. And instead of having like a little link icon beside it, it can have a little stock icon.
You can do all of that stuff. It is fully customizable Now we're not going to get into all of that stuff because we're going to be here for a long time. This is an entire course on its own, but I wanted to give you an introduction into how you can create inline styles and block element styles inside of your rich text editor. So I'm just gonna publish that, and that is all there is to this lesson. I hope you learned a lot in this lesson. We did go over quite a bit. And don't forget, you can always check out the source code on GitHub. I will leave the link in the description down below My name is Caleb Tallinn. I'm an author on learnwagtail. com. If you like this video, don't forget you can subscribe, you can share, you can comment.
I love hearing feedback from people. And because this is such a big subject, I would highly recommend going to the Wagtail. io documentation at docs. wagtail. io to further expand your knowledge on how to work with the draft tail editor.
Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published August 26, 2026
Published July 9, 2026
Published May 20, 2026
Published April 16, 2026
Published March 12, 2026
Published March 10, 2026