Redesigning and refactoring Wagtail components

This video is from Wagtail Space 2025 in Online.

Redesigning and refactoring Wagtail components
0:30:01
Published November 19, 2025
75 views

Refactoring components can be hard in any CMS framework due to content governance and technical challenges. When a redesign needs a block to have a new required field, drop an existing one, or change its placement, how can we guarantee that content won't be lost and that UI won't be broken? Wagtail stream field's JSON structure poses some challenges if we want to make changes to blocks' structures without having to rebuild existing content.

This talk will go over the issues we faced implementing a redesign on a Wagtail site and the lessons we learned from it.

💻 Wagtail is the easiest open-source Python CMS to use:
Install the demo and start building your first site in 10 minutes: https://wagtail.org/get-started/

📹 Related Videos To Watch Next:

â–¶ Quick Video Tour of Wagtail CMS 7.0 https://youtu.be/r5RbV7TveFU
â–¶ The Latest on Wagtail AI https://www.youtube.com/watch?v=4zfs1u4Vy5Y
▶ What’s New in Wagtail CMS 7.0 https://youtu.be/v92-6Dy4axI

Wagtail future proofs your CMS system, as it’s open source, continuously updated and built on Python, one of the most popular global programming languages, used widely in machine learning and big data. So you’re always ahead of the curve when it comes to CMS platforms.

Wagtail is the #1 choice for accessibility, is scalable and most importantly, secure.

👉 Get started with Wagtail CMS for free: https://wagtail.org/get-started/
and see how easy it is to build a website that works for you.

📊 Read why Google, NASA, and the British NHS, are powering their digital estates with Wagtail: https://wagtail.org/about-wagtail/

🎥 More Wagtail Videos: https://www.youtube.com/watch?v=cne2kxemMAQ&list=PLfwZ-fob20cPvSQ_v1hkjto8BAPN21tLJ

📣 Follow us on social:

#WagtailCMS #Django

Summary

Mariana explains how to design Wagtail components that give editors useful content choices without exposing every detail of a design system. She recommends separating full-width section blocks from smaller reusable elements, limiting settings to avoid confusing editors and producing untested combinations, and splitting overly complex blocks when appropriate. Using examples from a rebrand, she shows how refactoring a heading or button changes StreamField JSON and therefore requires a strategy for existing production content: Wagtail StreamField migrations, custom recursive transformations, carefully named blocks, or—in small cases—manual edits. Alternatives include marking blocks or page types as deprecated, validating them out of future edits, rebuilding pages and swapping slugs, or preserving radically incompatible legacy pages as raw HTML. The technical migration must be paired with content governance: document the new system with example pages, identify and transition affected content, set deadlines, verify completion, and remove legacy code only afterward.

Key takeaways

  • Keep section-level blocks focused on page structure and use smaller reusable blocks for elements such as headings, buttons, images, and cards.
  • Give editors as few presentation decisions as possible, since excessive settings create confusion, complex code, and combinations that are difficult to test.
  • When a block’s structure changes, plan for existing StreamField data with a migration, a recursive custom transformation, or manual edits for a very small number of pages.
  • Consistent names for nested blocks and fields make it much easier to locate and transform content in large JSON structures.
  • If data cannot be migrated cleanly, deprecate old blocks or page types, rebuild and swap page slugs, or retain legacy output in a raw HTML block.
  • Treat refactoring as a content-governance project by documenting the new blocks, coordinating editor changes, tracking affected pages, and verifying the transition.

Summarised automatically from the transcript.

