 All right. Good morning, everyone. Welcome to our very early morning session, at least for me, I don't know. My name is Tony Savarelli. I work as a senior web architect at Pegasystems, software company based in Cambridge, Massachusetts. And this is Hector Lopez from Stryker Lingo Tech. He will introduce himself in a second. We're used to talk about plugins. It's going to be a two-part presentation. That stems from our recent collaboration between our web team, and by that, I mean myself, mostly. And the Drupal developers at Lingo Tech, I think we can just get started. It's going to be about 30 minutes, depending on how fast I talk. And then we'll leave room for questions. No, it's sorry. Hi, everyone. So like Tony said, I'm Hector Lopez. I'm a developer for Stryker Lingo Tech. It's a translation services company that has a Drupal module. So we've actually met some of you and invited you here. So if you don't know who we are, we have a booth right with the other vendors. Next to the coffee in the bathrooms. So pretty easy to find, kind of hard to see. And also, just ignore the shaking and the voice quivering for my first Drupal con. I decided to do trainings, be a vendor, and come out here to speak. So trifecta. Let's get started. All right, so there's different ways of extending your module. Some of them are events and hooks. Events are based on, just like JavaScript events, they're based on events that you can subscribe to and modify your code that way. Hooks, they allow external modules to modify your data and perform actions when they are invoked. But again, you have to kind of attach those hooks when they're invoked, so your code can be run with them. Plugins are more of a design pattern that uses interfaces to extend and decouple those modules. And as you'll see in some of our examples, you can extend multiple parts of the plugin pattern here. So in Drupal 9, there's three main parts of this design pattern. And two of them actually combine. So there's the plugin types. And the type is the class that defines how plugins of a specific type are going to be discovered and how they're going to be instantiated. And the type works together with the discovery to create the plugin manager, which we'll talk about in a bit. But the discovery of the plugin is the process of finding the plugin within the code base. So that's the specific type so that you can have different types of discoveries. The most common one is annotation, which we'll have an example of. There's also YAML-based discovery, which is mainly used for menus and views and links. There's also hook-based discovery. That one's mainly used for legacy support. It's not used very often. And then there's also static discovery, which is mainly used for testing code, so it's not used. It's used even less frequently than the other ones. And then the third part of the design is the factory, which is when you actually instantiate the plugins. So a very simple plugin has the manager, as we discussed earlier, which is the type and the discovery together. So once you've had your manager define and your discovery added to whatever you're using, which would either be annotation or YAML, then you create your plugin interface. And that's different from a plugin base. The interface tells the plugins what they're required to have. And you can extend that in any way. A lot of plugins use a plugin base as a kind of base class that then you can extend, or you can just leave the interface by itself and have plugins extend that on their own. Show you an example of, so this is an annotation in the services file for Lingo Tech. So as you can see, you have there the class that defines the plugin manager and most plugins will have their parent as the default plugin manager. So this is how you add the discovery. And then this is an example of a plugin manager itself. As you can see, it's extending another manager. And that manager is also extending the default plugin manager itself. So that's one of the nice things about plugins is that you can extend multiple parts of a plugin. You can extend manager. You can extend the annotation. You can extend the interface even. So it really reduces the duplication of code. And it also helps you override methods much easier. So as you can see here, I'll kind of explain what the constructor does as well, since it's not very clear right here, since it's not the parent manager. So the first part, yeah, so right here, oh, here we go. So right here is the plugin subdirectory location. The next part is the root paths that are keyed by the namespace to look for plugin implementations. And here is just the module handler. And then you've got your more optional parameters here. So this is the interface that the plugin will implement. And then this is the annotation that defines the plugins that will be used. So this is an example of a base class annotation. So as you can see, we've already defined everything here. The plugin ID, title, group, the weight, the form IDs, and the entity types. And we can even extend that annotation on itself. This one doesn't add very much to it. But if we needed to, we could add more to the annotation. So that's a very simple overview of how to start your plugin manager and discovery out. And then from there, you can go on to define your plugin interface and your base class. But yeah, so there's never enough room in here. I'll get it. Why plugins? These are only a few of the reasons why it's a good idea to use plugins on your sites. First of all, and why plugins exist as a design pattern in Drupal 8 Plus, let's call it. 9 Plus at this point. First off, they allow for more customization when extending Drupal Core. More than what hooks alone would allow, it's more flexible. It allows you to use less code and to just override the parts that you really need on a case by case basis. In addition to Drupal Core, they also allow, and this is the main reason we're doing this, they allow you to extend and decouple contributed modules to other modules. You can't create a tiny little module or large module that whose only purpose or whose main purpose is to modify parts of a different module to change functionality, user interface, you name it. But also if you're just like in the case of our web team, you have many websites, many for me. They're only about eight, so it's not a huge amount of websites. But even if you have more websites that have some core functionality that pertains to all of them, you will also be able to provide plugin types and plugin systems within your own ecosystem to specify more targeted functionality and UI elements through the plugins. So when to implement a plugin or a new plugin type? Hopefully, well, you're not going to have to. Because in the end, Core and the better architective modules, contrary modules, they already implement most or all of the necessary plugins. So you don't have to. For example, views in the Drupal 8 Plus views architecture, everything you see when you go to the views interface ultimately is a plugin. Fields or plugins, filters or plugins, everything else. Contextual filters are also plugins and all that. And it's almost never necessary to add your own field plugin because the entity system and views integrate perfectly to provide everything you need. The field system is also mainly composed of plugins, field types, field elements, widgets, four matters. They're all plugins. And it can create your own to extend what the basic functionality is. On the other hand, you can have, sorry, I need to be able to bring my notes back. I mean, I know what I'm talking about, but still. You might have, on the other end of the spectrum, you might have API only or API first modules, such as one of my favorites. It's clunky sometimes, but Display Suite is one of my favorite modules of this kind, which are not useful by themselves. Well, they are useful, but they're not doing much by themselves, especially when it comes to creating new display field types. If you've ever used Display Suite, that's the kind of thing you need to do. You're going to have to implement plugins of different types to achieve all your entity display goals. But then there's somewhere in between where a module provides some basic functionality, but you might want to extend that in a way that adapts more closely to the needs of your specific application. And this is where our real-world example comes into play. So I actually did another talk a couple of days ago about the work that I've been doing for the past couple of years as a localization developer, a Drupal localization developer at Pegasystems, where I found myself, I don't want to repeat the talk that I gave the other day, but I found myself needing to integrate to the API integration between our two main localization vendors. One is Lingotech, which has a very good integration, and the other one was a different vendor, which could be integrated, but it wouldn't interface directly with Lingotech. So I found myself with a Lingotech module, which is great, and it allows us to connect to Drupal to the Lingotech service very well. But I also found myself with years of internal legacy code that was overriding what the Lingotech module was doing in a way that was not unsustainable. Originally, we've had one site that was being localized. We had the prospect of localizing more and very complex ones at that and writing what we could call spaghetti code to override forms on the fly, and all of that was not, wouldn't cut it anymore. So one of the things that I did was to create a, I always forget to advance one of those. One of the things that I did was one of these options. So when you're faced with a module that does what you want but doesn't do all the things that you want or doesn't do the things that you want exactly the way you want them to, you have a few options. The ideal thing is to start a collaboration. Sometimes it just works. We're here, so the collaboration has started. But sometimes collaborating with people from different teams and different companies means that you're gonna have to wait for things to happen. Contributing code takes time, code reviews take time, and so it might not always fit with your internal timelines. On the other side of this, the cumbersome and dangerous option of forking the module. I could have taken the Lingotech module, created my own little Lingotech module and spend the rest of my life trying to keep up with all the changes that the original module would inevitably implement. Don't do that, don't fork, if at all possible. Superficially less cumbersome is to patch the module. If you have only one site to handle, that's sometimes okay. Patching is a useful thing to know how to do, but unfortunately it takes effort. It's, again, it forces you to keep up with all the changes, create new patches, and again, if you have only one site, patching is easy. If you have two, three more sites that need the same patches all the time, especially when all these sites are handled by different sub-teams, it becomes unwieldy, and so not recommended. The happy medium is to extend an override, and if the original module is extensible out of the box, great, if it's not, and frankly, it's almost impossible for a good Drupal 8 Plus module not to have extensible parts. So I targeted those extensible parts, meaning forms, services, mainly forms and services, created my own plugin types to make the parts of the system that I needed to be more flexible, more flexible, and then contributed my own module, which is how I got discovered by the Lingo Tech guys, and that's where really the collaboration started, because at that point, what I did, it's not that I'm not self-clarifying here, it's not that what I did was so insanely good that they just had to have it, but it was the embryo of a good idea to help us, me, give back to the community, in this case, to the Lingo Tech team, and I think it's a great example of the open-source community at its best. So, sorry. So the reasons I had to create new plugin systems, well, in this specific case, was to standardize the existing interface, reduce code complexity and favor separation of concerns so that even if we did have some very specific internal only needs to, say, add a field, or add a column to a table, or add a special filter that was only useful to us, we could do it without writing bad code to just keep it simple. And also, more useful to our localization specialists in our case was to easily add new functionality and interface elements. And in my specific case, allow us to integrate with yet another vendor without any need for the two vendors to even know anything about each other from a technical perspective. I mean, in person, they know about each other. So this is... Is it fuzzy? It's fuzzy here. I don't know why. So this is an example. Actually, that's not an example. This is an example of a Lingutech administration form. It's the before. Before any of my code comes into play, this is taken from Peg Academy, which is our developer training platform. This is just to show you. It's an example. So this is the way the table works. So this is a giant form, list of entities that we can perform operations on, send the content to Lingutech for translation, bring it back, and so on. We have all the content type column, bundle column, the other fields that pertain to the status of the translatable source and the translated targets and all of that. And this is not a view, by the way. And the main reason is that in some cases, in the case of the Lingutech integration, we might need to display within the same table entities of different types, not entities, not different bundles, but really different entity types. Because especially, particularly in this form, we need to be able to display related entities that are not nodes. And views does not do that out of the box. And frankly, we could have extended views, but that's a big can of worms nobody should ever have to do to open. So we went a different way. Every now and then, we wonder whether we are rebuilding views. The answer is maybe, but also maybe not. So far, it works. And the next slide is the after. It's not quite the same, but my local decided to stop working the moment I had to really send in those slides, so sorry about that. And also, I'm using the JIN admin theme, and it doesn't play well with some of the customization that we did to the UI, so we're working on that. It will be prettier. So the difference, some of the differences that are more obvious are, for example, I'll go back and forth. We added, back, forth. We added a entity ID field, for example, here. There are a couple of fields, content, sorry, what's it called? Current revision and latest revision, which are specific to content moderation. I've been doing a lot of work on the interaction between content moderation and content translation. I don't wish it on anyone. So that's part of it. Those are new fields. The last field there, TMGMT, is part of that other integration that I added. All these columns that don't exist in the before screenshot are all basically field plugins that I was able to add thanks to the addition of a plugin system to the Lingotech module. Well, initially, to my own contributed module that overrode the form, that then added the ability to discover these new plugins, specifically fields, filters up there, not pictured, and operations up in the bulk document management. As part of our collaboration, some of these plugin types, specifically for the time being, fields and filters on this interface, are a little bit of time being moved to the main module, so actually the version 4.x, let's call it, of the Lingotech module will include some of these new plugins, which has a very beneficial effect for me, really, which is I won't have to maintain them as closely as I've had to so far, so that's great. Thank you, guys. Hector earlier showed you an example of one of these plugin types, which is the, it's a mouthful, so it's the Lingotech form component field plugin type in the form of, you saw the plugin manager, you saw the annotation for the plugin, and I'll just go back very quickly. This should be sleeper, but it's not. So this is the, again, this is the annotation, so what the annotation for this plugin type does is provide the idea of the plugin, that's necessary, the title, which in the case of a table, of that table's column becomes the header of the column, then the group, not actually needed in this case, I won't go into it, the weight as weight, we've all seen weight, presumably. If I say weight, is anyone, okay, okay. And the form IDs are, again, our way for the plugin manager to know when to display a certain, when to discover, and when to display certain plugins, and entity types, again, if we want to target specific entity types for a certain plugin, we can do that. And this is specific to this plugin type. You have other plugin types, of course, that are not related to forms or anything, that will have different properties. The annotation class will allow you to define what the properties of the plugin are. And going forward to the example, this is what the plugin looks like. This is the plugin for the entity ID, so the first column that appears on the stable here, it's very simple, it doesn't do much more than just grab the entity ID from the entity and just spit it back out on the page. But this is what the annotation looks like. It's in a comment. We are saying, we're telling the system that this is a LingoTech form component field plugin, and these are the properties that we saw in the annotation class. So the ID, the title, the weight, I really want the weight to be low, and the form IDs on which this column will appear. In this case, I actually targeted all the possible forms. Well, actually, it's not all the possible forms. Shut up. No, that's not true. I targeted the forms that I needed. And then we have a couple of methods here that get the job done. So actually, this is old code. So some of this is not actually... In any case, the get header allows us to display either the title as it appears here or a custom title. Get data allows us to get the data. Sorry, I can't say any simpler than that. And then sort is a way to provide the tables, the table column's sortability. And in fact, I think if we look at it, it's not super clear, and also this is just a screenshot, but these are clickable, and we should be able to sort the table. I think... Why is it not showing? Well, there was another slide, presumably, with a series of links. And we don't have that slide for some reason. Great job, PDFs. So presumably, we can provide that... I don't know if this... We'll make sure that if the slides are made available, they'll have all the content that they need to have. So this is all we have. This is... I think the main takeaway from all of this is plugins are awesome. I know it's very... Plugins are really great. They are a little daunting, especially if you come from a Drupal 7 mindset. But many things in Drupal 8 Plus are plugins, including entities. They are defined as plugins. So that's a very useful thing to know. It makes... Plugins make module extension much easier. It makes... They make collaboration much easier because you don't need to necessarily rely on somebody else's work to get your job done and get to the place where you want to get. And so they are really useful and indispensable, really, not just useful concept to know more about. That's it. Any questions? Thank you. Are there any questions? Why don't you come up here so that we can... The microphone is not portable, so... Sorry, it's not on because... Hello. Thank you so much. You were talking that with a great architecture in Drupal Core, we are using plugins, for example. And you also mentioned that the mindset with Drupal 7 was not using, for example, plugins because it wasn't available, of course, with hooks and so on. What do you think about this possibility? Because, for example, one point that is not so good is because we have a lot of possible to do the same thing. So, for example, in Drupal 9, we can use plugins that is the best approach, in my opinion, of course. But there is a way to continue using like Drupal 7. So it's like a problem. So we need to change the mindset. So, for example, now we can use plugins, and it's better, and after learning that, we can start doing that. What is your opinion, the first point, about a lot of possibilities to do the same thing in Drupal? And the second one is, do you have some recommendation about how to teach our junior developers, new developers, about how to use plugins and something like this, just to recommend? Well, I'll start from the end. I think junior developers are the least of your problem because they are learning, and so it's easier to just send them off on the right path. I think... So, I've been working with Drupal for 16 years. I started with 4.7. There was nothing like this, and getting to embrace plugins was not easy because it was just a different mindset. So I think targeting more seasoned developers is really what you really would have to do. And ultimately, it's the direction that Drupal has taken. It's not the direction it's taken. It has taken this direction. Hooks, I suspect, eventually will disappear, go away. So I don't have a recommendation because if you want to keep working with Drupal in an efficient and mind-saving way, I think it's important to do a lot of internal, almost advocacy to make sure that everyone is aware that there are new ways to do things. At Pega, we do a lot of... I don't know where you work and how large your team is, but we do a lot of internal demos, like we have almost weekly demos about one part of the technology or other, and sometimes about something else, which is also important. But it's important to make sure that everyone knows what's new, what's coming, what the advantages are, and I think that's my two cents, really. Do you have opinions? Well, just a little bit, because I started with Drupal a couple of years ago, so Plugins was new to me at the time, too, because I started with Drupal 7, so I was more familiar with Hooks. But I think, like Tony said, it helps to have your more seasoned developers also be willing to change their mindset. The developer who trained me on Drupal 8 and Plugins was more willing to do it the Plugin way instead of being stuck with Hooks. So it really depends on the mentor of the new developer. Anyone else? I was just curious, when you become the collaboration with the people with the original module, is it easy to bring the Plugin architecture into the module? Is that hard, or do you have to do a lot of conversion? Well, in the end, I'm not going to do this, because it's a little easier for me. Well, each developer has their own way of doing things, and they're all mostly correct, I think, except my own. So, you know, there's always going to be a process of adapting what, in this case, the specific Plugin system or several Plugin types will adapt in the way they work and they look and they're architected to the destination module. I mean, if you're just writing a new module, you can do pretty much whatever you want, but that's communication, mostly, I think. And we have been communicating for a couple of months, three months at this point, and it's a long process, especially because it might not be your main focus on your daily work. Yeah, but I think in the end, if we're all clear on the path to take and what we really want to achieve, talk about it, do code review, discuss, and nothing is insurmountable in the end. But yeah, it's not like something that happens overnight, for sure. I don't think so. I might be wrong, but yeah. I'm not sure how Christian, I mean, we were in touch as companies, but I'm not sure, like, one day he just slapped me and he's like, oh, I saw your module. And I'm like, oh no. Busted. Sometimes it's just somebody opening an issue saying, hi, I created this. Well, if you're on the other side of the issue or the one who's extending somebody else's module, I think the best way is just to create an issue and at some point, which I would have done, frankly, but time is always, anyone else? I'm gonna take it as a no. So thank you again for joining us today. I hope we were informative and somewhat entertaining as well. So have a good last day of DrupalCon.