 Okay, so it's five o'clock. Let's start. Thank you all for coming. I'm gratified to see that you all are interested and didn't have a lot too much for every session today. I'm Peter O'Lanon. If you don't know me, I'm Peter O'Lanon on Drupal.org in IRC. I've been involved using Drupal since Drupal 4.7 and involved on and off with core development Drupal 5.6.7 and now 8. And today I want to talk to you really about a little bit of a paradigm shift in Drupal 8. We're moving to use a plugin system as a way to discover functionality instead of using, we'll use the previous versions, which was an info hook that gave you a list of data. Here's a summary of what we're going to talk about. So just, I'm going to give you some background about Drupal 8. Hopefully this will be stuff you guys have heard before, but I want to make sure at least the terms are in your head before I start using them and tell you what a plugin is as and then give you some code examples show back and forth between Drupal 7 and Drupal 8 how a Drupal 7 hook in implementation was converted into a plugin. Then move on to a simple example, but one that you'll probably use in your modules, which is just buying a tab, otherwise known as a local task on a page. Then talk about slightly more advanced, but not really more advanced examples of implementing a custom block and implementing a custom text filter. And finally just touch on very briefly some considerations if you need to define your own plugin for a module that you're porting to Drupal 8. So my clicker works. There we go. All right, so Drupal 8 background. Basically, you need to know these things. I'm just going to run through them. So you've heard the terms if you haven't before. So Drupal 8, we're making very extensive use of a dependency injection container or DIC, also the container service container. That's just an object that contains other objects, instances of them, and those are basically stateless services. They tell you things like the current request, the current user, how to generate URLs. So that when I talk about a service, it's something that you can request from this container service container. You should also know that we have a new routing system. And there's really the fundamental concept you need to know about this new routing system is we have route names. And the route name is the unique ID in Drupal 7. And before you remember that there's a system path and that was basically unique ID. Now it's a machine name. But it really works much the same. So that route name, that machine name connects you to a path pattern, connects you to a callback or a set of callbacks that provide potentially a title, the content for the page, the access control. So all the things that you would have expected to use in a Drupal 7 menu router are being provided through this named route in Drupal 8. And Drupal 8 also makes extensive use of namespace classes. So in case you haven't seen this already, this is a PHP 5.3 feature. We're making extensive use of it. That's what the class names are going to look like all over Drupal 8. So they start with a section called Drupal because that's the name of the vendor. The name will module, in this case search. And then some descriptive sections are a plug-in, and it's a block plug-in, and it's a search block plug-in. And that whole string together is the actual class name. And I'll come back to why we're using that later. But again, so when I talk about namespaces or namespace classes, that's how it looks in code. So what is a plug-in? Plug-ins encapsulate some functionality. And ideally, it's a reusable functionality. Plug-ins are always a class. So one plug-in, one unique idea of a plug-in, maps to one class. And generally, that class is going to implement one or more specific interfaces. So it's reusable functionality behind one or more standard interfaces. So plug-ins combine in Drupal 7. What was an info hook? They see a listing of things, together with the implementation of those things. So for an example, in Drupal 7, I did lots of work with search. So hook search info, if you've used it, you know it returns you a list of modules. And the modules are declaring that they have hook search execute. So it's a combination of that info hook together with the implementation in hook search execute. Or an example we're going to come back to later in this talk is hook block info. Hook block info is the list of all the blocks that all the modules provide in the system. And each module that provides blocks need to have a hook block view to render blocks and would need to hook block configure. To configure blocks, hook block save to save the configuration. So again, we have an info hook that lists the things, and then we have separate functions. Those functions might not even be in the same file. Or if they were in the same file, it might be in a different part of the file. They're rarely organized together in a coherent way that you could go from understanding this info hooks array to actually seeing what the implementation was. There was no, you had to basically grep through the code to find it. So Drupal 8 hooks evolved in a way from the concepts in Drupal 7 and 4 that were used by C tools and views. They both had plugins, plugin systems that were used widely. But you'll see that we're using different mechanisms to discover those plugins than were used in Drupal 7. Another feature of Drupal 8 is that every plugin system generally has a plugin manager. And this is the plugin manager's service. So it's registered to that service container. Basically anywhere in your Drupal code that you need to access these plugins, you can say give me that manager. And the manager then can give you the list of plugins or can give you an instance for one specific plugin you're interested in. Each plugin has a unique ID. And often that's going to be in its definition. You'll see a simple example of that in a little bit. It might also be generated as a derivative. And I'm not really going to talk about derivatives, but it's a concept you should be aware of. And an obvious example is views blocks. So views doesn't write a new class each time you want to declare a block. Instead what it's going to do is create a derivative. So it has one class that has the implementation. But for each block you create through views, it's going to create a plugin derivative that has a different unique ID. So it's basically a combination of a base identifier and then a unique derivative identifier. So what I'm going to say about derivatives, you should just be aware that that's a feature of the plugin system. For a given plugin ID, you get a unique ID that maps to a single class. So any instance of a plugin with that plugin ID is going to use that class. But the plugin ID instance is further specified by the combination of the class and some configuration values. And those configuration values are potentially coming from a config entity. This is something I'll talk about later, but basically you can imagine this is just configuration. So we have a class. We have a configuration. Together they make a specific instance of the plugin that you can do something with. So you guys probably have seen this phrase before. The dropper is always moving, and that means the code in Drupal 8 is not going to be compatible with the code in Drupal 7. But your data, your content can be upgraded between Drupal versions. So let's just see what that looks like. How is the code changing between Drupal 7 and Drupal 8? And the example I want to start with was hook image toolkits. So this is, in a sense, a classic info hook. Again, many of those info hooks don't actually have info in their name. But that's what it is. It's returning an array of data. And this is the system module version of that hook, and it's just telling you about the GD library. The GD library generally is compiled into PHP. In Drupal 7, we'll return a unique key, just GD, you see there, title, human readable. And then we actually had to check if this library was available through PHP. So sometimes you can compile PHP without it. So you see we're using a function check here to set this available flag. In this info array, this return from this info hook, even though it's not named info. So that's Drupal 7. Drupal 8, we actually end up doing something very similar. So Drupal 8, instead of doing the module invoke all to find all the implementations, we ask the manager for the list of implementations or the list of available toolkits. And the manager has a method here, just get available toolkits. And inside that it's actually using something that's pretty common to all managers, which is get definitions. And you think of get definitions is really a one-to-one mapping from the info hook in Drupal 7. It's getting back arrays of information. And then we're just iterating over those. We have IDs. And for each of those possible IDs, we're checking a method to see if the library is actually available. So you see there's really a one-to-one mapping in a sense between the Drupal 7 code. We got a list of all the things. We call the function to see if the library is actually available. Drupal 8, we're basically doing the same thing. The plugin manager is discovering all the possible plugins and validating that each one is actually available on our version of PHP. If we look at a particular function of the image library, now this would have been organized potentially in an include file, but there was no real requirement as to how you would have organized this function compared to the info hook. You see here that we're actually using another layer of indirection in Drupal 7 because we have to call back into our toolkit method so we actually get the right underlying function called right underlying toolkit. But really, you know, we're just passing an image object and calling the function on it. In Drupal 8, it's actually a little clearer because this class knows that it's dealing with the GD library. So there's no extra level of indirection that's needed. If we're using this plugin, we know that we're using the GD library. And you'll see something we're going to come back to later that there's an annotation on this class. At the top, you'll see that at image toolkit. And that's saying that this class is an image toolkit plugin. And you'll see that that ID equals GD is exactly the same thing that was in the Drupal 7 info hook as the top level key. So we've really just done a straight port from Drupal 7 here. The things that were in the info hook are in this annotation now. So the ID and the title. And you saw that the manager itself took care of checking whether it was available. And this desaturate method, again, GD is one of these somewhat wonky libraries that doesn't always implement all the things it's supposed to implement. But in general, we can directly call the underlying GD function within this class to manipulate the image. So that's it. It's really a 1 to 1 mapping from Drupal 7 to Drupal 8. But the code organization you see has changed quite a bit. So whereas in Drupal 7, we might have been in an include file, we had all these discrete functions. In Drupal 8, each one of those discrete functions is going to be a method on this one single class. They're all going to be grouped together in that one class file. They're together with the annotation. So you know that this is annotated as that plugin. You know what its ID is. You know what its title is. And you know all the implementation. And it's all in one place. So that right there is really one of the big advantages of plugins. I'll keep coming back and hammering on that point. But you can see it right away. So what about hooks? I mean now everyone loves hooks. I mean as a Drupal developer, that's sort of your bread and butter. So Drupal 8 is still going to make pretty extensive use of hooks. Almost every plugin manager has an alter hook. And I'll come back to the reason why this is important later. So there's still going to be alter hooks. There's still going to be info hooks, in fact. So things that are just returning data that don't have an implementation should stay as info hooks. They shouldn't be converted to plugins. A good example of that, again, without the name info and the name, is hook permission. So that's just returning you a huge array of permissions and human readable strings. There are no functions involved with that, right? So if you implement hook permission, you don't also implement some other functionality related permissions in your module. So this is just a pure info hook. It shouldn't ever be a plugin. So coming back to discovery, as I said before, the discovery of plugins really is analogous to invoking the info hook on all the modules. Some advantages of using plugins, you can actually have more than one plugin for your module. Whereas in Drupal 7, you might have had to have a long list of different array entries in that one hook. In fact, plugin discovery is very flexible. I'll talk about the standard ways that Drupal 8 is doing it, but you could use a hook if you wanted to as a plugin discovery mechanism. There's nothing that stops you. It's just not what we're recommending is the best practice. So really, plugins are, give me some information about the plugins, and the manager is going to process that. And then you could ask the manager to give you a specific instance of a plugin. So again, discovery just gives you that array of definitions. It's very boring. It's just like invoking the info hook in a way. And then the discovery process can also fill in some defaults. And the most common default, for example, is filled in is the name of the module providing the plugin. Usually you don't care, but just in case you care, that's always filled in. So plugin discovery and configuration in Drupal Core currently, there's really two main mechanisms that are being used. One, for various simple plugins that we're going to look at as our first example, we're using YAML files as the discovery mechanism. And so there are three plugin types that are actually all still potentially pending some more changes. So, but we expect the local tasks are nearly done. We may do some tweaks in those local actions, also nearly done contextual links still baking. But these are sort of a special case because almost every local task, local action or contextual link is going to use the same plugin implementation. So the only plugins to handle really the edge cases, I'll come back and talk about those edge cases later. But because almost all of them use the same class, there's really, it doesn't make sense to associate the discovery information together with the class because they're all the same class. In contrast, almost every other plugin, most things that really are a good fit for a plugin system, we're using annotation, as I showed you before. And that keeps the information for the discovery together with the class. One first sort of category of plugins use annotation to be discovered. And they may have some configuration, but they're not using the config entity system, which I'll talk about more. So these, for example, search plugins, the node search plugin has some configuration it pulls in for itself. The user search plugin doesn't have any configuration. So there's not really a consistent need for configuration across the search plugins. Same for the image toolkit, the archiver, stream wrapper, those potentially using annotation but not any consistent system of configuration that's common across all the plugins. And then the majority of plugins at Drupal 8 are using a combination of annotation and a config entity. The most important example probably for developers is going to be a block plugin. And so we're going to go through that. Things like views display, image effect tips from the tour module. So these are all using annotation together with a config entity. And then we have the entity system itself in Drupal, which looks like a plugin but isn't exactly one, but makes extensive use of the annotation in the discovery and definition of the different entity types. So with that as background, let's sort of jump in and start looking at what it would mean for you to implement one of these Drupal 8 plugins. So a prerequisite is you need a module, of course. And Drupal 8 modules, it's not much harder to do than a Drupal 7 module. You need an info file and a module file. But Drupal 8 basically YAML has become sort of the standard format for any static file. And so we've converted the PHP INI format into a YAML format for the info file. So you need my module.info.yaml. But really, the data is exactly the same. It's just a slightly different format. You can see right there, that's all you have. And an empty PHP file, once you have those two things, you can enable your module. Once you've enabled your module, we can start defining plugins that are provided by that module. Now I'm going to sort of jump a little bit ahead here and then circle back to some of the details. But I just want to show you really how easy it is in a way to add tabs which are actually plugins, plugin instances in Drupal 8. So I'm just going to add this YAML file. The YAML file is what allows these plugins to be found. The plugin ID is the top level key. I have the route name, which again then links me to a path, links me to access control, links me to everything else. I have a title for the tab. And then I have this route ID. So the tab route basically just gives me the organization between these two tabs. One of which is basically the first one is its own route. So it's essentially the anchor. The second tab references the first one. And you'll notice here that we don't need that silly jumping through hoops of the default local task, which is the thing that you never see, but you have to have to render the tab. Did that annoy anyone? Yeah, so that's gone. You don't have to have anymore. Similarly, it's not listed here, but hierarchical relationships are again explicitly defined. So I'll show you later that you can define explicitly the parent ID of a tab. So if you want to define any hierarchical relationship, a child tab to a parent tab, it doesn't matter what path they're on or anything else, you can define that relationship just by writing this little YAML file. So what does that look like? Just with that YAML file and the other setup I'll come back to. And now I have two tabs. And you'll see I've not only had to avoid that defining a default local task that we used to have to do, but there's actually no requirement on the hierarchy between the two paths. So I have totally arbitrary paths that I've assigned that based on the routes, these two tabs linked to. But yet I'm able to group them together. So this gives you a lot more flexibility. You could probably have achieved this in Drupal 7 by jumping through hoops and calling an alter hook, but this is now very straightforward to do. And you'll see both these pages give you some content. And the way you do that, of course, is you need to define routes for your module. I'm not going to go into this in depth, but routes more or less look at this at this point similar to the way we define these plugins. The YAML files, they tell you a path where you can that route basically resolves from. It tells you the name of a class and the name of a method to use for the content. You could potentially do the same for the title. These just have static titles. And then some access control. Again, these are sort of the same things you would do in Drupal 7 through the hook menu. Here we're just doing it in this file. And you'll see, as a side note, that here we're defining titles for these routes. And if I jump back, those are the titles that appear on the page. So my module list, my module settings, the titles on the tab, we're just the things I defined for the plugin. So very easy here, total separation of concern between defining the page, the page title, and defining the tabs and the tab titles. That's a theme we've really been working on for Drupal 8 for sort of these menu-related pieces is trying to separate all the concerns to make it very explicit when you want to do something. You know how to do that in just that one thing and you don't get confusion between routing, which is really about serving a page request, and tabs, which is about sort of a visual presentation. So what are all the options for these local task plugins? You can see those listed in the local task manager, that class that gives you the instances of these tabs. And we have route name, route parameters, which we're not using, title, which I showed you, the tab route, which we're basically always going to want to have. Again, a tab parent, if you want a hierarchical relationship between your tabs, a wait. Of course, you guys all know about wait. And you can fill in options. So if you want attributes, you want a query string, you want to do something, options, you know how something like the URL function would render the options. You can now apply that to your tab easily. And there's a class specified here. So this is the default class. Again, I told you that almost every tab is going to use this default class. In the rare edge cases that you need to do something different, you can override that by specifying a class. And those rare edge cases look like things like you want a dynamic title. So you want the title of your tab, let's say, to reference the current user. Or you want the path of the tab to relate to the UID of the current user. Those are cases where that information is not readily accessible as sort of a default parameter. It's something that you have to fill in. So you'd have to override one of the methods on. You'd have to create your own class, probably subclassing this one, override that method. And you'd have to figure out exactly what you want to do. So then you have complete control over the render your title and what path that tab links to. Okay. So that's sort of an easy example. Blocks are really not much harder. They just use, again, a different discovery technique, which is really the preferred and most common one in Drupal-A-Cole, which is using annotations. So really to run through how you would conceptualize blocks in Drupal-8. So blocks, each custom block is going to be its own class because each custom block is its own plug-in. When the administrator places a block into a region, and I'll come back and show you what this looks like, a configuration object is created that basically tracks the setting of that block and that region and any other settings the block needs. And that configuration object is a config entity. And that sounds a little scary, but it's just an abstraction on top of CMI. So if you've heard about the CMI, the configuration management initiative in Drupal-8, that's just saying I'm going to write things out to YAML files and I can potentially deploy them between sites if I have configuration. And so this config entity is an abstraction on top of that and lets you use the entity function, things like entity load, entity list, to get lists of your configurations. So this is really useful because now I can get a list of all my active blocks. I can load the configuration for a specific block. This abstraction lets me just kind of have less custom code related to blocks and just keep reusing the entity system throughout Drupal Core. I'll also say as a developer, especially as you start to implement your box, you generally don't have to worry about this config entity. Drupal Core is taking care of that for you, but you may keep in your mind that there's some configuration associated with a specific block instance. But you'll see in the code examples that there's nothing related to the configuration we need to do to implement our first block. So what do we need to do for blocks? Well, we need to use the right interface. Remember, I told you every plugin implements one or more specific interfaces. So blocks, of course, implement the Drupal block plug-in interface. If you extend this abstract class that Drupal Core provides, then really almost all the work is done for you that implements all the methods that are needed on the block plug-in interface. Really, all you have to do is implement the build method, and that's the same essentially as hook block view in Drupal 7. So in this case, I added to my module a class called Drupal. My module plug-in block my block. Again, we need this full namespace. Let me just give you a side note on why we need that full namespace. So Drupal 8 is using a new technique to auto load classes different than Drupal 7. So you might, if you've ever run into trouble with it, you may call it the hated registry of classes in Drupal 7. If you didn't run into it, you still might have noticed that you had to list all your class files, new .info files, and if you didn't, they wouldn't be picked up. So in Drupal 8, we're using PHP community standards for auto loading, and that's really important because it also lets us integrate things like the symphony components and other external code components more easily because they're all using the same kind of system for auto loading classes. So when I add this custom block class to my module, there's a corresponding file at this file path, which is a little long. It's module is my module lib, Drupal my module plug-in block my block.php. Yeah, so it's a long, it's a little annoying, but you'll notice that there's a very simple mapping, which is that the full name of the class matches that full directory listing under the lib directory. Really, the only thing that's different is we reverse the direction of the slashes and we take off the PHP extension. So even though it's long, it's a very, you know, there's a one-to-one mapping, and actually the PHP community as a whole got a little annoyed with this. So there's a new standard that's coming out called PSR4. That's going to be adopted by Drupal Core as early as next week, and really once that happens, these directory paths will be a little shorter, because of course, Drupal already knows that a module is under the Drupal namespace and that it belongs to your module. So then we can just have under lib directory plug-in block my block.php. So these directory paths will be a little shorter. As I said, that's going to be as soon as next week, so really this is just at this point almost a legacy note for a Drupal 8 development cycle. Okay, so what does that class look like? This is really it. I took out a little bit of formatting, but essentially this is it. It just returns a render array from the build method. I have to provide the annotation, and that's it. So the annotation, it's a block plug-in, so I use this at block annotation. An ID, that's a unique ID for my block plug-in. As always, you name space it with your, the name of your module just so you don't conflict with anybody else. And I have an administrative label. And there's actually another annotation inside there that you'll see very commonly, which is at translation. That means that this string is something that the Drupal localization system is going to parse out. And so when you download a translate, a localization from localize.drupal.org, hopefully you will have, you know, in place a localized version of the string if you're deploying Drupal in another language. Otherwise, this is very simple. So build just returns a render array. This is very similar to what you might do in Drupal 7. The thing that is different here is that we have this type link. And you can use type link in your render arrays instead of having to call something like the all function. So that'll get rendered in the end. So I have type link. I just have a title. And a route name, which is going to link back to those routes I talked about before. So how do we, once I save this file, clear cache, Drupal will pick it up. I go to the box admin page. And you'll see that there's a totally new section on the box admin page. And this is actually one of the best features probably about Drupal 8 that I don't know if people know about yet, which is that you can have more than one instance of the same block. So in Drupal 7, if you had one block, you can only put it once in one region and it would appear the same region on every page. Drupal 8, you can have as many instances of this block as you want in different regions. You can configure each one differently, potentially to appear on different pages, even with different settings. This this block obviously doesn't have any settings. But you can, you know, many blocks would have settings, how many items are listed, other settings. So this sidebar in Drupal 8 gives you the block plugins that are available to be placed. And then the center section shows you only the things that have been placed and are active on the site. So if I click this link, it pops up a dialog. This looks again very much like what you would have seen in Drupal 7 for configuring a single block. Here we're configuring again this block instance. If I pick the sidebar region, hit save. Most of this configuration, of course, is just coming from the block system. It's not something I would implement. Standard settings, which pages, what content types, what roles. This is all familiar. But again, it's per block instance. So I can configure different instances of the block with different settings. So if I do that, I'll just stick in the sidebar at the top. And now I have it. I have a custom block. It has those two links. Those link back to those two pages I defined as routes. And that's it. It really isn't any harder than Drupal 7. It's really about code organization. So in Drupal 8, I need to organize all my code into this one class file. All those discrete hook and permutations have to go in for the block that would go in one place. And here's kind of a side by side comparison. What you might have done in Drupal 7 and how we're going to do it in Drupal 8. So in Drupal 7, you had hook block info, of course. That's what we've killed. And so now we have a block plugin manager. And as long as you put the right annotation on your block class, you put it in the right directory, the block plugin manager is going to find it when it looks for definitions of block plugins. And it'll be available to be enabled. Hook block view had to take a delta parameter because your module might have had multiple blocks and each block had a different delta. And that was something you had to keep track of. In Drupal 8, again, this one class is one block. So there's no ambiguity about what you're rendering. You just have this simple build method. In Drupal 7, if you wanted some special access control, you probably had to hack something into a block view. In Drupal 8, there's a dedicated access method if you need something unusual. Hook block configure, again, had to take a delta. In Drupal 8, we're getting a form array. So we're moving towards more consistency which is using the form API and not sort of a block specific configuration form. Drupal 7 didn't give you any automatic validation opportunity. You would have had to stick that in yourself. In Drupal 8, you'll likely get a chance to validate the form values. And again, Drupal 7 had delta and the edit array. Edit array, right? What was that? I think that's from like Drupal for something has been, you know, was in the block system until Drupal 7. In Drupal 8, again, it's standard form API. You get the form state with the form values. You can add them to the block config and they'll be saved. So it's really, I think, going to be a better experience because there's a lot more consistency now with the block system as compared to everything else that does forms in Drupal. So just, again, reminding you how the system is working. Every plugin type has to be in the expected class data space for your module. So for blocks, it has to be under plugin block, under your module, under Drupal. So that's the full class name. Most core plugins you'll see like that at block is it's a custom annotation class. And so you have to use the right annotation for your plugin. Again, you know, it's at block. It's not anything difficult. And I'll show you what this annotation class looks like for blocks. It's actually pretty straightforward. So it provides, in this case, the annotation class is really providing documentation about what the possible keys of information that are coming back from the annotation. And they also actually fill in default values. So you can see if there's some default value that's going to be filled in if you omit it. There's also a generic plugin annotation class. So if you want to get started creating a plugin for your module, you don't want to figure out at first how to do this custom annotation. You can just use this generic plugin and just based on the directory name you put your plugins in, you can find them. So this is what the block plugin annotation class looks like. It only has those two keys that you saw in my implementation of a block. The ID of the plugin again has to be unique and administrative label. And here you'll see, you know, some additional code comments indicating that this, when we have one of these, we expect to be translatable. So this is really just documentation except when we discover the plugin, we actually instantiate this class with the information from the annotation in your block class. And that's how we're able to fill in default values because we get an instance to this class. It can fill in for all these properties. It'll fill in if the property has a default value, it'll be applied when it's instantiated. So, okay, let's go on to another example. Again, I want to show you that this is again mostly about organizing your code. And that, you know, for me, once you get used to it, this is actually a much better experience because your code is all in one place. It's easier to find it, easier to manage it. So in Drupal 7, we had hook filter info. So this is, I shortened this up a little bit, but this is hook filter info from the Drupal 7 version of the project module on Drupal.org. You guys are probably familiar with this project module filter if you've been in issue queue and you see that people put in square brackets, an issue number, and it automatically turns into a link. Right, so this is in Drupal 7 project modules version of that filter, it's basically taking a token of some sort, converting it into HTML. And you see in this info hook in Drupal 7 that we had an explicit title, we had a description, and then we had to tell Drupal about the functions to use that implemented this filter. So we have a process callback, a tips callback, some other information. And, you know, where are those functions located? They could be anywhere in the file, they're not together with this. I have no easy way to associate them, or if I wanted to copy paste them to another module, no easy way to copy paste them. Everyone's favorite mechanism of starting development, copy paste. Hey, that's what open source is all about, right? So in Drupal 8, in that example module, I told you about this link from the presentation. So I've created a slightly hacked and simpler version of the same filter as an example, so you can see how you replace a token in Drupal 8 with some HTML. And so this, you know, is again, uses the app filter, plugin annotation, again, a unique ID with my module, the name of the module, title, which is going to be translated, again, that translation annotation in Drupal 8, wants to know what type of filter it is from the annotation. So again, a short set of static data about the plugin, the most important of which, of course, is the ID. And then the class. So you see here again, we have conveniently a base class that we're extending, so most things will have a default implementation. And the two key methods here that I'm implementing are the process method and the tips method. Those are both in the interface that's used for filters in Drupal 8. So we have to have these methods by implementing these methods with our unique functionality. We can do the substitution. I'm not showing you the actual replacement callback. You can look up the example code, but basically this process function just defines a regular expression, which is looking for basically something like square brackets with a hash and a set of numbers, and then calling a replacement callback on all of these. And then we have a tips, instead of a tips callback, we just have a tips method. So again, it's organized together all in one class. And you'll see that this tips text will show up when we enable this filter. So what is just again to show you what that looks like? Yeah, I created a first node, something boring, it's a test post, node one. So it's node ID is number one. If I go into my administrator section, click configure on my text formats, you all have done this. This doesn't look too different than previous versions of Drupal. And I'm going to enable this plugin as active for this particular basic HTML format. Once I've done that, I can go back and create my node number two. You'll see here that in node number two, so I'm just going to reference node number one, the square brackets number one. And you see down at the bottom, I got that tip out of my tip method. So that's all I had to do that very short bit of code plus a little bit to actually implement the replacement. And I've got a functional text filter using the Drupal plugin system. If I submit that, you'll see that it substitutes it with the title of my first node. If I have it over that, I'll get the correct URL. So moving towards the end, and I'm moving plenty of time for questions because I hope you guys have some. Let's just talk about implementing your own plugins. So you see, this is really pretty straightforward. It's about code organization. And so you may already have had a module that had a plugin in Drupal 7. View C tools, that would be a very convenient way to allow other modules to hook into whatever you were doing. For example, I worked on Fasted API. Fasted API uses the C tools plugin system so that modules, different search modules can provide implementations for facets. So if you want to think about upgrading your C tools or whatever system or an info hook together with some implementation to Drupal 8, you should start out by assuming that you want to use this annotation based discovery. So that's keeping the metadata about your plugin essentially the thing that would have been returned from the info hook together actually in the same file with the class that's going to implement it. So that really should be your starting point, your default. The YAML discovery which we talked a little bit about is sort of an edge case. So that's when every plugin is probably going to use the same class except for the 1%. So probably if you implemented, if you had a plugin for your module in Drupal 7, that's not going to be the case. These few ones I showed only with something like that is it going to be appropriate probably if you're using this YAML discovery. And that's it. So it should be straightforward. Again, you take all the implementation you had in Drupal 7, put it in the class, annotate it, put it in the right namespace, and Drupal can find it and make it available. I will see if you input on your own, you'll have to write a manager. But there's a default manager you can extend. So you really have to just define a few things like what annotation you're using and what directory your plugins are found in. So, a few general resources. So again, on the session node, I've linked to the demo code that's on a sandbox on Drupal.org. I'll probably try to keep this up to date also over the next few weeks if things change a little bit. Drupal.org has documentation already in the handbook. So there's a section on converting Drupal 7 modules to Drupal 8. And a big section on the plugin API. I hope that you all know that all the handle pages on Drupal.org are like wiki pages, and that means that you can edit them. So if you use these pages and you find some place that they need to be improved, please edit them, please add to them. You'll see that you will list your name on that page then, so you get some credit for your contribution. That is really a key thing that helps the whole community stay up to date with the rapid development that Drupal 8 is still undergoing. And finally, I could recommend this blog post on understanding Drupal 8's plugin system. It covers many of the same things I covered in the talk, but just from someone else's perspective. So let me start to wrap up here. So I just want to run through some of the Drupal 8 features I remembered so you can keep them in your mind as great reasons to look forward to Drupal 8 release. One of the features I think that people don't yet appreciate, but it's going to be the most powerful, is this widespread use of interfaces. So remember I told you that almost every plugin manager has an alter hook. What does that alter hook let you do? It lets you go in and change the class that is implementing a specific plugin. The thing about that, if you don't like the way any core module, any contributing module implements its block, you can implement this alter hook. You can substitute your class for the class that the Drupal core wanted to provide or that module wanted to provide. So the level of plugability, the level of customizability of Drupal 8 is actually going to be vastly more than Drupal 7. You can really replace any of these plugin implementations with your own implementation. And I think that that's a power that's going to be in Drupal 8 that people haven't yet started to appreciate, but really there's not going to be any reason to hack core because you're going to be able to replace almost anything in core with your version of it. So minor feature, but one that I like is that we're now able to do things because we're using these route names rather than paths. We're switching to where we can just arbitrarily group things together like tabs. So they can be grouped together regardless of hierarchy, have parent child relationships that are explicit. They'll have to figure out how to make the paths match up in a hierarchy in order to get them to appear together on the page. A very powerful feature of routes, and you might have, I don't know if any of you went to the talk on rest earlier today, but an important feature of Drupal 8 is that one path can be resolved to more than one route. And what does that mean? So in really simple terms, think of the request headers may ask for HTML or the request headers may ask for JSON. And depending on those request headers, the Drupal routing system may say, well, you're using the same path. You're using node one. But if you ask for HTML, I'm going to give you the HTML route. If you ask for JSON, I'm going to give you the JSON route. Similarly, you could separate first on the verb. Is it a get request or a post request? Maybe I want to do something different. I'm going to end up at a different route. That's going to end up at a different controller for the content or the page. So we have a lot more flexibility here, and this is one of the key things in Drupal 8 that's going to make that goal that you've heard about in making Drupal 8, basically a great rest server. This is what makes it possible. That we can now serve one path, can resolve to multiple routes, and we can find the most specific, the most correct route based on the headers, based on the verb. That's something that was extremely difficult to do in Drupal 7, except through very nasty hacking. I talked a little bit about config, or that came out of the configuration management initiative. If you're upgrading from Drupal 7 and you have variables in your module, you have to actually think a little bit about a split here between config, which most things are, and config is deployable. So it's written out to yellow files. You can copy some configuration you have from your development server to your live server if you want to reconfigure your live server. There's a different subset of variables that were mapped into something called state for Drupal 8, and state is things that's not deployable. It's not something you'd ever want to sync between sites, so think of the last cron run. Why would the time stamp for the last cron run in Drupal 7 is sort of a variable? In Drupal 8, it's state, and that means it's specific to this Drupal site. It's not something you're ever going to deploy between sites. Why would your production server care the last time you did a server run cron? It's not appropriate to synchronize. So again, if you're upgrading a module to Drupal 8, think about the split between configuration and state and what the right thing to be using is. Another Drupal 8 feature is that YAML is really a standard. We're adopting for most configuration data files. So depending if your module had files of some sort, you know, in any format, you might think about converting those to YAML. And the other feature I told you about for blocks was that you can have multiple instances of the same block. Again, this is sort of a, you might think of this as almost as an edge feature, sort of a fallout of the plugin system, but I think this is going to be really great for site builders. It's going to give you tremendous flexibility compared to Drupal 7. We were locked into that one block, and if you wanted to again, you either had to copy the code or jump through a lot of hoops to get it twice. So let me sum it up here. So plugins combine the discovery of the functionality with the implementation of the functionality generally just within that one class file. In Drupal 7 that looked like an info hook and then a bunch of functions that implemented some functionality. But those could have been scattered all around. They could have been different files. In Drupal 8, we're reorganizing them. We're putting together in one class file. And if you are defining a plugin for your module, generally you should be looking at using this annotation-based system unless you have a very clear reason why your plugin type is quite outside the norm. So that's it to wrap up. Just, you know, you all probably know, but Friday is Sprint Day. So if you haven't been involved in Drupal Core development so far and you'd like to be, or if you want to contribute to a module, help fix bugs, help mentor people, or be mentored. If you want to get involved or get mentors available, please stay around on Friday. It's actually often, for me, the best day of the entire DrupalCon. The most energy, the most excitement. So there's information on the DrupalCon website. And finally, of course, please wait the session. Let me know what you thought. If it was useful. With that, I'd be happy to take your questions. Questions? Looks like no sessions and great sessions. Thanks. I was looking at some examples, actually, from the talk we mentioned, at one of the presentations of blog posts you linked to. And having a load of problems with getting Drupals actually, it got my plug in. And there seems to be very little in the way of tools to diagnose why that's not happening, which is a bit more difficult than it was in D7. So, for example, if you have the wrong annotation class or you, you know, place it in the wrong folder or you call your files something wrong, are there any hints and tips around that? Okay, that's a good question. Let me repeat it. So, gentlemen has been trying to follow along some examples and finding it more difficult to debug this annotation-based discovery, as opposed to Drupal 7, where maybe you would have just dumped, I guess, the info array or something. I mean, in a sense, you could dump what the plug-in manager finds. It is just an array of information, but it's in a different place. I think that Drupal 8, yeah, some of the DevTools we do need to work on. So, I think that's an important piece for the developer experience, the same thing for routes. So, if you're a developer and you're trying to think about, like, I'm looking at a page, how do I think that route is serving that page? That's the kind of DevTools that we do still need to build. So, I agree right now that developer experience for a lot of these things is a little rough and it is maybe hard to debug. So, certainly if you have feedback on what tools you want to see, we'd appreciate that. But, yeah, that's a good point. So, yeah, a lot of these core annotations were converted from the generic app plug-in to be a more specific one, the app block. So, if you use the wrong one, it's just never going to be found and that could be a little frustrating. In fact, I've seen even presentations this week, people still have encode snippets referencing app plug-in when they should have been referencing app block. So, yeah, it's still moving pretty fast. And, you know, that's why, I mean, I updated some of the plug-in documentation myself to try to correct those a little bit more. But if you run in those frustrations, yeah, please do try to update the documentation and give people feedback so they can keep their examples up-to-date. Yeah, it's about discovery again. Yeah, speak close to it. It was picking up. Okay, about discovery too. You mentioned YAML discovery and annotation discovery. Will it still be possible to keep info hook discovery or other methods? Okay. So, info hook discovery, there is actually an info hook discovery system in Drupal core. We had some debate about whether to keep it or not. Currently, it's still in Drupal core, but it's not being used by anything. So, that was sort of the question. So, we really need to at least write some tests to validate that it's going to work correctly or, you know, or we might remove it. But if you look at the code, it's very minimal code. So, if you needed to re-implement it yourself, it's a trivial thing. But yeah, probably I would say at this point it looks likely that it'll ship at least with some tests, if not an actual usage in Drupal core. But again, I would say that's more like when you want to do the YAML discovery where it's a better fit when most of the classes are the same. If the classes are distinct, the annotation discovery, you know, is better in terms of keeping the metadata together with the class. So, it's all in one place. Thank you. Settings form Drupal 7. How will that be the values that you store there? Would that be a state? So, settings form, that's in general config. So, yeah, because a settings form usually we're setting some persistent settings for your module. You know, the vast majority of variables were converted to config. There's only those few things like the last timestamp I did X that really make sense as state because they're not something you'd ever synchronize between sites. So, yeah, I believe if you use that kind of settings form, it will give you the opportunity to write it as a config object. Okay. No other questions. Thank you all for coming. And yeah, please give me your feedback on the session. I just want to say I made a big difference. Yeah. Okay. Thank you. It's like it's a tiny little link. At least I'm plugged in. Yeah, you did that. Yeah, because I can't play.