Chapters

  1. 0:00 Introduction Mariana introduces herself, Lincoln Loop, and the talk’s focus on redesigning and refactoring Wagtail components.
  2. 2:01 Wagtail Block Architecture An overview of section-level blocks, inner blocks, and the smaller content elements that compose them.
  3. 5:08 Editor-Friendly Component Design Guidance on limiting editor choices, avoiding overly flexible blocks, and balancing guardrails with stakeholder needs.
  4. 9:49 The Rebranding Case Study Lincoln Loop’s quickly built Wagtail site needed to be refactored when the company introduced a new brand and design system.
  5. 12:13 Refactoring Heading Blocks The talk demonstrates replacing a simple heading field with a reusable, configurable heading component.
  6. 13:46 StreamField Data Migrations Changing block structures in production requires preserving existing content through migrations or other controlled approaches.
  7. 15:17 Migrating Nested Button Data A detailed example shows how to move button settings into a nested structure throughout a StreamField JSON tree.
  8. 21:28 Block Deprecation Strategies Naming conventions, manual updates, deprecated blocks, and validation can help manage refactors when full migrations are impractical.
  9. 23:47 Content Governance Successful redesigns require coordinating with editors, documenting the new blocks, and planning how existing content will change.
  10. 25:19 Transition Plans and Legacy HTML The final strategies cover deadlines, rebuilding pages and swapping slugs, and preserving radically outdated content in raw HTML blocks.
  11. 29:10 Questions The speaker invites questions and closes the session.

Transcript

3,371 words · auto-generated Show

Automatically transcribed, so expect mistakes in names and technical terms.

0:00

Speaker 1: Okay, we've got lots of people joining, so I think we can make a start. Um say hi everyone, I'm Abigail, I'm the principal delivery manager for Wivetail at Torchbox And I am delighted to introduce your speaker for this session, Mariana from Lincoln Loop, who's going to tell you about redesigning and refactoring Wagtail components. If you do have any questions as we go, then pop them in the Q<unk>A and we'll try to get to them at the end. But I'm going to hand over to you, Mariana.

0:29

Speaker 2: Thank you, Abigail. Hey everyone, nice to meet you in virtually. I hope you're all there though I can't see you. I'm Madiana and I'm here to talk about how to refacture uh light tail components. So that's me. I work at Lincoln Loop. I'm based in Rio, in Brazil. Fun fact, I actually graduated in history. I have this past in the humanities, though I didn't last too long as a teacher. And I practice aerial

1:15

Speaker 2: acrobatics. That was my birthday there. I work at Lincoln Loop, we're a software development uh shop. We will work mostly with Django and we have been working a lot with Bagtail recently. We've been given a lot of thought into what makes a good Wagtail website if you hang out a little later today. We have Mike also talking about what makes good Wagtail websites. So uh I'm going to talk about

2:01

Speaker 2: uh refactoring blocks uh in Mike Tao, but first let's talk about uh how we usually structure uh our blacktail websites. So uh we have basically two kinds of blocks We split them basically into two categories. The first one is the section level blocks. It's basically the first level of blocks that you see on a website. They will usually be full-width blocks that he and that will semantically in the HTML be uh section. So if you scroll through a web page, those will be

2:47

Speaker 2: the big chunks of content that you see from with composing the website. Those are heroes, card, lists, spanners, a big chunk of text, basically everything that goes full width. So this is an example of a very simple white tail page that has when you click to add a new block, that's what you would see. an intro which would be a hero , generic sanction, a banner, notification. So those are examples of first slap of blocks that we we usually build for

3:35

Speaker 2: websites. And those first slap of blocks are usually composed of uh smaller inner blocks, which basically correspond to elements or HTML tokens. That could be anything from images in text to and buttons To more uh slightly more complex uh structures as cards, and those will be composed of even smaller bits like headings, uh buttons, text, images, etcetera. Um

4:21

Speaker 2: so when you're uh building those uh smaller bits of content, those elements, uh you will usually have the fuse there that corresponds to the content itself. So we have a the example of a button that is uh that has a text, a link. and um we're leaning it towards this pattern of having uh all of our blocks having those set settings uh which control the presentation of the component. So you can have a theme for the button, primary, secondary, you can have it

5:08

Speaker 2: have an icon, etc. But how do you decide what goes into what and how small are the small bits? that compose those bigger blocks. I could obviously give an entire well maybe not me, but someone could give me we 'll give you an entire uh talk about how to uh decide uh how you compose all of those pieces into the real blocks that you will have on the page But in general, we try to lean towards

5:55

