 There are more seats up here. You guys come up here quick before I start. All right, I think we're a quarter after. So thank you everyone for coming this afternoon. I'm going to talk about Drupal 8. Where did the code go? This is a story about converting info hooks to plugins between Drupal 7 and Drupal 8. This is kind of the outline of what's in the talk. So I'm going to give you just a tiny bit of background about Drupal 8. Hopefully everyone knows enough that this won't be overwhelming in terms of the Drupal 8 terminology. I spent quite a bit of time talking about plugins, plugin system, plugin managers. Do a little back and forth comparison between Drupal 7 and Drupal 8 in a few different places. So in particular, I'm going to show you a conversion of an info hook in Drupal 7 to a plugin in Drupal 8 and show you that the code is really one to one. There's not different code in Drupal 7 and Drupal 8. It's just located in a different place in a different file. Then I'm going to talk about how you would use the plugin system in Drupal 8, which of course means writing your own custom module. So I'll show you a really easy example you'd probably do. One of the first things to the module, add some tabs to a page, local tasks. So there was a way you did that in Drupal 7 involving hook menu in Drupal 8 that's done through a plugin. Then talk about a couple more, slightly more complicated plugins, but not much more complicated. Custom block and a custom text filter to show you how you could implement those. And a custom module and wrap up with some considerations. If your module basically wants to provide an API, wants to provide a plugin type, just a few thoughts on best practices around that. So this is me, a bunch of facts about me. Hopefully you believe that I know what I'm talking about. In particular, I did help in Drupal 8 create several of the plugin types, including at least one I'll be talking about today. So converted the search plugins from hook search info and help break apart hook menu in Drupal 7 into Drupal 8. So we have menu link, menu local tasks, local action, and contextual link plugins. Also do Drupal organizing, and I'm on the Drupal security team. So important Drupal 8 terminology. So these are things that you'll be a little lost with because I'll keep talking about them during the rest of this talk if you don't know what they mean. So the first thing you'll need to know about is the dependency injection container. You'll sometimes see that called the DIC, you'll sometimes see it called the container, the service container. These are all referring to the same thing. This is just an object that gives you other objects. And the objects it gives you are services. And those are basically stateless utilities that the current Drupal request is going to use. They may be things like the current logged in user, the current request, the URL generator that generates a path from a route. And it can also be the plugin managers. And I'll come back to that later. You also need to know about the new routing system. So Drupal 8 basically adopted at least sort of the facade of the symphony routing system, though actually a lot of the code was ported also from Drupal 7 because the symphony system doesn't handle the scale of Drupal routes that we needed. So the key difference is that you refer to a route, which is basically a page that Drupal is going to render by a unique machine name. So it's a route name. And the path is no longer actually unique. So more than one route can refer to the same path. And that's sort of an edge case, but can be really useful if you want to do something like have different routes sort of get requests and post requests to the same path. You could do that in Drupal 8. You couldn't do that in Drupal 7. So a route name is just a machine name. It links to information like the path to callbacks, provide the content, the title, the access checks. So this is just like a menu router in Drupal 7 where you had the page callback. You had the access callback. You had the title element, all these things. Again, conceptually, Drupal 8 is not that different. It's just we put these things in a different place and we're using a slightly different notation to define them. The last thing I'll show you a bunch of is namespace classes. And this has been a feature since PHP 5.3. And then what it looks like is at the bottom there where Drupal search plugin block, search block, is the name of the class. So the class name is that whole thing, but those backslashes basically give you logical separations in the namespace of the class. And you can see how it kind of builds up from starting from Drupal, the name of the module, and then the type of the class, and finally the class name. Okay, so this talk is about plugins. And to give you a really formal definition, plugins encapsulate some reusable functionality in a class implementing one or more specific interfaces. And all those things are really important to wrap your head around. So Drupal 8, we're using classes. The code is going into class files. And these classes have to implement interfaces. And this is actually one of the really important features of Drupal 8 that because we're implementing interfaces, we can change the implementation of almost anything in Drupal 8 core. Because as long as your version implements the right interface, you can substitute it for the version that comes with Drupal core or that comes with one of the modules. So this use of interfaces, the fact that we're using interfaces to decide what to do rather than specific concrete classes is really important in Drupal 8. So plugins in Drupal 7 and Drupal 8 are basically a combination of things that we had in Drupal 7, but they were a little bit spread out. So in Drupal 7, we had info hooks and then we had implementation hooks. So this is not too common to have implemented, but if you've ever implemented hook search info, a hook search info was just a return and array of data. And that array of data gave you some things like the title of the page or something. And but Drupal core search module knew that if you implemented hook search info, you must also somewhere be implementing hook search execute because you wouldn't have implemented the info hook unless you also provided the execute hook to implement the search, right? But there was really those two things might not be grouped together, they might not be in the same file. And Drupal actually didn't have a good way to enforce that you implemented the execute hook if you implemented the info hook. Similarly, probably most people here have written a implementation of hook block info. If you've written a Drupal 7 module, that's one of the first things someone has to do, make a custom block, put something in it, put a widget in it, right? So if you implement hook block info, it returns an array, or the array is just a list of blocks your module provides. You also had to implement hook block view and possibly hook block configure and hook block save, right? So again, you see this coupling of an info hook that gives you metadata, gives you the list of the things with an implementation hook that actually provides the code that returns the content that's gonna be printed to the page. So plugins in Drupal 8 basically wrap those things together in one logical unit. So it's the functionality combined together and that interface is kind of like that hook system where we know the naming of the methods that we're gonna call to make it work. So Drupal 8 plugins evolved from C tools and views plugins in Drupal 7. So if you've used those, a lot of the concepts apply to Drupal 8, but the discovery mechanisms which I'll talk about in this talk are quite different in Drupal 8 than what we used in Drupal 7. So every plugin type has a plugin manager. So the plugin manager is a service that's in that service container. So Drupal provides you ways in your modules, in your code, if you want to get a service to just grab it basically using a machine name, the service, you have to figure out what the right machine name is for the plugin manager you care about and then you could get plugins. Usually you're not gonna be directly doing this unless it's the plugin type that your module defines. Usually this just happens behind the scenes for you. But the plugin manager is that service. You basically give it a plugin ID and it will create a class instance using that plugin ID and maybe some configuration values. So each plugin has an ID and you'll see plugins that have the ID in their definition, they're just a static string. They also can be generated as derivatives and derivatives, the IDs might look like something like a combination of a static string and a UUID. So there's multiple, different versions of the same plugin with unique IDs generated from one base plugin. For a given plugin ID, that's always gonna map to one class. So there should be one to one mapping between plugin ID and the class implementing it. But a little tricky to get your head around is that you can actually have more than one instance of the same plugin with the same plugin ID. And that notion of instance is a combination of the plugin ID, the class instance and configuration values. And those configuration values almost always in Drupalator coming from a configuration entity. I'll come back and talk more about those later, but again, just trying to introduce these concepts. So plugin instance, I instantiated class. It's a plugin ID that maps to a particular name of a class and then I feed it some configuration values that can come from config entity and that gives me the instance that's gonna do one specific thing that I want. So, do people know the saying? Dree has kind of referred to it in his keynote. Also, if you went to that, the drop is always moving, which is the Drupal philosophy that we're gonna break code compatibility between versions, right, but allow you to migrate your code forward. But part of my goal of this talk is for you to leave feeling a little more comfortable with Drupal 8, especially if you're a Drupal 7 developer, so that you understand that Drupal hasn't actually changed that much. It's that the code moved, right? So what you need to kind of figure out is Drupal 7 developer, if you're looking at Drupal 8, where did the code go? Yeah, where do I find it? How do I understand how this new system works? But most of the Drupal concepts, the way Drupal works, are still fundamentally the same as it were in Drupal 7. The code is just a different place. We brought in some libraries, but it's still Drupal. If you haven't ever seen that philosophy, there's a link to the handbook page where it's quoted in depth. Okay, so to give you some of that comfort level about the comparison between Drupal 7 and Drupal 8, we're gonna look at hook image toolkits. Now this is kind of a red herring because it doesn't have the name info in it, but this is an info hook. So all hook image toolkits gives you is basically a data array back. And you can see that data array there. The top level key of the data array is GD because this is the GD image tool kit. Then we have a title key and a value that's a translated string. And then we have an available key and that's dynamically set to true or false based on whether the GD function is available. Right, straightforward. So let's look at how that works in Drupal 8. So Drupal 8, the image toolkits are plugins and the data describing the plugin, the definition of the plugin, comes from an annotation. And annotations are these specially formatted code comments you see at the top of the class file. And they, even though they're encapsulated in the code comment, they're actually parsed out and turned into an array and can have default values filled in and have validation. So you have to get the formatting of these annotations correct. And you can see here we have an image tool kit annotation. The ID of the plugin is GD. That's exactly the same as the array, top level array key in Drupal 7. So you see we basically have mapping one to one in Drupal 7 to Drupal 8 here. The title, which is marked as being translatable, is exactly the same string, translatable string we had in Drupal 7 in the info hook. And you see that this class has an isAvailable method and uses basically the same strategy checking if one of the GD image functions available to say that this plugin is available. So again, conceptually the code is working the same way. We've just moved, the info hook is now basically, that metadata is this annotation at the top of the class. And then the more dynamic part is the class method. And then of course I mentioned managers before, so the image tool kit manager is the one that actually uses this annotation to find the plugins. All that gets back from that annotation parsing is just a data array. So essentially the same thing as the info hook. And then it iterates over them and excludes all the ones where the isAvailable method returns false. So we end up here with basically the same thing in Drupal 7 and Drupal 8. We have a data array of available image tool kits and we flagged or removed the ones that aren't available. We can go in a little more depth and again show the parallelism between Drupal 7 and Drupal 8. So Drupal 7, if we wanted to operate on an image, we called image desaturate. Then that delegates to the image tool kit for the desaturate operation. You see here we're passing through the image object. In comparison in Drupal 8, the image object itself implements the desaturate method. So we just kind of reverse that a little. So now images are real proper objects that have methods on them. And in Drupal 7, it was just a standard class object, something really boring that didn't have methods. But it's still the same strategy here. You see that we're calling just a desaturate option. It's just a string key that lets us call back then to the image tool kit and ask the image tool kit to run the desaturate option. So again, the parallelism is there more or less one to one between Drupal 7 and Drupal 8. It's just that this code is moved from a function in an occlude file to being in a class, the image class. And finally, just to look even deeper at this operation, desaturate option, take it all the way to the bottom. In Drupal 7, all we did was take a bunch of strings, concatenate them together, and hope that function existed, right? And you guys know how this works. So we take image, we take gd, we take tchass, desaturate, concatenate them together, ask if that function exists, if it does, we call it. And you see that this then, as long as the built-in image filter function exists, we just run image filter on the image object and give you the result. Drupal 8 is very similar. We actually have here another level of plugins. So each operation is itself a plugin, so you could substitute the implementation of one of these operations if for some reason it didn't work on your server. But again, the code in this method executing desaturate is exactly the same as the code in Drupal 7. You can see we're checking exactly if the function exists, image filter. If it doesn't exist, we log an error and we return false. If it does, we call image filter on the image. That's it. So again, we have very much a one-to-one parallelism between Drupal 7 and Drupal 8, but you have to know where that code went to find it and see that clear parallelism in the functionality. Okay, so you may be thinking, all right, well, Drupal 7, I always worried a lot about hooks. Do hooks still matter in Drupal 8? And the answer is, of course, yes, because it is still Drupal. And even if we wanted to, we didn't have time to remove every possible hook from Drupal 8. And in fact, I think there may be, in some cases, more hooks in Drupal 8 than there were in Drupal 7, at least more possible hooks, because every one of these plugin managers implements an alter hook. So this is one of your strategies if you want to, as I said, you could replace something using a different class for the same interface. So implementing these alter hooks in your module is one of the easy ways to do that. So you can go ahead, for example, in hook block alter, and we'll talk about blocks more later, but in hook block alter, the plugin manager is basically just getting an array of all the blocks that are available in the system. And in your module, you could actually say, I'm gonna replace the class implementing a block with a class that I prefer. We'll look more in detail with those, but again, so alter hooks are still very important. Those could be in your module. Other hooks that look like info hooks tend to be gone, but they did not become plugins. So if you think about a hook that only returned a data array, like hook permissions. So hook permissions, there's no functions. There's no permission functions, like search execute. Instead, there's just an array of data. And so what happened in Drupal 8, that actually became a YAML file. So do people know the YAML format? Mostly some. So, I mean YAML, I'll show you a bunch of examples of it's a very pretty straightforward format to write by hand, it's related to the JSON format. But basically what happened in Drupal 8 is a lot of these hooks, like hook permissions, they just returned an array of data. We decided that it was even easier, not even to have it in PHP, just put it in a file, because that's a lot easier to keep track of. And then that file could just basically be parsed into a data array, because that's all the hook did. There are of course other hooks, like hook cron, hook entity access, that we didn't have any replacement for, so if you need to implement those, you'll still do them in your module. Okay, so I've alluded to plug-in discovery a couple times, and told you already a couple times that plug-in discovery, the thing you get back from the process is just a data array. So fundamentally, plug-in discovery is pretty much like invoking an info hook, except it's a little bit different, and your module can implement, can provide as many plugins as it wants, but it would have only implemented the info hook once. So there's a little bit of difference there. You can actually implement plug-in discovery as an info hook, if you really are attached to hooks, that's still possible in Drupal 8, though I don't think core does it anywhere except in tests. And again, discovery is a process, just think of it as an abstract plot process. The plug-in manager says, I'm gonna discover the plugins. The end result of that process is it gets a data array back. That's a list of plugins and plug-in definitions. The discovery process then fills in defaults, things like the provider, which is like which module provided that class plugin. And discovery again can make derivatives, so many from one. And I saw people looking a little confused when I first talked about derivatives, so I'm gonna give you a concrete example here, but then not talk anymore about them. But a concrete example so you can wrap your head around when you might want a derivative is the field UI local task. So field UI, so the thing that puts fields on entities wants to put a tab on every bundle of every entity type. So a bundle is like a node type and earlier versions of Drupal. And so field UI can't know in advance every bundle of every entity type because you might create a new entity type any day. So it instead wants to make derivative. So we will ask the entity system, tell me about every entity type and tell me about every bundle for every entity type. I'm gonna make a derivative, which is basically the tab that will appear corresponding to that entity and bundle. So that's an example when you might want derivatives where you have sort of a dynamic thing like entities and bundles that you might get more or less of and you want to have a plugin that corresponds to each one of those. So in Drupal Core, we primarily use two strategies for plugin discovery. So that's YAML-based and annotation-based. So the YAML-based, as I told you, YAML files are very popular in Drupal 8. And this is really just these four plugin types use YAML-based discovery. And those use YAML-based discovery because they're almost all used in the same class. And I'll show you a little bit more about that. Then there's a few that use annotation like I showed you for the image toolkit. So in that example, the annotation, that specially formatted comment at the beginning of the class is parsed and turned into that data array. And then there's a lot, a lot of plugins in Drupal 8. They use a combination of annotation and a configuration entity to make that specific plugin instance. And there's a huge, huge number of them in the views module, of course, because this sort of evolved from views. Also the block module, image effects, search plugins. So the majority of plugins in Drupal 8 core are using this strategy of annotation and then together with some configuration to make a specific instance of the plugin. And finally, the entity system. So if you go and pull open the node class in Drupal 8, you'll see it's got a lot of annotation. But it's sort of not a pure plugin. It's, it does a lot of other things. So don't, if you wanna understand the plugin system, don't try to start at the entity system, please. It's very complicated, it's doing a lot of extra things. So pick one of these simpler plugin systems if you wanna try to understand how to build your own or understand how it works. Okay, so let's start learning the Drupal 8 plugin toolkit. And the only way, of course, we can define plugins is to define a module. So as in Drupal 7, in Drupal 8, all your custom code basically is gonna be in a custom module. You need a module and in Drupal 8, instead of a .info file, you're gonna have a .info.yaml file. But it really, the content is almost identical to a .info file. You can mechanically translate it if you need to. What's kind of cool about Drupal 8 is you don't even need a .module file at all. So if you just create this .info.yaml file in a directory in the right place, you go to your modules page, you can see that you can enable the module. Now, it's obviously not gonna do anything, but it's enabled. And that's pretty cool. But again, most of the code in Drupal 8 lives in class files. So really the expectation is this, .yaml file tells Drupal you can enable the module and then once the module is enabled, Drupal adds your module to the list of places it will look for PHP classes. And that's why you don't need the module file at all. So here's the example, the full path, if you wanna create this. And the code I'm showing is all in a sandbox. So you can pull that down from Drupal.org if you wanna play with it yourself. So the full path in Drupal 8, you can put custom modules in the modules directory. That's another fun new thing. And core modules are all under the core directory. So they're separated out. And so that thing where you always told people not to put modules in the modules directory, now you have to change that for Drupal 8. But it's the thing they wanna do anyway, so it's okay. But you create modules mymodule.info.yaml, again, name, type, description, core compatibility, the same things you would've done basically. Type is module or theme or profile. So there's a little extra metadata in there since they all use the same info.yaml format. And then I wanna create two tabs. And I can do this more or less without adding much code to my module. So I'm gonna add two tabs. And these use the yaml discovery, so I just need to write the simple text format to add two tabs to the page. Yeah, so I need to name this file. So the discovery is based on naming of the file, mymodule, links.tas.yaml. The top level key is the plugin ID. So that's gotta be unique, so you should probably use your module name in it as you would with a hook or anything else, an earlier versions of Drupal. Then you see I have a route name, a title, and a base route. I'll come back to the route name part of it. And the base route is basically a grouping. So what this says, I'm creating two tabs. I'm gonna give them different routes, different titles, but I'm gonna group them together. They're gonna be grouped around this base route, which is the same as the route the first module uses and the route the plugin uses and the route the plugin uses basically just defines the link. So that's, yeah, when you click on the tab, that's where it's gonna go. It's gonna go to this route, mymodule.list. Okay, so this is what that looks like. Turn it on, you can see that there's, the default tab is on the right. The list one, and that's the default tab because the base route and the route name were the same. So already things are easy in Drupal 8. You don't have to define a default local task. All that silliness is all gone. You just define the ones you want. It's automatically the default if it's on the same route as the route that is the group. And then you see on the left side, we have the second tab also appearing there. And a trick here is that because we're using machine names for routes, I'm no longer tied to any hierarchy of paths in the URL. So I can group together any set of administrator pages I want to regardless of the path that's assigned to them. You see the one on the right says admin config mymodule list, the one on the left, admin config also mymodule settings. That's not something you could have done in Drupal 7, in Drupal 8, you're completely free. And you see the page content, here is something custom and it's just printing out name of a class and a method. So I did kind of trick you guys, sorry, I skipped ahead and made the tabs before I made the routes. So you do obviously need routes. There's route names that it's referring to have to exist in advance. And you could have, I could have used a routes that already existed in Drupal Core, but it was easy to make custom ones. And the routing files, the default is also YAML. Again, I told you YAML was really important in Drupal 8. So if you don't like reading YAML, learn to love it. The top level key here is the route name. So these are not plugins, these are routing definitions, but they look quite similar. The routing definition format is actually borrowed from symphony. So you can look at the symphony documentation and you'll see that most of these keys are defined in the symphony documentation as well as in the Drupal documentation in terms of what they do generically. Drupal of course has some Drupalisms in here, not so much in this example, but in other examples in Core. This is a very simple example. So we're defining a path for the routes. Obviously that's how it gets rendered, went as a link. The controller is very much like the page callback in Drupal 7. These controllers are just methods on a class, they return a render array. That render array just has the name of the class. So these are the dumbest possible controllers. You can look at the example code on how to get a bother showing it to you. And then title and then access checks here. They're just setting access to true. You can set access based on permissions as you did in Drupal 7 or any kind of custom access check that you want to apply to your routes. So these are in mymodule, mymodule.routing.yaml. That's how we define routes. So local task plugins need a route. That's why we bother to do that. So now we've got our routes, we've got some tabs going, what else can we do? So we might want to think about what else can we define in those local task plugin definitions, right? So and where do you find the documentation? How do you know what's a valid key? In this case, you look at the manager. So the local task manager for these different YAML discovery plugins is the place that we put the documentation and all of the default values. And you can see that the route name, the title, the base route are all among the keys mentioned here. And with empty default values because you should really provide something. The other thing in here is a parent ID. So you can have hierarchical tabs in Drupal 8, the way you did in Drupal 7 visually. But the mechanism is different here. You basically use this parent ID to say, I want to be a child of some other plugin when it gets rendered. So we tried to simplify this, make it a little more logically clear how to group these things together. And again, these are totally decoupled from the paths that those tabs link to. So you're no longer tied at all to any strict hierarchy of paths among the tabs that you group together. And finally, you'll see that there's a class key. And this class, if you want to create a custom tab, so imagine you want a tab that renders the current user's name on the tab as opposed to just a static string from the title. So you would have to provide your own class that implemented the right interface and the right methods and render the current user's name instead of a static string. But most people don't want to do that. Most people when they're defining tabs are happy to leave it as a static string. And that's why we have this system make it as easy as possible for developers to get started and add some tabs to their administrative interface. Okay, so on to blocks. So I think you'll love the new block. It's great. So blocks as plugins in Drupal 8. Every custom block is defined in code as a separate class. When you, as the Drupal administrator, go into the interface, and I'll show the screenshots of this, and you place a block in a region in a theme. There's a configuration object, a configuration entity, created the track set setting. So there's basically a class corresponding to a plugin ID and a configuration object. And those two things together define that block instance. So config object is a config entity, a word I've said a bunch of times now. And that's just an abstraction on top of Drupal 8's configuration management system. So configuration management is about the ability to import, export, and look at your Drupal configuration as YAML files. So again, YAML. Very important in Drupal 8. The fact that it's an entity means it actually implements some of the same interfaces as things like nodes. So now your Drupal configuration can be listed and loaded in the same way you can list and load things like nodes. In fact, you can make a view of the active blocks on your site. I don't know why you do that, but you can because it uses the same interface and you can actually make a view of these things. In the example I'll show you, you'll see that I don't actually worry about it at all about this configuration. The default classes that Drupal Core provides handle, creating, saving these configuration entities, and I don't have to worry about it. So only if you have custom configuration associated with your block, you need to sort of delve in to adding a form and adding those settings to the block configuration. Okay, so we're gonna implement a custom block. So we have to implement the block plugin interface. All blocks have to implement that, but we can make it really easy on ourselves and there's a block-based class in Drupal Core. And if we implement that, as you'll see, all I have to do is implement one method in that class, the build method, which is the same as hook block view, essentially, and all it does is return a render array. Everyone knows how to do that, right? Right, you can method, you return a render array, you get something rendered. Really easy. So in this example module I added Drupal in my module plugin block my block as the class. So how many people here know about PSR4? Not even half, okay, so. So there's a reason why we're using these namespace classes a lot, and that is because when I write that class name, that class has to live at a particular place in the file system in order to work, at least with the autoloader standing standard that Drupal 8 is using. So the Drupal my module plugin block my block class has to be in a file under modules, my module SRC plugin block my block dot PHP. And if you look at that class name with the backslashes, and you look at the file path with the forward slashes, you'll see that there's more or less of one-to-one correspondence, especially in the last three sections. And then of course we're under my module, every class my module provides has that, and then we're under Drupal, of course, who's a part of the Drupal installation. So this one-to-one mapping between a class name and an actual PHP file on disk is how the PSR4 autoloader's autoloading standard allows Drupal to find and load these class files by name without you having to tell Drupal in advance about the classes. So you might remember Drupal 7, you had to say this file has a class in it, right? In the .info file or the autoloader wouldn't find it. In Drupal 8, all you have to do is name your classes correctly, put them in the correct file location, and they're automatically loaded. So that's what PSR4 is, it's just again, that's why there's these strict rules about where you place your classes and how you name them. Okay, so this is the block plugin, it's really easy. So this again has an annotation, it has an block annotation. The idea of the plugin is my module, my block, it has administrative label, the administrative label is translatable, and as I said, all I have to do is implement the build method. The build method, all it has to do is return on a render array. This is a pretty easy render array, I'm using actually the same two routes I defined earlier. In the render array, and I'm using a new render type in Drupal 8, type link, but you can see how it works pretty obviously. Link has a title and it has a URL. URL is an object that encapsulates the route name, route parameters, route options, kind of like a call to URL function in Drupal 7, but this object basically encapsulates these things and then can be rendered later into a URL. And that's it, so we got two links. Return those from the build method. Obviously, if I create this file, I'll have to clear some caches in Drupal so the discovery process runs and finds the block. And now we can go and create an instance of the block, have it appear on the site. If you haven't used the Drupal 8 blocks admin, there's a new thing there, and you may be a little perplexed when you first go, because you won't see any blocks, except the ones that are already active. And instead, you see in each region this button that says place block, right? And place block, if you click it, will actually take you to a list of all possible blocks that Drupal knows about, and you can filter that by name, so here I filtered it down with my module block, click place block again, and then you get a configuration page that looks a lot more like the Drupal 7 interface, right? So now you can say which content type should appear on pages, roles, region, things you know from the block system. But this, under the covers, what's happening is if I click save here, I'm creating a block plugin instance. So I'm creating a configuration object that says there is an active plugin with this plugin ID configured for this theme, for this region. And that's how Drupal will be able to find it later and create that plugin instance and show it on the site. So I save this, save the blocks page, go back to my home page, and voila, you see, we've got now a block, custom block provided by my module, with two links to the customer outs I provided. And that's all we need to do, that one little build method basically inside the annotated class. So to give you again a little more sense of the mapping, Drupal 7, Drupal 8, there's pretty much again a one to one correspondence of these things, a hook block info, talked about it a couple times, the block manager is the one that uses the annotations in the block classes. They get parsed into basically the info array and they come back from the definitions list from the block manager. Generally you won't actually be doing that call directly, but when you have an annotation, it basically participates in that process. Hook block view maps one to one to the block plugin build method. And the one thing that's different there is you see in Drupal 7, you always had to worry about deltas. So you remember deltas and each delta was essentially a separate block. In Drupal 8, each delta, each separate block is a separate class. So Drupal 8, you don't have any intermixing between the code for different blocks. Each block, independent block is represented by a separate class and all the logic related to that one block is all together in that one class file. So that's actually one of the things I think is really great about Drupal 8 that it makes it much more clear when you're reading a set of code. If you're looking at one class file, you know that everything you're looking at relates to that one block and there's no intermixing with other blocks or other functionality going on. At Drupal 7, didn't actually have a good way to control access to blocks. I don't know if anyone's run into this. You basically had to hack the view method. Instead, Drupal 8 has an access method on those block plugins. So if you want to control access very specifically to your block, you can. You get an account object which represents essentially the user trying to view the block. You can call permission checks. You can do whatever you want to return an access result there. And then in Drupal 7, we had hook block configure and hook block save. And these were actually kind of weird. I don't know if people remember the annoyance of dealing with these. They don't really follow the pattern of the form API. So you get the delta again because you have to know which block you're dealing with. And then hook block configure doesn't take a form or form state and hook block save takes an edit array and again not a form or a form state. So you had to, every time I had to do this, I'd dive in the documentation, try to remember what these things actually were and what the edit array was and how to handle it correctly. What's nice in Drupal 8 is it's much more standardized in terms of form API. So we now have a form builder function, block form, a validate function, block validate, submit function, block submit. You know how that works. Drupal 8, the form is still an array. The form state is actually an object with methods on it and you can do interesting things like set your form errors on the form state object. But again, the pattern, it looks very much like Drupal 7. We basically moved things from these Drupal 7 block hooks into the methods for the specific block that's carrying out those actions in Drupal 8. So if any of you were paying close attention, you might also be wondering how does this discovery thing and annotations work? Like how did Drupal find those annotations and parse them and know that this was a block and not some other kind of plugin? So the way that works is really a combination of two things. So the first is the namespace. And again, the namespace also determines where on the disk you have to save that file. So the namespace for a block plugin has to follow this pattern where it's under Drupal and the module name and then backslash plugin, backslash block. Have to do that. You can't use any other namespace because that's part of how Drupal finds those plugins. Similarly, I mentioned a block annotation. So the block class has to have a block annotation or Drupal will not accept it as a block plugin. It's kind of makes sense, but again, this is how that works. So the plugin manager calls some other code that basically looks through those class files, says is it in the right place to be a block plugin? And if it is, is it using the right annotation? And if it is, okay, I'll parse it and give it back to the manager as one of the things that discovered. So the annotation class, so this at block notation actually references an annotation class and I'll show you what that looks like in that. Like the local task manager was where we had to stick the documentation for local tasks, but in most of these plugins, the documentation for the definitions is in this annotation class. And that basically shows you the possible keys and values of the block of the plugin definition and also fills in default values. There's a generic plugin annotation class, but if you're writing your own plugin, you're gonna want to extend that. And this is what it looks like. The annotation class is really simple. They basically don't have any methods. They just have some properties and default values for the properties. And here you can see these are the two things we listed in the block annotation. We listed the ID and we listed the admin label. The admin label itself, you can see here is actually a separate annotation that at block or at translation tells the annotation parser. This is an annotation class. So there's also annotations for things that are translatable. This is how Drupal's integrating with this plugin system with the internationalization system. People may have gone to talks about how great Drupal aids internationalization and translation system is. So we had to think hard, for all these different subsystems, how do we indicate which strings can be translated or not? And so for plugins, this at translation annotation is the way you do it. So that's it. This block plugin annotation documents all the things that can go in that annotation at the top of your block class file. All right, so wrapping up towards our last example, filtering text. So in Drupal 7, if you use the Drupal Outer Org issue queue, you put, hopefully you guys know the trick, if you put a issue number in brackets with a hash in front of it, it's actually rendered as a link to the issue with color coding. You guys know that? No, you should know that trick, it's great. So that filter is provided by the project issue module on Drupal.org. And here's the info hook. And you can see it gives you a title, a description, a process callback, and a tips callback. Those are the things I'll focus on. So basically, just again, tells you how to display it in the admin UI, the title and description, and then what functions to call to process the text or get a list of filter tips. So we can do, basically, I'm gonna implement, re-implement the same thing in Drupal 8, but much more simply. So it's, we'll work for any node type, not just for issues. I won't have any color coding, it's just gonna be really simple. So I'm gonna create a filter plugin, give it an ID labeled with my module, translatable title, and then there's, again, a base class. So the same way we had block base, we have filter base. So Drupal 8 is full of these base classes and they make your life easier as a developer because if you extend those, everything you need, except maybe one or two key methods is already implemented. So you can basically get a shortcut to working code and then you can iterate and add more customizations if you need to. Here are the two, only two things that really need you to implement were the process and tips methods, which are exactly the same things as the process callback and tips callback in Drupal 7. Again, you can see if you had a text filter in Drupal 7, I had a process callback and tips callback, you basically just copy that code, move it into class file in the process method and the tips method in Drupal 8. That's where the code would have gone. I sort of shortened this code but basically there's a regular expression, looks for that pattern of a node in brackets with a hash, uses an anonymous function to process each of those, basically load the node and render a link to the node and then we wrap the result in a filter process result which is an object that just carries cacheability metadata. So the Drupal 7 info hook had some cache info in Drupal 8, we're actually gonna put the cacheability info on this filter process result. And then we have a tips method that returns just again a tip about how to use this text filter and that's pretty much all I need. Again, you can look at the code, create a node, first test post and then I go to the admin page and enable this text filter, so I'm gonna configure the basic HTML text format that's one that comes built into Drupal 8. I'm also gonna disable a CK editor there so you can see the text tips more easily. This string that was in the annotation now appears in the admin interface as an option I can check off. So I just check that off. Go to node two, I edit my second node and I basically wanna put a reference to the first node. All I have to do is put this bracket hash one, that's gonna look for node one, load it, render the title and you can see that the filter tip from the tips callback is now appearing underneath the text area. So that's all we had to do to get a working text filter in Drupal 8, a text filter plugin. If I save that, you see it works. I get the rendered first node title. If I hover over it, you can see in the bottom left, I get a link back to that first node. So, sort of moving to the last topic we was gonna talk about is creating your own plugins and just a couple suggestions for best practices. These are things most people don't need to worry about. This is really gonna be the case if your Drupal 7 module provided an info hook. So your module called module invoke all something info and then looked for implementation hooks. Or if you had, for example, a Ctools plugin type, so you defined your own Ctools plugin type. These are not common things people did in Drupal 7, but if you did, you're gonna probably wanna convert them to these new plugins in Drupal 8. I would say as the best practice, use this annotation discovery by default, the things I've been showing you where you put those annotations at the top of the class file. The reason for that is it keeps the metadata basically the info about that plugin together with the actual implementation of the plugin in the class. So you've got everything all together in one file. It makes it really great to sort of copy and paste things, start from one of those and make a new one. Also makes it easy to find that information when you're reading the code. That YAML discovery I showed you for local tasks is sort of an edge case. So we've done it for the menu things in Drupal 8 to make them plugins to give you a lot of flexibility, but most developers are not gonna put a custom class there. They just wanna use the default class. So only if your module had a case like that where the 99% use case is the same class and 1% which is gonna substitute it. You might use this YAML discovery, but that's really uncommon. So think about using this annotation system if you need to define your own plugins. Okay, so some resources if you wanna learn more. Again, the slides are already posted. You can download them, get these links, all the code I showed you is in a sandbox in Drupal.org. I tested it recently, it all works for the current version of Drupal. Converting 7x to 8x modules, there are handbook pages on the process of doing that. They go in quite a lot of depth. So if you have this as a task ahead of you, I would look at that handbook page. There's also a handbook page on the plugin API. So if you wanna know about the plugin API, go and take a look at that. And another handbook page, it actually has a good back and forth discussion so it actually kept the comments. There should have been a long discussion. If you're interested in the philosophical reasons why we have plugins and use this system, look at that page. If you're just gonna use them, you don't need to read it. And then DrupalizeMe had a nice blog post on this whole system also. Has some nice pictures and diagrams about how it works. So just to wrap up, and so you kinda leave with a few things in your mind. Maybe if you haven't started using Drupal 8 yet and you're excited to use Drupal 8, here's a few good reasons to be excited. So widespread use of interfaces. So class interfaces means I can replace the implementation as long as it uses the same interface. The Drupal 8, the plugability, your ability to customize Drupal 8 is massively beyond what Drupal 7 provided. So most people don't kinda realize that just looking at the code. We get some fun little features for your UI, like you can group your tabs together however you want without worrying about the paths. You do need to pay attention to these route names if you're converting your module, please do try to convert your code to use the route name instead of the path. And some of the interesting features that gives you again that multiple routes can serve the same path and can serve different kinds of content or different HTTP verbs. You saw that all over Drupal 8 we're using YAML files instead of those custom things like any format we used to use for info and that even a lot of hooks like hook permission were converted to YAML files as a pure data. And also Drupal's configuration. Configuration, essentially most of the things that were variables in Drupal 7 are exportable as configuration, exportable as YAML files. So you can version those, you can track those, you can actually deploy them between different versions of your site. And finally, each block instance has a corresponding config entity and I didn't show this but one of the great features about Drupal 8 is you can create as many instances as you want of the same block. So if you ever hit the frustration with Drupal 7 core that you wanted the same block to appear on a different set of pages in a different region, you couldn't do it in Drupal 7 unless maybe you used panels or used views and made two copies of the block or something, you kind of had to hack around that. Drupal 8, you can have as many instances of the same block as you want, you can configure them differently, put them in different regions, give them different rules. So it lets you really get a lot more value out of that one plugin by reusing it over and over again to make different instances. So that's kind of it for the talks. Let me just sum up. Again, plugins combine the discovery process. I'll let you find the plugins together in often the same file, that one class file with the implementation of it. In that maps back from Drupal 7 and info hook in those implementation hooks, that's sort of the same purpose. So in your head, think about, okay, if I had that in Drupal 7, that's now a plugin in Drupal 8. If you're gonna define your own plugins, please start with annotation as what you define them. Again, so it keeps everything in that one file, makes it easy for people to find. So that's all I have. I hope that was informative. We have time for questions. So if you have questions, I'd be happy to take them. There's a mic over here for questions. If you can go over there, that would be great. Thanks. Thank you for a great presentation. First question I have, you had an example of the plugin manager you were getting, you were iterating through the result of get definitions and that returns back an array of the definitions and you were accessing those by using the array elements themselves and the array keys. Is that a best practice or is it a better practice when you get each one of those definitions to create an instance of the plugin and access it through the defined getters? I think you mentioned permissions. I was talking about the slide that you had it was near the beginning. Okay. So if you were talking about one of your plugin managers, you called your example called get definitions and iterating through the array of definitions. And I'm wondering if it's best practice to do that and access those plugin definitions via the array keys or to just create an instance of each plugin and use the defined getters. Okay, so in this case, so this is inside the managers. The manager really has to know about the guts of the plugin and this particular call to get available tool kits just wants the list. So it's really would be premature to create the instances at that point because there may be some significant overhead of instantiating a bunch of services or doing something to create the instance. So in this manager, I mean, this is a little bit of one-off most plugins don't have the sort of filtering method. You just get the list of definitions back and then use them to list the available plugins. But so the manager, and then the manager will take a plugin ID, will get the specific definition and then create one specific instance from the definition and a configuration it needs. Second question, a lot of the configurable entities have methods for building lists that build it out as a table of available plugins. Is there a way to short change that to build a select list of available plugin names? Is there? I would suspect there is, but I don't know it off the top of my head. Thank you. Yep. Kind of curious, I've never seen comments have like system critical functionality in them before. Why have the annotations and comments like that instead of being a static function that returns an array in the class or something like that? So it's a good question. So the reason we ended up using annotations, and this is actually not that uncommon. So if you look at other languages like Java and we adapted this as a PHP standard library. So this is used by Symphony, this is used by a lot of other actually PHP projects. But the fundamental technical reason we did that is because once you load a class into memory in PHP, you can't unload it. So if you want to iterate over all the classes basically on the whole file system in Drupal install, you would end up with every one of those classes in memory and you would probably have PHP run out of memory. So the fact that it's an annotation allows us to basically just parse that leading comment as text. So we're not actually loading the class file, we're just parsing the text out of that. And that constrains the amount of memory we use in this process. So that's the technical reason, but it's actually, it's not something we've ever done in Drupal before, but it's not actually that uncommon in other projects and languages. Thank you. You're welcome. Is this thing on? Anyway. If it's on, it's sort of barely on, yeah. Okay. For your controllers. For the controllers, yep. You're pointing to a function. Yes. And it looked like it was called statically. That was actually, it was named in the static style but it was not called statically. Right, so does that assume that you're working within a class, it doesn't require a constructor? What's going on behind the scenes if that class method requires a constructor to have been wrong? So there's a bunch of different ways to specify your controllers in, I have to look. So a lot of Drupal 8 classes actually have essentially a static create method. And that create method then gets a copy of the service container and is able to pull out the dependencies it needs for the constructor. So you can basically have a strategy of saying, well, I'll just give you the class name and the class has basically a static factory itself. And then the factory uses the service container to populate the values it needs for its constructor. So that's how that ends up working in most of Drupal 8. So that you don't have, the other way that that can work is you can actually define your controller as a service in the service container. And in the service definition, you describe what dependencies it has on other services and those are passed into the constructor. So there's basically two different ways you can do it. There's, I think a couple more, but. The code doesn't rely on that mind as a static method. No, no, it's a instance method, yep. Thank you. You're welcome. Okay, any other questions? Not, thank you all for coming. I hope that was informative. Thank you.