Rich text fields are a one of the most flexible components in Wagtail, giving content editors many options for formatting text, embedding content etc.
But sometimes there can be too much choice, this is where customising Rich Text fields can be really useful. For example, we might only want one H1 on a page. Or we might have a specific field in the page model where we upload images - rather than within the Rich Text field.
Not only does this keep pages content well structured it also cuts down on content-review time.
In this weeks video, we’re going to show you how you can improve the Rich Text field experience in your Wagtail site, in just a few simple steps.
Intro - Welcome To Wagtail Wednesdays
Hi and welcome to the second installment of Wagtail wednesdays.
This week we're going to be talking through customising features within a Rich Text Field and why it's important to provide content editors with the right tools for the job.
Section One -Example Set Up
Here we have basic page in which we've added three editors.
The first one is just the default editor you get when you add a rich text field to your model.
The second one here has every currently available feature in Wagtail 2.0 enabled. The only difference between this and the default are three additional header block styles.
Our final editor is currently the same as our default one. This is just where we'll be adding and removing features throughout the course of this video.
Section Two - All Features Overview
Before we move on to customising which features are available let's just quickly take a look at our complete editor and go through what each feature does.
Firstly, we have the basic inline styles - bold and italic. After that we have a few different block type styles starting with headers 1-6. The last two block styles we have here are unordered and ordered lists.
The next two features are just utility. The first creates a horizontal rule and the second creates line breaks.
The next group of four are entity features. These include the image chooser feature, where you can choose from existing images or upload a new one. The insert embed feature which allows you to add a url for embeddable content such as a YouTube video.
The insert link feature which allows you to select an internal page, type an external link or add a mailto email link. And finally there's a document chooser feature, which works pretty much the same way as the image chooser.
These last two, on the end here, are just undo and redo and work how you would expect. One thing to note is that when we customise the features in our editor the line break, undo and redo features will still appear as these are always present and aren't configurable with the technique we'll be showing off in this video.
Section Three - Customising Available Features
So let's take a look at how we can customise the features for our editor. If we look in our models.py file we can see the Rich Text Field for our custom editor defined here.
To override the default features we simply add 'features' to the list of keyword arguments in the Rich Text Field invocation and pass in a list of strings that represent the features we want to add. So let's just add 'bold' and 'h2' to our list for now.
If we go back and refresh our page, we'll see that it now only contains the two that we specified in our model, plus the linebreak and undo redo buttons.
Section Four - Setting Up Custom Feature Groups
We've done things a little differently with our complete editor. If we take a look at it, you can see that we've passed in a variable called 'ALL_RICHTEXT_FEATURES'.
That variable is imported here from our base.py file. Looking at our base.py file we have the 'ALL_RICHTEXT_FEATURES' list defined here at the bottom, which is just created from the amalgamation of the lists above.
We've separated out the features into these separate lists here just so you could see the different types of feature. Such as 'inline', 'block-level', entity and then we've got 'hr' on it's own which we've just called a 'utility' feature.
Let's create a new list which we'll just call 'OUR_LIST' and let's add 'h2', 'h4' and 'bold' to it.
Back in models.py we need to add this to our import statement, up here. We can then pass this in as the value of our features argument for our custom editors Rich Text field. If we go and refresh our page, we'll see the new list of features has taken effect as expected.
Section Five - Working With Lists (The Bad Way)
Now, let's imagine that this list represents a set of features that we've set up to use in some of our editors across our site. We might want to just add or remove certain features from this list for one of our Rich Text fields, without creating a new list. So let's have a look at how we could achieve that.
The first technique we're going to show you is a way we don't actually recommend for manipulating the list. We'll show you some issues that you're likely to run into with that method and after that show you a way that's much more robust.
Firstly, we want to create a copy of our list which we'll call 'customised_list'. Because Python passes by reference by default we'll need to import 'copy' up at the top here and call 'copy.deepcopy' and pass the 'OUR_LIST' list into it.
Now we have a perfect clone which we can modify without modifying the original - in case we want to use that elsewhere in this model.
Next we can type 'customised_list.append' and then pass in the string representation of the feature that we'd like to add. Here we'll just add 'ol' to enable the ordered list feature.
Now we just need to paste 'customised_list' in place of 'OUR_LIST' in our Rich Text fields features argument. If we refresh our page, we should see that the ordered list has now become available.
Now let's take a look at removing a feature. If we go to our base.py and choose one of these features to remove... we'll just do 'h2' for this example. In our models.py we can type 'customised_list.remove' and pass in the string 'h2'. And then if we refresh our page we'll see that it's been removed successfully.
This is the first place that you can hit a bit of trouble with this approach. If we change this 'h2' to a feature we don't actually have in the 'OUR_LIST' list of features and then try and save, we'll get a Value Error. You can see here in the terminal that we have a Value Error that says that we tried to remove x where x didn't exist in the list.
If you were intent on using this method, you could work around this by implementing a try/catch block like this. We try to remove and catch any Value Error that might occur. If we do catch a Value Error we simply 'pass' which essentially means we do nothing.
Back in the terminal the error has disappeared and everything is running OK.
Now you can imagine that if we wanted to append a lot of features, this could quickly become quite messy. One way to add multiple items to a list is to simply type 'customised_list' plus equals and then type a new list of features that you'd like to add.
This is where we'll show you snag number two. It's actually possible to add multiple of the same item to a list, like this 'h1' here. When we go into our page and refresh we can see that we now have all the features we've added in, including multiple 'h1s'.
Now for the final issue that you can face using these techniques.
If you try to remove several features in the same way, by typing 'customised_list' minus equals then a list of features to remove we'll get an error in our console.
The console is telling us that this is an unsupported operand for lists in Python.
Section Six - Working With Lists (The Better Way)
So taking into account the various potential niggles with these methods let's take a look at a more robust way.
First let's remove all of this, and then what we're going to do is turn 'customised_list' into a 'set' which is a data type that consists of an unordered collection of unique and immutable objects.
Already, by turning our list into a set we've prevented any chance of duplicates. If we try to add multiples of the same value to a set the duplicated are simply ignored and won't be appended.
We can add one, or multiple features to the set using the update method and pass in a list of the new entries we'd like to add.
To remove one or multiple features, we can simply subtract a set of the features we'd like to remove from the current set. If we try to remove something that isn't there we won't get an error so no need to worry about that either.
If we take a look at our page we can see it's all working nicely. One thing that does look a bit strange is the order of some of these features. Luckily - there's an easy fix!
In our model here, we just need to add one line where we call 'sorted' and pass in our set. Our features should now be in a nice order on the page.
Section Seven - Overriding Wagtail Defaults
The last thing we'd like to go over in this video, is how to override Wagtail's own default set of features. This can be useful if you know you'll only ever want one set of features throughout the site and it'll save you have to pass anything into your Rich Text field's invocation.
In our base.py we need to declare a 'WAGTAIL_ADMIN_RICHTEXT_EDITORS' dictionary. Let's add the 'default' key which will hold two keys within it - 'WIDGET' and 'OPTIONS'. In 'WIDGET' we need to pass in the Draftail RichText Area widget, this just tells Wagtail that we want the default Rich Text editor to be Draftail.
In 'OPTIONS' we create a key called 'features' and for the value we simply enter a list of the features we want to be enabled by default for our Rich Text fields. We'll just add unordered list, ordered list and link in here to test it.
After refreshing our page, we can see that our default editor now has a different set of features.
Thanks For Watching
Thanks for watching our quick guide on how to customise features in Rich Text fields. If you enjoyed the video, please like and subscribe to the channel. You can also sign up to our mailing list for early access videos - the link for this is in the description below.
We really want to make sure that these tutorials are useful for everyone so if you have any ideas for future tutorial topics follow the link in the description and send us your suggestions. Alternatively you can comment on this video with your suggestions as well as any other feedback and questions you might have.
Thanks and we'll see you next time!
Want Early Access To Future Videos?
Want Early Access To Future Videos?
Pop your email address in the box below and receive new videos before everyone else!
Thanks for subscribing!
Look out for the early access links in your inbox.