Speaker 2: having the most simple and basic decisions to your editors. So unless you have uh your the the person editing your content is a very technical person and uh or if they don't need a lot of control over uh what's the layout who 's uh they're they're building uh You want to give them the least options to choose from as possible. Because too many options can be overwhelming if you have uh huge list of um uh uh settings

6:41

Speaker 2: uh and you don't know which one which each of them mean uh you have to make a ton of decisions to just put a simple card on the the screen. Even if you have a bulletproof design system , giving too much control for your editors. can lead to broken visuals can you because you cannot account for all the possible combinations uh of things that you can put on the screen Of course, the code gets more complex. And above all, your editors should be thinking about their content, not about the presentation.

7:27

Speaker 2: So here on the right, I have you, I show you an example of things that you probably don't want to do with your um CMS, which is a container that where you can control the padding, the team, the dividers, the number of columns that have in it, and that container have so many elements that can go inside of them that it's basically uh impossible to test all the possible combinations of things that will go inside that container and it will probably lead you to making mistakes and building uh basically ugly websites But that's not the theme of the talk, but there's just

8:16

Speaker 2: a thought that we want to stick to when we want to think about refactoring components. So if you see yourself building your blocks one -to-one to your design system, it's probably a bad sign. uh it means that you don't you haven't put enough decisions into your block architecture uh and of course of course it depends on who are the people who you who are building your system So usually more guard radials will prevent

9:02

Speaker 2: uh broken layout, but there will always be that marketing person that says, yeah, can I make that button red? Can I put that extra thing on the right? So you will always have to wait between those guardrails and the things that are asked from you. So yeah, some of the restrictions may frustrate your stakeholders and you will have to make those decisions with them. But at the same time, too many variations will be uh overwhelming to editors. So instead of having a ton of settings in the same block, you might want to

9:49

Speaker 2: split that existing block into a different one. At the same time, if you have too many similar blocks, it can be also confusing because the person doesn't know which one to choose from. So let me talk about uh our rebranding story. Uh at Linkaloo we had a static website. There's small a simple website to talk about company what we do present our services And uh this site has always been edited by technical people who can could just write HTML directly. And at some point we had a non-technical person that needed to

10:37

Speaker 2: edit the content on the website. Uh so We built them very quickly a Wagtail website. We basically got all the not all most of the existing pages that needed uh to be edited by that person, put them one one-to-one in Wagtail Since we knew this would be throwaway work, we basically created the blocks. exactly as uh they already existed on the HTML that we had, uh

11:25

Speaker 2: just to give them quick access to to do that But at the same time, we had a parallel work going on of rebranding our entire company. And a part of that rebranding was a new design system. So basically as soon as that uh redtail uh site was ready, it was already time to refactor it and make it compatible with our new design system. So the heading component was one of the examples of how that uh refactoring went on.

12:13

Speaker 2: Now that we have a nice design system, we want to apply it to everything, we created this heading block that has uh the main heading, an optional accent text, an optional subheading text uh it can be left or right line and you can choose the the heading level so h1 age two etc and uh uh in the proportions of the text sizes will match depending on the the level you choose from. Cool and now we want this heading block to be part of our all of our our section blocks that have headings of course

12:58

Speaker 2: so we have some uh We had a few of those examples of uh those section level blocks uh that had headings which were just one rich text field and now we have we want them to have that uh entire uh heading block that you can compose. Cool. But that obviously uh what once you move make that change it will change the JSON structure uh of your uh of your stream fields data, right? Before you In this example we had a heading that was a string

13:46

Speaker 2: and now your heading is represented by a dictionary and each of the keys will be strings. that data has to change on the database or your content to be there. So if you're refactoring something that doesn't have content, it's easy. You don't have to take a care take care about this but of course you're usually refactoring something that already has content that's already in production and you have to keep that production content in place. You don't want the person to have to rebuild the entire page from scratch. So how do you do that? So ideally you do a data migration.

14:31

Speaker 2: In that case, I was too lazy. I had access to uh production database. I opened a Django shell, copied the JSON from there was there were basically two or three pages that had those blocks copy to the JSON from uh from the shell, edit them on my text editor, paste it back on the shell, save the page. No one has to know what happened Cool. But usually that's not what you would do in a production. uh situation. So let me give you another example

