Mastering Plone 6 at Ploneconf 2021. Part 1 of 2
CC Attribution 3.0 Germany:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Bauer, Philip
What you will learn: The core technologies involved in Plone 6 programming and how to write your own add-on package and customize your Plone site by writing Python code and React components. Prerequisites: Basic Python and Javascript Knowledge. 0:00 Introduction 9:25 The Case Study
 I hope you can hear me well. I think audio should be fine with the microphone. There's one here. So we're super excited that so many of you decided to join this training. A big welcome from me and Katja, my co-host. Please, Katja, say something. Hi, all together. Nice to meet you here. Katja is in Sorrento, sunny Sorrento. Hopefully, I guess you're holed up in your hotel room. Well, I am in Munich. So the marvels of modern technology bringing us together here to give that training together. I hope that will work. Katja, I guess you can share your screen. You have the screen sharing feature as well, because I'm making you excellent. So you can make yourself heard and visible. If you have, before we start, some, I don't know, general tips and tricks, we'll have a couple of breaks. I hope. So this is going to be four hours now for our training. I we will stop at 7 PM central European summertime. So four hours from now. If we're finished earlier, that's also fine. If it takes five minutes longer, that's also fine. But the point is, if you need to go away, if your family pulls you away from the screen or stuff like that, that's not a problem. All of this training will be recorded and will be on YouTube after the conference at some point. Paul will have to do one of the foundation board members. We'll have to do that job and it'll probably take a couple of days to download everything from Zoom and upload everything onto YouTube. We will also add chapter markers to the video training. And yeah, so you can, if you miss something, the point is, don't worry, it'll be on YouTube. So if you need to take a break. Also, if you have questions, please use the Slack. That will be the best to use Slack. You could also use the chat here in Zoom. But in case we miss a question, because there were too many discussions going on on the side, please just ask them again or just unmute yourself and say something loud, that's fine. If you don't want to be recorded, because the whole Zoom meeting is being recorded, just keep your camera disabled. That is fine as well. Before I start sharing my screen, I would love to see all of you just for a second. I promise you, this part will not be on YouTube. I will cut this part. So you're not going to be on YouTube with this part. But if you just enable your camera for a second, so I can wave at you and wave back. So many faces I know. Really happy that you decided to join our training. You should give this training, probably. A couple of you have been around with Plone as long as I have. So you know more than me, probably. Let's see. Let's find out. OK, excellent. I'll take a screenshot of that. Maybe, yeah. Something like that. Yeah. I'll not post that anyways. Just a memorizer for me. OK, I'll start sharing my screen. So here goes. Screen sharing, excellent. In case screen sharing drops off or something, just yell at us so we can enable that again. You should see a browser saying Mastering Plone 6 Development. So this is also the documentation. We're following. It's on trainingplone.org. And it's the Mastering Plone 6 Development training that we're following. It's been updated yesterday and today and many days. A lot of times. But I think the last commit was a couple of minutes ago. I hope that went through. So if you want to follow the code examples, use this to copy and paste. Don't type. Please don't type. This is only two times four hours training. And we don't have time for you to correct your typo mistakes. I make them all the time. This is not a critique. It's just it takes much, much longer to type it. But a vertebral advice, if you do the training at home, continue the training or redo the training at home, which I strongly recommend that you do that. Don't copy and paste. Type instead. If you have the time, talk to your boss. Say, hey, I've got this training for free from the conference. And it's just it's maybe good, but not sure yet because it was only the two times four hour sneak preview. So I want to work through the whole thing. Type the code because when you do your own projects, you're going to have to type it anyway. A lot of your custom code. And it'll stick in your memory much better. So yeah, this if you want, you can switch off your video. If you want, it would probably be good for bandwidth issues. But if you want, you can also keep your video on. So you can wave at me if I say something stupid or at Katja if she says something stupid, which will certainly not happen. So this training is by default takes a week. So what are we going to do to make that happen in two times four hours? We're going to start skip a lot of chapters. And we're going to stop very early. So this training has as you see here, 54 chapters and we will stop, I don't know, somewhere much earlier here sponsored. We're not going to get to sponsors. 31 is the chapter we did last year at the end. So and we're going to jump ahead a lot. So if you think you missed something, just read the online training or and that's also very important. We can be hired Katja and me. We are certainly available to do in-house trainings for you or your company. We did that a couple of times already, various topics. So feel free to contact us, either her or me or even us as a team. She lives in Switzerland. Don't you Katja? Where exactly do you live? In Zurich. Beautiful. So if your company is based in Switzerland, Italy, or somewhere south of Munich, you probably should call here. If you're in Norway, you should probably call me. No. Yeah. The point is we are for hire, guns for hire, and not only for trainings, but also for plan development. We live of this stuff. So consider giving us a job. We're both pretty busy at the moment. So this is not a plea for jobs. But at some point, we will looking for more. So OK, this is about this thing is 10 years old, the training now. This is the video. This is incredible. I would love to hear some of you, something about you. But since it's online training, I will not force you, will not do this introductory round. If you the point here is we would like to hear what's of interest to you mostly, to discuss and give depth, more in-depth, deal with these issues more in-depth during the training. Since it's only abbreviated online training, we can't really do that. But at the end of today and at the end of the training, tomorrow, we'll have about an hour or 45 minutes open for discussion. And feel free to jot down any questions that you have. For example, I have this business requirement, or my client asks me to do this and that, or can we do this and that with Plone? This is that would be an excellent time to pick our brains to get these questions answered. So during this training, we will create, guess what, a website. That's what Plone is good for. And the website we're going to build is for a conference. And the conference is going to be a Plone conference. And it's the Plone conference in the year 2035. And it's going to be held on Mars, because Plone obviously rules the galaxy by then. And we're going to try to fulfill a couple of requirements. I'm not going to go through all of them. But obviously, if you have a conference, people should go to that website and learn something from about the conference, when it happens, where it happens, if there is a talk registration open, stuff like that. And then you also want to find information about what kind of talks are there, if there are trainings, what are the keynotes and the keynotes speakers. So this is basically stuff that you could do with just normal documents. You just write that down. But we want to structure that some more. And to be able to structure that, we could do that without structured content. But we want our speakers to be able to submit their own talks. And to have that in the same way, we create a content type for talks. And so speakers can submit them. And then I want to be able to edit my talk before I submit that. And I want to be, as an organizer, I want to see a list of all submitted talks, and so on and so forth. Yeah, a couple of requirements. And the most important point about that is not like there are complex comments. These are like everyday things. The requirements change because your boss forgets something or just a new requirement comes in. And all of these things happen during the lifespan of a project. Because let's be frank, you never got a project definition before you started that. That was 100% set in stone and never changed during the course of the project when you did the project. So for example, at some point we decide, we're not going to only have talks. Actually, these talks are going to happen at a certain time in the year. So we need to add time and dates. And also, these talks are going to happen in a certain room. Hopefully next year we're going to be in a physical room and not in a virtual room. So these are things that in this use case, you forget. You forgot when you started creating your website. And at some point, yeah, we will need to do that. And there is a lot of talks, tasks, that we need to solve for this. It will be interesting for you to read through that. I'm not going to go through that. You'll realize what's going to happen. And also, it's most important what we not do actually. We're not discussing professional theming. There's actually two trainings about that. One for the classic front end in plan 6, that is today. And one for theming Volto. That happens tomorrow. A training about that. We're also not going to discuss professional deployments. So if you really put that on the web and hosting websites, this is not covered in this training as well. These are the two most important things that we're not discussing. There's a lot of technical stuff that we're not going to do. I'm not going to tell you what PLONE is because you're going to learn about that. But I'm going to point out a couple of core concepts that if you are new to PLONE, and I guess a couple of you are maybe unfamiliar to you. And one is traversal. So that traversal stems from the fact that PLONE, as a content management system, stores content in a tree structure. So there is a tree where the content lives. So in this example here, you have the site root. And this tree has many branches and leaves. And the whole tree acts like a nested dictionary. So each branch has, again, a dictionary within it. And traversal is starting from the root and walking down that path towards an object. It's like a folder structure in Windows or Mac or Linux. So it's very familiar to you how the content is structured. And to access this certain kind of content, for example, from the site, you have a folder. And in that folder, there is a page. You can do exactly that. You traverse to that page going from the site to the folder, to the page, walking down that path. And this is also the way that URLs are built. So you have a URL. If you go to demo PLONE org, there is a demo site that you can use. And you have this structure here. Demo, a folder, a page inside a folder. So there is no routing like you would do in, say, Flask to expose a page inside a folder under this URL. But this is actually the structure of objects in that object tree that's exposed like this. OK, that's number one. Number two is also super important. That PLONE is built around the concept of object publishing. So if you have an object in your site, in your database, you can call that object. And this object will publish itself. So when you go to this URL, for example, or let's make it a bit simpler, DE demo, a page, this object is found via traversal, traversing down that path, that tree. And this object is found. And then this is called. So in Python, if you call something, you just do, how did I go there? You actually call that by with this. You open your brackets and close them. So here's your object. And then you call them. And once you call them, a lot of magic happens. There's actually a Dunder call method in a base class in there. And that, at some point, makes sure that a template or whatever happens in there is rendered. And it returns HTML to you. And this is actually what you see in the browser. So in a nutshell, this is exactly what happens when you open this URL. This object is called. And this HTML is returned. And your browser is smart enough to render that HTML in a nice way. That is the second basic concept of Plone. Third one is schema-driven content. So the content, Plone is built with content types, for example, a folder or document or a news item. And all of these have a different schema. And the schema defines, in other frameworks, it's called model, which kinds of fields basically are available to edit. So if I use this demo page again, and I log in as an admin here, and I go to this edit that, I have a couple of fields here. So this is classic Plone. We're going to move to Volto in Plone 6 in a second. These are the fields that are available. And these fields, all of these, there's a couple of fields, actually, they are defined in a schema. And these schema fields are then accessible as attributes on your object. So you not only can call your object, but you can have these objects have attributes. And the attributes store the value that you enter in a field that field is defined in a schema. There is not only string, like text, like here's some description, but also more complex attributes, obviously, like an image that is its own object, named blob image in this case. And it stores the data as the attribute data. And here you have the binary data from that image, for example. And objects can have multiple schema, and they are combined to give you functionality that you can reuse. Enough of that, I'm not going to go into the component architecture, but it's just a thing to prove that we are super smart, and you should be in awe of everyone who actually worked on that. And starting with Plone 6, Plone comes with two frontends. So there is the classic frontend that you're seeing here on the demo Plone org page, because Plone 6 is only in alpha stage now. But there is also a demo Plone 6. And these look a little, let me, classic. Let's open these side by side. So this is Plone 6 classic, and this is Plone 6. This is the official naming. Plone 6 has a brand new frontend written in React, a JavaScript framework that you're probably familiar with. It is client-side rendered. So the magic happens on your laptop or in your browser, basically, where the templates are rendered. This, whatever you see here, is rendered in your browser. And here, this is in Plone 6 classic. This is server-side rendered templates. So the HTML is returned via the concept of object publishing here. Actually, that's interesting. I should probably update that. Where's the object publishing part this year? Because Plone 6, modern Plone 6, actually doesn't call the object. It uses the Plone REST API to get a representation of that object as JSON and React or Volto. The frontend has its own name. It actually has its own logo that we're not using here. That makes sure that it's rendered. So object publishing actually is only true for Plone 6 classic, because that's where the objects are directly called. And it's your job to decide for whichever project you want to do which frontend you want to use. There is still a ton of classic frontend projects around. And it's been very modernized. It uses Bootstrap 5 and Webpack. And it's super modern and it's super cool. But it's not JavaScript. It's not React. So in Katja, there's a lot of Volto projects. So yeah, it depends on what you're doing. If you're a university and you have Plone site with 200,000 objects in it and you're migrating to Plone 6, going all into Volto would be a hard task because you'd have to rewrite a lot of your own code. So they will probably use the classic frontend. But if you're starting a completely fresh, a new project, Volto is definitely a smart default choice. OK, installation and setup are not going to go into that because you already, hopefully, installed Plone for the training. And if not, if you had any issues installing Plone for the training, please write something in the Slack channel so we can try to help you. Katja is available while I'm talking to help you assist you or if there's something fundamentally broken, we can discuss that together. But you should all follow this installation. This is the technical setup as a training. Here, installing Plone without Vagrant. We're not, hopefully, nobody tried to use Vagrant because this will probably not work on a Windows laptop at the moment because our setup is not updated for that. And Volto would not run. But you could probably run the back end in Vagrant. So use it directly on your laptop like this. If you had problems, just tell us. After we did this, you follow these whole instructions here and you got your Plone running, you should have a setup that looks like this. 3 minus L2. Let's say 1 first. So you have a folder that is basically empty except that it also has two folders, one for the back end and one for the front end. The back end is in Python and the front end is in React, in Volto. So if I expand that to 2, make that a bit bigger, you see that inside the folder back end, there is a source folder that will contain the code that we write during this training for the back end and a couple of other folders that I'm not going to go into now. And a front end folder that also has a SRC folder, which will hold the code that you write for the front end during this training. So I just decided that last year I used Sublime for the back end and VS Code for the front end. This year I will use VS Code for both, but me and Katja will both, when we switch from back end to front end and vice versa, we will always try to take you with us and tell you where we actually are because we'll have to do a lot of tasks on both, not the same task, but to fulfill a requirement, you need to make changes to the back end and then you make changes to the front end. And only some tasks require changes in one of these places. Actually, a lot of them require changes in only one of these. But yeah, it's a complex system and it's not getting easier by having a front end that is decoupled from the back end. Good. Since no one wrote any help, nothing is working in the Slack. I'll just keep on going and we'll continue with chapter 8, starting and stopping plowing, because that's what I'm going to do now. Here. So when I'm in this folder, I first stop everything first. Actually, I already started my front end because that takes a while, but I'll do that again for you. So I have two terminals and you should do the same when you're doing plowing development on your local machine. If you're a front end developer, that's a different story. You probably, some back end developer, got you a Docker container and that's running and you only care about React. If you're a back end developer and you only do back end, you have plowing running locally and you're doing your stuff there and you don't care about any of the JavaScript nonsense that your colleagues, tomes over are doing. So but in this training, you're doing both because you're going to be a full stack developer. I hate this word, but still, this is what you're going to do. You're going to learn how to work with Python and with JavaScript. But not only Python and JavaScript, but actually, clone, which is a huge stack on top of Python and React, which is a huge stack on top of JavaScript. Did I? Yeah, well, didn't say anything stupid here. So I'll go into the back end after I ran build out, which I already did, and I'll start my back end with bin instance FG. FG stands for front foreground, not front end, foreground. So this is the debug mode. So I'm going to see a output. Everything that's happening in my plowing side is visible to me here. And here I start my front end with yarn start after I install that. So you should have approximately the same setup right now. And if you go to a, let me close these demo sites, if you go to once it started, you can go to localhost 8080, because the back end is, by default, running on 8080. The front end is, by default, running once it's finished. It takes some time, especially when screen sharing, which also takes a toll on my laptop. It's a bit slower than. It runs on port 3000. So I'm going to start my browser here and go to localhost 8080. And it's already telling me, plow is running. And your plow side has not been added yet. I'm going to solve this riddle in a second. OK, Volto, here you see in the front end, also it has finished. And I can start that. And I can go to the front end. And it will tell me this page doesn't seem to exist, because I didn't add plowing yet. So to create a plowing side, I need to go to the back end. Always, you can't create a plowing instance in the front end. So when I say instance, we're talking about Python here. So a instance is, so there is a class defined. There's a class plow side, actually. I think that's what it's called. And when you create an instance of that, someone is instantiating that plow side, calling plow class. Site equals plow side brackets. And in a nutshell, that's what's happening when I click the button here. You should use the advanced button. Going to switch to English here, obviously, because that's the training language. Keep your time zone. Leave the name of your plow side as plow and pick the plowcon site add-on. You need to pick that, because otherwise, the front end will not work properly. This is auto-created and automatically checked out by buildout when running buildout. I'll click this button now, and plow switches to English. And when I go to the back end, I see when I scroll up, I saw ready to handle requests. And then I clicked after here, serving on. And then a lot of stuff happened, and plow told me about everything that it did, including here, finished bundle compilation. That's the last statement I see. And then I see a plow side, actually. Plow conference 2035. That's what it says. And starting now, I can actually see, this is the back end user interface. And now I go to the front end user interface. And I reload that. I should probably log out and log in again as admin. So when I say this is the back end user interface and the front end user interface, this is actually plow classic. So there is no what actually there is, but we're getting to that later. But this is the back end is the same as plow classic. So when we're developing plow six using React, and we say, we need to do something in the back end, that either means we need to write some code in our editor, or we can go to the classic user interface and do some manual changes there. And you see the content is the same. So if I modify, if I create a site here, for example, create a site and I say test. And page. And here's my, here's test. It just says test. Why does it say welcome as well? It's kind of weird. Something's wrong here. I should be able to reload this. And here it is. So this is just a visual representation of the same data that lives on the back end. So these are connected. These are not two separate things. These are separate processes, but these are not separate databases. The database of the back end is the same for the front end. That's the whole point of that. So here I got my site. I created a site. I chose the language. I checked PlonCon site, clicked create PlonSite. Then I saw that. And then I started, or even actually I did that before. I ran YarnStart. And I saw my front page in the front end. And I can skip over these exercises. You should do them at home. And then I see my site. I walk you through the user interface, the most important parts of the site. So obviously, we're always talking about, when we talk about the visual representations, always the React user interface that we're using here. And we're talking about. So here you have the header around the site. There is a logo that is always linked to your site route. You have a automatically built navigation that is created from the content that is in the site. You already have some content, which is weird, because you didn't create that. Plon did that for you. It's auto-generated content that is created when installing Plon. And I'm going to delete that. And you should do the same. Just select everything. OK, that was probably a bit too quick. Let's step back. So this is the navigation. Here's a site search. You can say, I don't know, test. Should be findable, because I created that. You have a content area, which is here's a header. Here is a content area where you can just write stuff, save it, and it's visible. This is what you're editing when you edit stuff. And there is a footer that has some links that can obviously also be configured by you. And there is a toolbar to the left side, which has the link that I just used to show you how to delete everything. That's a very important link. It's the link to contents. If you hover over these icons, they explain to you what they're doing. You can add various content types. You have more where you can change the workflow, change the view, inspect the history, and stuff like that. We're getting through that. Most important one is add, edit, and contents. We're going to use contents quickly to navigate to a page where you can manage content in bulk. There are breadcrumbs that you can use to navigate to the side route. I can select everything. And I'm just going to delete everything. Just kill it with fire. So now my blog site should be empty. Should only have this description here. If I do a hard read, that's caching in both. Obviously, I did a hard reloads there. So I got everything in the navigation. Just died and went away. So we covered the footer, the toolbar, edit, folder, contents, and add. We're going to ignore these for now. Yeah, very important. You also have your portrait here. You can log in and log out. There should be your photograph. You can modify your profile. And you have a link to the site setup where you can configure the site. So why am I not seeing this? And why does it say admin and not Philip Bauer? That's because we haven't created a user yet. And that's actually something you should do as a very, very first step. And we're doing that now. Well, you're doing that now if you're following along. So click on the picture here. So OK, I skipped over that. When you open your browser, your site in your browser, you have to log in for the first time. And the password is admin. And the user name is also admin. And please never use that in production. That would be pretty stupid. This is just for development. You can use admin or test one, two, three, or whatever you fancy. But if you ever host a site on the internet, that will certainly not be OK. So click on the portrait. Click on site setup. And here you have all these links to various control panels. And click on users and then create a new user. So how do you do that? Here is a small icon to the left where you can add a user and then pick your name. I'll use Pbauer. I'll use mine. You use yours. Bauer.de. Password. I always use tester for these trainings because it's five letters. It's lowercase. It's small. And give yourself the role of, no, you can't. You can give yourself any role, but not here. Manager. Yeah. Add yourself to the group of managers or to the, oh, OK. Complex. Add yourself to the group of administrators. Then you're an admin. And that's how I'll get to that. How complex systems should be set up. You have groups. Members go in groups and groups have roles. So every system does it that way. So this shouldn't be new to you. Everyone does it like that. So now I created this user. I should probably save. No, I already have saved. So he should be there. Yes, he's there. And now I can log out, hopefully, here. Log out and log in again as Pbauer tester. Log in failed. Super. Why? Let's see. Maybe the default is the email address already? No. Did I do a typo? Crap. I seem to have made a typo somewhere. What's wrong? Does anyone know what I did wrong? I can always. Your press don't cancel. What did I cancel? Oh, you think I pressed cancel? Because I got my user here. He should be OK. I can delete that. I can delete me again. I'll just do that and create me again. OK, username Pbauer. BauerHTWD tester. OK. Test groups. Administrators. OK. Let's see if it works now. User created. Good idea is to have two browsers where you can log in as different users to try this stuff out and not having to log in and out all the time. Yay. I obviously made a typo when I entered my password for the first time and we grabbed that typo. And so I had no idea what my password was in the first place. So now I can actually, I can really log out and log in as Pbauer. Yes, here I am. So now it actually tells me my name. I can edit my profile and add a picture here. I'm not going to do that. You're going to see enough of me. So here I am. I'm an administrator and I'm a real-clone user. Excellent. I did my first job. So next up. We're not going to configure a mail server, but for production purposes, you should do that. Because we have an add-on called products printing mail host. We're not going to send any emails during this training, hopefully, unless you disable this add-on. But you should, hang on. Why am I not seeing site setup and only my preferences? Because I don't seem to be an admin. I can't even add content. So yeah, so the thing is, I'm not sure if that's to blame, probably not. Probably I'm to blame because I couldn't press Enter properly. This training uses clone 600 alpha 1. And that was released yesterday afternoon, I don't know, around 4 o'clock. I saw that and I updated the training build out this morning to actually use this version. So it's brand new and may still have issues. Maybe not. Maybe it does. So maybe that's to blame. Maybe it's me, probably me, because this alpha is pretty good. So I'll need to go to site setup again and go to groups and add myself to the group of administrators. Admin? Yeah, how do you do that? I'm not going to delete that group. Go away here. OK. This changed in, why can't I add a user to a group? Katja, can you tell me if that is something I missed? OK, I'll just make me a manager and save. But it should be in the user interface should allow you to click the group and edit the group. Maybe there, but there's only delete and not edit. So add users to a group should be possible. I'll show you that. The point is, if something is not working, you're not crap, let's use another system. You can't keep this system, even though it's alpha 1, because all of this is also available in the back end. And you have a list of users and groups and the same user we just created is here. And here's actually the link that I was looking for. You just click on that. And then you can say group memberships. And I want to, yeah, I'm not, I'm only in authenticated users, but I wasn't added to probably I didn't press save at some point. So now I'm the group administrators, which is fine. And I can, I'm a manager because I'm in that group. So I'm inheriting that role. I'm actually, yeah. So now I should be here when I reload. So this is a very important moment where you learn about the power of these roles. I was a second ago, I was just logged in as Pbauer. As a user, I had no permissions to do whatsoever. And someone changed my permissions and I reload the page. And suddenly I get all these icons. So now I'm a manager and I have the power to modify, change, and create content, add users, and whatnot. So that is important. But what I actually wanted to do is go to the control panel and get rid of the annoying error message that you get at some point when you're not adding, oh, there's actually a default set now. Oh, that didn't used to be the case. That's fine. So we have a default mail server that obviously doesn't exist because I don't have a mail server running on my laptop. But that's fine. OK, let's create some site structure because that's like the first task at hand. There's a plon conference. People need to learn about the content of that conference, talks, whatever training stuff. Without programming, we just use plon to create some content. I will create a couple of folders here. So yeah, actually it says some of these need to be a page. Some of these should be a folder. So let's just change that text here. Yeah, it doesn't really matter what I add here. Let's can add some. You see while we're doing that, you see a interesting new editor. If you ever use plon 5 or 4, the editor looked much different. We're going to go into much more detail there. But we'll slowly, slowly approach that. So let's just create some page called training. OK, page training. And I'll just add some Latin nonsense. A folder called schedule. Folder called schedule. And you see it's a different user interface. How come? That is weird. You can think about that while I'm continuing to do that. I'm not make sure that you're not adding, because once I added the folder schedule or the page training, I was in training and in schedule. And if I create new content, it'll end up in there. But we want that in the site route. So click on the plon logo before you create the next item. This is the location. Page about sponsors. Oops, page. Come on, see. Page about sponsors. Again, different user interface from folders. Page for sprints. Sprint and a page contact. Don't worry if you're not creating all of these. We're not using all of these. For the whole story, it would be a useful setup if we do a one week training, which we're not going to do. So this is how it should look like from your end. And then once we did that in, oh, actually, we should have kept a news folder. I shouldn't. That is stupid. I removed that. Why is it as it doesn't say news here, but in news. Katya, can you make a note that we update this part somehow? Yeah. I'll create a folder called news, where we add a news item called conference website online. That's like the first thing we created. So the order is weird. So let's change the order here. So again, we go to contents. And we can just grab one of these items and move that to the top. News are the most important things. So they should be the beginning. And here they are automatically at the beginning. And I'm going to create a news item, obviously. The title is this. Let's add some nonsense text here. And actually add an image. And a summary will be good. So you see the user interface is different from pages, because you can keep that in mind already. The editor for all types, except for pages, is schema-based and only schema-based. And the pages use a block editor, block-based editor. It also has a schema, but it's small. So this, by the way, it looks like not much, but this is a rich text editor here, this small field here. And you can add all kinds of stuff here. You can add headings and subheadings. Let's say this is the subheading here. Here is a heading, or subheading maybe. This is going to be italics or whatever. And this is a link to something. Where my links, here is a link. So I can select a link to something in the site, for example, to location. And done. And when I save, this gets rendered, and here's my link. So this works as expected. OK, I created a news item. Then I'll add another news item just to annoy you. New item, submit your talks, more Latin nonsense. OK, let's add an image, because it's nice to add images. Another image. And so we have two news items. And now let's switch to a different browser and logout. You don't have to do that. I'll do that. How do I logout? Am I logged out? No idea. I am logged out. Good. So I'm logged out. Where's my content? None of the content is actually visible, because we only created the content. We haven't published the content. So Plone is a super secure system in such a way that when you add content and you don't publish it, there is no way, no way, that this content will be visible to users on that visit your website. And that is not because it's not hidden away. And if you know the URL, you will find it, for example. If you copy this here and you enter the, it tells you, no. This is not for you. And Plone has a very, very strong security record. And it's built in on object level. Each object has a couple of attributes that store, that define which roles you have to have to be able to see this item. And whenever something is traversed to, Plone checks for these roles. And you don't have to do that. This is, Plone does that for you. That is one of the reasons why CIA and FBI are using Plone for their websites. I'm not sure if that's a positive recommendation or not. But I guess they're kind of security sensitive these organizations. So yeah, also we should have a folder called events, which we don't have yet. I'll create that. So you see a lot of additional stuff that you can add there. And in there, I'll add an event. And you learn about another content type. What's the event deadline for talk submission? I know the dates are going wildly around like 2035, 2550. Who cares? So here you can add start and end date for an event. Let's say this is on Monday. Because I used English as a language, the calendar seems to think that the beginning of the week is on Sunday, which I think is weird. But that's America for you. 10 in the morning, 2 in the afternoon, that seems fine. There's also a whole day and open end. And we'll figure out why that is there. Also, still I haven't finished talking about the publishing on content. If I reload this, none of this is still public. I will need to publish that, click on the three dots, and switch it from private to public. You can also switch it to review, which is like a pending state where something is not visible to the public. But if you have a more complex setup where you have more users with more different roles, you can easily show you the groups again. You see administrators, reviewers, reviewers. That's the ones that you want in this case, because you have a couple of people in your organization that are gatekeepers for content before it's published. That's what this role is for. So this item is now public. The folder is now also public. And once I reload this site, I see events, but nothing else. And I can go, I said there is a feature for bulk editing. I go to contents, I select everything, and I change the state, which is the lights. And I change it to publish and to everything that's in there. And voila, my whole website is public, even my super secure intranet that I didn't want to have published. So make sure you're actually only publishing the content that you want published, because otherwise you may have problems. So here, my news items are public. I'm an anonymous user, and I can see everything. I can't edit anything. I can't even pretend I can edit. If I click edit, this doesn't work. I get an unauthorized exception. OK. The default content types already did that, but I'll show you the beauty of the editor again a little. So in the front page, we have a page type. Actually, it's not a page type, but it's page type-ish. It doesn't matter where we have this blocks editor. And when you press Enter here, you can add a new block. And this is a beautiful and super powerful way to create beautiful and very different layouts and sites. You have these, by default, a text block is created that you can just type to. And it's a rich text editor again, where you can have all kinds of different styles, call out, whatever type headings. You can add lists and stuff like that. But there are more than these types. There are image blocks where you can add an image. Let's upload an image. And it should be, is there something in the story? What kind of image I should upload here? Probably a Plome logo or something like that. Let's add a Plome logo. It's uploading the image in the background. And you can configure each block on the right side. There is a toolbar to the right. You can tell this block, OK, this should be small to the right. This should be hero sized to the left or full width. I'll make that small. You can add a link to that image. And then you can save the page. And voila, yes, there's your image. And anonymous users also sees that instantly. OK, what else do we, yeah, let's add a table like thingy here. Here is a table. Let's see. Stuff, whatever. There's a nice way to have content in tables. And there are very powerful blocks that contain dynamic content. In this case, I added a, what did it say? Listing, a listing block. And the listing block is it displays the results of a search that you define. So for example, here you say, add criteria. I add all news items, for example, matches any type is news item. And it automatically shows me while I click there, I already see the news items that I want displayed there. I can change the variation where I actually have an image gallery or a summary view where I have these little pictures. And I can also add a list of the items that I want to display. I have these little pictures. I can change the sorting. I'll do that by publishing date, which is called effective, yeah, effective date, reverse order. So the newest one is on top, limited to five. So we don't get spammed. And I save that. And I have a semi beautiful front page with dynamic content in here. So this is the page content type, which has this powerful editor that is probably all you need to create beautiful content. But it also has the schema that I mentioned when I sent the schema based content and the fields that you saw when we added a folder. You can expand that and you have all these fields that are defined in the schema available. So you can tag content, for example, from page, whatever it is. It's now tagged as that. You can set the language. If you have multiple languages in your site, you can add a link to something else as a related item. You set a publishing date and an expiration date and stuff like that and copyright information, allow discussion, and whatnot. A word of warning about publishing date, this is not workflow. So if you set the publishing date in the future, this doesn't hide. It hides your content, but it only hides you like this. Everybody knows you're there, but actually you think you're not, unless you're a cat. But so if the URL is, if you know the URL, you can access that. It's just not showing up in the navigation. OK, so that is the page. A folder is obviously a folder, but only displays a title and a description and can have different types of listings for the content inside that. So for example, the News folder has a view called Listing View. At the moment, I can change that to Summary View or Tabular View or whatever. There's a couple of views that you can see, but it doesn't have a rich text editor. You can't add rich text here. That's a folder. It is created to create structures. File, obviously, is for binary data. Image, obviously, is for images. Event, you already saw that. A link is also a content type that can link to either internal or external content. So you can add a URL here. Or you can select an item from the site that you link to. So it's a very powerful feature. And only if you are allowed to edit that link, you get redirect. You see the link when you click on it. You go to the link, and it points to this and there. But if you're not an editor, you actually automatically get forwarded to whatever the target destination of that link is. So that's a super powerful thing to create ad hoc links to locations that are actually somewhere different than where you are. A news item, you already saw that. That's basically like a document, like a page, just with an image and a different editor. It doesn't have the blocks editor. A collection is, we're not going to go into that. It's like the listing block, but as a content type. So there's a content type that does exactly, exactly the same thing as a listing block. And if you're asking, why do we have that? That's because listing blocks don't exist in classic clone. In classic clone, when you go here, this is the same database. You see all the content that was just created by me here, deadline for talk submission with date and time and the news items, including the images. So it's all the same. This doesn't have the blocks editor. So it doesn't have a listing block. And a lot of sites are using, still need to display dynamic listings of content. That's where collections come in. For clone six with the React front end, you probably don't use them. OK, we'll skip. You should read that content rules are so powerful, but we'll skip that because it's way too, we have way too little time for that. Also, working copies are super cool. Placeful workflows are great. You can create a folder and say, this folder is called internet. And it has a different default workflow than the rest of the site. And this default workflow that you're configuring there doesn't have a published state. So it only has, I don't know, private and internal. And so you only see this content when you're logged in user. So it's a perfect internet. So we have a lot of clients who have a website with clone and have an internet. And it's the same website, but it's a folder that has a placeful workflow where you are not able to see any of the content that is in there. So that's a powerful feature and a lot of other powerful features. If you don't know them, read up on that. We'll just keep on going. It is already 10 past four. I'd say when shall we make the first break? I think tomorrow maybe. Let's keep on going a little more, like 20 more minutes. If you don't have the attention span, just get some coffee and catch up what you missed on YouTube. Or yell at us in the chat. I see Sean had a question here. Kadi, can you look at that? And if it's important, we can discuss that in there. I have a look. Excellent. So yeah, we could probably skip all that, but it's not super unimportant. So if you're new to Plone, this is important. Plone has been around for 20 years. Yes, it's been the 20th birthday of Plone. Two or three weeks ago was the day. And like 20 years ago, there was no React or JavaScript framework. So it is obviously, it started as a back end system, this one. And it didn't start from scratch. It started as a user interface for a system called Zope. And Zope actually also started as something before, Bobo. That's what it was called. And it actually had another third name, whatever. So it's Plone, it sits on top of Zope, which is written in Python. So at the lowest level, there's Python, the programming language. On top of that, it's Zope. It's like an application server. If you know Java, Tomcat, comes to mind, for example. Then on top of Zope, there is CMF, is Content Management Framework. So it's a framework to build content management systems. So if you know some computer science theory, it's like a factory factory. And then the whole thing on top of CMF, the Content Management Framework, sits Plone, which inherits, like it's multi inheritance from CMF and from Zope, and a lot of objects on top of that. It uses a database called CMF, called the ZODB, Zope Object Database. And it's not a relational database. It stores Python objects natively in the database. They're serialized as pickles. If you have never heard of pickles, it's in the standard library. It's a way to serialize instantiated Python objects as stringish types. It's not meant for human consumption. You don't read that as a human. But it works great in the ZODB because you don't ever have to think about your database. You don't have to model or manage your database. Obviously, you need to back it up. But you don't have to write a schema for the object relation manager, the ORM. So we store the objects directly without an ORM. And there is no scene between the code and the database. This is an example how you actually store something. You inherit from persistent. Not going to go into that. And it's super powerful. It used no SQL when that name was not even invented. It can use multiple clients that talk to the database. And that's called ZEO. It can replicate using a system called ZRS. Or, alternatively, you can use Rails Storage to store these pickles, not in the ZODB, but in a relational database. Again, in Postgres or MySQL or MariaDB, you're not going to have tables with my title, here's my description, here's my relation to whatever. But you're going to have a Python pickle in there. So this is, again, not good to read for you. But it is Rails Storage. So you can give it to your database admin to say, OK, you guys take care of replication because I don't want to be bothered with ZRS, for example. So that's powerful. And binary data, obviously, is not stored in the database. These UDB as strings, but stored as files in the file system. It's called Blob Storage. And that happens automatically. Here, I'm not going to go into ZOP and CMF. There's a lot of history in here and nothing about Pyramid. There's a lot of to be done. The important thing here and now is that Plone has, for a couple of versions, now has a REST API and uses the REST API to decouple the back end and the database and the logic and the content from the front end that is called Volto. We should probably write something in there. Not going to go into the history of Plone. If you want to discuss that, there is plenty of time during the conference. This is Plone 6. You'll see it while we talk about that. And it only runs on Python 3, obviously. So Python 2 is dead, dead, dead. But you can migrate to Python 3 if you have a Python 2 database. There are talks about that. One is actually by me, I think, on Wednesday. Katja, I think that's one of your chapters, isn't it? Yeah. Excellent. So I'll stop my screen sharing and mute. Hi again. So Plone 6, what is Plone 6? What is new, which changes came with this version? Philip already mentioned the very important points. So what leads to me is, if you know Plone 5 already, I think most of you do. Why is there an inversion? What's new? For me, my personal opinion is that two important goals to review, to rework the whole thing is to achieve a new editing experience. The editing experience means how does an editor compose a page? There were several add-ons in Plone before. And the meaning was this could be easier. There are new techniques available. And we want to use it also in Plone. So yeah, as I said, to make the life of an editor a little bit easier. And Plone 6 itself with the Volto front end, as you've seen with Philip's presentation, comes with an editor, not an editor, a way to edit pages that use blocks where you can break your text in blocks and rearrange. This is part of default front end of Plone 6. But there are also already add-ons, which help you do even more to compose a page with columns and so on. And beside the editing experience that I think is really improved is that the development of a theme is much easier. Volto or Plone 6, as we say now, comes with several helpers to customize the default theme. It's possible to customize single isolated components. And it's also a lot easier to customize default components by the so-called component shadowing, which we will see in the next chapters. And yeah, I think these are two points that are important for Plone 6. About the details, I will skip the long list of cool things that comes with Plone 6. But maybe one important point you have, as you've seen already, two parts back end front end. And these two do communicate via the REST API. There are default endpoints, REST API endpoints, which we can use when we develop with Volto or the Plone 6 front end. For example, if we want to fetch data, we use the search endpoint. And we can also create add-ons with custom endpoints. If this is necessary to communicate in a special way with back end. So yeah, there are a lot of helpers to make the life of a developer easier. Two more component shadowing I already mentioned. The other one, which I want to mention and talk about in the after the next chapter is semantic UI. This is also a cool helper for making the code a little bit to enhance the readability of the code. Because semantic UI or the corresponding read package semantic UI read comes with helper components for small things you don't want to write again and again, like buttons, drop down menus, and so on. But we will see this in one of the next chapters, not in detail, but a short overview. What you can find there and where to look for these helpers to avoid writing a simple code again and again. And to concentrate on the important things of your add-ons, of your apps in Plone 6. And one more thing in this chapter I would like to mention is the question if you want or if you need to switch to Plone 6 or if you can stay with Plone 5 or even stay with Plone 4. And I think it's recommended to use the new front end. And the question if switching with an existing project, I think it depends if there are add-ons that can help you to realize what you want to achieve or if it's possible to implement that what's missing. And for me, it's important to realize that you can use existing Plone add-ons, back end add-ons, as long as they are doing business logic, as long as they do not touch the UI. So they are still valuable and they are there. And there's a huge ecosystem of Plone add-ons and the corresponding side, the ecosystem of Volto or Plone 6 add-ons is growing constantly. So yeah, I think it's worth thinking about. Thank you. Philip, do you want to continue with customizing Volto components? Sure. Good. So actually, before we customize Volto components, we'll quickly configure and customize in Plone through the web. We're not going to go into a lot of detail here. You should just click and see what's there or read the documentation that is here. And I will show you a couple of the most important things that there are. So when you go to the side route, sorry for that, you have this link to the site setup and you have the control panel. And they can configure, obviously, the date and time. And also, yeah, the first weekday. Excellent. I like Mondays. Actually, I don't. But for the first day of the week, Mondays is my favorite choice. I can configure languages. You can have multiple languages. We're not going to go into detail there. You set your mail server and user. You configure the navigation, which items should be shown up in the navigation, which should not show up. And so on. I can configure the search, what items should not show up in the search. And so on. Here's the most important one, sites, where you say what's the title of your site. For example, site title is Plone Conference 2035. In this case, I can add a site logo. You can't upload that here. That is only for Plone Classic. You see, this is a base64 encoded string. I already uploaded that something in Plone Classic. You'll see it soon. You can configure lots and lots of things here, including a JavaScript snippet for statistics and stuff like that. Save that. Go back. Then there is social media. The URL of the Volto site. That should be configured. That's something for hosting. You can install and uninstall add-ons. We'll do that pretty soon. You can actually inspect the database and see how many items there are in your database. And where it lives, you see it lives in back end bar, file search, datafs. That's your ZODB database. That's where it is. And there's a lot of other things. I'm not going to go into detail because we're going to see some of these later. And most of them are discussed here, especially the ones that are not there. And that's what's important here. So this is the control panel in Volto. And here is your control panel in Classic Plone. I just uploaded a logo. And you see that here, Mastering Plone. And here, it doesn't say Mastering Plone. Because it uses a different rendering. It is different there. And that's in the next chapter, we're going to customize the logo that shows up here. Here, you have the same control panels plus some more. Because some don't make any, it doesn't make sense to have them in Volto. And maybe there may be even others that are not yet implemented in Volto. I think everything that's important is already there. But for example, the theming control panel for Plone Classic doesn't make any sense in Volto. Because we're not going to use, it's a completely different theming setup. It doesn't make sense to use a diazo theme, if you know what I mean, in Volto. So this doesn't exist in Volto. Because it wouldn't make sense. And also in Plone, you have access to the ZOP user interface, called ZOP Management Interface, ZMI, for short. And there are even more in-depth things that you can use, mostly as an admin or a developer. So you will certainly spend time there. And we will go there today at a later stage, for example, to inspect the portal catalog, which is the search engine that is built into Plone. And we can see representation of all the content that I already created and how it can be found in using the search. You see the search bar here. This uses this catalog. And it has a couple of indexes that we can use. And you can create new ones. There's a lot of complexity and a lot of power there. We're not going to use much of that. We're going to skip ahead. And I suggest, since we already spent 1 and 1 half hours to make a five-minute break, or let's say seven minutes, to actually be able to visit the restroom and get some coffee, before we customize the first Volta component, where we're going to change the logo. And a couple of the views or the display ways, items are displayed. And there we're actually going to use the editor into some real development. There we're jumping in. But before that, you can steal yourself with your poison of choice. I'll get some coffee. And we will meet you in, let's say, seven minutes. OK. If you have questions so far, please put them in Slack. And we'll find time to answer that before the next slot. I'll mute myself in the recorded video. This break will be just mentioned as break. And you can skip to the next part, because we'll probably be too lazy to edit the whole breaks out of the video. Doesn't really hurt. Yep. I think we should continue. So no tough questions in the Slack. Let's continue. So next, we're customizing some things that we're seeing in the browser for our users. So this is a front end chapter in the documentation of the training. You see these sidebars here at the beginning of a chapter. Let's specify if a chapter is dealing with the front end or the back end. And if you're dealing with the front end, obviously you need to go to the folder front end and make changes here. And if you're dealing with the back end, you need to go to the folder back end. And if you want to follow that training, you can use the link here. You can use the link here to find out how you can check out the code from a certain chapter and use that chapter to start the beginning or at the end of this chapter. See what's the result of what should be the result of that. To customize a visual representation of what you're seeing in Plone, in Volto, we use a technology called, let me hide, it's a bit ugly, I'd say. So, yeah, I would love to hide some things, but I'm not going to go there. We're using a technology that allows us to override existing items. And you'll see that pattern over and over again, that we're not forking Plone or download Plone to your hard disk and change everything, whatever you want. I heard that is what you were supposed to do with some other systems at least. A couple of years ago that don't have a system where you can override features in React, that's called component shadowing. And it allows you to create a copy of an item that you want to modify in a certain container, in a certain folder, and it will be automatically found in a certain folder. And it will automatically found on startup, and it will replace the component, the file, that you want to, that you're overriding with. So that is pretty, pretty nifty, and it's basically the same as what you do, did in classic Plone, using an add-on called J-Bot, just a bunch of templates, where you just add a copy of a file into a certain folder, following a certain pattern, and on startup it's discovered and it replaces the original file that is shipped with Plone. There is also, I should mention that in this sidebar, there's a link to solve the same requirement in classic Plone. So if you follow that link, you'll see a broken navigation, because this item is not part of the navigation, but you will do the same tasks, or similar tasks, in classic Plone, in this case, the logo is already done in the early, early chapters, so we don't need to do that in Plone Classic, but here we're modifying the new item template, and the listing template, it's all discussed here, how that works in classic Plone, and it says classic UI, but we are going all in with Volto, so we're using this component shadowing technology to modify the logo in this, as a first step. You can download the logo here, it's on our website, it's just a SVG file, it's not very exciting, it just says mastering Plone in some crazy font. So what you need to do is you need to fire up the editor of your choice, I use VS Code, and I will actually use two instances of VS Code, so I already have one terminal here, one for the back end, one for the front end, and I'm going to fire up a new one, a third one, where I go into training Plone 6, that's where I have that front end, and I say code. Which starts up VS Code for me, and it opens the front end folder for me here. So I have two different editors that I can switch back and forth from. That is just to, I don't know, make it easier for me. You already have, upon installation for the training, you already got this whole site setup, and we're going to follow the documentation here to add stuff into our front end setup. The front end setup that we have here does not contain Volto. We didn't download Volto and started Volto, we actually created a package that depends on Volto. So in this case, as there is Volto installed, but not in SRC, SRC is a bunch of empty folders, so there is nothing here. And in your package, Jason, this package that you created depends on Volto, that's here, dependencies, Plone Volto, version 14.0.0, alpha 23. So that's the newest alpha of Volto, I think, that we're using here. And by building that using Yarn install, Volto got installed, and there's a couple of nifty things in this package that makes sure that Volto is actually available in a folder called omelet, and in there, omelet, SRC, I don't know, let's say actions or components, more importantly, theme, breadcrumbs. Here, this is Volto, this is the real Volto, you shouldn't change that because that is the equivalent of checking our Volto and changing it on your directly. We want to override that, so we're not changing Volto in the omelet directory, we're extending it and overriding it in our SRC folder, this is our package, this is our thing, it's called Plone Conf minus Volto, I think that's the name of the source checkout that we're using here. So we're using, we're going into the front-end folder and using this path and name to download the logo, to add the logo SVG, SRC, customizations, components, theme, logo, okay, I'll copy that, I already have a SRC folder, customizations, components, and that's empty, so I need theme and logo as a path, and I can add that like this, which is nice, components, theme, logo, and inside logo, I'll just open that in Finder, here is my folder, so if I go up, you see the structure, customizations, components, theme, logo, and inside logo, I'll just dump the SVG that I just downloaded, so it's here, and I should see it here, VSCode doesn't have a preview for SVG, so I could edit it if I wanted, I'm not going to do that, obviously, and now I need to restart Volto, is anything unclear about that, I guess not, we could just stop Volto using ctrl-c and yarn start, which will take a while, but while that happens, I can discuss, what should I discuss, there's nothing to discuss actually, so it's important to, you need to really restart your front-end instance, the process that is running the front-end, when you add something in a customization, when you modify at existing code, you don't have to do that, the development mode of the JavaScript application makes sure that it's automatically recompiled, and your browser is actually automatically updated, it shows the right stuff, but if you add a file, you actually need to restart that, and it takes a while to compile, and now it's done, and once I reload, I should actually, I already see it there, it says master in code, so master in code, so yay, for us, that is something we already did, so now you made a change, so you guys are professional developers, or actually you want to be, so if you go into the front-end folder, so you have this training code 6, you go into front-end, and you say, git status, and it tells you, hey, there is a new folder, a new thingy here, and you can see that you could commit, that is what you should do now, you shouldn't do that during this training, because it's already, everything is already there, but you should now make a commit, and say, okay, just add logo, and there you are, and that's, so that change is in your git history, okay, this was the logo, there was the easy part, now let's go to the footer, why are we not dealing with the footer, so there's no, we're not changing the footer, obviously, maybe the heading should go away, let's change the news item view, so why do you want to change the news item view, that's something that's been bothering me forever and ever and ever, so you visit the website, and you go to the press release, or news section, and you click on the news section, and news item, and you see it, and say, yeah, that's really nice and exciting, you have a new board member, or you have a new release, but what's missing? When was that, was that like 2015, and your site is super out of date, or is that super recent, was that a new release that was just made yesterday, so what's missing by default, which is, I still don't know why that is, it's probably so we don't have to change this training, and keep, can keep editing news items in Plon Classic and Plon, and in Volto, so we can display the date here, so what we want to have here is the date that this new item was actually published, let's do this, so first we need to find out where the actual news item is rendered, so the news item is, yeah, that's a bit tricky, I'm not going to go into there, that how to find that, but I'll just take my word for it, it is in Omlet, where Volto exists, source, components, theme, view, news item view, it's a same folder structure, and if you, it would be probably, since you know what the content type is called, you could just search for news item, hang on, why doesn't it find anything, news, that is weird, news item, files to include, files to exclude, why is my search not in all files, I seem to have misconfigured my search somehow, but I'll find it by hand, it is in SRC, components, theme, view, and here are all my content types, news item views, so here's my component, it's a React component, and I want to customize that, so how do I do that, I copy the whole file into a different folder, so this is the file, we can look at that actually a little bit, and you can see your first glance at Volto view in React, so it has some, a couple of imports, and it uses the object that you're looking at, so the news item, which is like this here, the whole, the thing that you can edit, the thing that lives in the content tree under this, in this branch, and this leaf on this branch probably, this is the content in this case, and it's passed to the news item view, and this creates some HTML basically, using the, yeah, that's JSX for you, I'm not going to go into detail how that all works, but it's basically, one example here, if there is a content title, so if the object has an attribute title, then render the h1 tag, class name, you see this is not HTML, like per se, this is React, so you can't use class because in JavaScript, that is a reserved statement, it needs to be class name, and pass, use document first heading as class name, and replace the content of that with content title, and then content subtitle, and whatever, there is more stuff in there, and then there's the description, and then there's the image, you see the image here, that is using the image, that is not a HTML tag called image, because you remember HTML, it's called IMG, the image is a component from semantic UI that is used here to render the image, and you pass some arguments here, the title, and the SRC, which is automatically created, it creates a URL for that image, and float it equals write, is also not a classical HTML tag, it is a argument for the image component that is used here, so this is how the view looks like, and it exports as the news item view, and has these prop types that you probably know when you're doing react development, if you're just overriding stuff, this is something you do not yet need to know, you just need to be able to understand the basic logic of that, saying that if the content has an argument, has an attribute called text, then render that text attribute as dangerously set in our HTML, that's a monomer of most favorite words here, so this is a react built-in thingy, obviously, and that renders then the content text data, which is the real HTML that is returned from the rest API. So here we have the view, now we want to modify that, so we copy this, the whole thing, into a, yeah, oh, there's, you should probably read that, because that's really interesting, because we should look at that just quickly. I hope I have my developer tools enabled, so why doesn't it, oh, God, I don't have my developer tools enabled, Katja, I guess you will have to do that in your later chapter, I seem to have disabled my React developer toolbar, doesn't really matter, we can redo inspecting an item in a later chapter, but it read that and it's important and it helps you to figure out where that component actually lives and how it works. So copy this file into customizations, components, theme view, so customizations, components, theme view, do we have that already, let's see, so in our, not in omlet, please, so close that, customizations, components, and then in components we need more, we need a folder called theme view, let's here now, so here is theme and view and then there we need the news item and I'll just copy, can I copy the whole file, probably can, if I find it here, where's my news item view, here copy, and I paste it in this folder, paste, here I have it, so again, I need to restart, I'll do that, and I don't get a message that, hey, I found a new customization, you'll just need to see that this happens, and now very important happens to me like every two weeks, don't modify the original, because now you have both items open, modify your copy, yes, it's confusing when you have an editor in the same file open twice, make, if you're uncertain, make sure that it starts with SRC customizations, then you're in the right place. And how do you find out that this is actually the one that is then rendered, once sort of is finished, it just takes a little while, so obviously just add some nonsense to it, and that is visible in the site. So let's see, let's just add a h1 saying hello world. So once I reload, I hope I didn't get an error, still starting up. It has interesting messages, which I will just ignore. And here we already see it, hello world. Yes, I actually already customized that. If I wouldn't make these stupid change like this, it would look exactly like the original, so without hello world. And you see, I just saved and upon saving, this is the message that I get, it does a reload. It reloads the site, the code. So, okay, good. So what was the task we should add a date. We could just type a date there, but that's stupid, we're not gonna do that. So the content I already said that is the item that we're looking at, the news item, submit your talks, and the news item, this item has, okay, I should really enable this feature because this is really important now, where is my React? Oh, I could just use Chrome for that. No, I'll just, developer toolbar, I think that's what it, oh, can't type. This is not it. Come on, React developer tools here, this one. You need this, you need this, no questions asked, you just need that. This is super important when you're developing for Volto or any kind of React stuff. And it's already there, here's my developer toolbar, it says, hey, it's development build, and now I can inspect my components, not the HTML, but actually the React components. I can inspect them, and I can inspect lots of things. I'm not gonna go into too much of the components, I'm not gonna go into too much detail, but this is like the code. Here is my news item view, and inside this news item view, when I at some point I find it, it's pretty complex tree, but here's the news item view component, and it has a content object, and this is this. This is the news item view, and it has a content attribute property, it's a prop actually, prop in these properties. Now, in content, in the property content, there is a lot of stuff, and we will figure out what we're gonna need from that, and I already found it. So for example, a lot of stuff is used here already, so type is the news item, there somewhere is probably the title, title here, submit your talks. Here's the text, which is a object itself, and has data, you remember I said this is data, that is rendered down here, content text data. So this item doesn't have any text, let's add some text, so it'll actually show up, and make that a bit more interesting, at least adding one HTML tag, and now where's my view component? I lost my component. Hang on, news item, you can search, which is super useful. So here's my news item view, it has content, and here now the text should be more, so we have data actually holds the HTML, that is passed from the backend via the REST API to the React application that's running here. So what do we need from that? We don't need the text, because when I have that, we want effective in this case. This is a date, and it's automatically the date that is used by Plone, no, created, we use created, it's the creation date. There are a couple of different dates, obviously, there's like the date you were born, there's the date you got your driver's license, and the permission to drink alcohol, and these are different dates, and depending on for content, it's also, if you write a news item, but you only publish it two weeks later, you need to talk to your client, what should be visible there, because every client has a different idea of what should be visible there, and what should be visible if the item is not yet published and stuff like, so there's huge complexity, and there's also the modification date. So if you have a news item from 2015, and someone changes the typo, is it suddenly a super new news item if you use the modified date? Yeah, so you see that's pretty complex. So created is the date we want here, so let's just use this thing, and add that here, content.created, and save, and I don't need to do anything else, because after I pressed save, you see this automatically happened, and this automatically happened, even didn't have to reload my browser, so that's modern JavaScript development for you. The tool chain is really, really good. The result obviously is total crap, because this is nothing a human can read, but it is a date, it's a visual representation of a date. We'll use JavaScript to fix that, we could do some nifty string replacement and changing, but we're not gonna do that. Instead, we use the power of the vast ecosystem of JavaScript libraries, and one is the moment library, we'll import moment from moment at the top here, and if you have a good editor, tells you, hey, you imported something, but you're not using that, please get rid of it, we'll use it in a second, be calm, and then pass that attribute that, where did we put it, actually after the image, not before the image, pass it here and move it after the image before the text, and don't, do we need a paragraph, oh, we want a paragraph around that. Okay, save, and again, if you have a good editor, it automatically takes care of indentation and form a code formatting. So we're passing this date object to the moment, it's actually a string to the moment library and passing it a format, LL is one of the default formats that you can use, can read up all about that in the documentation for the moment, JS library, we're not gonna do that, I'll just, I didn't have to reload and automatically we have this, so that's excellent, we're already done, we have the date, and yeah, that's it, I think, yeah, we have a date, excellent. So here's a whole discussion about what happens with these dates, gonna use the solution here, so use effective if there is effective, otherwise use created, so this is basically a try accept, or if else statement, save, and the editor even makes these nifty space thingies here, which are ugly, I still hate JavaScript with the vengeance, but it is a lot of fun developing with it. So yeah, that's it, we did our first, second customization, the logo, and the news item view, we have a date here, so you visit your website and you see the list of talk, the list of news, and you realize something, yeah, why is it blue? Okay, let's get rid of the blue, that's just selection nonsense, oh, because I clicked here, interesting, can I unclick that? Probably, yeah, like this, so I have my news, and here I have my date, but in this view, I don't have a date, ah, darn, okay, one more view to customize, and another task for you, so this case, we're customizing the summary view, that is not a view for one content type, but a view that is, a sign that is usable on folders, as there's more, what I wanna say is, there's more than one view for folders, you can go to a folder and say, hey, I wanna look at this as a listing or as a summary, in this case, we'll use the summary view, otherwise our changes will not show up here, so and again, we can use the inspector here to find the component that is used, summary view, here it is, and now we can, here's the, wow, there's the code, how do we, what happens here? Nothing happens if I click here, interesting, so summary view is the name of the game, and I can use my search, which is not working again, why is it not, yesterday it worked, oh, now it works, you, no, it doesn't work anymore, I have no idea what's wrong there, probably I configured it to not follow symbolic links or something like that, my editor, so I'll look for the summary, if you please fix your search, if you have the same issue as I do, it's in the same folder actually, so here's my summary view, I'm just gonna copy the whole file and drop it into the same folder, paste, paste, paste, where's paste, paste here, summary view, so now I added this file, and again, I need to start up, gonna skip through this part, but yeah, no, I'm not gonna skip through that because that's important, while I explain something, I'll restart, so you remember I said that in the news item view, the view component was passed the argument content, which is the content object that we're looking at, the instance of a news item that we're looking at directly, in news, in summary views, we're also looking at a content object, but the content object is actually not the news item, but a folder that contains these news items, and inside this summary view, the logic is iterating over the argument items or the property items of content, so content, which is the folder, obviously has something called items, and we're doing like four items in items, I always try to read JavaScript as if it was Python, because I really, really prefer Python to that, and then we have item is one of these items in the list of things that are displayed there, and then these again have URL, title, image, description, text and whatnot, so the same applies to item that used to apply to, again, I have two summary views open, don't modify the wrong one, close the original. So after I restart finished, so if I, oh, I can, let's try that, that's gonna be fun. I already did that, so I'm not gonna do that again, I just copy and paste my code in here and put it, I don't know, somewhere here under the, before the description, under the description, who cares, and save and say, hey, we're done, it's all good, reload the whole thing, because it realized we're broken, and there we are, so a moment does not define, didn't import moment, yeah, it's true, moment, here we are, reloading again, see, this, I have no idea what it's doing there, but it works, it's excellent, so, and here we are, so imagine next week, you add a new item, everything has the same date, that's the error you just made, or that I just made, is I use content effective, and not item effective, and that is, yeah, everyone does that, and everyone has to go through that, pitfall to pick the wrong item again, so, yeah, that's the solution here, that we're using save, item created, item effective, same display format, if we'd have news items that have a different creation date, and publishing date, then the date would change, so the question now comes up, can you actually, can you do that, yes, you can, so imagine the conference website was already online last week, you can just go there, and in dates, you say, hey, the publishing date, that's what we wanna display, that was on Monday, we were pretty early, so save, and when I reload this, when I hard reload this, hopefully, okay, October 17, that is correct, so that was the date that I selected, but for this view, maybe some crazy caching is happening there, because I fixed the code, it says item effective, or item created, and item effective is what we're displaying, so I'm gonna go ahead and go ahead and go ahead and go ahead and go ahead and go ahead and go ahead and go ahead and say item effective is what we're displaying, so this, I would say this is a caching issue, and it's always good to kill things by restarting it and figure out, find out if that is the issue before you do further debugging, because cache invalidation and naming things the two hardest things in IT. And this would be number one, cash invalidation. This hopefully it was that. Let's go further. We'll skip this next part where we let's see if it happens here. So you can do that at home. We also have a listing block. Actually, we should do that, but it will cost time that we don't have. So we're not doing that. In the next block here, 13.6, we would customize the listing block. You remember, we used the listing block on the front page to display news items. So the thing with the cash invalidation is obviously wrong. What is going wrong here? So did I modify the wrong file? Oh, yes, I did. I, yeah, exactly what I told you not to do. No, not. Sorry. Again, customizations. Kat, you do have any idea why that's happening? I thought first it was a type about the spelling is okay. Yeah, I think so too. Let's add foo. See if I made something. A stupid mistake. Foo shows up. It should be okay. I have no idea. It should work. Just tell your client it should work. That's always good enough. No, it's not. Let's move on. It actually, it works, pretend it works. So in the next chapter, we would modify the listing block, which we have here that we can use to display if we, hang on, if we edit that to actually display our news items that are here. And we want to show up the date here as well. And that's what we're doing in this chapter. And the tricky thing here is this is not a view for a content type. So it lives in a different place. It lives in components, manage, blocks, listing, default template. So that's a bit hard to figure out. You can figure it out using the the React developer tools. See that it's, hey, there is something called default template. And that's probably, probably what's used here. And then you can customize that. A lot of the knowledge, what to change. You can just remember, learn, but debugging is just, you can, it's not a problem. You can totally do that. Just change some file, put some typo in a file and see if something happens. So if I look at the default template, JSX, I'm not going to do that now. And see if you have something and it changes in your browser, you're obviously editing the right file. And then you can copy that into your customizations and do a proper change and make a commit in your Git history so that everybody can figure out that it's you who did this change. And if you've did that, then this will happen. Just a short note. Yes. I think it's important to, it's worth noting that if you want to find out what you have to customize, for example, this default template, the React developer tools are very useful because everything is a component. And if you find with the developer tools, the component here by this search thing, and then most of the time, you know the file name that you have to customize. Because this is most of the time corresponding component name and file name. Here's source. It actually says listing buddy JSX. It even tells you the line number. And yeah, but there is more with blocks extensions and anonymous default view. This is yeah, whatever. Inject Intel. Yeah. Lots of stuff to discover here. Let's one pretty important thing that we're not dealing in the whole training, except for this small part, we're not dealing with internationalization. In this part, we do because we want display is a date is displayed in different languages in a different way. So in English, it says October 23rd. And in German, it would be 20, 20, 26 October and so on. So and people, even though a website is in English, people would probably want the dates to be displayed in a way that they actually understand that. And to do that, we can use this react into internationalization stuff and pass set the locale that is used by the site. If you have a multilingual site, that's super important or the browser sets that. And then the moment moment JS automatically uses that. We're not going to do that now. You can do that at home. If you fancy that. Let's go to the next chapter about semantic you are cut here. Take it away. Thank you. Okay. Semantic UI, we already heard about it. It's a little helper on a big helper for developers to concentrate on the important things and to use the components that semantic UI or semantic UI react and provide. These components are things like buttons, labels, help us to structure the page by so called containers to have boxes with the already prepared padding and margin and so on. And so I skipped to the chapter talk where we have where we will create a view for our content type talk. And this would look something like this where we have a label for the audience of the talk. And we take the component label from semantic UI, which will, yeah, which is something like a widget with a theming and can easily choose a variation of it. For example, in this case, the color or also the shape and so on. And so you take the component from semantic UI, modify some attributes and it looks fine and you can concentrate on your main part of your development and also very often used as the container. And that's the bottom part of this page. You see a box with a border and the padding most of the time is okay. So we can put your content that you want to display in this container and, yeah, you have a structured page. So this is a semantic UI. It comes with a default. And also the default theme is relying on this red package based on semantic UI. So you, if you use it, your, your modifications fit in well to the default theme called Pasternakha. And when we now step to the next chapter where we want to do some small customizations, not writing on components or customizing, as we've seen in the last chapter, but only modify the some CSS style, then we can, I don't have my chapter. Oops. Yeah. Then one typical example is to change the font name, the font or the font size or what do I have here? Letterspacing. Then we can write on CSS rule and we will see now where we do it and that we can use predefined variables, like in this case font name. And for this to see where we customize, I should, do I have to change the sharing? Sorry for interrupting. I think you're, you're not clicking on your browser. Sorry, I forgot to say. I think you're clicking on the browser with a video and not the real browser. I don't get it. I have the, now I'm sharing the Firefox. Yeah, but you click with your mouse and drag. Drag. That is the video. You're looking, you're looking, you're clicking on the zoom window and not on the Firefox window. You're clicking on the Firefox within Zoom. Minimize your zoom window and then you have the browser and you can. Okay. Okay. So, you know, I should see my editor. The theming is done. We have seen the omnet folder for the Volto code and beside the source code where we have components, actions, reduces and so on, we have a folder called theme. Is my editor now share? Yes. Okay. Thank you. We have the folder theme and with Volto, we have the Pasternagar theme and also the default theme. A default means that this is what a semantic UI provides. Pasternagar is the theme of Volto or Plon6 and it comes with some variables and CSS rules. And if you want to, for example, customize the font, we will find a variable here and we have not one big CSS file, but it's organized by topics and something like font, which is a global thing we find in the global folder and most of the files here are pairs. A pair of a variable file and an overrides file. Our variable is here. We find our font name variable, which we can modify to change the font and we have the other part of the pair overrides and this case is empty. Normally, you will find CSS rules here. This is what comes with Volto. If you want to override, we create a new file with the same name and use the path. On top here, we see the path. We take the path from the theme name on. Globals and then our site overrides. Globals, we create a folder, Globals and the file site overrides. I want to do that now because it's really easy to do. Then we change the variable name and the other case would be that there is no variable and we want to place a custom CSS rule. We take the part site overrides. If it's global or if it's something like in collections, we have menu, table, forms, very important form overrides. Then we can pick the matching rule here and we also look at the path again. We are in collections, file form override and then we go to our app code. I close the omlet and I close the source part of our app. At the same level as the source folder, we have a theme folder and we change to this. I already prepared two folders, Globals folder where you find the customized site variables. Here I have my font name changed to Lato. This is a font name of Google font. If we use Google font, we can just modify the value and Volto cares about getting the source from Google Google font website. This would be the way to change the font. The other one would be, for example, to customize the letter spacing. Then I create the other part of the site modifications, site overrides and I place my CSS rule here. Then as we created new files, we have to start Volto again and then the modifications can be seen. I think it's easy. Questions? If not, I would hand over to Philippa then. Thank you. Wow, that was quick, the seeming part. Let me share my screen. I found out that we have a bug. We have a bug in Volto. We should have realized that a bit sooner because when we changed the view to summary view here from list, summary view, the picture is here. The images didn't show up. There are no images. In the template, there is an image tag. The objects obviously have an image, but they're not showing up. What's going wrong here? The reason is I didn't have time to find the change log message, but at some point in Volto, it's not that long ago, the default way that the content of folders is returned by the rest API to the front end was changed to not contain all information about the objects. How did I figure that out? That's important for you. Inspect components, look for the... Just use inspect to find the wrapper. Then we have the container. Where was that? Summary view. Here is the summary view. That's what we're using. It has a property called content. In the template, you remember I showed you this, we're iterating over item for item in items, for item in items of content, for item in content items. Here's the summary view. Here's content. Here is items. If I expand this, if I expand the first item here, it should become obvious that this is not what we saw when we looked at the news item earlier, where we saw lots of information. Here, we only see a tiny piece of information that is returned by the rest API, because this is the data that is available to the view component here. There is no effective, there is no image, and this is why image is not rendered. There is an error in the way that the summary view is constructed. It's not getting all the data from the items in this folder. This is why it's not possible to display a date. Why does it show a date then? Here comes the next crazy thing, the moments library that we're using to render the date. Let me go back to the original way. If you don't pass anything to the moments library, it returns the current date. It's similar to Python, date time, if you call date time, it returns the current date, at least the update time. I don't think Python date time does that. Maybe it does, I'm not sure. This returns today's date, and five years from now, this news item would still be from today, which is super stupid. I have no way of fixing that right now, but it's certainly something both creating a ticket for. Just to show you that, there is here, when I save it, you see this actually changes. Now we have a different visualization, because I changed the format, but the date is still, a date is still there. So, yeah, it's not our fault, it's Volta's fault. This makes no sense to be in the summary view, if the item is not passed to a summary view. How do you create a ticket? If Plone is, we haven't talked about that yet, it is an open source system, and it's maintained by a huge community of volunteers. There's not a single person paid for doing any of that. We don't, Katja and me, we both don't get anything from doing, for giving this trend, actually we do, but it's like, it's a symbolic gesture. And we actually, we even had to buy our own ticket for the conference. So, we're doing this out of the sheer goodness of our hearts. And the same is true for Volta, and the whole development that goes on goes on in Plone. And it's all open source, it's all available there. And Volta is a repository on GitHub, it's all open source, and there is a list of issues. And I could just create an issue that explains what's going on here, that the images are not showing up in the summary view, because the items that are passed to the summary view do not contain all necessary information. There is actually, in a later chapter, there is a small part where we actually discuss this issue, which is actually a feature, but I wasn't aware that it, the summary view was basically broken in Volta. Okay. And you're also invited to file a ticket for an issue, if you find something unclear in the training documentation. That is very true. The training is, okay, this is fixed base class, so there's nothing about the summary view. The training, since you mentioned that, I'm going to show that the training is also open source, it's actually, it's not even GPL, but it is Creative Commons Attribution 4, whatever that means, not a lawyer, but it means you can just do whatever you want with it, as long as you mention that it's open source, something like that. And you can create a ticket here and say, okay, there's something wonky, or you make a pull request and change stuff. And there's all the trainings that are in this, that are on trainingplown.org in there, and masteringplown is one of them. And we are right now, just to show you that in Volta-theming, so Volta-theming, this is the file we're looking at at the moment. And you can create a pull request, can make a change, feel free to do that. And it, yeah, that's important. So I'm not going to fix that issue now. Okay, we already saw that we can customize Plown by overriding components in React using component shadowing. And I quickly mentioned that we could do something similar in Plown Classic by creating a copy of that file in a certain folder. It's basically exactly the same approach. Plown, the point of this chapter is to teach you that Plown is built on top of the idea to be customized and extended and not forked and branched, but that you can take almost every a part and aspect of Plown and customize it to suit your requirements. And there are a couple of extension technologies that are discussed here. I'm not going to go into details. We're going to visit them soon, see how they interact with Plown in different ways. But basically, they allow, there's a whole system built to customize Plown. So why is that? Maybe that is important. Let me quickly go into the back end of Plown, the original back end in the Zope management interface. This is not only for looking at items. This is actually in Zope, was built to be as a development environment that you can write code in the browser. So there's this select type to add and then there is this script Python thingy where you can actually write Python code in the browser. And when you go to the URL of the idea of the object that you created, this Python code is executed in a safe way. So there is actually a whole huge package called how's it called? Restricted Python that makes sure that you're not deleting your hard drive by writing a Python script because obviously in Python you could do that, can delete your whole system. But you don't want to do that. So this is, it's basically, it's in a sandbox. It's a safe subset of Python commands that you can use in there. So Zope, when it was invented, was the whole idea is to give the user the power to customize it and extend it through the web in the browser. And the same approach is true for file system development. There's a lot of hooks and crannies that you can plug into to make Plone do what you actually wanted to do. So that's, and that is what we're doing. That's why in the whole training, especially in the, we're not going to write a lot of code. Most of the code that you write like lines of code wise is copying templates from one place to another. And it's not writing, it's copying and pasting. And the things that we actually write ourselves are not that much. So, and to do that, to allow Plone to hold our own code in the back end in this case, we need to write a Python package. And there is a lot of existing add-ons already, Python packages that are connecting to Plone that you can use to connect to Plone and extend Plone. And this chapter mentions a couple not going to go through that because we're not doing classic Plone. Most of them are using classic Plone. There's a later chapter about Volto add-ons that also exist. There are add-ons that change Plone back end that provide new content types, for example, that you can also use in the front end. And there are add-ons that provide functionality that is used visible in the browser that make no sense in Volto. So there you need a Volto React component to talk to the back end to that. So, in some cases, you actually have a Plone add-on that comes in two, in two, comes as two parts. And that is what we're doing in this training. We have one Plone add-on called Ploneconf site, which is a Python package that we create to provide extensions to Plone and overrides to Plone the back end. And we have Ploneconf-Volto, which is a front-end package that extends the front end of Plone. And both are not forks or branches. They override the minimum time that is necessary to make that possible. So we're going to skip this whole thingy and we're going to quickly... Oh, God. I could talk for hours about that, but I'm not going to do that. So this is to customize, to configure Plone in the front end. You have this package JSON that tells you it requires, I told you that before, this Ploneconf site package, Ploneconf Volto package, JavaScript package, NPM package, depends on Volto. So it extends that. In Python, we have something similar. And I haven't opened my editor for the back end yet, so I'm going to do that right now for the very, very first time. So let's add another terminal. Training Plone 6 back end code. So here is my VS code instance. Last year, that was actually convenient to have two different editors for two different things, because my laptop screen is pretty small, so it's easy to get confused. But a little confusion is just required. So this is the back end folder that we're looking at now. And it holds the configuration for Plone the back end or Plone classic. And the most important part is the build out CFG file here. So build out is a configuration or orchestration system that builds Plone, configures Plone, and extends Plone, and does a lot of other things. You can add other things. You can actually make build out, compile, Apache or solar for you, which is kind of stupid to do. But it is possible. That's why I say it can spawn all kinds of things. So here is the main file for build out. And here is a minimum example for a build out that is used to build a Python Plone site in Python. It has only two parts. So it's built, it's separated into parts. They are, this is the INI syntax. You probably know that. The square brackets build out. It has one part that's this one instance, and it extends. So it's pluggable and extendable, and it's increasingly complex if you use it in real life. And it has recipes. So it has build out itself. And it can use recipes that tell a part, in this case, the part instance, to do something. And in this case, build Plone using the recipe Plone Recipe Zog2 instance, which is the default recipe used to build a Plone site. And if you use that and run build out against that, using the logic that you learn when installing Plone, it's just call build out, which is executable. Then it reads that and installs and builds Plone from that. There's a lot of stuff in here that we're not going to go into in detail. Let's quickly look at the real life example of this training. So here's build out. It's like, it's always the main section. It extends versions from the freshly released 6, Plone 6 Alpha 1 version. This is a URL. If I open that in the browser, it holds Python package version pins only, lots of those. And it also extends the version pins of Zolk. And the Zolk version pins, again, oh, they don't open the browser. They extend and extend. So there's a whole, I don't know, a red tail, that you can follow there with versions. It also pulls in the versions of a file, version CFG, where we have pins for the versions that we added in our build out. And it has a couple of defaults. The most important ones are these eggs. Python packages like, I don't know, the request library or Plone itself or Pillow, which is a Python imaging library, are called eggs. That's, by the way, this is why the packages folder that's here used to be called omelet. And in Volta, it's still called omelet, even though the NPM packages are not called eggs. So that is, if, I don't know, five years from now, they don't change that. No one will ever remember that Python packages are also called eggs, because nobody uses that word anymore for Python packages. And so everyone would be irritated why is Volta and all the other dependencies in a folder called omelet. Yeah, so that's history for you. So these eggs declare what Python packages should be installed for the system we're building. And this is Plone. This Plone package pulls in everything itself. So this is a Python package. It actually lives on PyPy, but also on GitHub. If you go there, you can find that it's a meta package, doesn't have any code. It just depends on more packages. Oh, crap, there's setup. So you need setup CFG. Here are the packages that it depends on. Where are they? Install requires setup tools, REST API, and CMF Plone. And that is actually Plone itself. That's the package where the code of Plone exists on GitHub. So there's a shitload of code here. And that again pulls in many, this time the dependencies are obviously in setup Py. This pulls in a lot of additional packages. So when you install Plone, and you already did that, you have a executable called bin instance here. And it has all the Python packages that are used to run Plone. And these are 200 and more than 260 Python packages that I used here. So and build out is there to make it manageable to actually pin the right versions for each of these 260 packages without you going crazy. And on top of that, extend the Plone that you build with your own add-ons. For example, here's some development add-ons that we're going to discuss later. And the one that you're writing yourself, Plone comp site. And that one will also be tested because there's a test setup that is in there. And this package Plone comp site, hang on, is actually not downloaded from PyPy, the Python package index, but from GitHub using a build out extension called MrDeveloper. There is so much to learn and to know there. So if you're not not, if you don't know that, you will learn it through practice. It would take us a lot of time to discuss all of that. So we're going to just jump to the end of that. This is the build out of, there's lots of documentation here. I really, I beg you to read that. There's examples for super small build outs and really big and complex build outs and how to figure out how to work with that. And what are you going to, what are we going to do now? Or what already happened? So we're not going to do that. But it, if you would start from scratch, you could do that. And I'm going to just quickly show you how that works because it's really cool. So when you have, when you follow the installation instructions, you have Plone, but you don't have your own package yet. And you can create your own package using this Plone CLI command line interface helper thingy. I'll go into my backend folder. I'm going to call that Plone.com site too. So I'm not going to, I'm going to throw that away after I did that. I already installed Plone CLI and I create a, no, please don't correct this. Otherwise, it will override it. It'll ask you a couple of questions, including your GitHub username and what do you want to do that with that? And I'm going to just answer the questions as in, as instructed here, but you don't have to do that because you already have this package. I'm just going to show you that this actually works. There is still an issue. So I get an error on ISORT. I don't know why we need to ISORT it automatically. I wouldn't do that, but I'm not maintaining that package anymore. So yeah, can ignore this, this problem. And now when I open my editor in SRC, I just created a from a Plone Python package. If you know other systems, this is like cookie cutter. It's cookie cutter is more popular in for most systems, but this is real, used using something called Mr. Bob, whoever Bob is, I get probably Bob the builder or something like that. It's like names happen at Plone Sprints. So there is Mr. Bob and Bob templates, Plone creates this structure and that is a Python package that extends Plone. Why does it extend Plone? Because yeah, because it does. It is just it's built to extend Plone. It doesn't pull in Plone. You need to pull that into your Plone, but it is it is preconfigured to be a sane approach to Plone extensions. I'm going to delete the whole folder here, move it to the trash, and going to get to the next item. We already did the same thing for Volto add-ons when during installation you did the you used create Volto app or didn't we switch to you man or something like that. Yo, to create the add-on. So maybe this this is not the right name. Never mind. So let's have a look at the Python package that was created. I used the one that I checked out, but it's exactly the same. I created it this morning around nine o'clock and it's up on it's on GitHub. So there is a pretty complex folder structure here. And first of all, there's a lot of files here, and you will probably have no idea what they mean or what they what what's coverage RC, Bob template, CFG license. There is some license thingy here and manifest and the setup UI and what the heck is this all this stuff. And you could ignore a lot of that because it is mostly boilerplate. So what you see here is a build out CFG. And now you get super confused. Didn't we just didn't didn't that guy just say that we have our own build out for the training. It's in the folder back end. As a file called build out CFG. Where is it here? Build out CFG that pulls in the other package plonkrom side. And now I'm in plonkrom side here as RC plonkrom. And it has a builder of CFG again. Why is that the simple reason for that is you can just ignore that for your for the development purposes. But the default for when you create such a new package is that it should give you all the defaults to have this a self contained package that is testable and publishable publishable on pipy. So to be testable, it needs to have obviously plonkrom and some test runner and all this nifty things to automatically run tests on using GitHub actions, for example, or Travis CI and here GitHub actions, I guess that is here here GitHub actions. So run tests using plonkrom 6 and plonkrom 5 and do all that stuff. So all of that is already included in this boilerplate template. And you can ignore all of that. The only thing that you need is actually inside SRC, PONKROM site and our guard again. Why is that such a complex folder structure? Let's go into that. LL SRC plonkrom.side. This is a namespace package. SRC plonkrom site. So this is actually the, yeah. Let's go into SRC. When I look at the tree of the whole thing that I just created, I have a pretty complex folder structure, including all these files that you don't need and SRC and plonkrom site. And this is only there to make the again this file self contain, self testable, self buildable, and you can ignore all that. And every time we talk during this training about, hey, add a file in Bababa, Bababa actually starts here and not up here. If you, when you need to add a file, you always add it in inside this folder structure, where you have setup pandlers in it, configures that ZML and so on. So this is, this is where we actually add our stuff. I will repeat that a couple of times. Here is in the documentation it, yeah, let's quickly go through that. The most important, it's all explained here. The configure ZCML is a XML syntax file that registers components and stuff basically for your plonk side. In, if you use fast API or other frameworks, you probably are used to using decorators to register routes, for example. In a plonk, you don't do that that often, sometimes you do, but more often you use generic, ZOP component market language, ZCML to register, for example, a view for a content type or a interface or any code that you want to run. We're not going to do that much. So I'll just skip ahead to the next part where we have this empty shell that looks horrible and complex. But the good thing is you just run this command to create this, this, this, this package and then commit everything that's in there. If you look at the git history of the plonk.com side package, plonk.com side, I use source tree quite often for git stuff because it has a nice user interface. You see in this initial commit that has zero features but adds a ton of files, these are all auto-generated. So just add them and this is the important one. This is what you do yourself. This is where you write your own code. This commit actually, we are at the moment here at Volta. And this is like your commits, this is the important part. The small things where you say, hey, I'm a new content type. These 500 files, don't think about them. Don't get irritated by them, at least. Okay. Okay. Good. Content types. I hope that was not too horrible that part. But it is what it is. Python is a complex ecosystem, especially if you want your stuff tested and automated. And if you have a lot of dependencies, if you ever try to install Sentry, for example, by yourself, that it is horrible. It has so many dependencies. It is so many databases and containers that you need. It is just, if you have a complex system, you have to deal with this complexity that builds these things that you then can use. And we try with the clone and build out and build templates with these templates to make it as approachable as possible. And actually with clone 6 in the future, you can just say pip install clone and you get everything. But yeah, we're not 100% there yet. So installation is still a bit complex. Okay. Next chapter is content types. So it says dexterity one content type. Why does it say dexterity? Because in clone 4, we used to have also content types, obviously, because it's a content management system, but they were not called dexterity, but archetypes. These are basically two different frameworks. You can forget this name right away. It was really important to know that dexterity exists as long as you still had archetypes around. And if you need to migrate from archetypes to dexterity, that's a complex task. But if you start with clone 6 or clone 5, you will only have dexterity. So actually what we're talking about is just content types, ignore dexterity. So a content type is an instantiated object of a class that is defined in Python and stored in the database ZODB. That is from the clone perspective, that is a content type. From a user perspective, a content type is something that you click on an ad menu and select one of these content types and it is automatically created for you. So it needs to be somehow registered in clone that a content type like here, a document, page is called document in the back end, exists. And also the schema of that content type needs to be registered somewhere. You remember the news item had a different schema than the document. It had a lead image on top of the rich text and has lots of other fields. And also when you, a content type is, that's for the editor, that's a content type, but for the visitor, the content type is just a page that you look at. So it has three parts. One is the factory information that tells clone that you can actually create this thingy using a factory. Remember the factory factory. And the second is the schema that defines which kind of fields then should be available. And the third thing is the visual representation. So each content type usually comes with some kind of visual representation to the user. It doesn't have to have one, but in our case, we want one. So that is the important things about a content type already said some things about that. So in clone, as I said, as so is very configurable, it even goes a long way to make sure you can modify existing content types and add new content types through the web. So the first thing we'll do, we'll add a new feature to a existing content type. The news item, let's look at if you go to the control panel. Okay, I'll go back. So you might have missed that. If you go to site setup, this is the control panel here to the content type control panel. And there you have all these types that are available, including the news item, click on news item. And there you see the news item and the name and all this information. We're not going to change the name of the news item. We're going to go to the schema of the news item. We're going to not going to not adding the FTI but the schema, not the factory type information, but the schema and you actually get a schema editor in Volta, but you can add new fields. So what we're going to do is we're going to add a field of the type yes, no, so it's a Boolean field, you can check stuff and say, is this hot news or is this, I don't know, cold news. So let's do that. I'll add a new field. No, I'm not going to add a new field set. I'm going to add a new field here below that. And it's a yes, no field if I can find that. Where is my yes, no field? Come on. Type too many options here. Okay, there is a scroll bar and at the very end is the why. Yeah, maybe a small UI issue with nested scroll bars. Okay, the title is hot news for this field. So is this hot news? Yes and no. No description. It's not required, although if it would be required, everything would have to be a hot news, which doesn't kind of defeats the purpose. And here's my hot news field. And now, so what do I have to do? Yeah, I have to save. And then I'll open a the site in a new tab. And I go to my news listing here, and say the conference website online, and click on edit and guess what, it's already there. Isn't that super dark magic? So I can in I can without writing a single line of code without restarting the instance. I can add a new field to the schema to or model if Django if your Django developer, for example, that would be a model. And then you can add a hot news field and store this data. And it is stored in the database. So, okay, let me take you a little bit down the rabbit hole. So here is my news item. Let's go to the back end quickly. So the classic thingy here, we have news conference website online, I can edit that, I can see my button here, I can view that. And I was always saying, okay, this is some is the instance of a Python object. Let's make sure that it actually is PDB, if you don't know PDB, that's the Python debugger. And we have a add on in our build out that allows us to call PDB on any object. What happens, I don't see anything, why don't I see anything? Because I need to go to my back end, which runs in the foreground. And here I have a PDB. So self context is my news item. And my news item can be inspected. And my news item has a new field that I'm having programmed, hang on, that I added in the editor here. And it's called hot news. So there's a space in between, you can't have a Python, Python attribute with a space in between. Well, let's look at hot news self context. Hot news, no, minus wouldn't work as well. So maybe underscore. No, not that. This wouldn't work again. So how can we see that? Can we see that? No, that doesn't seem to work. Where is my hot news? Why can't I see that? Hang on. Am I on the right object conference website online? Yes. And it has hot news as a field. How is that called in this case? Let's just use the capital H. Who came up with that idea? Self context. Here. That's, yeah. Here it is. Hot news, too. It's a, it replaces the space with underscore. And this is my attribute. And it's actually stored persistently in the database. So, yes. We not only magically created a field, it is actually stored in the same way in the database. I'm not a huge fan that in Volto, new fields have uppercase characters that seem stupid, because in the back end, these are all lowercase automatically. But yeah, that's tiny, tiny issues. Okay. We did that. We can edit that. We save it. We can look at plenty of stuff here. We can even create complete new content types through the web, not only modify existing ones, we can just say add talk and have a talk content type there. And do I need to restart my site? Do I need to do anything? No, it's already there. So it's beyond imaginable what dexterity or the content types in Plone allow you to do. You can create custom types through the web, but we're not going to do that. I'm going to delete this thing because we are not mouse pushers. We are developers. We want to do stuff and have people check the Git history in two years from now and say, hey, what did you do there? That was horrible. Why did you do that? So we're going to write a content type in Python and register that in a Python package as a dependency of Plone. So why do we do that? Not only because we want to show off what we know, but because our projects tend to have a long lifespan. We're doing sites for universities. I don't know. Plone runs the Brazilian government website and a lot of UN sites and stuff like that. So it's not your neighbor bakery. These projects have a lifespan not of years, but sometimes of decades. And they have tens of thousands to millions of content and a lot of custom code. So they need to fulfill certain requirements for stability. And if you just create your content type through the web and click around a little until you achieved your goal, if you leave this project and five years from now a new developer comes in, he will be completely lost and he will hate you, which may not interest you, but his life is then miserable and it should be in your interest to make the life of other developers great. So we're going to do that in Python and not through the web. Oh, God. It's already half past six. Katja, what do you think? We're way behind schedule. Should we make a short break before we do another half hour to actually create these talks? Last year we were quicker. I had the feeling. What do you think? You want to make a break? We have only half an hour now from now. I think people are going to break. Yes, but maybe just a short bathroom break, five minutes. Maybe I don't know what time it is for you. You can get a beer depending on your time zone. Five minutes? Good. Let's have a five minute break. Let's actually really meet in five minutes so we can get the most out of the next 30 minutes. Again, if you have questions, please put them in the Slack. We'll try to discuss them. Am I too? Someone said I was not loud enough. Sorry. I didn't see that. See you in five. I pull. Maybe you need to restart your browser or reload the page. The developer tools, when they're freshly installed, may need a little kicking. Here are components and then you can inspect. There's two inspect buttons. This is for HTML and this is for React components. I always click the wrong one. This should then show up. You need, for some reason, this scrolls very far to the right. Then you can find that. Let's continue with the talks. We are way behind schedule, but that's just what it is. I don't know where we lost so much time, but it is, yeah. Okay. We will register a custom type. Why do we do that? Excellent, Paul. Good. So since we're organizing a conference and we could have talks as documents and say, okay, it's topic, speaker, whatever, information is just in HTML. But if you want to sort your content by speaker or link to that specifically or order that by date or day or room or stuff like that, it is good to have structured content. Data is just, it's perfect as structured content. Talks is perfect for that. So first, I said we need three parts for a content type. First is the type factory information. So we tell Plone that there is a content type called talk that should be available in Plone. So to do that, we go into Plonkconf site and that means SRC, Plonkconf.site, SRC, Plonkconf site, and then in profiles. So from now on, we say go into profiles or Plonkconf site profiles. This is where you end up because the Python namespace actually ends up here also in use the default profile, not the uninstalled profiles. The default profile is where configuration ends up that you put configuration in there that is applied upon installation of your add-on. And here you create a new file called types.xml and you paste the content from this snippet here. So, oh, God, why is this not Python? Can't we do this in Python? This is XML. This is something called generic setup. It's one of the extension approaches for Plone. And everything you have something in XML and you make a change in XML, this is only applied upon installation of an add-on. So after I save that and I reinstall or install my add-on, this code is then read. Restarting, reloading the browser won't help you. You need to install this package because then the generic setup profile is applied. And this generic setup profile will raise an error because it tells there should be a type called talk in my profile. And it's not. There's only document for some reason, for a very good reason. But we need a talk XML as well. And that lower case for custom content types, I always use lower case. You can do what you want. But I think lower case is a good best practice. You copy and paste the whole FTI here. So I haven't learned anything right now. That's what you probably say. That's not true. You've learned something very, very important because you can copy and paste code. And you can copy and paste code from the location where it is always updated. Not every month. But it uses these same defaults. And it is what I do at least twice or three times a week when I write my custom client projects. I go to the mastering plan training documentation, go to the chapter that is close to what I'm doing and copy the defaults that are in there and make the changes that are required for my client project. Because I'm just way too lazy to type all this stuff. And I don't want to memorize that. And nobody wants to. There is a lot of documentation about the mastering plan training is certainly the most up to date and the most comprehensive one if you want to deal with creating content and modifying content types. And it's basically the same approach as like, plan does it. You don't fork plan. You also don't fork the mastering plan training. You just take the bits and pieces that you want for your projects and you use them and then you change what is required in your projects. This time we don't have to change anything obviously because we specify a content type called talk, which has a title with an uppercase t. It has an icon. It has a factory and ad view and it has a class, a Python class that is used to instantiate the object that then lives in the database and it has a schema that is both not yet in existence. And it has a couple of behaviors. We'll get to these later. So this is your FTI and it's basically the first part is done. You registered a content type for PLOM. The second part is the schema. You need a schema and the schema can be done in multiple ways. Again, we can use the browser to add fields until we have our schema and that is absolutely okay to do that if your project has a limited lifespan or if you do rapid prototyping. But if you have a longer running project, it would be better to do that in the file system. And again, there's two ways to do that. One is again in XML, but I hate XML. XML is written for robots. I'm not a robot. I'm a human being. I want to read Python. I want to write Python because Python is meant for humans. So we're going to create a Python module inside our package. A module is a folder with an initpy file if you don't know that. So here content, that folder obviously already exists. For me, for you, it should not initpy. So now we have, there is a module called content. It doesn't contain anything yet. And in there, we create a file called talkpy. That then is a, talkpy. And that will hold the schema. I'll just copy and paste the whole thing and save it. And then I'll go through that step by step. So here we define the schema. It is basically a Python representation of what we saw. Not here, but here. This is the user facing representation of the same thing that we're looking at now for a different type, obviously. So we define a schema, which is an interface. I'm not going to go into interface theory, but it defines a contract, basically. The contract that talks have these attributes and can do these and such and such a thing. So this is the interface and it's defined, it is referenced here in the class. So this here, this is the interface with the schema. And then there's class again with a k because c is, would be reserved, reserved word at some point when you load that and you get error messages. So that's why it has a k. And then there, hang on, here at the very bottom is a talk. This is the instance. So when you create a talk then or a news item, this is the object or the news item in that, in the other case, would be instantiated and it implements this interface so that it can store these, the values that are added to the fields in the, the, the widgets in the browser and can store these, these values as attributes persistently in the database. So, okay. So this always, again, you don't have to memorize all of that. When you write your own content type, you go to the mastering, the training and you copy and paste this thing here, the whole thing, if you want, and you throw away what you don't need and you add what you need. I'll show you how you, how to find what else you need in the next chapter. So here we have a couple of fields type of talk and they follow a, they have a certain, each field has a certain type. You remember, we added the hot news field, which was a yes, no field or Boolean would be like this. In this case, it's a choice field which stores strings. So text here, one of these values. Here we have a rich text field. It's in, it's imported from a different place, the definition of rich text field. But again, this is something you don't have to memorize. You can copy and paste that from dexterity documentation. That is actually the next chapter is the dexterity documentation itself. And each field has a title and what is the title? It's not super unexpected. This is the title of the field here. The title of the field is summary. Here the title of the field is hot news. A description of a field is, for example, this here, this is some help text. This is the description. You can configure various fields as required. So there has to be something in there. Either a box needs to be checked, we need to add some text and so on. Here's a text line field. That's a very simple one. Speaker, where you can just add a line of text as title description is not required. And so on and so forth. And there's an interesting one. There's block image, name block image, which makes sure that the file is actually stored not in the database, but only a pointer to that file stored in the database. And the file itself ends up in the file system where binary data is best stored. So after I save this file, I need to, what do you think would I need to do? So this is, we extended blown in two ways. We added a factory type information for talk here. We referenced that factory type information in the portal types tool. That's how it's called. That we extend here with type. And then we added a Python module. Python modules are only read on startup. So reloading the browser wouldn't help us. So at least we need to restart our instance. Just stop it with control C and restart it with instance FG. Remember that you need to do that for the back end, not the front end in this case. And then we, as I said, the XML files are only read upon installation of the add-on. So here we have a problem because the add-on, Plurcon site that we created here is already installed. Remember when we created the site, we checked the box at the very bottom of the list of add-ons that are available. So it's already installed. How do we reinstall that? Actually, the way to reinstall that is to uninstall it and install it again. And at this point, it is actually still safe to do so. It will at some point no longer be safe, but we'll see that. So where are my add-ons? Here are add-ons. So in the list of installed add-ons here, five installed add-ons, there's Plurcon site. And I can say, just drop that. Remove it. And Plurcon site, just reinstall it. Install it again. So I clicked my button here. And a couple of things happened in the back end. So you see, it was applying the profile, Plurcon site default. Remember the folder called default. Held this. Then it installed roles permissions. Why is that? Did we do anything there? No, we didn't do anything there. But there is a empty roll map XML that can hold custom roles and permissions. And that file was read and applied. So nothing changed, but it said, hey, there's a file. I'm going to read that. Catalog was imported because there is a catalog XML. Again, empty. But there is more types tool imported, document type import and more, and talk in type info imported. So it obviously saw that we have this. And it saw that we have these files, these two files. And then it applied these profiles. So this configuration is now somehow in the database. And it's, yes, it is visible in the front end. When we move this thing, when we move to the to the dexterity control panel, we can see our new type here. Talk. Here it is. Similar to when we would have added that. And we can actually see the schema that we defined. So this is the schema. It's all there. And it's not only visible in Volto as a admin where you can modify that. But again, in the back end, in clone has, clone has a, the classic has a equivalent of that user interface. Not going to show you that. But the types tool that stores that configuration actually has a user interface in this soap management interface, portal types. And here is my talk content type. And here is my reference to the schema and the behaviors and the class and whatnot. So a lot of stuff is in multiple places. And that is because clone wasn't built last year. It has quite some history. And this is where you see that various layers on top of each other. Okay, to make, to finish that, let's go to schedule and add a talk. Here it is. Dexterity. Some Latin nonsense, please. A type of talk. Here we have, I said it's a choice field with strings text, pick from here you have rich text field, you can add some rich text. Add that and yeah, edit that. Add stuff. Audience again, a choice field. In this case, a multiple choice field. Beginner advanced professional dexterity is for everyone. A field for the speaker. Or let's go back into history. Martin has barely one of the brains that dreamt up dexterity. No idea where he works at the moment. Let's pretend he works for me. That would be fun. Martin had clone.org. Probably shouldn't have a space. Let's see. Yay. So this email field, obviously, isn't a text field because otherwise it wouldn't have complained that it's not a valid email address. So having the schemata is not only cool to show off that you know how to do that, but with certain fields you get data validation, input validation. And that is obviously super important. So you have valid data in your database and that you don't end up with invalid data. So if, I don't know, clone, if you later try to send an email to all these people who registered as speakers, you don't get error messages. Philip, that's a question. Yes. Let's see. Paul, it is stored in the DB, but you should have the schema. Oh, the first one. If you create the schema through the web, it gets stored in the database. Yes, is that why you say it's not good for long projects? Yes. The schema is, if you create it through the web, it is stored as XML in the database. And there is a way to export that. You can export a schema into as XML and import that into your Python package to put it into version control. So that is a totally valid approach. And the earlier versions of this trainings actually did this. So we created the content type talk through the web, exported the XML into your Git repository and committed that to Git. But as I, it's a matter of choice. I much prefer Python to XML. It is feature equivalent a schema, but there are tiny things that you, sometimes you need to use in more complex projects that you can't do in XML, for example, default context aware defaults. So a method that runs to define a default value for some field that takes into account where this object is created. And so on. A couple more examples like that. So in Python, you can basically do everything. So that's why I much prefer that. And Paul had another question. He answered that question. That is actually nice. Okay, let's add some website here. I think like that. Okay, I'm not Martin. I should not pretend to be Martin. He's so much smarter than me. So let's pretend I will do that. Talk. I can upload an image of biography. You see, obviously. And the third part that is, that I meant said a content type is made out a view representation. You get that automatically. But, and that's a big but. This is, we don't see any of the exciting data that we just added. Only a Plon classic so far has that feature. So when we go to schedule and see the Dix 30 for the wind talk, I can see a default rendering of the values in that schema, which is often good enough, especially for, I don't know, internal use as intranet stuff like that. But as a for visual representation to client or conference website, this is not like this is like Excel. Just dump me a Excel sheet. What do you think you're doing? That's not okay. So don't do that. We in the next chapter, we're going to much improve that. So we already created this type. We tested this type. You see the user interface is slightly is slightly different. But if we change this to a keynote, for example, and save it. And we added that again in Volto. We have the same data. So here's the keynote now. So this is, again, this is the react front and talks to the same back end. As Katja already said, at some point, you need to decide which user interface you need to take. And you can't really switch back and forth in like one folder in Volto and the other in classic. But the data is in both places. We're going to take care of the visual representation of the data in react only. So what else is there to say? Yeah. Ignore that. We created a first content type custom one in Python. So it's readable. It's great to test and to repeat the process and change it for the next iteration. You can control all kinds of data that is stored in the database for these talks. You could extend the schema now in the later stage. We can do that. And if I said this is what you learned was not how to actually write a schema, but you learned how to copy and paste the best parts for writing a schema. And the next chapter, we have five more minutes to discuss that, is the dexterity reference documentation about all schemas that are fields that are available for you when you create your content types. And this is where you need to go when you have a requirement and you need to fulfill that. And this is how do I do that? How do I do this? These are all types of fields that are available. And they are all which is kind of crazy. They're all in one content type. So there is one content type called example in this schema. And it has various field sets for various field types. So these are field sets here, different field sets. And you can, so they're sorted by, you see these sort dates, date fields have one field set, text fields have one field set and stuff like that. And here are, I'm not going to go through them. Don't worry. Here are examples for all kinds of fields that you will probably ever need. And there are plenty of those. And to make things even better, there is a screenshot for how these field sets, also also these fields look like in Plone Classic, all of them. And also how they look like in Volto in Modern Plone. Six. So you can check them. They, some look a bit different, handle a bit different. That's all discussed here. And on, to make things even better, there is a Python package that has this content type and it's installable. And it is, where the heck is it? I should have added a link to that. Example. Come on. Example.con, I obviously forgot to add the link. It's called example.content type. It comes in two branches. One is called Volto and one is called master. Because some fields don't work in Volto. They are fields that you don't usually use. For example, time delta, which stores the difference of time, which is why would you need a field for that? Yeah. So, and so this is where you can, you can install that. You can check that and look at the, here's the schema for Plone Classic and here's the schema for Volto, which has a couple of fields are commented out because they don't work. For example, the data grid field, you can use that, install that and play around with these packages or you just copy and paste the schema from here. There is more. There are third party packages in here. The data grid field, which is in Plone Classic and the excellent addition to Plone to add an arbitrary number of lines of, again, schema defined data. So you have, for example, the field would be talks, but the talks are not content types itself, but a simplified schema with title, speaker and type of talk. And you have an infinite, can add an infinite number of rows of that data to that. And something very similar is the mixed field that Katja, I think, created where you have something, again, a data grid where you can add rows of data that are defined in a schema. And the code for all of this is here. You can have that. You need the object list widget to display to be able to import that data. And then you have these kinds of items. You will actually see these at a later stage in some of the blocks in Plone. For example, no, I'm not going to jump ahead there. There's a search block or actually the collection. The collection has, you can have defined criteria and each criterion, you can have infinite number of criteria is similar to a data grid field or these kinds of blocks. And that's the code for that. Here's some links to widgets. And there is also information in this chapter. This is why you really need to keep this bookmark, because it has all the information what you can do on top of that with the schema, because I went over that. Here's a directive to change the widget of the choice field to a radio field widget to make that radio buttons and not a drop-down list. So you might wonder, yeah, why did I see a drop-down list then? Because this radio field widget doesn't work in Volto yet. There is only a radio field widget for Plone Classic. So when you edit a content type, this content type in Plone Classic, you get a different widget. This one instead of a drop-down widget, because I think it is stupid to have a drop-down if you only have three options. If it's 50 options, obviously you want drop-down and not radio buttons, because you'll have a full page of radio buttons, which is horrible. So you can define the widgets here. And there is more. There's validation. You can constrain the data. You can have methods that are then called upon entering the data automatically. They're called. And they can raise an exception if the date, for example, of an event is after the start date of the event. Or you can't start after you already stopped, obviously. Then a default factory or default values. What else is there? There's an invariant to validate data, a context aware. That's it. You can do basically everything with these couple of snippets. So we've reached the end of today's training. And next up, tomorrow morning, no, not tomorrow morning, tomorrow afternoon, at least for us Europeans, we will realize that our schedule is, the talk is nice, but it looks terrible. We want to display the data. So Katja will walk you through creating a view for this talk in Plone in Volto with the new front end. And if you're so inclined, you could also look at the old version of that, where we discuss creating view for the same content type in Plone Classic, which obviously works completely different. You write page templates in Chameleon, while here you write your page templates, which are not page templates as view components in React. So that's an exciting chapter for tomorrow. If you want, we can, if you have any questions, we can discuss them now. We don't need to go right away. Obviously, there at some point, there is dinner in Sorrento, I think at 8 for Katja. But if you have questions or feedback, ask it now or in the chat and we will answer that tomorrow morning before Katja starts off with this chapter 23. Yeah, I think we should start tomorrow with 10 minutes questions and answers. But if you have no questions, that it would be good, then we would be better prepared tomorrow. Yeah. I guess we drown you in content. Don't be shy. If you have questions, you can also ask us by email or in the Slack. We'll see that tomorrow morning. Slack will be open all day, all night. Obviously, stop sharing my screen. Maybe for those who are still there, a sneak preview as a motivator for what's coming tomorrow, we're probably not going to get as far as we did last year. But after we created this, the visual representation for talks, you will probably learn, unless you already know all of that, a lot about React components and what nice tools you can use there to make beautiful pages, renders. We will learn about behaviors to extend the content type. The content type is there to extend clone with a new content type, obviously, and behavior can be there to extend that content type. It's like Lego. You put these little Legos. It's even better than Lego. I don't have a reference right now. But we can extend this piece with something that already exists to give it more features and more functionality without writing a single line of code, which is extremely powerful. The best code that is created in this training is the one that is not written, but is reused by just plugging the right components on top or together, just connecting the right dots. That's what we're going to do in the chapter 24, also 25. We're not going to write a lot of code there. More complex code will be the listing view for talks. That's more React for you. We'll discuss, I love chapter 30, where we do a small change to give a lot of power to existing content types again. If we can get there, we'll add customizable functionality, a control panel where you can configure the site. Here in clone, you can go here to the control panel and configure all kinds of things. Obviously, you can do that with your own add-ons to say, I don't know what types should be listed in what kind of listing block and stuff like that. You can do whatever you like to extend flow. That's super powerful. That's the whole idea of this training to teach you about these little components that you can hook into to reuse them. Because clone is already so big, most of the requirements you get from your projects or your clients, you won't have to write a single line of code for them, because they either exist as an add-on or as a feature that you don't know, or as a combination of these two. You just combine this add-on with this feature and what are they? That's the magic. I don't see any questions. Katja, what's for dinner in Seren to? I don't know. Sorry. The restaurant in Seren to is excellent. If you ever get a chance to go to Plone Open Garden, which usually happens in spring and is now not Plone Open Garden, but the Plone Conference Fan Zone, the restaurant on top of the restaurant with a beautiful view of Mount Vizouvius, has gorgeous food. It's just terrible. You come back a couple of pounds heavier than you went there, probably. I always do. Okay. Any last words for today? Thanks for bearing with us. Thanks for listening. I hope we didn't bore you to death or overloaded you with information. The good thing is you can always re-watch the video on YouTube, make it slower or faster, or skip chapters. The second good thing is you can read all of that, or most of that, at least, in the online training. Thanks for tuning in and have a great evening and talk to you tomorrow. Good appetite. Katja. Thanks for attending and hope to see you tomorrow.
 I hope you can hear me well.  I think audio should be fine with the microphone.  There's one here.  So we're super excited that so many of you  decided to join this training.  A big welcome from me and Katja, my co-host.  Please, Katja, say something.  Hi, all together.  Nice to meet you here.  Katja is in Sorrento, sunny Sorrento.  Hopefully, I guess you're holed up in your hotel room.  Well, I am in Munich.  So the marvels of modern technology  bringing us together here to give that training together.  I hope that will work.  Katja, I guess you can share your screen.  You have the screen sharing feature as well,  because I'm making you excellent.  So you can make yourself heard and visible.  If you have, before we start, some, I don't know, general tips  and tricks, we'll have a couple of breaks.  I hope.  So this is going to be four hours now for our training.  I we will stop at 7 PM central European summertime.  So four hours from now.  If we're finished earlier, that's also fine.  If it takes five minutes longer, that's also fine.  But the point is, if you need to go away,  if your family pulls you away from the screen or stuff like that,  that's not a problem.  All of this training will be recorded  and will be on YouTube after the conference at some point.  Paul will have to do one of the foundation board members.  We'll have to do that job  and it'll probably take a couple of days  to download everything from Zoom  and upload everything onto YouTube.  We will also add chapter markers to the video training.  And yeah, so you can, if you miss something,  the point is, don't worry, it'll be on YouTube.  So if you need to take a break.  Also, if you have questions, please use the Slack.  That will be the best to use Slack.  You could also use the chat here in Zoom.  But in case we miss a question,  because there were too many discussions going on on the side,  please just ask them again or just unmute yourself  and say something loud, that's fine.  If you don't want to be recorded,  because the whole Zoom meeting is being recorded,  just keep your camera disabled.  That is fine as well.  Before I start sharing my screen,  I would love to see all of you just for a second.  I promise you, this part will not be on YouTube.  I will cut this part.  So you're not going to be on YouTube with this part.  But if you just enable your camera for a second,  so I can wave at you and wave back.  So many faces I know.  Really happy that you decided to join our training.  You should give this training, probably.  A couple of you have been around with Plone as long as I have.  So you know more than me, probably.  Let's see.  Let's find out.  OK, excellent.  I'll take a screenshot of that.  Maybe, yeah.  Something like that.  Yeah.  I'll not post that anyways.  Just a memorizer for me.  OK, I'll start sharing my screen.  So here goes.  Screen sharing, excellent.  In case screen sharing drops off or something,  just yell at us so we can enable that again.  You should see a browser saying Mastering Plone 6  Development.  So this is also the documentation.  We're following.  It's on trainingplone.org.  And it's the Mastering Plone 6 Development training  that we're following.  It's been updated yesterday and today and many days.  A lot of times.  But I think the last commit was a couple of minutes ago.  I hope that went through.  So if you want to follow the code examples,  use this to copy and paste.  Don't type.  Please don't type.  This is only two times four hours training.  And we don't have time for you to correct your typo mistakes.  I make them all the time.  This is not a critique.  It's just it takes much, much longer to type it.  But a vertebral advice, if you do the training at home,  continue the training or redo the training at home, which  I strongly recommend that you do that.  Don't copy and paste. Type instead.  If you have the time, talk to your boss.  Say, hey, I've got this training for free from the conference.  And it's just it's maybe good, but not  sure yet because it was only the two times four hour  sneak preview.  So I want to work through the whole thing.  Type the code because when you do your own projects,  you're going to have to type it anyway.  A lot of your custom code.  And it'll stick in your memory much better.  So yeah, this if you want, you can switch off your video.  If you want, it would probably be good for bandwidth issues.  But if you want, you can also keep your video on.  So you can wave at me if I say something stupid or at Katja  if she says something stupid, which will certainly not happen.  So this training is by default takes a week.  So what are we going to do to make that happen in two  times four hours?  We're going to start skip a lot of chapters.  And we're going to stop very early.  So this training has as you see here,  54 chapters and we will stop, I don't know,  somewhere much earlier here sponsored.  We're not going to get to sponsors.  31 is the chapter we did last year at the end.  So and we're going to jump ahead a lot.  So if you think you missed something,  just read the online training or and that's also very important.  We can be hired Katja and me.  We are certainly available to do in-house trainings for you  or your company.  We did that a couple of times already, various topics.  So feel free to contact us, either her or me or even us  as a team.  She lives in Switzerland.  Don't you Katja?  Where exactly do you live?  In Zurich.  Beautiful.  So if your company is based in Switzerland, Italy,  or somewhere south of Munich, you probably should call here.  If you're in Norway, you should probably call me.  No.  Yeah.  The point is we are for hire, guns for hire,  and not only for trainings, but also for plan development.  We live of this stuff.  So consider giving us a job.  We're both pretty busy at the moment.  So this is not a plea for jobs.  But at some point, we will looking for more.  So OK, this is about this thing is 10 years old, the training  now.  This is the video.  This is incredible.  I would love to hear some of you, something about you.  But since it's online training, I will not force you,  will not do this introductory round.  If you the point here is we would  like to hear what's of interest to you mostly,  to discuss and give depth, more in-depth,  deal with these issues more in-depth during the training.  Since it's only abbreviated online training,  we can't really do that.  But at the end of today and at the end of the training,  tomorrow, we'll have about an hour or 45 minutes open  for discussion.  And feel free to jot down any questions that you have.  For example, I have this business requirement,  or my client asks me to do this and that,  or can we do this and that with Plone?  This is that would be an excellent time  to pick our brains to get these questions answered.  So during this training, we will create, guess what,  a website.  That's what Plone is good for.  And the website we're going to build is for a conference.  And the conference is going to be a Plone conference.  And it's the Plone conference in the year 2035.  And it's going to be held on Mars,  because Plone obviously rules the galaxy by then.  And we're going to try to fulfill  a couple of requirements.  I'm not going to go through all of them.  But obviously, if you have a conference,  people should go to that website and learn something  from about the conference, when it happens, where it happens,  if there is a talk registration open, stuff like that.  And then you also want to find information  about what kind of talks are there, if there are trainings,  what are the keynotes and the keynotes speakers.  So this is basically stuff that you  could do with just normal documents.  You just write that down.  But we want to structure that some more.  And to be able to structure that,  we could do that without structured content.  But we want our speakers to be able to submit their own talks.  And to have that in the same way, we  create a content type for talks.  And so speakers can submit them.  And then I want to be able to edit my talk before I submit that.  And I want to be, as an organizer,  I want to see a list of all submitted talks, and so on and so  forth.  Yeah, a couple of requirements.  And the most important point about that  is not like there are complex comments.  These are like everyday things.  The requirements change because your boss forgets something  or just a new requirement comes in.  And all of these things happen during the lifespan  of a project.  Because let's be frank, you never got a project definition  before you started that.  That was 100% set in stone and never changed  during the course of the project when you did the project.  So for example, at some point we decide,  we're not going to only have talks.  Actually, these talks are going to happen at a certain time  in the year.  So we need to add time and dates.  And also, these talks are going to happen in a certain room.  Hopefully next year we're going to be in a physical room  and not in a virtual room.  So these are things that in this use case,  you forget.  You forgot when you started creating your website.  And at some point, yeah, we will need to do that.  And there is a lot of talks, tasks,  that we need to solve for this.  It will be interesting for you to read through that.  I'm not going to go through that.  You'll realize what's going to happen.  And also, it's most important what we not do actually.  We're not discussing professional theming.  There's actually two trainings about that.  One for the classic front end in plan 6, that is today.  And one for theming Volto.  That happens tomorrow.  A training about that.  We're also not going to discuss professional deployments.  So if you really put that on the web and hosting websites,  this is not covered in this training as well.  These are the two most important things  that we're not discussing.  There's a lot of technical stuff that we're not going to do.  I'm not going to tell you what PLONE is  because you're going to learn about that.  But I'm going to point out a couple of core concepts  that if you are new to PLONE, and I guess a couple of you  are maybe unfamiliar to you.  And one is traversal.  So that traversal stems from the fact  that PLONE, as a content management system,  stores content in a tree structure.  So there is a tree where the content lives.  So in this example here, you have the site root.  And this tree has many branches and leaves.  And the whole tree acts like a nested dictionary.  So each branch has, again, a dictionary within it.  And traversal is starting from the root  and walking down that path towards an object.  It's like a folder structure in Windows or Mac  or Linux.  So it's very familiar to you how the content is structured.  And to access this certain kind of content,  for example, from the site, you have a folder.  And in that folder, there is a page.  You can do exactly that.  You traverse to that page going from the site to the folder,  to the page, walking down that path.  And this is also the way that URLs are built.  So you have a URL.  If you go to demo PLONE org, there  is a demo site that you can use.  And you have this structure here.  Demo, a folder, a page inside a folder.  So there is no routing like you would do in, say, Flask  to expose a page inside a folder under this URL.  But this is actually the structure of objects  in that object tree that's exposed like this.  OK, that's number one.  Number two is also super important.  That PLONE is built around the concept of object publishing.  So if you have an object in your site, in your database,  you can call that object.  And this object will publish itself.  So when you go to this URL, for example, or let's make it a bit  simpler, DE demo, a page, this object  is found via traversal, traversing down that path,  that tree.  And this object is found.  And then this is called.  So in Python, if you call something, you just do,  how did I go there?  You actually call that by with this.  You open your brackets and close them.  So here's your object.  And then you call them.  And once you call them, a lot of magic happens.  There's actually a Dunder call method in a base class in there.  And that, at some point, makes sure  that a template or whatever happens in there is rendered.  And it returns HTML to you.  And this is actually what you see in the browser.  So in a nutshell, this is exactly what  happens when you open this URL.  This object is called.  And this HTML is returned.  And your browser is smart enough to render that HTML  in a nice way.  That is the second basic concept of Plone.  Third one is schema-driven content.  So the content, Plone is built with content types,  for example, a folder or document or a news item.  And all of these have a different schema.  And the schema defines, in other frameworks,  it's called model, which kinds of fields basically  are available to edit.  So if I use this demo page again,  and I log in as an admin here, and I go to this edit that,  I have a couple of fields here.  So this is classic Plone.  We're going to move to Volto in Plone 6 in a second.  These are the fields that are available.  And these fields, all of these, there's a couple of fields,  actually, they are defined in a schema.  And these schema fields are then accessible as attributes  on your object.  So you not only can call your object,  but you can have these objects have attributes.  And the attributes store the value  that you enter in a field that field is defined in a schema.  There is not only string, like text,  like here's some description, but also more complex attributes,  obviously, like an image that is its own object,  named blob image in this case.  And it stores the data as the attribute data.  And here you have the binary data from that image,  for example.  And objects can have multiple schema,  and they are combined to give you functionality  that you can reuse.  Enough of that, I'm not going to go into the component  architecture, but it's just a thing to prove  that we are super smart, and you should be in awe of everyone  who actually worked on that.  And starting with Plone 6, Plone comes with two frontends.  So there is the classic frontend that you're seeing here  on the demo Plone org page, because Plone 6 is only  in alpha stage now.  But there is also a demo Plone 6.  And these look a little, let me, classic.  Let's open these side by side.  So this is Plone 6 classic, and this is Plone 6.  This is the official naming.  Plone 6 has a brand new frontend written in React,  a JavaScript framework that you're probably familiar with.  It is client-side rendered.  So the magic happens on your laptop  or in your browser, basically, where the templates are rendered.  This, whatever you see here, is rendered in your browser.  And here, this is in Plone 6 classic.  This is server-side rendered templates.  So the HTML is returned via the concept of object  publishing here.  Actually, that's interesting.  I should probably update that.  Where's the object publishing part this year?  Because Plone 6, modern Plone 6,  actually doesn't call the object.  It uses the Plone REST API to get a representation  of that object as JSON and React or Volto.  The frontend has its own name.  It actually has its own logo that we're not using here.  That makes sure that it's rendered.  So object publishing actually is only  true for Plone 6 classic, because that's  where the objects are directly called.  And it's your job to decide for whichever project  you want to do which frontend you want to use.  There is still a ton of classic frontend projects around.  And it's been very modernized.  It uses Bootstrap 5 and Webpack.  And it's super modern and it's super cool.  But it's not JavaScript.  It's not React.  So in Katja, there's a lot of Volto projects.  So yeah, it depends on what you're doing.  If you're a university and you have Plone site  with 200,000 objects in it and you're migrating to Plone 6,  going all into Volto would be a hard task  because you'd have to rewrite a lot of your own code.  So they will probably use the classic frontend.  But if you're starting a completely fresh, a new project,  Volto is definitely a smart default choice.  OK, installation and setup are not  going to go into that because you already, hopefully,  installed Plone for the training.  And if not, if you had any issues installing  Plone for the training, please write something  in the Slack channel so we can try to help you.  Katja is available while I'm talking to help you assist you  or if there's something fundamentally broken,  we can discuss that together.  But you should all follow this installation.  This is the technical setup as a training.  Here, installing Plone without Vagrant.  We're not, hopefully, nobody tried to use Vagrant  because this will probably not work on a Windows laptop  at the moment because our setup is not updated for that.  And Volto would not run.  But you could probably run the back end in Vagrant.  So use it directly on your laptop like this.  If you had problems, just tell us.  After we did this, you follow these whole instructions here  and you got your Plone running, you  should have a setup that looks like this.  3 minus L2.  Let's say 1 first.  So you have a folder that is basically empty  except that it also has two folders, one for the back end  and one for the front end.  The back end is in Python and the front end is in React,  in Volto.  So if I expand that to 2, make that a bit bigger,  you see that inside the folder back end,  there is a source folder that will contain the code that we  write during this training for the back end  and a couple of other folders that I'm not going to go into now.  And a front end folder that also has a SRC folder,  which will hold the code that you write for the front end  during this training.  So I just decided that last year I  used Sublime for the back end and VS Code for the front end.  This year I will use VS Code for both,  but me and Katja will both, when we switch from back end  to front end and vice versa, we will always  try to take you with us and tell you where we actually are  because we'll have to do a lot of tasks on both,  not the same task, but to fulfill a requirement,  you need to make changes to the back end  and then you make changes to the front end.  And only some tasks require changes in one of these places.  Actually, a lot of them require changes in only one of these.  But yeah, it's a complex system and it's not getting easier  by having a front end that is decoupled from the back end.  Good.  Since no one wrote any help, nothing is working in the Slack.  I'll just keep on going and we'll continue with chapter 8,  starting and stopping plowing, because that's  what I'm going to do now.  Here.  So when I'm in this folder, I first stop everything first.  Actually, I already started my front end  because that takes a while, but I'll do that again for you.  So I have two terminals and you should do the same  when you're doing plowing development on your local machine.  If you're a front end developer, that's a different story.  You probably, some back end developer,  got you a Docker container and that's running  and you only care about React.  If you're a back end developer and you only do back end,  you have plowing running locally and you're doing your stuff  there and you don't care about any of the JavaScript  nonsense that your colleagues, tomes over are doing.  So but in this training, you're doing both because you're  going to be a full stack developer.  I hate this word, but still, this is what you're going to do.  You're going to learn how to work with Python  and with JavaScript.  But not only Python and JavaScript,  but actually, clone, which is a huge stack on top of Python  and React, which is a huge stack on top of JavaScript.  Did I?  Yeah, well, didn't say anything stupid here.  So I'll go into the back end after I ran build out,  which I already did, and I'll start my back end  with bin instance FG.  FG stands for front foreground, not front end, foreground.  So this is the debug mode.  So I'm going to see a output.  Everything that's happening in my plowing side  is visible to me here.  And here I start my front end with yarn start  after I install that.  So you should have approximately the same setup right now.  And if you go to a, let me close these demo sites,  if you go to once it started, you  can go to localhost 8080, because the back end is,  by default, running on 8080.  The front end is, by default, running once it's finished.  It takes some time, especially when  screen sharing, which also takes a toll on my laptop.  It's a bit slower than.  It runs on port 3000.  So I'm going to start my browser here  and go to localhost 8080.  And it's already telling me, plow is running.  And your plow side has not been added yet.  I'm going to solve this riddle in a second.  OK, Volto, here you see in the front end, also it has finished.  And I can start that.  And I can go to the front end.  And it will tell me this page doesn't seem to exist,  because I didn't add plowing yet.  So to create a plowing side, I need to go to the back end.  Always, you can't create a plowing instance in the front end.  So when I say instance, we're talking about Python here.  So a instance is, so there is a class defined.  There's a class plow side, actually.  I think that's what it's called.  And when you create an instance of that,  someone is instantiating that plow side, calling plow class.  Site equals plow side brackets.  And in a nutshell, that's what's happening  when I click the button here.  You should use the advanced button.  Going to switch to English here, obviously,  because that's the training language.  Keep your time zone.  Leave the name of your plow side as plow  and pick the plowcon site add-on.  You need to pick that, because otherwise, the front end  will not work properly.  This is auto-created and automatically checked out  by buildout when running buildout.  I'll click this button now, and plow switches to English.  And when I go to the back end, I see when I scroll up,  I saw ready to handle requests.  And then I clicked after here, serving on.  And then a lot of stuff happened,  and plow told me about everything that it did,  including here, finished bundle compilation.  That's the last statement I see.  And then I see a plow side, actually.  Plow conference 2035.  That's what it says.  And starting now, I can actually see,  this is the back end user interface.  And now I go to the front end user interface.  And I reload that.  I should probably log out and log in again as admin.  So when I say this is the back end user interface  and the front end user interface,  this is actually plow classic.  So there is no what actually there is,  but we're getting to that later.  But this is the back end is the same as plow classic.  So when we're developing plow six using React,  and we say, we need to do something in the back end,  that either means we need to write some code in our editor,  or we can go to the classic user interface  and do some manual changes there.  And you see the content is the same.  So if I modify, if I create a site here, for example,  create a site and I say test.  And page.  And here's my, here's test.  It just says test.  Why does it say welcome as well?  It's kind of weird.  Something's wrong here.  I should be able to reload this.  And here it is.  So this is just a visual representation of the same data  that lives on the back end.  So these are connected.  These are not two separate things.  These are separate processes, but these  are not separate databases.  The database of the back end is the same for the front end.  That's the whole point of that.  So here I got my site.  I created a site.  I chose the language.  I checked PlonCon site, clicked create PlonSite.  Then I saw that.  And then I started, or even actually I did that before.  I ran YarnStart.  And I saw my front page in the front end.  And I can skip over these exercises.  You should do them at home.  And then I see my site.  I walk you through the user interface,  the most important parts of the site.  So obviously, we're always talking about,  when we talk about the visual representations,  always the React user interface that we're using here.  And we're talking about.  So here you have the header around the site.  There is a logo that is always linked to your site route.  You have a automatically built navigation  that is created from the content that is in the site.  You already have some content, which is weird,  because you didn't create that.  Plon did that for you.  It's auto-generated content that is created when installing  Plon.  And I'm going to delete that.  And you should do the same.  Just select everything.  OK, that was probably a bit too quick.  Let's step back.  So this is the navigation.  Here's a site search.  You can say, I don't know, test.  Should be findable, because I created that.  You have a content area, which is here's a header.  Here is a content area where you can just write stuff,  save it, and it's visible.  This is what you're editing when you edit stuff.  And there is a footer that has some links that can obviously  also be configured by you.  And there is a toolbar to the left side,  which has the link that I just used to show you  how to delete everything.  That's a very important link.  It's the link to contents.  If you hover over these icons, they explain to you  what they're doing.  You can add various content types.  You have more where you can change the workflow,  change the view, inspect the history, and stuff like that.  We're getting through that.  Most important one is add, edit, and contents.  We're going to use contents quickly to navigate to a page  where you can manage content in bulk.  There are breadcrumbs that you can use to navigate  to the side route.  I can select everything.  And I'm just going to delete everything.  Just kill it with fire.  So now my blog site should be empty.  Should only have this description here.  If I do a hard read, that's caching in both.  Obviously, I did a hard reloads there.  So I got everything in the navigation.  Just died and went away.  So we covered the footer, the toolbar,  edit, folder, contents, and add.  We're going to ignore these for now.  Yeah, very important.  You also have your portrait here.  You can log in and log out.  There should be your photograph.  You can modify your profile.  And you have a link to the site setup  where you can configure the site.  So why am I not seeing this?  And why does it say admin and not Philip Bauer?  That's because we haven't created a user yet.  And that's actually something you should do  as a very, very first step.  And we're doing that now.  Well, you're doing that now if you're following along.  So click on the picture here.  So OK, I skipped over that.  When you open your browser, your site in your browser,  you have to log in for the first time.  And the password is admin.  And the user name is also admin.  And please never use that in production.  That would be pretty stupid.  This is just for development.  You can use admin or test one, two, three, or whatever you fancy.  But if you ever host a site on the internet,  that will certainly not be OK.  So click on the portrait.  Click on site setup.  And here you have all these links to various control panels.  And click on users and then create a new user.  So how do you do that?  Here is a small icon to the left where you can add a user  and then pick your name.  I'll use Pbauer.  I'll use mine.  You use yours.  Bauer.de.  Password.  I always use tester for these trainings  because it's five letters.  It's lowercase.  It's small.  And give yourself the role of, no, you can't.  You can give yourself any role, but not here.  Manager.  Yeah.  Add yourself to the group of managers or to the, oh, OK.  Complex.  Add yourself to the group of administrators.  Then you're an admin.  And that's how I'll get to that.  How complex systems should be set up.  You have groups.  Members go in groups and groups have roles.  So every system does it that way.  So this shouldn't be new to you.  Everyone does it like that.  So now I created this user.  I should probably save.  No, I already have saved.  So he should be there.  Yes, he's there.  And now I can log out, hopefully, here.  Log out and log in again as Pbauer tester.  Log in failed.  Super.  Why?  Let's see.  Maybe the default is the email address already?  No.  Did I do a typo?  Crap.  I seem to have made a typo somewhere.  What's wrong?  Does anyone know what I did wrong?  I can always.  Your press don't cancel.  What did I cancel?  Oh, you think I pressed cancel?  Because I got my user here.  He should be OK.  I can delete that.  I can delete me again.  I'll just do that and create me again.  OK, username Pbauer.  BauerHTWD tester.  OK.  Test groups.  Administrators.  OK.  Let's see if it works now.  User created.  Good idea is to have two browsers where  you can log in as different users to try this stuff out  and not having to log in and out all the time.  Yay.  I obviously made a typo when I entered my password  for the first time and we grabbed that typo.  And so I had no idea what my password was in the first place.  So now I can actually, I can really log out and log in  as Pbauer.  Yes, here I am.  So now it actually tells me my name.  I can edit my profile and add a picture here.  I'm not going to do that.  You're going to see enough of me.  So here I am.  I'm an administrator and I'm a real-clone user.  Excellent.  I did my first job.  So next up.  We're not going to configure a mail server,  but for production purposes, you should do that.  Because we have an add-on called products printing mail  host.  We're not going to send any emails during this training,  hopefully, unless you disable this add-on.  But you should, hang on.  Why am I not seeing site setup and only my preferences?  Because I don't seem to be an admin.  I can't even add content.  So yeah, so the thing is, I'm not sure if that's to blame,  probably not.  Probably I'm to blame because I couldn't  press Enter properly.  This training uses clone 600 alpha 1.  And that was released yesterday afternoon,  I don't know, around 4 o'clock.  I saw that and I updated the training build out this morning  to actually use this version.  So it's brand new and may still have issues.  Maybe not.  Maybe it does.  So maybe that's to blame.  Maybe it's me, probably me, because this alpha is pretty good.  So I'll need to go to site setup again and go to groups  and add myself to the group of administrators.  Admin?  Yeah, how do you do that?  I'm not going to delete that group.  Go away here.  OK.  This changed in, why can't I add a user to a group?  Katja, can you tell me if that is something I missed?  OK, I'll just make me a manager and save.  But it should be in the user interface  should allow you to click the group and edit the group.  Maybe there, but there's only delete and not edit.  So add users to a group should be possible.  I'll show you that.  The point is, if something is not working,  you're not crap, let's use another system.  You can't keep this system, even though it's alpha 1,  because all of this is also available in the back end.  And you have a list of users and groups and the same user  we just created is here.  And here's actually the link that I was looking for.  You just click on that.  And then you can say group memberships.  And I want to, yeah, I'm not, I'm only in authenticated users,  but I wasn't added to probably I didn't press save at some point.  So now I'm the group administrators, which is fine.  And I can, I'm a manager because I'm in that group.  So I'm inheriting that role.  I'm actually, yeah.  So now I should be here when I reload.  So this is a very important moment where  you learn about the power of these roles.  I was a second ago, I was just logged in as Pbauer.  As a user, I had no permissions to do whatsoever.  And someone changed my permissions and I reload the page.  And suddenly I get all these icons.  So now I'm a manager and I have the power  to modify, change, and create content, add users, and whatnot.  So that is important.  But what I actually wanted to do is go to the control panel  and get rid of the annoying error message  that you get at some point when you're not adding,  oh, there's actually a default set now.  Oh, that didn't used to be the case.  That's fine.  So we have a default mail server that obviously doesn't exist  because I don't have a mail server running on my laptop.  But that's fine.  OK, let's create some site structure  because that's like the first task at hand.  There's a plon conference.  People need to learn about the content of that conference, talks,  whatever training stuff.  Without programming, we just use plon to create some content.  I will create a couple of folders here.  So yeah, actually it says some of these need to be a page.  Some of these should be a folder.  So let's just change that text here.  Yeah, it doesn't really matter what I add here.  Let's can add some.  You see while we're doing that, you  see a interesting new editor.  If you ever use plon 5 or 4, the editor looked much different.  We're going to go into much more detail there.  But we'll slowly, slowly approach that.  So let's just create some page called training.  OK, page training.  And I'll just add some Latin nonsense.  A folder called schedule.  Folder called schedule.  And you see it's a different user interface.  How come?  That is weird.  You can think about that while I'm continuing to do that.  I'm not make sure that you're not adding,  because once I added the folder schedule or the page training,  I was in training and in schedule.  And if I create new content, it'll end up in there.  But we want that in the site route.  So click on the plon logo before you create the next item.  This is the location.  Page about sponsors.  Oops, page.  Come on, see.  Page about sponsors.  Again, different user interface from folders.  Page for sprints.  Sprint and a page contact.  Don't worry if you're not creating all of these.  We're not using all of these.  For the whole story, it would be a useful setup  if we do a one week training, which we're not going to do.  So this is how it should look like from your end.  And then once we did that in, oh, actually,  we should have kept a news folder.  I shouldn't.  That is stupid.  I removed that.  Why is it as it doesn't say news here, but in news.  Katya, can you make a note that we update this part somehow?  Yeah.  I'll create a folder called news, where  we add a news item called conference website online.  That's like the first thing we created.  So the order is weird.  So let's change the order here.  So again, we go to contents.  And we can just grab one of these items  and move that to the top.  News are the most important things.  So they should be the beginning.  And here they are automatically at the beginning.  And I'm going to create a news item, obviously.  The title is this.  Let's add some nonsense text here.  And actually add an image.  And a summary will be good.  So you see the user interface is different from pages,  because you can keep that in mind already.  The editor for all types, except for pages,  is schema-based and only schema-based.  And the pages use a block editor, block-based editor.  It also has a schema, but it's small.  So this, by the way, it looks like not much,  but this is a rich text editor here, this small field here.  And you can add all kinds of stuff here.  You can add headings and subheadings.  Let's say this is the subheading here.  Here is a heading, or subheading maybe.  This is going to be italics or whatever.  And this is a link to something.  Where my links, here is a link.  So I can select a link to something in the site,  for example, to location.  And done.  And when I save, this gets rendered, and here's my link.  So this works as expected.  OK, I created a news item.  Then I'll add another news item just to annoy you.  New item, submit your talks, more Latin nonsense.  OK, let's add an image, because it's nice to add images.  Another image.  And so we have two news items.  And now let's switch to a different browser and logout.  You don't have to do that.  I'll do that.  How do I logout?  Am I logged out?  No idea.  I am logged out.  Good.  So I'm logged out.  Where's my content?  None of the content is actually visible,  because we only created the content.  We haven't published the content.  So Plone is a super secure system in such a way  that when you add content and you don't publish it,  there is no way, no way, that this content will  be visible to users on that visit your website.  And that is not because it's not hidden away.  And if you know the URL, you will find it, for example.  If you copy this here and you enter the, it tells you, no.  This is not for you.  And Plone has a very, very strong security record.  And it's built in on object level.  Each object has a couple of attributes  that store, that define which roles you have to have  to be able to see this item.  And whenever something is traversed to,  Plone checks for these roles.  And you don't have to do that.  This is, Plone does that for you.  That is one of the reasons why CIA and FBI  are using Plone for their websites.  I'm not sure if that's a positive recommendation or not.  But I guess they're kind of security sensitive  these organizations.  So yeah, also we should have a folder called events,  which we don't have yet.  I'll create that.  So you see a lot of additional stuff  that you can add there.  And in there, I'll add an event.  And you learn about another content type.  What's the event deadline for talk submission?  I know the dates are going wildly around like 2035, 2550.  Who cares?  So here you can add start and end date for an event.  Let's say this is on Monday.  Because I used English as a language,  the calendar seems to think that the beginning of the week  is on Sunday, which I think is weird.  But that's America for you.  10 in the morning, 2 in the afternoon, that seems fine.  There's also a whole day and open end.  And we'll figure out why that is there.  Also, still I haven't finished talking  about the publishing on content.  If I reload this, none of this is still public.  I will need to publish that, click on the three dots,  and switch it from private to public.  You can also switch it to review,  which is like a pending state where something is not  visible to the public.  But if you have a more complex setup  where you have more users with more different roles,  you can easily show you the groups again.  You see administrators, reviewers, reviewers.  That's the ones that you want in this case,  because you have a couple of people in your organization  that are gatekeepers for content before it's published.  That's what this role is for.  So this item is now public.  The folder is now also public.  And once I reload this site, I see events, but nothing else.  And I can go, I said there is a feature for bulk editing.  I go to contents, I select everything,  and I change the state, which is the lights.  And I change it to publish and to everything that's in there.  And voila, my whole website is public,  even my super secure intranet that I didn't  want to have published.  So make sure you're actually only publishing the content  that you want published, because otherwise you  may have problems.  So here, my news items are public.  I'm an anonymous user, and I can see everything.  I can't edit anything.  I can't even pretend I can edit.  If I click edit, this doesn't work.  I get an unauthorized exception.  OK.  The default content types already did that,  but I'll show you the beauty of the editor again a little.  So in the front page, we have a page type.  Actually, it's not a page type, but it's page type-ish.  It doesn't matter where we have this blocks editor.  And when you press Enter here, you can add a new block.  And this is a beautiful and super powerful way  to create beautiful and very different layouts and sites.  You have these, by default, a text block  is created that you can just type to.  And it's a rich text editor again,  where you can have all kinds of different styles, call out,  whatever type headings.  You can add lists and stuff like that.  But there are more than these types.  There are image blocks where you can add an image.  Let's upload an image.  And it should be, is there something in the story?  What kind of image I should upload here?  Probably a Plome logo or something like that.  Let's add a Plome logo.  It's uploading the image in the background.  And you can configure each block on the right side.  There is a toolbar to the right.  You can tell this block, OK, this should be small to the right.  This should be hero sized to the left or full width.  I'll make that small.  You can add a link to that image.  And then you can save the page.  And voila, yes, there's your image.  And anonymous users also sees that instantly.  OK, what else do we, yeah, let's add a table like thingy here.  Here is a table.  Let's see.  Stuff, whatever.  There's a nice way to have content in tables.  And there are very powerful blocks that contain dynamic content.  In this case, I added a, what did it say?  Listing, a listing block.  And the listing block is it displays the results of a search  that you define.  So for example, here you say, add criteria.  I add all news items, for example, matches any type is news item.  And it automatically shows me while I click there,  I already see the news items that I want displayed there.  I can change the variation where I actually have an image gallery  or a summary view where I have these little pictures.  And I can also add a list of the items that I want to display.  I have these little pictures.  I can change the sorting.  I'll do that by publishing date, which is called effective,  yeah, effective date, reverse order.  So the newest one is on top, limited to five.  So we don't get spammed.  And I save that.  And I have a semi beautiful front page with dynamic content in here.  So this is the page content type, which has this powerful editor  that is probably all you need to create beautiful content.  But it also has the schema that I mentioned when I sent the schema  based content and the fields that you saw when we added a folder.  You can expand that and you have all these fields  that are defined in the schema available.  So you can tag content, for example, from page, whatever it is.  It's now tagged as that.  You can set the language.  If you have multiple languages in your site,  you can add a link to something else as a related item.  You set a publishing date and an expiration date and stuff  like that and copyright information, allow discussion,  and whatnot.  A word of warning about publishing date,  this is not workflow.  So if you set the publishing date in the future,  this doesn't hide.  It hides your content, but it only hides you like this.  Everybody knows you're there, but actually you think you're not,  unless you're a cat.  But so if the URL is, if you know the URL, you can access that.  It's just not showing up in the navigation.  OK, so that is the page.  A folder is obviously a folder, but only displays a title  and a description and can have different types of listings  for the content inside that.  So for example, the News folder has a view called Listing View.  At the moment, I can change that to Summary View or Tabular View  or whatever.  There's a couple of views that you can see,  but it doesn't have a rich text editor.  You can't add rich text here.  That's a folder.  It is created to create structures.  File, obviously, is for binary data.  Image, obviously, is for images.  Event, you already saw that.  A link is also a content type that  can link to either internal or external content.  So you can add a URL here.  Or you can select an item from the site that you link to.  So it's a very powerful feature.  And only if you are allowed to edit that link,  you get redirect.  You see the link when you click on it.  You go to the link, and it points to this and there.  But if you're not an editor, you actually automatically  get forwarded to whatever the target destination of that link  is.  So that's a super powerful thing to create ad hoc links  to locations that are actually somewhere different  than where you are.  A news item, you already saw that.  That's basically like a document, like a page,  just with an image and a different editor.  It doesn't have the blocks editor.  A collection is, we're not going to go into that.  It's like the listing block, but as a content type.  So there's a content type that does exactly, exactly  the same thing as a listing block.  And if you're asking, why do we have that?  That's because listing blocks don't exist in classic clone.  In classic clone, when you go here,  this is the same database.  You see all the content that was just created by me here,  deadline for talk submission with date and time  and the news items, including the images.  So it's all the same.  This doesn't have the blocks editor.  So it doesn't have a listing block.  And a lot of sites are using, still need to display  dynamic listings of content.  That's where collections come in.  For clone six with the React front end,  you probably don't use them.  OK, we'll skip.  You should read that content rules are so powerful,  but we'll skip that because it's way too,  we have way too little time for that.  Also, working copies are super cool.  Placeful workflows are great.  You can create a folder and say, this folder is called internet.  And it has a different default workflow  than the rest of the site.  And this default workflow that you're configuring there  doesn't have a published state.  So it only has, I don't know, private and internal.  And so you only see this content when you're  logged in user.  So it's a perfect internet.  So we have a lot of clients who have a website with clone  and have an internet.  And it's the same website, but it's  a folder that has a placeful workflow where you are not  able to see any of the content that is in there.  So that's a powerful feature and a lot of other powerful features.  If you don't know them, read up on that.  We'll just keep on going.  It is already 10 past four.  I'd say when shall we make the first break?  I think tomorrow maybe.  Let's keep on going a little more, like 20 more minutes.  If you don't have the attention span,  just get some coffee and catch up what you missed on YouTube.  Or yell at us in the chat.  I see Sean had a question here.  Kadi, can you look at that?  And if it's important, we can discuss that in there.  I have a look.  Excellent.  So yeah, we could probably skip all that,  but it's not super unimportant.  So if you're new to Plone, this is important.  Plone has been around for 20 years.  Yes, it's been the 20th birthday of Plone.  Two or three weeks ago was the day.  And like 20 years ago, there was no React or JavaScript  framework.  So it is obviously, it started as a back end system, this one.  And it didn't start from scratch.  It started as a user interface for a system called Zope.  And Zope actually also started as something before, Bobo.  That's what it was called.  And it actually had another third name, whatever.  So it's Plone, it sits on top of Zope,  which is written in Python.  So at the lowest level, there's Python, the programming  language.  On top of that, it's Zope.  It's like an application server.  If you know Java, Tomcat, comes to mind, for example.  Then on top of Zope, there is CMF,  is Content Management Framework.  So it's a framework to build content management systems.  So if you know some computer science theory,  it's like a factory factory.  And then the whole thing on top of CMF, the Content Management  Framework, sits Plone, which inherits,  like it's multi inheritance from CMF and from Zope,  and a lot of objects on top of that.  It uses a database called CMF, called the ZODB, Zope Object  Database.  And it's not a relational database.  It stores Python objects natively in the database.  They're serialized as pickles.  If you have never heard of pickles,  it's in the standard library.  It's a way to serialize instantiated Python objects  as stringish types.  It's not meant for human consumption.  You don't read that as a human.  But it works great in the ZODB because you  don't ever have to think about your database.  You don't have to model or manage your database.  Obviously, you need to back it up.  But you don't have to write a schema for the object relation  manager, the ORM.  So we store the objects directly without an ORM.  And there is no scene between the code and the database.  This is an example how you actually store something.  You inherit from persistent.  Not going to go into that.  And it's super powerful.  It used no SQL when that name was not even invented.  It can use multiple clients that talk to the database.  And that's called ZEO.  It can replicate using a system called ZRS.  Or, alternatively, you can use Rails Storage  to store these pickles, not in the ZODB,  but in a relational database.  Again, in Postgres or MySQL or MariaDB,  you're not going to have tables with my title,  here's my description, here's my relation to whatever.  But you're going to have a Python pickle in there.  So this is, again, not good to read for you.  But it is Rails Storage.  So you can give it to your database admin  to say, OK, you guys take care of replication  because I don't want to be bothered with ZRS, for example.  So that's powerful.  And binary data, obviously, is not stored in the database.  These UDB as strings, but stored as files in the file system.  It's called Blob Storage.  And that happens automatically.  Here, I'm not going to go into ZOP and CMF.  There's a lot of history in here and nothing about Pyramid.  There's a lot of to be done.  The important thing here and now is that Plone has,  for a couple of versions, now has a REST API  and uses the REST API to decouple the back end  and the database and the logic and the content  from the front end that is called Volto.  We should probably write something in there.  Not going to go into the history of Plone.  If you want to discuss that, there  is plenty of time during the conference.  This is Plone 6.  You'll see it while we talk about that.  And it only runs on Python 3, obviously.  So Python 2 is dead, dead, dead.  But you can migrate to Python 3 if you have a Python 2 database.  There are talks about that.  One is actually by me, I think, on Wednesday.  Katja, I think that's one of your chapters, isn't it?  Yeah.  Excellent.  So I'll stop my screen sharing and mute.  Hi again.  So Plone 6, what is Plone 6?  What is new, which changes came with this version?  Philip already mentioned the very important points.  So what leads to me is, if you know Plone 5 already,  I think most of you do.  Why is there an inversion?  What's new?  For me, my personal opinion is that two important goals  to review, to rework the whole thing  is to achieve a new editing experience.  The editing experience means how does an editor compose a page?  There were several add-ons in Plone before.  And the meaning was this could be easier.  There are new techniques available.  And we want to use it also in Plone.  So yeah, as I said, to make the life of an editor a little bit  easier.  And Plone 6 itself with the Volto front end,  as you've seen with Philip's presentation,  comes with an editor, not an editor,  a way to edit pages that use blocks where you can break  your text in blocks and rearrange.  This is part of default front end of Plone 6.  But there are also already add-ons,  which help you do even more to compose a page with columns  and so on.  And beside the editing experience that I think  is really improved is that the development of a theme  is much easier.  Volto or Plone 6, as we say now, comes with several helpers  to customize the default theme.  It's possible to customize single isolated components.  And it's also a lot easier to customize default components  by the so-called component shadowing, which we will see  in the next chapters.  And yeah, I think these are two points that  are important for Plone 6.  About the details, I will skip the long list of cool things  that comes with Plone 6.  But maybe one important point you have,  as you've seen already, two parts back end front end.  And these two do communicate via the REST API.  There are default endpoints, REST API endpoints,  which we can use when we develop with Volto or the Plone 6  front end.  For example, if we want to fetch data,  we use the search endpoint.  And we can also create add-ons with custom endpoints.  If this is necessary to communicate in a special way  with back end.  So yeah, there are a lot of helpers  to make the life of a developer easier.  Two more component shadowing I already mentioned.  The other one, which I want to mention and talk about in the  after the next chapter is semantic UI.  This is also a cool helper for making the code a little bit  to enhance the readability of the code.  Because semantic UI or the corresponding read package  semantic UI read comes with helper components  for small things you don't want to write again and again,  like buttons, drop down menus, and so on.  But we will see this in one of the next chapters, not in detail,  but a short overview.  What you can find there and where  to look for these helpers to avoid writing a simple code  again and again.  And to concentrate on the important things of your add-ons,  of your apps in Plone 6.  And one more thing in this chapter I would like to mention  is the question if you want or if you need to switch to Plone 6  or if you can stay with Plone 5 or even stay with Plone 4.  And I think it's recommended to use the new front end.  And the question if switching with an existing project,  I think it depends if there are add-ons that can help you  to realize what you want to achieve  or if it's possible to implement that what's missing.  And for me, it's important to realize  that you can use existing Plone add-ons, back end add-ons,  as long as they are doing business logic,  as long as they do not touch the UI.  So they are still valuable and they are there.  And there's a huge ecosystem of Plone add-ons  and the corresponding side, the ecosystem of Volto or Plone 6  add-ons is growing constantly.  So yeah, I think it's worth thinking about.  Thank you.  Philip, do you want to continue with customizing Volto components?  Sure.  Good.  So actually, before we customize Volto components,  we'll quickly configure and customize  in Plone through the web.  We're not going to go into a lot of detail here.  You should just click and see what's there  or read the documentation that is here.  And I will show you a couple of the most important things  that there are.  So when you go to the side route, sorry for that,  you have this link to the site setup  and you have the control panel.  And they can configure, obviously, the date and time.  And also, yeah, the first weekday.  Excellent.  I like Mondays.  Actually, I don't.  But for the first day of the week, Mondays  is my favorite choice.  I can configure languages.  You can have multiple languages.  We're not going to go into detail there.  You set your mail server and user.  You configure the navigation, which items  should be shown up in the navigation, which should not  show up.  And so on.  I can configure the search, what items should not show up  in the search.  And so on.  Here's the most important one, sites,  where you say what's the title of your site.  For example, site title is Plone Conference 2035.  In this case, I can add a site logo.  You can't upload that here.  That is only for Plone Classic.  You see, this is a base64 encoded string.  I already uploaded that something in Plone Classic.  You'll see it soon.  You can configure lots and lots of things here,  including a JavaScript snippet for statistics and stuff  like that.  Save that.  Go back.  Then there is social media.  The URL of the Volto site.  That should be configured.  That's something for hosting.  You can install and uninstall add-ons.  We'll do that pretty soon.  You can actually inspect the database  and see how many items there are in your database.  And where it lives, you see it lives in back end bar,  file search, datafs.  That's your ZODB database.  That's where it is.  And there's a lot of other things.  I'm not going to go into detail because we're  going to see some of these later.  And most of them are discussed here,  especially the ones that are not there.  And that's what's important here.  So this is the control panel in Volto.  And here is your control panel in Classic Plone.  I just uploaded a logo.  And you see that here, Mastering Plone.  And here, it doesn't say Mastering Plone.  Because it uses a different rendering.  It is different there.  And that's in the next chapter, we're going to customize  the logo that shows up here.  Here, you have the same control panels plus some more.  Because some don't make any, it doesn't make sense  to have them in Volto.  And maybe there may be even others that are not yet  implemented in Volto.  I think everything that's important is already there.  But for example, the theming control panel for Plone Classic  doesn't make any sense in Volto.  Because we're not going to use, it's  a completely different theming setup.  It doesn't make sense to use a diazo theme,  if you know what I mean, in Volto.  So this doesn't exist in Volto.  Because it wouldn't make sense.  And also in Plone, you have access  to the ZOP user interface, called ZOP Management Interface,  ZMI, for short.  And there are even more in-depth things  that you can use, mostly as an admin or a developer.  So you will certainly spend time there.  And we will go there today at a later stage, for example,  to inspect the portal catalog, which  is the search engine that is built into Plone.  And we can see representation of all the content that I already  created and how it can be found in using the search.  You see the search bar here.  This uses this catalog.  And it has a couple of indexes that we can use.  And you can create new ones.  There's a lot of complexity and a lot of power there.  We're not going to use much of that.  We're going to skip ahead.  And I suggest, since we already spent 1 and 1 half hours  to make a five-minute break, or let's say seven minutes,  to actually be able to visit the restroom and get some coffee,  before we customize the first Volta component, where  we're going to change the logo.  And a couple of the views or the display ways,  items are displayed.  And there we're actually going to use the editor  into some real development.  There we're jumping in.  But before that, you can steal yourself  with your poison of choice.  I'll get some coffee.  And we will meet you in, let's say, seven minutes.  OK.  If you have questions so far, please put them in Slack.  And we'll find time to answer that before the next slot.  I'll mute myself in the recorded video.  This break will be just mentioned as break.  And you can skip to the next part,  because we'll probably be too lazy to edit the whole breaks  out of the video.  Doesn't really hurt.  Yep.  I think we should continue.  So no tough questions in the Slack.  Let's continue.  So next, we're customizing some things that we're seeing in the browser  for our users.  So this is a front end chapter in the documentation  of the training.  You see these sidebars here at the beginning of a chapter.  Let's specify if a chapter is dealing with the front end  or the back end.  And if you're dealing with the front end,  obviously you need to go to the folder front end  and make changes here.  And if you're dealing with the back end,  you need to go to the folder back end.  And if you want to follow that training,  you can use the link here.  You can use the link here to find out how you can check out  the code from a certain chapter and use that chapter  to start the beginning or at the end of this chapter.  See what's the result of what should be the result of that.  To customize a visual representation of what you're seeing  in Plone, in Volto, we use a technology called,  let me hide, it's a bit ugly, I'd say.  So, yeah, I would love to hide some things,  but I'm not going to go there.  We're using a technology that allows us to override existing  items.  And you'll see that pattern over and over again,  that we're not forking Plone or download Plone to your hard disk  and change everything, whatever you want.  I heard that is what you were supposed to do with some other  systems at least.  A couple of years ago that don't have a system where you can  override features in React, that's called component shadowing.  And it allows you to create a copy of an item that you want to  modify in a certain container, in a certain folder,  and it will be automatically found in a certain folder.  And it will automatically found on startup,  and it will replace the component, the file,  that you want to, that you're overriding with.  So that is pretty, pretty nifty, and it's basically the same as  what you do, did in classic Plone, using an add-on called J-Bot,  just a bunch of templates, where you just add a copy of a file  into a certain folder, following a certain pattern,  and on startup it's discovered and it replaces the original file  that is shipped with Plone.  There is also, I should mention that in this sidebar,  there's a link to solve the same requirement in classic Plone.  So if you follow that link, you'll see a broken navigation,  because this item is not part of the navigation,  but you will do the same tasks, or similar tasks,  in classic Plone, in this case, the logo is already done  in the early, early chapters, so we don't need to do that  in Plone Classic, but here we're modifying the new item template,  and the listing template, it's all discussed here,  how that works in classic Plone, and it says classic UI,  but we are going all in with Volto,  so we're using this component shadowing technology  to modify the logo in this, as a first step.  You can download the logo here, it's on our website,  it's just a SVG file, it's not very exciting,  it just says mastering Plone in some crazy font.  So what you need to do is you need to fire up  the editor of your choice, I use VS Code,  and I will actually use two instances of VS Code,  so I already have one terminal here, one for the back end,  one for the front end, and I'm going to fire up a new one,  a third one, where I go into training Plone 6,  that's where I have that front end, and I say code.  Which starts up VS Code for me,  and it opens the front end folder for me here.  So I have two different editors that I can switch back and forth from.  That is just to, I don't know, make it easier for me.  You already have, upon installation for the training,  you already got this whole site setup,  and we're going to follow the documentation here  to add stuff into our front end setup.  The front end setup that we have here does not contain Volto.  We didn't download Volto and started Volto,  we actually created a package that depends on Volto.  So in this case, as there is Volto installed,  but not in SRC, SRC is a bunch of empty folders,  so there is nothing here.  And in your package, Jason, this package that you created  depends on Volto, that's here, dependencies,  Plone Volto, version 14.0.0, alpha 23.  So that's the newest alpha of Volto, I think, that we're using here.  And by building that using Yarn install,  Volto got installed, and there's a couple of nifty things  in this package that makes sure that Volto is actually available  in a folder called omelet, and in there, omelet, SRC,  I don't know, let's say actions or components,  more importantly, theme, breadcrumbs.  Here, this is Volto, this is the real Volto,  you shouldn't change that because that is the equivalent  of checking our Volto and changing it on your directly.  We want to override that, so we're not changing Volto  in the omelet directory, we're extending it and overriding it  in our SRC folder, this is our package, this is our thing,  it's called Plone Conf minus Volto, I think that's the name  of the source checkout that we're using here.  So we're using, we're going into the front-end folder  and using this path and name to download the logo,  to add the logo SVG, SRC, customizations, components,  theme, logo, okay, I'll copy that, I already have a SRC folder,  customizations, components, and that's empty,  so I need theme and logo as a path,  and I can add that like this, which is nice,  components, theme, logo, and inside logo,  I'll just open that in Finder, here is my folder,  so if I go up, you see the structure, customizations,  components, theme, logo, and inside logo,  I'll just dump the SVG that I just downloaded,  so it's here, and I should see it here,  VSCode doesn't have a preview for SVG,  so I could edit it if I wanted, I'm not going to do that,  obviously, and now I need to restart Volto,  is anything unclear about that, I guess not,  we could just stop Volto using ctrl-c and yarn start,  which will take a while, but while that happens,  I can discuss, what should I discuss,  there's nothing to discuss actually,  so it's important to, you need to really restart  your front-end instance, the process that is running  the front-end, when you add something in a customization,  when you modify at existing code,  you don't have to do that, the development mode  of the JavaScript application makes sure  that it's automatically recompiled,  and your browser is actually automatically updated,  it shows the right stuff, but if you add a file,  you actually need to restart that,  and it takes a while to compile, and now it's done,  and once I reload, I should actually,  I already see it there, it says master in code,  so master in code, so yay, for us,  that is something we already did,  so now you made a change, so you guys are professional  developers, or actually you want to be,  so if you go into the front-end folder,  so you have this training code 6,  you go into front-end, and you say,  git status, and it tells you,  hey, there is a new folder, a new thingy here,  and you can see that you could commit,  that is what you should do now,  you shouldn't do that during this training,  because it's already, everything is already there,  but you should now make a commit,  and say, okay, just add logo, and there you are,  and that's, so that change is in your git history,  okay, this was the logo, there was the easy part,  now let's go to the footer, why are we not dealing  with the footer, so there's no,  we're not changing the footer, obviously,  maybe the heading should go away,  let's change the news item view,  so why do you want to change the news item view,  that's something that's been bothering me  forever and ever and ever,  so you visit the website,  and you go to the press release, or news section,  and you click on the news section,  and news item, and you see it,  and say, yeah, that's really nice and exciting,  you have a new board member, or you have a new release,  but what's missing?  When was that, was that like 2015,  and your site is super out of date,  or is that super recent, was that a new release  that was just made yesterday,  so what's missing by default,  which is, I still don't know why that is,  it's probably so we don't have to change this training,  and keep, can keep editing news items  in Plon Classic and Plon, and in Volto,  so we can display the date here,  so what we want to have here is the date  that this new item was actually published,  let's do this, so first we need to find out  where the actual news item is rendered,  so the news item is, yeah,  that's a bit tricky, I'm not going to go into there,  that how to find that,  but I'll just take my word for it,  it is in Omlet, where Volto exists,  source, components, theme, view, news item view,  it's a same folder structure,  and if you, it would be probably,  since you know what the content type is called,  you could just search for news item,  hang on, why doesn't it find anything,  news, that is weird,  news item, files to include, files to exclude,  why is my search not in all files,  I seem to have misconfigured my search somehow,  but I'll find it by hand,  it is in SRC, components, theme, view,  and here are all my content types, news item views,  so here's my component, it's a React component,  and I want to customize that,  so how do I do that,  I copy the whole file into a different folder,  so this is the file,  we can look at that actually a little bit,  and you can see your first glance at Volto view in React,  so it has some, a couple of imports,  and it uses the object that you're looking at,  so the news item, which is like this here,  the whole, the thing that you can edit,  the thing that lives in the content tree under this,  in this branch, and this leaf on this branch probably,  this is the content in this case,  and it's passed to the news item view,  and this creates some HTML basically,  using the, yeah, that's JSX for you,  I'm not going to go into detail how that all works,  but it's basically, one example here,  if there is a content title,  so if the object has an attribute title,  then render the h1 tag, class name,  you see this is not HTML, like per se, this is React,  so you can't use class because in JavaScript,  that is a reserved statement,  it needs to be class name,  and pass, use document first heading as class name,  and replace the content of that with content title,  and then content subtitle, and whatever,  there is more stuff in there,  and then there's the description,  and then there's the image, you see the image here,  that is using the image,  that is not a HTML tag called image,  because you remember HTML, it's called IMG,  the image is a component from semantic UI that is used here  to render the image,  and you pass some arguments here, the title,  and the SRC, which is automatically created,  it creates a URL for that image,  and float it equals write,  is also not a classical HTML tag,  it is a argument for the image component that is used here,  so this is how the view looks like,  and it exports as the news item view,  and has these prop types that you probably know  when you're doing react development,  if you're just overriding stuff,  this is something you do not yet need to know,  you just need to be able to understand the basic logic of that,  saying that if the content has an argument,  has an attribute called text,  then render that text attribute as dangerously set in our HTML,  that's a monomer of most favorite words here,  so this is a react built-in thingy, obviously,  and that renders then the content text data,  which is the real HTML that is returned from the rest API.  So here we have the view,  now we want to modify that,  so we copy this, the whole thing, into a,  yeah, oh, there's, you should probably read that,  because that's really interesting,  because we should look at that just quickly.  I hope I have my developer tools enabled,  so why doesn't it, oh, God,  I don't have my developer tools enabled,  Katja, I guess you will have to do that in your later chapter,  I seem to have disabled my React developer toolbar,  doesn't really matter,  we can redo inspecting an item in a later chapter,  but it read that and it's important  and it helps you to figure out where that component actually lives  and how it works.  So copy this file into customizations, components, theme view,  so customizations, components, theme view,  do we have that already, let's see,  so in our, not in omlet, please,  so close that, customizations, components,  and then in components we need more,  we need a folder called theme view,  let's here now, so here is theme and view  and then there we need the news item  and I'll just copy,  can I copy the whole file, probably can,  if I find it here, where's my news item view,  here copy,  and I paste it in this folder, paste,  here I have it, so again, I need to restart,  I'll do that,  and I don't get a message that, hey,  I found a new customization,  you'll just need to see that this happens,  and now very important happens to me like every two weeks,  don't modify the original,  because now you have both items open, modify your copy,  yes, it's confusing when you have an editor in the same file  open twice, make, if you're uncertain,  make sure that it starts with SRC customizations,  then you're in the right place.  And how do you find out that this is actually the one  that is then rendered,  once sort of is finished, it just takes a little while,  so obviously just add some nonsense to it,  and that is visible in the site.  So let's see, let's just add a h1 saying hello world.  So once I reload, I hope I didn't get an error,  still starting up.  It has interesting messages, which I will just ignore.  And here we already see it, hello world.  Yes, I actually already customized that.  If I wouldn't make these stupid change like this,  it would look exactly like the original,  so without hello world.  And you see, I just saved and upon saving,  this is the message that I get, it does a reload.  It reloads the site, the code.  So, okay, good.  So what was the task we should add a date.  We could just type a date there, but that's stupid,  we're not gonna do that.  So the content I already said that is the item  that we're looking at, the news item, submit your talks,  and the news item, this item has,  okay, I should really enable this feature  because this is really important now,  where is my React?  Oh, I could just use Chrome for that.  No, I'll just, developer toolbar, I think that's what it,  oh, can't type.  This is not it.  Come on, React developer tools here, this one.  You need this, you need this, no questions asked,  you just need that.  This is super important when you're developing  for Volto or any kind of React stuff.  And it's already there, here's my developer toolbar,  it says, hey, it's development build,  and now I can inspect my components, not the HTML,  but actually the React components.  I can inspect them, and I can inspect lots of things.  I'm not gonna go into too much of the components,  I'm not gonna go into too much detail,  but this is like the code.  Here is my news item view,  and inside this news item view,  when I at some point I find it, it's pretty complex tree,  but here's the news item view component,  and it has a content object, and this is this.  This is the news item view,  and it has a content attribute property,  it's a prop actually,  prop in these properties.  Now, in content, in the property content,  there is a lot of stuff,  and we will figure out what we're gonna need from that,  and I already found it.  So for example, a lot of stuff is used here already,  so type is the news item,  there somewhere is probably the title,  title here, submit your talks.  Here's the text, which is a object itself,  and has data, you remember I said this is data,  that is rendered down here, content text data.  So this item doesn't have any text, let's add some text,  so it'll actually show up,  and make that a bit more interesting,  at least adding one HTML tag,  and now where's my view component?  I lost my component.  Hang on, news item, you can search, which is super useful.  So here's my news item view, it has content,  and here now the text should be more,  so we have data actually holds the HTML,  that is passed from the backend via the REST API  to the React application that's running here.  So what do we need from that?  We don't need the text, because when I have that,  we want effective in this case.  This is a date, and it's automatically the date  that is used by Plone, no, created,  we use created, it's the creation date.  There are a couple of different dates, obviously,  there's like the date you were born,  there's the date you got your driver's license,  and the permission to drink alcohol,  and these are different dates,  and depending on for content,  it's also, if you write a news item,  but you only publish it two weeks later,  you need to talk to your client,  what should be visible there,  because every client has a different idea  of what should be visible there,  and what should be visible  if the item is not yet published and stuff like,  so there's huge complexity,  and there's also the modification date.  So if you have a news item from 2015,  and someone changes the typo,  is it suddenly a super new news item  if you use the modified date?  Yeah, so you see that's pretty complex.  So created is the date we want here,  so let's just use this thing,  and add that here, content.created, and save,  and I don't need to do anything else,  because after I pressed save,  you see this automatically happened,  and this automatically happened,  even didn't have to reload my browser,  so that's modern JavaScript development for you.  The tool chain is really, really good.  The result obviously is total crap,  because this is nothing a human can read,  but it is a date, it's a visual representation of a date.  We'll use JavaScript to fix that,  we could do some nifty string replacement and changing,  but we're not gonna do that.  Instead, we use the power of the vast ecosystem  of JavaScript libraries, and one is the moment library,  we'll import moment from moment at the top here,  and if you have a good editor,  tells you, hey, you imported something,  but you're not using that, please get rid of it,  we'll use it in a second, be calm,  and then pass that attribute that,  where did we put it, actually after the image,  not before the image,  pass it here and move it after the image before the text,  and don't, do we need a paragraph,  oh, we want a paragraph around that.  Okay, save, and again, if you have a good editor,  it automatically takes care of indentation  and form a code formatting.  So we're passing this date object to the moment,  it's actually a string to the moment library  and passing it a format, LL is one of the default formats  that you can use, can read up all about that  in the documentation for the moment, JS library,  we're not gonna do that,  I'll just, I didn't have to reload  and automatically we have this, so that's excellent,  we're already done, we have the date,  and yeah, that's it, I think, yeah, we have a date, excellent.  So here's a whole discussion about what happens  with these dates, gonna use the solution here,  so use effective if there is effective,  otherwise use created, so this is basically a try accept,  or if else statement, save,  and the editor even makes these nifty space thingies here,  which are ugly, I still hate JavaScript with the vengeance,  but it is a lot of fun developing with it.  So yeah, that's it, we did our first,  second customization, the logo, and the news item view,  we have a date here, so you visit your website  and you see the list of talk, the list of news,  and you realize something, yeah, why is it blue?  Okay, let's get rid of the blue,  that's just selection nonsense,  oh, because I clicked here, interesting,  can I unclick that?  Probably, yeah, like this, so I have my news,  and here I have my date, but in this view,  I don't have a date, ah, darn, okay,  one more view to customize, and another task for you,  so this case, we're customizing the summary view,  that is not a view for one content type,  but a view that is,  a sign that is usable on folders,  as there's more, what I wanna say is,  there's more than one view for folders,  you can go to a folder and say,  hey, I wanna look at this as a listing  or as a summary, in this case, we'll use the summary view,  otherwise our changes will not show up here,  so and again, we can use the inspector here  to find the component that is used,  summary view, here it is, and now we can,  here's the, wow, there's the code,  how do we, what happens here?  Nothing happens if I click here, interesting,  so summary view is the name of the game,  and I can use my search, which is not working again,  why is it not, yesterday it worked,  oh, now it works, you, no, it doesn't work anymore,  I have no idea what's wrong there,  probably I configured it to not follow symbolic links  or something like that, my editor,  so I'll look for the summary,  if you please fix your search,  if you have the same issue as I do,  it's in the same folder actually,  so here's my summary view,  I'm just gonna copy the whole file  and drop it into the same folder, paste, paste, paste,  where's paste, paste here,  summary view, so now I added this file,  and again, I need to start up,  gonna skip through this part,  but yeah, no, I'm not gonna skip through that  because that's important,  while I explain something, I'll restart,  so you remember I said that in the news item view,  the view component was passed the argument content,  which is the content object that we're looking at,  the instance of a news item that we're looking at directly,  in news, in summary views,  we're also looking at a content object,  but the content object is actually not the news item,  but a folder that contains these news items,  and inside this summary view,  the logic is iterating over the argument items  or the property items of content,  so content, which is the folder,  obviously has something called items,  and we're doing like four items in items,  I always try to read JavaScript as if it was Python,  because I really, really prefer Python to that,  and then we have item is one of these items  in the list of things that are displayed there,  and then these again have URL, title, image, description,  text and whatnot, so the same applies to item  that used to apply to, again, I have two summary views open,  don't modify the wrong one, close the original.  So after I restart finished,  so if I, oh, I can, let's try that, that's gonna be fun.  I already did that, so I'm not gonna do that again,  I just copy and paste my code in here and put it,  I don't know, somewhere here under the, before the description,  under the description, who cares,  and save and say, hey, we're done, it's all good,  reload the whole thing, because it realized we're broken,  and there we are, so a moment does not define,  didn't import moment, yeah, it's true,  moment, here we are, reloading again, see,  this, I have no idea what it's doing there,  but it works, it's excellent, so, and here we are,  so imagine next week, you add a new item,  everything has the same date, that's the error you just made,  or that I just made, is I use content effective,  and not item effective, and that is, yeah,  everyone does that, and everyone has to go through that,  pitfall to pick the wrong item again,  so, yeah, that's the solution here,  that we're using save, item created, item effective,  same display format, if we'd have news items  that have a different creation date,  and publishing date, then the date would change,  so the question now comes up, can you actually,  can you do that, yes, you can,  so imagine the conference website was already online last week,  you can just go there, and in dates, you say, hey,  the publishing date, that's what we wanna display,  that was on Monday, we were pretty early, so save,  and when I reload this, when I hard reload this, hopefully,  okay, October 17, that is correct,  so that was the date that I selected,  but for this view, maybe some crazy caching is happening there,  because I fixed the code, it says item effective,  or item created, and item effective is what we're displaying,  so I'm gonna go ahead and go ahead and go ahead  and go ahead and go ahead and go ahead  and go ahead and go ahead and say item effective  is what we're displaying, so this, I would say this is  a caching issue, and it's always good to kill things  by restarting it and figure out, find out if that is  the issue before you do further debugging,  because cache invalidation and naming things  the two hardest things in IT. And this would be number one, cash invalidation. This hopefully  it was that. Let's go further. We'll skip this next part where we let's see if it happens here.  So you can do that at home. We also have a listing block. Actually, we should do that,  but it will cost time that we don't have. So we're not doing that. In the next block here,  13.6, we would customize the listing block. You remember, we used the listing block on the front  page to display news items. So the thing with the cash invalidation is obviously wrong.  What is going wrong here? So did I modify the wrong file?  Oh, yes, I did. I, yeah, exactly what I told you not to do. No, not. Sorry.  Again, customizations. Kat, you do have any idea why that's happening?  I thought first it was a type about the spelling is okay.  Yeah, I think so too. Let's add foo. See if I made something. A stupid mistake.  Foo shows up. It should be okay. I have no idea. It should work.  Just tell your client it should work. That's always good enough. No, it's not.  Let's move on. It actually, it works, pretend it works. So in the next chapter, we would modify  the listing block, which we have here that we can use to display if we, hang on, if we edit that  to actually display our news items that are here. And we want to show up the date here as well.  And that's what we're doing in this chapter. And the tricky thing here is this is not a view for  a content type. So it lives in a different place. It lives in components, manage, blocks, listing,  default template. So that's a bit hard to figure out. You can figure it out using the  the React developer tools. See that it's, hey, there is something called default template. And  that's probably, probably what's used here. And then you can customize that. A lot of the  knowledge, what to change. You can just remember, learn, but debugging is just, you can, it's not  a problem. You can totally do that. Just change some file, put some typo in a file and see if  something happens. So if I look at the default template, JSX, I'm not going to do that now.  And see if you have something and it changes in your browser, you're obviously editing the  right file. And then you can copy that into your customizations and do a proper change and make a  commit in your Git history so that everybody can figure out that it's you who did this change.  And if you've did that, then this will happen. Just a short note. Yes. I think it's important to,  it's worth noting that if you want to find out what you have to customize, for example, this  default template, the React developer tools are very useful because everything is a component.  And if you find with the developer tools, the component here by this search thing,  and then most of the time, you know the file name that you have to customize.  Because this is most of the time corresponding component name and file name.  Here's source. It actually says listing buddy JSX. It even tells you the line number.  And yeah, but there is more with blocks extensions and anonymous default view. This is  yeah, whatever. Inject Intel. Yeah. Lots of stuff to discover here.  Let's one pretty important thing that we're not dealing in the whole training,  except for this small part, we're not dealing with internationalization.  In this part, we do because we want display is a date is displayed in different languages  in a different way. So in English, it says October 23rd. And in German, it would be  20, 20, 26 October and so on. So and people, even though a website is in English,  people would probably want the dates to be displayed in a way that they actually understand that.  And to do that, we can use this react into internationalization  stuff and pass set the locale that is used by the site. If you have a multilingual site,  that's super important or the browser sets that. And then the moment moment JS automatically uses that.  We're not going to do that now. You can do that at home. If you fancy that.  Let's go to the next chapter about semantic you are cut here. Take it away.  Thank you.  Okay. Semantic UI, we already heard about it. It's a little helper on a big helper for developers  to concentrate on the important things and to use the components that semantic UI or  semantic UI react and provide. These components are things like buttons, labels, help us to  structure the page by so called containers to have boxes with the already prepared  padding and margin and so on. And so I skipped to the chapter talk where we have  where we will create a view for our content type talk. And this would look something like this  where we have a label for the audience of the talk. And we take the component label from  semantic UI, which will, yeah, which is something like a widget with a theming and can easily  choose a variation of it. For example, in this case, the color or also the shape and so on. And so  you take the component from semantic UI, modify some attributes and it looks fine and you can  concentrate on your main part of your development and also very often used as the container.  And that's the bottom part of this page. You see a box with a border and the padding most of the  time is okay. So we can put your content that you want to display in this container and, yeah,  you have a structured page. So this is a semantic UI. It comes with a default.  And also the default theme is relying on this red package based on semantic UI. So you, if you use  it, your, your modifications fit in well to the default theme called Pasternakha. And  when we now step to the next chapter where we want to do some small customizations, not writing  on components or customizing, as we've seen in the last chapter, but only modify the some  CSS style, then we can, I don't have my chapter. Oops. Yeah. Then one typical example is to change  the font name, the font or the font size or what do I have here? Letterspacing. Then we can  write on CSS rule and we will see now where we do it and that we can use predefined variables,  like in this case font name. And for this to see where we customize,  I should, do I have to change the sharing? Sorry for interrupting.  I think you're, you're not clicking on your browser.  Sorry, I forgot to say.  I think you're clicking on the browser with a video and not the real browser.  I don't get it. I have the, now I'm sharing the Firefox.  Yeah, but you click with your mouse and drag.  Drag. That is the video. You're looking, you're looking, you're clicking on the zoom  window and not on the Firefox window. You're clicking on the Firefox within Zoom.  Minimize your zoom window and then you have the browser and you can.  Okay.  Okay. So, you know, I should see my editor. The theming is done.  We have seen the omnet folder for the Volto code and beside the source code where we have  components, actions, reduces and so on, we have a folder called theme. Is my editor now share?  Yes.  Okay. Thank you. We have the folder theme and with Volto, we have the Pasternagar theme and also  the default theme. A default means that this is what a semantic UI provides. Pasternagar is the  theme of Volto or Plon6 and it comes with some variables and CSS rules. And if you want to,  for example, customize the font, we will find a variable here and we have not one big CSS file,  but it's organized by topics and something like font, which is a global thing we find in the global  folder and most of the files here are pairs. A pair of a variable file and an overrides file.  Our variable is here. We find our font name variable, which we can modify to change the font and we  have the other part of the pair overrides and this case is empty. Normally, you will find  CSS rules here. This is what comes with Volto. If you want to override, we create a new file with  the same name and use the path. On top here, we see the path. We take the path from the theme name on.  Globals and then our site overrides. Globals, we create a folder, Globals and the file site  overrides. I want to do that now because it's really easy to do. Then we change the variable name  and the other case would be that there is no variable and we want to place a custom CSS rule.  We take the part site overrides. If it's global or if it's something like  in collections, we have menu, table, forms, very important form overrides. Then we can pick  the matching rule here and we also look at the path again. We are in collections,  file form override and then we go to our app code. I close the omlet and I close the source part of  our app. At the same level as the source folder, we have a theme folder and we change to this.  I already prepared two folders, Globals folder where you find the customized site variables.  Here I have my font name changed to Lato. This is a font name of Google font. If we use  Google font, we can just modify the value and Volto cares about getting the source from Google  Google font website. This would be the way to change the font. The other one would be,  for example, to customize the letter spacing. Then I create the other part of the site modifications,  site overrides and I place my CSS rule here. Then as we created new files, we have to start  Volto again and then the modifications can be seen. I think it's easy. Questions?  If not, I would hand over to Philippa then.  Thank you.  Wow, that was quick, the seeming part. Let me share my screen. I found out  that we have a bug. We have a bug in Volto. We should have realized that a bit sooner  because when we changed the view to summary view here from list, summary view,  the picture is here. The images didn't show up. There are no images. In the template,  there is an image tag. The objects obviously have an image, but they're not showing up.  What's going wrong here? The reason is I didn't have time to find the change log message,  but at some point in Volto, it's not that long ago, the default way that the content of folders  is returned by the rest API to the front end was changed to not contain all information about the  objects. How did I figure that out? That's important for you. Inspect components, look for the ... Just use inspect to find the wrapper. Then we have the container. Where was that?  Summary view. Here is the summary view. That's what we're using. It has a property called content.  In the template, you remember I showed you this, we're iterating over item for item in items,  for item in items of content, for item in content items. Here's the summary view. Here's content.  Here is items. If I expand this, if I expand the first item here,  it should become obvious that this is not what we saw when we looked at the news item earlier,  where we saw lots of information. Here, we only see a tiny piece of information that is  returned by the rest API, because this is the data that is available to the view component here.  There is no effective, there is no image, and this is why image is not rendered. There is an error  in the way that the summary view is constructed. It's not getting all the data from the items in  this folder. This is why it's not possible to display a date. Why does it show a date then?  Here comes the next crazy thing, the moments library that we're using to render the date.  Let me go back to the original way. If you don't pass anything to the moments library,  it returns the current date. It's similar to Python, date time, if you call date time,  it returns the current date, at least the update time. I don't think Python date time does that.  Maybe it does, I'm not sure. This returns today's date, and five years from now,  this news item would still be from today, which is super stupid. I have no way of fixing that  right now, but it's certainly something both creating a ticket for. Just to show you that,  there is here, when I save it, you see this actually changes. Now we have a different  visualization, because I changed the format, but the date is still, a date is still there.  So, yeah, it's not our fault, it's Volta's fault. This makes no sense to be in the summary view,  if the item is not passed to a summary view. How do you create a ticket? If Plone is,  we haven't talked about that yet, it is an open source system, and it's maintained by a huge  community of volunteers. There's not a single person paid for doing any of that. We don't,  Katja and me, we both don't get anything from doing, for giving this trend, actually we do,  but it's like, it's a symbolic gesture. And we actually, we even had to buy our own ticket for  the conference. So, we're doing this out of the sheer goodness of our hearts. And the same is  true for Volta, and the whole development that goes on goes on in Plone. And it's all open source,  it's all available there. And Volta is a repository on GitHub, it's all open source, and there is a  list of issues. And I could just create an issue that explains what's going on here, that the images  are not showing up in the summary view, because the items that are passed to the summary view  do not contain all necessary information. There is actually, in a later chapter, there is a small  part where we actually discuss this issue, which is actually a feature, but I wasn't aware that  it, the summary view was basically broken in Volta. Okay. And you're also invited to  file a ticket for an issue, if you find something unclear in the training documentation.  That is very true. The training is, okay, this is fixed base class, so there's nothing about the  summary view. The training, since you mentioned that, I'm going to show that the training is also  open source, it's actually, it's not even GPL, but it is Creative Commons Attribution 4, whatever  that means, not a lawyer, but it means you can just do whatever you want with it, as long as you  mention that it's open source, something like that. And you can create a ticket here and say,  okay, there's something wonky, or you make a pull request and change stuff. And there's all the  trainings that are in this, that are on trainingplown.org in there, and masteringplown is one of  them. And we are right now, just to show you that in Volta-theming, so Volta-theming, this is  the file we're looking at at the moment. And you can create a pull request, can make a change,  feel free to do that. And it, yeah, that's important. So I'm not going to fix that issue now.  Okay, we already saw that we can customize Plown by overriding components in React using component  shadowing. And I quickly mentioned that we could do something similar in Plown Classic by creating  a copy of that file in a certain folder. It's basically exactly the same approach. Plown,  the point of this chapter is to teach you that Plown is built on top of the idea to be customized  and extended and not forked and branched, but that you can take almost every  a part and aspect of Plown and customize it to suit your requirements. And there are a couple of  extension technologies that are discussed here. I'm not going to go into details. We're going to  visit them soon, see how they interact with Plown in different ways. But basically,  they allow, there's a whole system built to customize Plown. So why is that? Maybe that is  important. Let me quickly go into the back end of Plown, the original back end in the  Zope management interface. This is not only for looking at items. This is actually in Zope, was  built to be as a development environment that you can write code in the browser. So there's  this select type to add and then there is this script Python thingy where you can actually  write Python code in the browser. And when you go to the URL of the idea of the object that you  created, this Python code is executed in a safe way. So there is actually a whole huge package called  how's it called? Restricted Python that makes sure that you're not deleting your hard drive  by writing a Python script because obviously in Python you could do that,  can delete your whole system. But you don't want to do that. So this is, it's basically,  it's in a sandbox. It's a safe subset of Python commands that you can use in there. So Zope,  when it was invented, was the whole idea is to give the user the power to customize it and  extend it through the web in the browser. And the same approach is true for file system development.  There's a lot of hooks and crannies that you can plug into to make Plone do what you actually  wanted to do. So that's, and that is what we're doing. That's why in the whole training, especially  in the, we're not going to write a lot of code. Most of the code that you write like lines of code  wise is copying templates from one place to another. And it's not writing, it's copying and  pasting. And the things that we actually write ourselves are not that much. So, and to do that,  to allow Plone to hold our own code in the back end in this case, we need to write a Python package.  And there is a lot of existing add-ons already, Python packages that are connecting to Plone  that you can use to connect to Plone and extend Plone. And this chapter mentions a couple not  going to go through that because we're not doing classic Plone. Most of them are using classic  Plone. There's a later chapter about Volto add-ons that also exist. There are add-ons that change  Plone back end that provide new content types, for example, that you can also use in the front end.  And there are add-ons that provide functionality that is used visible in the browser that make no  sense in Volto. So there you need a Volto React component to talk to the back end to that. So,  in some cases, you actually have a Plone add-on that comes in two,  in two, comes as two parts. And that is what we're doing in this training. We have one Plone add-on  called Ploneconf site, which is a Python package that we create to provide extensions to Plone  and overrides to Plone the back end. And we have Ploneconf-Volto, which is a front-end package that  extends the front end of Plone. And both are not forks or branches. They override the minimum  time that is necessary to make that possible. So we're going to skip this whole thingy and we're  going to quickly... Oh, God. I could talk for hours about that, but I'm not going to do that.  So this is to customize, to configure Plone in the front end. You have this  package JSON that tells you it requires, I told you that before, this Ploneconf site package,  Ploneconf Volto package, JavaScript package, NPM package, depends on Volto. So it extends that.  In Python, we have something similar. And I haven't opened my editor for the back end yet,  so I'm going to do that right now for the very, very first time. So let's add another terminal.  Training Plone 6 back end code. So here is my VS code instance.  Last year, that was actually convenient to have two different editors for two different things,  because my laptop screen is pretty small, so it's easy to get confused. But a little confusion is  just required. So this is the back end folder that we're looking at now. And it holds the  configuration for Plone the back end or Plone classic. And the most important part is the  build out CFG file here. So build out is a configuration or orchestration system that  builds Plone, configures Plone, and extends Plone, and does a lot of other things. You can add  other things. You can actually make build out, compile, Apache or solar for you, which is kind  of stupid to do. But it is possible. That's why I say it can spawn all kinds of things.  So here is the main file for build out. And here is a minimum example for a build out that  is used to build a Python Plone site in Python. It has only two parts. So it's built, it's  separated into parts. They are, this is the INI syntax. You probably know that.  The square brackets build out. It has one part that's this one instance, and it extends. So it's  pluggable and extendable, and it's increasingly complex if you use it in real life. And it has  recipes. So it has build out itself. And it can use recipes that tell a part, in this case,  the part instance, to do something. And in this case, build Plone using the recipe Plone Recipe  Zog2 instance, which is the default recipe used to build a Plone site. And if you use that and run  build out against that, using the logic that you learn when installing Plone, it's just call  build out, which is executable. Then it reads that and installs and builds Plone from that.  There's a lot of stuff in here that we're not going to go into in detail. Let's quickly look at  the real life example of this training. So here's build out. It's like, it's always the main section.  It extends versions from the freshly released 6, Plone 6 Alpha 1 version. This is a URL. If I open  that in the browser, it holds Python package version pins only, lots of those. And it also  extends the version pins of Zolk. And the Zolk version pins, again, oh, they don't open the  browser. They extend and extend. So there's a whole, I don't know, a red tail, that you can  follow there with versions. It also pulls in the versions of a file, version CFG, where we have  pins for the versions that we added in our build out. And it has a couple of defaults. The most  important ones are these eggs. Python packages like, I don't know, the request library or Plone  itself or Pillow, which is a Python imaging library, are called eggs. That's, by the way,  this is why the packages folder that's here used to be called omelet. And in Volta, it's still called  omelet, even though the NPM packages are not called eggs. So that is, if, I don't know, five years  from now, they don't change that. No one will ever remember that Python packages are also called  eggs, because nobody uses that word anymore for Python packages. And so everyone would be  irritated why is Volta and all the other dependencies in a folder called omelet.  Yeah, so that's history for you. So these eggs declare what Python packages should be installed  for the system we're building. And this is Plone. This Plone package pulls in everything itself.  So this is a Python package. It actually lives on PyPy, but also on GitHub. If you go there,  you can find that it's a meta package, doesn't have any code. It just depends on more packages.  Oh, crap, there's setup. So you need setup CFG. Here are the packages that it depends on. Where are  they? Install requires setup tools, REST API, and CMF Plone. And that is actually Plone itself.  That's the package where the code of Plone exists on GitHub. So there's a shitload of code here.  And that again pulls in many, this time the dependencies are obviously in setup Py.  This pulls in a lot of additional packages. So when you install Plone, and you already did that,  you have a executable called bin instance here. And it has all the Python packages  that are used to run Plone. And these are 200 and more than 260 Python packages that I used here.  So and build out is there to make it manageable to actually pin the right versions for each of  these 260 packages without you going crazy. And on top of that, extend the Plone that you build  with your own add-ons. For example, here's some development add-ons that we're going to discuss  later. And the one that you're writing yourself, Plone comp site. And that one will also be tested  because there's a test setup that is in there. And this package Plone comp site, hang on, is actually  not downloaded from PyPy, the Python package index, but from GitHub using a build out extension  called MrDeveloper. There is so much to learn and to know there. So if you're not not, if you don't  know that, you will learn it through practice. It would take us a lot of time to discuss all of that.  So we're going to just jump to the end of that. This is the build out of, there's lots of documentation  here. I really, I beg you to read that. There's examples for super small build outs and really  big and complex build outs and how to figure out how to work with that. And what are you going to,  what are we going to do now? Or what already happened? So we're not going to do that. But it,  if you would start from scratch, you could do that. And I'm going to just quickly show you how  that works because it's really cool. So when you have, when you follow the installation instructions,  you have Plone, but you don't have your own package yet. And you can create your own package  using this Plone CLI command line interface helper thingy. I'll go into my backend folder. I'm going  to call that Plone.com site too. So I'm not going to, I'm going to throw that away after I did that.  I already installed Plone CLI and I create a, no, please don't correct this. Otherwise,  it will override it. It'll ask you a couple of questions, including your GitHub username and  what do you want to do that with that? And I'm going to just answer the questions as in, as  instructed here, but you don't have to do that because you already have this package. I'm just  going to show you that this actually works. There is still an issue. So I get an error on  ISORT. I don't know why we need to ISORT it automatically. I wouldn't do that, but I'm not  maintaining that package anymore. So yeah, can ignore this, this problem. And now when I open  my editor in SRC, I just created a from a Plone Python package. If you know other systems, this  is like cookie cutter. It's cookie cutter is more popular in for most systems, but this is  real, used using something called Mr. Bob, whoever Bob is, I get probably Bob the builder or something  like that. It's like names happen at Plone Sprints. So there is Mr. Bob and Bob templates,  Plone creates this structure and that is a Python package that extends Plone. Why does it extend  Plone? Because yeah, because it does. It is just it's built to extend Plone. It doesn't pull in  Plone. You need to pull that into your Plone, but it is it is preconfigured to be a sane approach to  Plone extensions. I'm going to delete the whole folder here, move it to the trash, and  going to get to the next item. We already did the same thing for Volto add-ons when during  installation you did the you used create Volto app or didn't we switch to you man or something like  that. Yo, to create the add-on. So maybe this this is not the right  name. Never mind. So let's have a look at the Python package that was created.  I used the one that I checked out, but it's exactly the same. I created it this morning  around nine o'clock and it's up on it's on GitHub. So there is a pretty complex  folder structure here. And first of all, there's a lot of files here, and you will probably have no  idea what they mean or what they what what's coverage RC, Bob template, CFG license. There is  some license thingy here and manifest and the setup UI and what the heck is this all this stuff.  And you could ignore a lot of that because it is mostly boilerplate. So what you see here is a  build out CFG. And now you get super confused. Didn't we just didn't didn't that guy just say that  we have our own build out for the training. It's in the folder back end.  As a file called build out CFG. Where is it here? Build out CFG that pulls in the other  package plonkrom side. And now I'm in plonkrom side here as RC plonkrom. And it has a builder of  CFG again. Why is that the simple reason for that is you can just ignore that for your for the  development purposes. But the default for when you create such a new package is that it should  give you all the defaults to have this a self contained package that is testable and publishable  publishable on pipy. So to be testable, it needs to have obviously plonkrom and some test runner  and all this nifty things to automatically run tests on using GitHub actions, for example,  or Travis CI and here GitHub actions, I guess that is here here GitHub actions. So run tests  using plonkrom 6 and plonkrom 5 and do all that stuff. So all of that is already included in this  boilerplate template. And you can ignore all of that. The only thing that you need is actually  inside SRC, PONKROM site and our guard again. Why is that such a complex folder structure?  Let's go into that. LL SRC plonkrom.side. This is a namespace package. SRC plonkrom site.  So this is actually the, yeah. Let's go into SRC. When I look at the tree of the whole thing that  I just created, I have a pretty complex folder structure, including all these files that you  don't need and SRC and plonkrom site. And this is only there to make the again this file self  contain, self testable, self buildable, and you can ignore all that. And every time we talk during  this training about, hey, add a file in Bababa, Bababa actually starts here and not up here.  If you, when you need to add a file, you always add it in inside this folder structure,  where you have setup pandlers in it, configures that ZML and so on. So this is,  this is where we actually add our stuff. I will repeat that a couple of times. Here is in the  documentation it, yeah, let's quickly go through that. The most important, it's all explained here.  The configure ZCML is a XML syntax file that registers components and stuff basically for your  plonk side. In, if you use fast API or other frameworks, you probably are used to using  decorators to register routes, for example. In a plonk, you don't do that that often, sometimes  you do, but more often you use generic, ZOP component market language, ZCML to register,  for example, a view for a content type or a interface or any code that you want to run.  We're not going to do that much. So I'll just skip ahead to the next part where we have this  empty shell that looks horrible and complex. But the good thing is you just run this command to  create this, this, this, this package and then commit everything that's in there. If you look at  the git history of the plonk.com side package, plonk.com side, I use source tree quite often  for git stuff because it has a nice user interface. You see in this initial commit that has zero  features but adds a ton of files, these are all auto-generated. So just add them and this is the  important one. This is what you do yourself. This is where you write your own code. This commit  actually, we are at the moment here at Volta. And this is like your commits, this is the important  part. The small things where you say, hey, I'm a new content type. These 500 files,  don't think about them. Don't get irritated by them, at least. Okay.  Okay. Good. Content types. I hope that was not too  horrible that part. But it is what it is. Python is a complex ecosystem, especially if you want  your stuff tested and automated. And if you have a lot of dependencies, if you ever try to install  Sentry, for example, by yourself, that it is horrible. It has so many dependencies. It is  so many databases and containers that you need. It is just, if you have a complex system, you  have to deal with this complexity that builds these things that you then can use. And we try  with the clone and build out and build templates with these templates to make it as approachable  as possible. And actually with clone 6 in the future, you can just say pip install clone  and you get everything. But yeah, we're not 100% there yet. So installation is still a bit complex.  Okay. Next chapter is content types. So it says dexterity one content type. Why does it say  dexterity? Because in clone 4, we used to have also content types, obviously, because it's a  content management system, but they were not called dexterity, but archetypes. These are  basically two different frameworks. You can forget this name right away. It was really important to  know that dexterity exists as long as you still had archetypes around. And if you need to migrate  from archetypes to dexterity, that's a complex task. But if you start with clone 6 or clone 5,  you will only have dexterity. So actually what we're talking about is just content types,  ignore dexterity. So a content type is an instantiated object of a class that is defined in Python  and stored in the database ZODB. That is from the clone perspective, that is a content type.  From a user perspective, a content type is something that you click on an  ad menu and select one of these content types and it is automatically created for you.  So it needs to be somehow registered in clone that a content type like here,  a document, page is called document in the back end, exists. And also the schema of that  content type needs to be registered somewhere. You remember the news item had a different  schema than the document. It had a lead image on top of the rich text and has lots of other fields.  And also when you, a content type is, that's for the editor, that's a content type, but for the visitor,  the content type is just a page that you look at. So it has three parts. One is the factory  information that tells clone that you can actually create this thingy using a factory.  Remember the factory factory. And the second is the schema that defines which kind of fields  then should be available. And the third thing is the visual representation. So each content type  usually comes with some kind of visual representation to the user. It doesn't have to have one,  but in our case, we want one. So that is the important things about a content type already  said some things about that. So in clone, as I said, as so is very configurable, it even goes a long way  to make sure you can modify existing content types and add new content types through the web. So the  first thing we'll do, we'll add a new feature to a existing content type. The news item, let's look at  if you go to the control panel. Okay, I'll go back. So you might have missed that. If you go to site  setup, this is the control panel here to the content type control panel. And there you have all  these types that are available, including the news item, click on news item. And there you see the  news item and the name and all this information. We're not going to change the name of the news  item. We're going to go to the schema of the news item. We're going to not going to not adding the  FTI but the schema, not the factory type information, but the schema and you actually get a schema editor  in Volta, but you can add new fields. So what we're going to do is we're going to add a field  of the type yes, no, so it's a Boolean field, you can check stuff and say, is this hot news or is  this, I don't know, cold news. So let's do that. I'll add a new field. No, I'm not going to add a  new field set. I'm going to add a new field here below that. And it's a yes, no field if I can find  that. Where is my yes, no field? Come on. Type too many options here. Okay, there is a scroll bar  and at the very end is the why. Yeah, maybe a small UI issue with nested scroll bars. Okay, the title  is hot news for this field. So is this hot news? Yes and no. No description. It's not required,  although if it would be required, everything would have to be a hot news, which doesn't kind of  defeats the purpose. And here's my hot news field. And now, so what do I have to do? Yeah, I have to  save. And then I'll open a the site in a new tab. And I go to my news listing here, and say the  conference website online, and click on edit and guess what, it's already there. Isn't that super  dark magic? So I can in I can without writing a single line of code without restarting the instance.  I can add a new field to the schema to or model if Django if your Django developer, for example,  that would be a model. And then you can add a hot news field and store this data. And it is  stored in the database. So, okay, let me take you a little bit down the rabbit hole. So here is my  news item. Let's go to the back end quickly. So the classic thingy here, we have news conference  website online, I can edit that, I can see my button here, I can view that. And I was always  saying, okay, this is some is the instance of a Python object. Let's make sure that it actually is  PDB, if you don't know PDB, that's the Python debugger. And we have a add on in our build out  that allows us to call PDB on any object. What happens, I don't see anything, why don't I see  anything? Because I need to go to my back end, which runs in the foreground. And here I have a  PDB. So self context is my news item. And my news item can be inspected. And my news item has a new  field that I'm having programmed, hang on, that I added in the editor here. And it's called hot news.  So there's a space in between, you can't have a Python, Python attribute with a space in between.  Well, let's look at hot news self context. Hot news, no, minus wouldn't work as well. So maybe  underscore. No, not that. This wouldn't work again. So how can we see that? Can we see that? No, that  doesn't seem to work. Where is my hot news? Why can't I see that? Hang on. Am I on the right  object conference website online? Yes. And it has hot news as a field. How is that called in this  case? Let's just use the capital H. Who came up with that idea? Self context.  Here. That's, yeah. Here it is. Hot news, too. It's a, it replaces the space with underscore.  And this is my attribute. And it's actually stored persistently in the database. So, yes.  We not only magically created a field, it is actually stored in the same way in the database.  I'm not a huge fan that in Volto, new fields have uppercase characters that seem stupid,  because in the back end, these are all lowercase automatically. But yeah, that's tiny, tiny issues.  Okay. We did that. We can edit that. We save it. We can look at plenty of stuff here. We can even  create complete new content types through the web, not only modify existing ones, we can just say add  talk and have a talk content type there. And do I need to restart my site? Do I need to do  anything? No, it's already there. So it's beyond imaginable what dexterity or the content types  in Plone allow you to do. You can create custom types through the web, but we're not going to do  that. I'm going to delete this thing because we are not mouse pushers. We are developers. We want to  do stuff and have people check the Git history in two years from now and say, hey, what did you do  there? That was horrible. Why did you do that? So we're going to write a content type in Python  and register that in a Python package as a dependency of Plone. So why do we do that? Not  only because we want to show off what we know, but because our projects tend to have a long lifespan.  We're doing sites for universities. I don't know. Plone runs the Brazilian government website and  a lot of UN sites and stuff like that. So it's not your neighbor bakery. These projects have a  lifespan not of years, but sometimes of decades. And they have tens of thousands to millions of  content and a lot of custom code. So they need to fulfill certain requirements for stability.  And if you just create your content type through the web and click around a little until you  achieved your goal, if you leave this project and five years from now a new developer comes in,  he will be completely lost and he will hate you, which may not interest you, but his life is  then miserable and it should be in your interest to make the life of other developers great.  So we're going to do that in Python and not through the web. Oh, God. It's already half past six.  Katja, what do you think? We're way behind schedule. Should we make a short break before we do another  half hour to actually create these talks? Last year we were quicker. I had the feeling.  What do you think? You want to make a break? We have only half an hour now from now.  I think people are going to break. Yes, but maybe just a short bathroom break, five minutes.  Maybe I don't know what time it is for you. You can get a beer depending on your time zone.  Five minutes? Good. Let's have a five minute break. Let's actually really meet in five minutes  so we can get the most out of the next 30 minutes. Again, if you have questions, please put them in  the Slack. We'll try to discuss them. Am I too? Someone said I was not loud enough. Sorry.  I didn't see that. See you in five.  I pull.  Maybe you need to restart your browser or reload the page. The developer tools, when they're  freshly installed, may need a little kicking. Here are components and then you can inspect.  There's two inspect buttons. This is for HTML and this is for React components. I always click  the wrong one. This should then show up. You need, for some reason, this scrolls very far  to the right. Then you can find that. Let's continue with the talks. We are way behind  schedule, but that's just what it is. I don't know where we lost so much time, but it is, yeah.  Okay. We will register a custom type. Why do we do that? Excellent, Paul. Good.  So since we're organizing a conference and we could have talks as documents and say, okay,  it's topic, speaker, whatever, information is just in HTML. But if you want to sort your content  by speaker or link to that specifically or order that by date or day or room or stuff like that,  it is good to have structured content. Data is just, it's perfect as structured content.  Talks is perfect for that. So first, I said we need three parts for a content type. First is the  type factory information. So we tell Plone that there is a content type called talk  that should be available in Plone. So to do that, we go into Plonkconf site and that means  SRC, Plonkconf.site, SRC, Plonkconf site, and then in profiles. So from now on, we say go into  profiles or Plonkconf site profiles. This is where you end up because the Python namespace  actually ends up here also in use the default profile, not the uninstalled profiles. The default  profile is where configuration ends up that you put configuration in there that is applied upon  installation of your add-on. And here you create a new file called types.xml and you paste the content  from this snippet here. So, oh, God, why is this not Python? Can't we do this in Python?  This is XML. This is something called generic setup. It's one of the extension approaches  for Plone. And everything you have something in XML and you make a change in XML, this is only  applied upon installation of an add-on. So after I save that and I reinstall or install my add-on,  this code is then read. Restarting, reloading the browser won't help you. You need to install  this package because then the generic setup profile is applied. And this generic setup  profile will raise an error because it tells there should be a type called talk in my profile.  And it's not. There's only document for some reason, for a very good reason. But we need a talk  XML as well. And that lower case for custom content types, I always use lower case. You can do what  you want. But I think lower case is a good best practice. You copy and paste the whole FTI here.  So I haven't learned anything right now. That's what you probably say. That's not true. You've  learned something very, very important because you can copy and paste code. And you can copy and  paste code from the location where it is always updated. Not every month. But it uses these same  defaults. And it is what I do at least twice or three times a week when I write my custom client  projects. I go to the mastering plan training documentation, go to the chapter that is close  to what I'm doing and copy the defaults that are in there and make the changes that are required  for my client project. Because I'm just way too lazy to type all this stuff. And I don't want to  memorize that. And nobody wants to. There is a lot of documentation about the mastering  plan training is certainly the most up to date and the most comprehensive one if you want to  deal with creating content and modifying content types. And it's basically the same approach  as like, plan does it. You don't fork plan. You also don't fork the mastering plan training. You  just take the bits and pieces that you want for your projects and you use them and then you change  what is required in your projects. This time we don't have to change anything obviously because we  specify a content type called talk, which has a title with an uppercase t. It has an icon. It has  a factory and ad view and it has a class, a Python class that is used to instantiate the object that  then lives in the database and it has a schema that is both not yet in existence. And it has  a couple of behaviors. We'll get to these later. So this is your FTI and it's basically the first  part is done. You registered a content type for PLOM. The second part is the schema. You need a  schema and the schema can be done in multiple ways. Again, we can use the browser to add fields  until we have our schema and that is absolutely okay to do that if your project has a limited  lifespan or if you do rapid prototyping. But if you have a longer running project, it would be  better to do that in the file system. And again, there's two ways to do that. One is again in XML,  but I hate XML. XML is written for robots. I'm not a robot. I'm a human being. I want to read Python.  I want to write Python because Python is meant for humans. So we're going to create a Python module  inside our package. A module is a folder with an initpy file if you don't know that. So here  content, that folder obviously already exists. For me, for you, it should not initpy.  So now we have, there is a module called content. It doesn't contain anything yet. And in there,  we create a file called talkpy. That then is a, talkpy. And that will hold the schema. I'll just  copy and paste the whole thing and save it. And then I'll go through that step by step.  So here we define the schema. It is basically a Python representation of what we saw.  Not here, but here. This is the user facing representation of the same thing that we're  looking at now for a different type, obviously. So we define a schema, which is an interface.  I'm not going to go into interface theory, but it defines a contract, basically. The contract  that talks have these attributes and can do these and such and such a thing. So this is the  interface and it's defined, it is referenced here in the class. So this here, this is the  interface with the schema. And then there's class again with a k because c is, would be reserved,  reserved word at some point when you load that and you get error messages. So that's why it has a k.  And then there, hang on, here at the very bottom is a talk. This is the instance. So when you  create a talk then or a news item, this is the object or the news item in that, in the other  case, would be instantiated and it implements this interface so that it can store  these, the values that are added to the fields in the, the, the widgets in the browser and can  store these, these values as attributes persistently in the database. So, okay. So this always,  again, you don't have to memorize all of that. When you write your own content type, you go to  the mastering, the training and you copy and paste this thing here, the whole thing, if you want,  and you throw away what you don't need and you add what you need. I'll show you how you, how to  find what else you need in the next chapter. So here we have a couple of fields type of talk  and they follow a, they have a certain, each field has a certain type. You remember, we added the  hot news field, which was a yes, no field or Boolean would be like this. In this case, it's a  choice field which stores strings. So text here, one of these values. Here we have a rich text field.  It's in, it's imported from a different place, the definition of rich text field. But again, this  is something you don't have to memorize. You can copy and paste that from dexterity documentation.  That is actually the next chapter is the dexterity documentation itself. And each field has a title  and what is the title? It's not super unexpected. This is the title of the field here. The title  of the field is summary. Here the title of the field is hot news. A description of a field is,  for example, this here, this is some help text. This is the description. You can configure various  fields as required. So there has to be something in there. Either a box needs to be checked,  we need to add some text and so on. Here's a text line field. That's a very simple one.  Speaker, where you can just add a line of text as title description is not required. And so on  and so forth. And there's an interesting one. There's block image, name block image, which makes  sure that the file is actually stored not in the database, but only a pointer to that file stored  in the database. And the file itself ends up in the file system where binary data is best stored.  So after I save this file, I need to, what do you think would I need to do? So this is, we extended  blown in two ways. We added a factory type information for talk here. We referenced that  factory type information in the portal types tool. That's how it's called. That we extend here with  type. And then we added a Python module. Python modules are only read on startup. So reloading  the browser wouldn't help us. So at least we need to restart our instance. Just stop it with  control C and restart it with instance FG. Remember that you need to do that for the back  end, not the front end in this case. And then we, as I said, the XML files are only read upon  installation of the add-on. So here we have a problem because the add-on, Plurcon site that we  created here is already installed. Remember when we created the site, we checked the box at the very  bottom of the list of add-ons that are available. So it's already installed. How do we reinstall that?  Actually, the way to reinstall that is to uninstall it and install it again. And at this point,  it is actually still safe to do so. It will at some point no longer be safe, but we'll see that.  So where are my add-ons? Here are add-ons. So in the list of installed add-ons here, five installed  add-ons, there's Plurcon site. And I can say, just drop that. Remove it. And Plurcon site,  just reinstall it. Install it again. So I clicked my button here. And a couple of things happened  in the back end. So you see, it was applying the profile, Plurcon site default. Remember the folder  called default. Held this. Then it installed roles permissions. Why is that? Did we do anything there?  No, we didn't do anything there. But there is a empty roll map XML that can hold custom roles  and permissions. And that file was read and applied. So nothing changed, but it said, hey,  there's a file. I'm going to read that. Catalog was imported because there is a catalog XML. Again,  empty. But there is more types tool imported, document type import and more, and talk in type  info imported. So it obviously saw that we have this. And it saw that we have these files, these  two files. And then it applied these profiles. So this configuration is now somehow in the database.  And it's, yes, it is visible in the front end. When we move this thing, when we move to the  to the dexterity control panel, we can see our new type here. Talk. Here it is.  Similar to when we would have added that. And we can actually see the schema that we defined. So  this is the schema. It's all there. And it's not only visible in Volto as a admin where you can  modify that. But again, in the back end, in clone has, clone has a, the classic has a equivalent  of that user interface. Not going to show you that. But the types tool that stores that configuration  actually has a user interface in this soap management interface, portal types. And here is  my talk content type. And here is my reference to the schema and the behaviors and the class and  whatnot. So a lot of stuff is in multiple places. And that is because clone wasn't built last year.  It has quite some history. And this is where you see that various layers on top of each other.  Okay, to make, to finish that, let's go to schedule and add a talk. Here it is. Dexterity.  Some Latin nonsense, please. A type of talk. Here we have, I said it's a choice field with  strings text, pick from here you have rich text field, you can add some rich text.  Add that and yeah, edit that. Add stuff. Audience again, a choice field. In this case,  a multiple choice field. Beginner advanced professional dexterity is for everyone. A field  for the speaker. Or let's go back into history. Martin has barely one of the brains that dreamt  up dexterity. No idea where he works at the moment. Let's pretend he works for me. That would be fun.  Martin had clone.org. Probably shouldn't have a space. Let's see. Yay. So this email field,  obviously, isn't a text field because otherwise it wouldn't have complained that it's not a valid  email address. So having the schemata is not only cool to show off that you know how to do  that, but with certain fields you get data validation, input validation. And that is  obviously super important. So you have valid data in your database and that you don't end up with  invalid data. So if, I don't know, clone, if you later try to send an email to all these people  who registered as speakers, you don't get error messages. Philip, that's a question. Yes. Let's  see. Paul, it is stored in the DB, but you should have the schema. Oh, the first one.  If you create the schema through the web, it gets stored in the database. Yes, is that why you say  it's not good for long projects? Yes. The schema is, if you create it through the web, it is stored  as XML in the database. And there is a way to export that. You can export a schema into as XML  and import that into your Python package to put it into version control. So that is a totally valid  approach. And the earlier versions of this trainings actually did this. So we created the  content type talk through the web, exported the XML into your Git repository and committed that  to Git. But as I, it's a matter of choice. I much prefer Python to XML. It is feature equivalent  a schema, but there are tiny things that you, sometimes you need to use in more complex projects  that you can't do in XML, for example, default context aware defaults. So a method that runs  to define a default value for some field that takes into account where this object is created.  And so on. A couple more examples like that. So in Python, you can basically do everything. So  that's why I much prefer that. And Paul had another question. He answered that question. That is  actually nice. Okay, let's add some website here. I think like that. Okay, I'm not Martin. I should  not pretend to be Martin. He's so much smarter than me. So let's pretend I will do that.  Talk. I can upload an image of biography. You see, obviously. And the third part  that is, that I meant said a content type is made out a view representation. You get that  automatically. But, and that's a big but. This is, we don't see any of the exciting data that we  just added. Only a Plon classic so far has that feature. So when we go to schedule and see the  Dix 30 for the wind talk, I can see a default rendering of the values in that schema, which is  often good enough, especially for, I don't know, internal use as intranet stuff like that. But  as a for visual representation to client or conference website, this is not like this is  like Excel. Just dump me a Excel sheet. What do you think you're doing? That's not okay.  So don't do that. We in the next chapter, we're going to much improve that. So we already  created this type. We tested this type. You see the user interface is slightly  is slightly different. But if we change this to a keynote, for example, and save it.  And we added that again in Volto. We have the same data. So here's the keynote now. So this is,  again, this is the react front and talks to the same back end. As Katja already said, at some point,  you need to decide which user interface you need to take. And you can't really switch back and  forth in like one folder in Volto and the other in classic. But the data is in both places. We're  going to take care of the visual representation of the data in react only. So what else is there to  say? Yeah. Ignore that. We created a first content type custom one in Python. So it's readable.  It's great to test and to repeat the process and change it for the next iteration. You can control  all kinds of data that is stored in the database for these talks. You could extend the schema now  in the later stage. We can do that. And if I said this is what you learned was not how to actually  write a schema, but you learned how to copy and paste the best parts for writing a schema. And  the next chapter, we have five more minutes to discuss that, is the dexterity reference documentation  about all schemas that are fields that are available for you when you create your content types.  And this is where you need to go when you have a requirement and you need to fulfill that. And  this is how do I do that? How do I do this? These are all types of fields that are available. And  they are all which is kind of crazy. They're all in one content type. So there is one content type  called example in this schema. And it has various field sets for various field types. So these are  field sets here, different field sets. And you can, so they're sorted by, you see these sort dates,  date fields have one field set, text fields have one field set and stuff like that. And here are,  I'm not going to go through them. Don't worry. Here are examples for all kinds of fields that you  will probably ever need. And there are plenty of those. And to make things even better, there is a  screenshot for how these field sets, also also these fields look like in Plone Classic,  all of them. And also how they look like in Volto in Modern Plone. Six. So you can check them.  They, some look a bit different, handle a bit different. That's all discussed here. And on,  to make things even better, there is a Python package that has this content type and it's  installable. And it is, where the heck is it? I should have added a link to that. Example. Come on.  Example.con, I obviously forgot to add the link. It's called example.content type.  It comes in two branches. One is called Volto and one is called master. Because some fields  don't work in Volto. They are fields that you don't usually use. For example, time delta,  which stores the difference of time, which is why would you need a field for that? Yeah. So,  and so this is where you can, you can install that. You can check that and look at the, here's  the schema for Plone Classic and here's the schema for Volto, which has a couple of fields are  commented out because they don't work. For example, the data grid field, you can use that,  install that and play around with these packages or you just copy and paste the schema from here.  There is more. There are third party packages in here. The data grid field, which is in Plone  Classic and the excellent addition to Plone to add an arbitrary number of lines of, again,  schema defined data. So you have, for example, the field would be talks, but the talks are not  content types itself, but a simplified schema with title, speaker and type of talk. And you have  an infinite, can add an infinite number of rows of that data to that. And something very similar  is the mixed field that Katja, I think, created where you have something, again, a data grid  where you can add rows of data that are defined in a schema. And the code for all of this is here.  You can have that. You need the object list widget to display to be able to import that data.  And then you have these kinds of items. You will actually see these at a later stage  in some of the blocks in Plone. For example, no, I'm not going to jump ahead there. There's a search  block or actually the collection. The collection has, you can have defined criteria and each  criterion, you can have infinite number of criteria is similar to a data grid field or  these kinds of blocks. And that's the code for that. Here's some links to widgets. And there is  also information in this chapter. This is why you really need to keep this bookmark, because it has  all the information what you can do on top of that with the schema, because I went over that.  Here's a directive to change the widget of the choice field to a radio field widget  to make that radio buttons and not a drop-down list. So you might wonder, yeah, why did I see a  drop-down list then? Because this radio field widget doesn't work in Volto yet. There is only a  radio field widget for Plone Classic. So when you edit a content type, this content type in Plone  Classic, you get a different widget. This one instead of a drop-down widget, because I think it  is stupid to have a drop-down if you only have three options. If it's 50 options, obviously you  want drop-down and not radio buttons, because you'll have a full page of radio buttons, which is  horrible. So you can define the widgets here. And there is more. There's validation. You can  constrain the data. You can have methods that are then called upon entering the data automatically.  They're called. And they can raise an exception if the date, for example, of an event is after  the start date of the event. Or you can't start after you already stopped, obviously.  Then a default factory or default values. What else is there? There's an invariant to validate  data, a context aware. That's it. You can do basically everything with these couple of snippets.  So we've reached the end of today's training. And next up, tomorrow morning, no, not tomorrow  morning, tomorrow afternoon, at least for us Europeans, we will realize that our schedule  is, the talk is nice, but it looks terrible. We want to display the data. So Katja will walk you  through creating a view for this talk in Plone in Volto with the new front end. And if you're  so inclined, you could also look at the old version of that, where we discuss creating  view for the same content type in Plone Classic, which obviously works completely different. You  write page templates in Chameleon, while here you write your page templates, which are not page  templates as view components in React. So that's an exciting chapter for tomorrow. If you want, we can,  if you have any questions, we can discuss them now. We don't need to go right away. Obviously,  there at some point, there is dinner in Sorrento, I think at 8 for Katja. But if you have questions  or feedback, ask it now or in the chat and we will answer that tomorrow morning before  Katja starts off with this chapter 23. Yeah, I think we should start tomorrow with  10 minutes questions and answers. But if you have no questions, that it would be good, then we  would be better prepared tomorrow. Yeah. I guess we drown you in content.  Don't be shy. If you have questions, you can also ask us by email or in the Slack. We'll see  that tomorrow morning. Slack will be open all day, all night. Obviously,  stop sharing my screen. Maybe for those who are still there, a sneak preview  as a motivator for what's coming tomorrow, we're probably not going to get as far as we did last  year. But after we created this, the visual representation for talks, you will probably  learn, unless you already know all of that, a lot about React components and what nice tools you  can use there to make beautiful pages, renders. We will learn about behaviors to extend the  content type. The content type is there to extend clone with a new content type, obviously,  and behavior can be there to extend that content type. It's like Lego. You put these little  Legos. It's even better than Lego. I don't have a reference right now. But we can extend  this piece with something that already exists to give it more features and more functionality  without writing a single line of code, which is extremely powerful. The best code that is  created in this training is the one that is not written, but is reused by just plugging the right  components on top or together, just connecting the right dots. That's what we're going to do  in the chapter 24, also 25. We're not going to write a lot of code there. More complex code  will be the listing view for talks. That's more React for you. We'll discuss, I love chapter 30,  where we do a small change to give a lot of power to existing content types again. If we can get  there, we'll add customizable functionality, a control panel where you can configure the site.  Here in clone, you can go here to the control panel and configure all kinds of things. Obviously,  you can do that with your own add-ons to say, I don't know what types should be listed in what  kind of listing block and stuff like that. You can do whatever you like to extend flow. That's  super powerful. That's the whole idea of this training to teach you about these little components  that you can hook into to reuse them. Because clone is already so big, most of the requirements  you get from your projects or your clients, you won't have to write a single line of code for them,  because they either exist as an add-on or as a feature that you don't know, or as a combination  of these two. You just combine this add-on with this feature and what are they? That's the magic.  I don't see any questions. Katja, what's for dinner in Seren to?  I don't know. Sorry. The restaurant in Seren to is excellent. If you ever get a chance to go to  Plone Open Garden, which usually happens in spring and is now not Plone Open Garden, but the Plone  Conference Fan Zone, the restaurant on top of the restaurant with a beautiful view of Mount  Vizouvius, has gorgeous food. It's just terrible. You come back a couple of pounds heavier than you  went there, probably. I always do. Okay. Any last words for today? Thanks for bearing with us.  Thanks for listening. I hope we didn't bore you to death or overloaded you with information.  The good thing is you can always re-watch the video on YouTube, make it slower or faster,  or skip chapters. The second good thing is you can read all of that, or most of that, at least,  in the online training. Thanks for tuning in and have a great evening and talk to you tomorrow.  Good appetite. Katja. Thanks for attending and hope to see you tomorrow.
Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_0_659.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_660_791.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_792_1583.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_1584_4547.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_4548_6323.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_6324_6503.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_6504_9683.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_9684_12407.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_12408_14207.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_14208_14819.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_14820_18455.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_18456_22775.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_22776_24059.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_24060_25691.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_25692_28283.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_28284_28391.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_28392_28571.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_28572_29303.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_29304_29483.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_29484_31211.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_31212_31631.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_31632_33311.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_33312_34343.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_34344_35507.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_35508_39215.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_39216_39335.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_39336_39503.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_39504_39611.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_39612_42983.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_42984_43319.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_43320_43583.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_43584_45095.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_45096_45863.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_45864_46091.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_46092_49871.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_49872_53963.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_53964_56531.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_56532_58079.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_58080_58631.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_58632_58967.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_58968_59243.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_59244_59387.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_59388_61703.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_61704_62363.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_62364_62987.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_62988_63071.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_63072_64199.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_64200_66383.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_66384_66803.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_66804_69143.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_69144_69587.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_69588_70355.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_70356_70727.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_70728_71159.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_71160_71675.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_71676_72479.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_72480_72995.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_72996_73199.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_73200_74039.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_74040_74339.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_74340_75167.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_75168_75827.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_75828_77831.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_77832_79163.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_79164_79271.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_79272_80375.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_80376_80435.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_80436_81623.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_81624_82307.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_82308_83531.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_83532_83759.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_83760_85079.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_85080_85127.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_85128_85751.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_85752_86351.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_86352_86399.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_86400_86855.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_86856_89843.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_89844_90095.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_90096_90743.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_90744_92195.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_92196_92471.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_92472_93467.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_93468_94415.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_94416_95591.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_95592_97007.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_97008_97967.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_97968_98039.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_98040_98675.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_98676_99683.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_99684_108827.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_108828_109523.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_109524_109703.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_109704_112115.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_112116_115739.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_115740_120167.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_120168_123839.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_123840_124187.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_124188_125699.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_125700_126407.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_126408_126803.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_126804_127007.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_127008_127055.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_127056_128135.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_128136_128195.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_128196_129383.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_129384_130007.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_130008_130079.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_130080_150779.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_150780_151523.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_151524_152699.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_152700_152747.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_152748_153143.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_153144_153935.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_153936_154199.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_154200_154835.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_154836_154883.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_154884_155015.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_155016_156443.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_156444_157871.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_157872_158867.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_158868_159155.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_159156_161171.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_161172_164639.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_164640_164723.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_164724_166379.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_166380_166991.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_166992_167207.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_167208_169619.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_169620_170735.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_170736_170807.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_170808_172247.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_172248_174083.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_174084_174827.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_174828_176771.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_176772_176819.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_176820_177119.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_177120_177167.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_177168_177491.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_177492_179147.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_179148_179555.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_179556_181667.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_181668_182651.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_182652_186467.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_186468_186791.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_186792_188183.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_188184_188519.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_188520_188579.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_188580_188675.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_188676_189707.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_189708_190871.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_190872_193775.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_193776_195851.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_195852_196379.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_196380_196571.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_196572_197087.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_197088_197711.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_197712_200831.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_200832_200987.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_200988_201743.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_201744_202043.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_202044_204203.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_204204_204743.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_204744_205415.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_205416_206411.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_206412_210335.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_210336_211199.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_211200_212495.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_212496_212687.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_212688_224555.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_224556_228383.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_228384_229091.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_229092_231419.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_231420_232115.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_232116_234443.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_234444_235595.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_235596_235727.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_235728_237671.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_237672_238523.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_238524_238859.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_238860_240191.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_240192_240407.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_240408_240467.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_240468_240599.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_240600_240659.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_240660_240887.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_240888_242375.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_242376_242903.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_242904_243323.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_243324_244031.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_244032_245363.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_245364_249107.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_249108_250847.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_250848_250943.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_250944_251339.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_251340_254939.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_254940_255011.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_255012_256043.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_256044_259115.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_259116_259211.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_259212_259835.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_259836_262079.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_262080_263663.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_263664_264119.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_264120_264203.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_264204_267623.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_267624_267803.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_267804_270863.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_270864_271523.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_271524_272795.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_272796_272999.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_273000_275039.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_275040_275699.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_275700_280115.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_280116_281735.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_281736_283439.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_283440_283523.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_283524_283907.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_283908_284147.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_284148_286163.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_286164_286247.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_286248_288515.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_288516_291347.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_291348_291599.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_291600_291647.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_291648_291839.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_291840_292799.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_292800_293651.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_293652_294119.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_294120_294851.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_294852_300119.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_300120_302903.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_302904_303047.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_303048_304067.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_304068_304115.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_304116_307187.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_307188_307871.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_307872_311783.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_311784_311963.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_311964_312047.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_312048_312155.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_312156_314003.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_314004_315155.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_315156_317207.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_317208_317399.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_317400_317675.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_317676_318599.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_318600_318695.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_318696_319367.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_319368_319643.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_319644_320795.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_320796_321023.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_321024_321527.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_321528_321875.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_321876_323243.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_323244_323891.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_323892_324227.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_324228_324815.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_324816_324959.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_324960_325271.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_325272_326003.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_326004_326927.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_326928_326999.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_327000_327611.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_327612_328751.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_328752_334595.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_334596_334787.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_334788_335111.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_335112_335171.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_335172_335483.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_335484_335675.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_335676_336347.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_336348_336611.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_336612_338219.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_338220_339287.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_339288_339395.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_339396_339551.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_339552_339755.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_339756_339863.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_339864_339935.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_339936_340091.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_340092_340235.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_340236_340319.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_340320_340727.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_340728_341747.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_341748_342167.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_342168_342359.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_342360_342587.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_342588_345155.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_345156_346499.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_346500_346583.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_346584_347111.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_347112_349235.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_349236_349931.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_349932_355931.png Mastering_Plone_6_at_Ploneconf_2021__Part_1_of_2_Jzuw3uWtzzI_355932_359233.png