15:17

Speaker 2: of what we did recently So at the time I didn't know about uh those migration operations that uh Wagtayo offer. If you search the documentation, it will be under advanced topics, under Stream Field Migrations. uh it would have been great to know that at the time maybe i would have been less lazy and would have written uh a real migration operation. And those are the there's a list of all the operations you can do uh that are ready

16:03

Speaker 2: for you there. Uh but in our case since Since that operation is something that's happening on a deeper level inside the block structure, so it's not the first child of our swim fields uh none of those custom operations would do the trick or at least uh I couldn't find out how to uh use any of them to uh in a dark situation maybe some of the developers uh will tell me that I did something wrong uh and it was in fact possible to use them directly. So uh I'll give you an example of how this should happen. So in a different

16:50

Speaker 2: in another project we're working on, uh we just refactored this button component. You see that new feature from White where you have this collapsible inner block that has you can put that uh little cog icon there looks pretty you you can go directly edit your content and uh don't have to uh think about the settings um uh right away. Uh so we Did that refactoring where we moved uh those four fields into the settings uh

17:35

Speaker 2: inner block. This is how our button block looks like. So we have a structure block for the button settings where you have the team, the icon, the icon position. And the button block includes the button settings. So now I have to go through all my blocks. that have buttons and I have to change the structure of uh those JSONs So before if you look at on the left, uh the buttons are a list of dictionaries. That dictionary has a value, the value had

18:22

Speaker 2: uh team external center, etc. And now some of those uh those fields have to move inside a new dictionary called settings and they have to live inside there Uh how do we do that? We got into the code. If you look on the right on that transform button list, um method we're basically going over a list of buttons for each button I get the value and I create a new settings dictionary inside that value where I put the theme icon, etc. inside of those settings. And

19:10

Speaker 2: I have to do that for each button on my uh tree. So on the left uh you can see that we walked through the the entire JSON from our stream field uh I look for the buttons list and when whenever I found the buttons list I transform those buttons. And I have to do this operation both for the intro and the section blocks. Those are the main

19:56

Speaker 2: section uh type blocks that have buttons inside of them. So on the section, for example, so in the on the intro the buttons are first level. block on the section for example I have them inside uh contents that have media content that has content that has button that has button So you have to know every place, basically every place in uh that you have a button and your migration has to be able to go through the entire uh tree to find that button Of course, that only

20:42

Speaker 2: works uh because all of the components that includes buttons. have use the same name for our buttons list uh if they use different names for that you would have to adapt the the migration to find them on the right place. So If you're if you find yourself in a situation where you have to migrate data uh Best thing is if from the chart you're very consistent with how you name your blocks and especially uh since those uh

21:28

Speaker 2: more elemental uh blocks like buttons, headings, images, uh the smaller bits that usually go inside other things If from the chart you have good naming conventions, it will make a lot easier when you have to migrate and find those elements inside your huge json blob and sometimes like in that case It might be just easier to do it manually. It will probably take you less time to edit a JSON in your text editor than to write a an

22:14

Speaker 2: entire uh data migration for that. But don't tell clients about this. Another option if you don't have the possibility to uh to use the entire data migration is to deprecate blocks. So you can, for example, flag a block as deprecated with the meta option. You can put an icon uh a warning icon you can put some help text there you can change the label uh of your block to indicate to to editors that they shouldn't be using that uh block anymore

23:02

Speaker 2: And you can even go further and add validation to your block that will prevent your page from being saved if that block is included on the page. So This won't change uh past existing data, but if someone goes there and tries to edit that page, they will have no option but to change that block for something else. if they want to save that page. Another step that you can take is to deprecate entire pages. So is instead of mix and matching uh your new refactured uh

23:47

Speaker 2: blocks with your it old uh blocks you may want to create entirely new page types and deprecate your old page types Again, you will not delete existing content, but if you uh set your parent page type to to an empty list that page type will disappear from the editing interface and no one will be able to create new pages from that page type. So, but in the end, uh it's all about content governance. Uh you know

24:34

Speaker 2: in a website that already has content, that already have people writing that content, you will need to communicate with those people. What to do about that old content that has to be changed. Ideally, uh you have uh structured all your blocks so perfectly that only the developers have to know What's happening, you write your data migration, everything changes, and your editors don't need to know about that. But that is probably never the case in real life

25:19

Speaker 2: So if you have a new pretty design that you're launching, first thing you have to do is Letting our editors know that things changed. Give them instructions on how to build the new things. I like especially to create example pages where I write on the text uh what each block is. So I add an intro and I choose a heading that says this is an intro. Then I add a section and I have a heading that says this is a section, this is a section heading, this is a button, etc.

26:06

Speaker 2: etc. So I basically try to create pages that guide the person into knowing exactly what they're looking at. Uh so after your editors know um uh what they're with dealing with, we have to have a transition plan. So you would need to query your database with all the pages that have uh old content that has to be changed. You have to instruct your editors how they go there and change to the new system

26:52

Speaker 2: uh we probably have to establish a deadline for them to do that. Then you have to verify that they actually did it and there's no page missing from it. And once you have all the your content transitioned, you have you 're able to delete the legacy code. Uh but yeah sometimes the easiest thing is to create everything new rebuild everything on the new system and then you can swap the old slugs by the new slugs. So for example you uh you have uh landing page

27:40

Speaker 2: the on a notes page type you create an entire new landing page uh and on the launch day uh you write a data migration that swaps their uh There are slugs, so you get the old slug into the new pages slug and whenever when when anyone clicks a link they'll land on the new page And sometimes a transition is just not possible at all. Sometimes the changes are too radical. and we just don't get to too proper data migration. Uh

28:25

Speaker 2: in that case We can always rely on raw HTML blocks. You can get the old rendered page. Stuck it in a Roy HML block and just move on with your new content. That's the more radical uh situation, but it's also possible But that's our experience. I would like to know what everyone else's experience is. What are your strategies? I suppose there are a lot of lessons to learn and a lot of better uh strategies that other people uh use.

29:10

Speaker 2: So I I will wait for you to pass your questions on the Q<unk>A. And that's it. Thank you for listening and getting contact if you like to. Looks like we have questions. Let me see.

29:32

Speaker 1: Thanks, Maria. Yeah, there's quite a few questions. We are unfortunately at time though, so I encourage everyone to add any questions that they've got. um into that lobby chat and we can carry on any conversations going on over there. But yeah, that was brilliant. Thank you so much for that. And if everyone would like to make their way back to the lobby for the next talks That would be great. Thanks everyone.

29:58

Speaker 2: Thank you. Goodbye.

29:59

Speaker 1: Bye

Questions this talk answers

How should I design Wagtail blocks so editors aren’t overwhelmed?

Keep editor-facing choices as simple and limited as possible rather than exposing every design-system setting. Too many combinations make the interface confusing, increase code complexity, and can produce broken layouts.

Discussed at 5:55

How do I migrate Wagtail StreamField data after refactoring a block?

Use a data migration to transform the existing JSON into the new structure, recursively finding affected blocks wherever they occur. Wagtail provides StreamField migration operations, but deeply nested changes may require a custom transformation; for a very small amount of content, manually editing the JSON can be practical.

Discussed at 13:46

How can I deprecate old Wagtail blocks or page types?

Mark blocks as deprecated, add warning/help text and validation, and prevent pages containing them from being saved until they are replaced. For whole page types, remove their allowed parent page types so editors can no longer create new pages from them, while preserving existing content.

Discussed at 22:14

How should editors transition existing content to a new Wagtail design system?

Explain the new blocks, provide example pages that demonstrate how they should be used, identify pages containing legacy content, set a deadline for updating them, and verify the transition before removing legacy code.

Discussed at 24:34

What can I do when a Wagtail content migration is too difficult or impossible?

Rebuild the content with the new page and block system and swap the old and new slugs at launch. If the change is too radical even for that, preserve the old rendered page in a raw HTML block and move forward with the new content.

Discussed at 27:40

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.

More videos from Wagtail Space