 And I'm already ruining everything. Hi, I'm Sam. This is a talk about the things you can and possibly shouldn't, but you can do with WordPress. WordPress obviously, everyone here knows what it is, hopefully. If you don't, then you got very lost and I'm going to apologize what you're about to go through. Who am I? I'm a web developer. I'm a massive nerd. I do stupid things for money. I've been programming for a long time. I've been freelancing for a while. I've been getting paid to program for a long while. And I tend to do rather bizarre things in my spare time. So for example, my personal blog is not WordPress. It is a single file of PHP that I wrote in a weekend that contains all of the templates, all of the functionality, everything for a complete blogging system, including comments, posts, pages, in about 3,000 lines of PHP. It's polymorphic, which means it has the installer. It runs the install and then deletes the installer from the file. It's a terrible idea, but it's been running for seven years and hasn't gone down once in that time. So it was a terrible idea, but that's kind of what I mean by I like to do weird things in my spare time. So let's talk about WordPress. What is WordPress? WordPress is a blog. A lot of people seem to forget this. WordPress does so much. A lot of people don't know this. Not too long ago, I had a client come to me and sheepishly ask, is there a plug-in I could find to add a blog to my WordPress site? And I had to sheepishly tell them no, there isn't a plug-in for that, because that's what WordPress does. WordPress is incredibly flexible. So that's why some people don't know that it is actually a blogging engine. There's a lot of things you can do with WordPress. The structure of WordPress, the hooks, the filters, all of this type of stuff that's built into WordPress means you can do a lot with it with obviously with a bit of skill and knowledge, but also just using plug-ins from the plug-in directory and things. You can get a lot achieved in a very short amount of time without too much knowledge of how websites work. WordPress is a platform. It's ascended past being just a blogging engine. It is a platform. There are ecosystems. There are ecosystems built for ecosystems. The fact that WooCommerce is a plug-in for WordPress and then has its own complete plug-in ecosystem for WooCommerce specific WordPress plug-ins, it's become a platform. You find people who advertise themselves as WordPress developers. They're not saying they're PHP developers, they are WordPress developers. It is the platform that they know, it's the platform that they use. And finally, WordPress is incredibly legacy software. It was written, I think, in 2003, was first version. I was in high school then. I was writing terrible code still, but I was in high school and Matt Mullenweg was changing the world, even if he didn't know it yet. It's still in production everywhere. It gets constant updates. It's clearly a great platform. However, there's a lot in WordPress, which is still very legacy. What that means is, as a modern PHP developer, there are a lot of things that I would normally do in a project which I can't really do easily in WordPress, because it's based on design decisions that were made 15, 16 years ago. We're built around the concepts of what was possible in PHP at the time. PHP as a language has evolved massively since that time, but WordPress is still, I won't say it's capable of running PHP for anymore, but you wouldn't know it from looking at some of the code. So what can't you do with WordPress? Not much. You can do a lot with it. So just from the WordPress repository, the plug-in store, whatever you want to call it, if you want to do e-commerce, here's a bunch of plug-ins. There's even more paid ones. If you want to do e-learning, here's some plug-ins. Social networking, you can build your own social network on a blog site. You can have thousands of users coming in and using it as your kind of Facebook, but it's WordPress. Some development, however, can get a bit painful. So some of you might recognize this picture of the double-clawed PHP hammer. It is the greatest thing that came as a result of a blog post about seven or eight years ago, which was called PHP, a fractal of bad design. And in it, someone listed every terrible thing with PHP, why it's the worst language ever, why it's completely unredeemable. And yet it's still one of the most popular programming languages. It's still running so much of the internet. And he described PHP as everything's just a little bit wrong. So the analogy was a hammer. You go and pick up a hammer, and it's got a claw on both sides. You can still bash a nail in with the side of it, so it's still functional as a hammer, but it's a little bit wrong. And that's the kind of era that PHP came from. Everything's just a little bit wrong. It's not how you would approach modern programming or modern development. So if we want to make WordPress a bit more developer-friendly, here are some of the things that we want. We want things that use a template language. So there's blade, there's twig, there's even smarty, which no one should ever touch. But there are many PHP templating languages out there. Models for custom data types. So a model encapsulates everything about a single piece of data. You can pass it around, you can make modifications, and it's all kept in one single object that you can pass around and use. Controllers to find models and views. So there's MVC architecture, which is model view controller. The idea is the controller does all of the grunt work. It finds, it modifies your models, and then it hands it off to a view, which just does display and doesn't do anything else. The ability to add tests to the code base, it is possible to do, but there's no great testing framework set up. It's difficult to test WordPress themes and plugins properly. Because they're built around a very old style of procedural PHP. And concise, predictable routing can be difficult with WordPress themes. It kind of does a lot of magic behind the scenes to find which template to run, and which file to run, and there is a lot of magic that happens based on file names or things just expected to be in the right place. So when we're talking about making WordPress more developer friendly, we're kind of talking about making it look a little bit more like a framework. So the current two of the big popular ones are Laravel and Symphony. They are everywhere. You're probably already using parts of them without realizing it. Symphony in particular is a whole bunch of little components which come everywhere. Laravel itself uses a whole bunch of Symphony. Anyway, they're the more modern ways of building PHP. So what already exists? We have Sage, which brings in blade templates from Laravel. It's really great. You can write nice, it's a templating language that is nice, concise, it's not too scary, it's really quick to run. Sage doesn't have all the rest of the MVC, it does have controllers, but really it's still just a nice wrapper around old theme development. Corsell is a really interesting project I came across. So Laravel uses an object-relational mapper called Eloquent. And Eloquent is a great little tool for accessing all of your database. And Corsell provides all of the models to access a WordPress database from a Laravel application, which is excellent, except we're not running a Laravel application. We're still working in WordPress. And there's Timber, which has been talked about a few times. It does its own kind of MVC architecture, it's got twig templating, it has controllers, it provides some kind of models, it's all right. I'm not a fan of it, but it's all right. So let's get a framework into a theme. I've gone with Lumen. Lumen is Laravel Lite. It is a microservice framework. It just doesn't have all of the big, heavy parts like session management and things like that because WordPress is already doing that. WordPress is already doing sessions, it's already doing user authentication, it's already doing all of the things that you would have to build out from a framework. So Lumen's a great place to start. We have a few problems. Lumen runs from the public folder. It is designed to be the entire application in and of itself, and most of the code is meant to live outside of the web route. So you have the public folder which contains one file, which is index.php, that's it. And an hgaccess file to tell the server to route all the requests through that one file. Lumen has its own router, it has its own environment, and as soon as it boots up, it doesn't know that it's part of another application. It tries to take over the entire request and go, yes, I'm running Lumen, what now? A bit of a problem because WordPress is still trying to run the show here as well. And WordPress is actually still trying to find files in the file system. So the way WordPress things work is it looks for a file name based on the type of template that it's trying to run, or the part of the template that it's trying to run. And it's looking for all of these things, which don't necessarily map well into Lumen application. So let's just have a talk about themes a little bit. Themes can provide style and functionality. They're kind of like special plug-in where you can only have one of them installed, but ultimately it's all running PHP. It can do kind of everything. It's common for themes to define custom post types with custom styling. So if you get a theme which is for real estate, it will have a properties post type that it defines, and it knows about that and it has all the custom styling and templates for that property post type. If you don't define a template for a page, it starts falling back to more and more general templates. It kind of has a hierarchy which it goes down to try and find the most specific template that it can to build something. The WordPress template hierarchy can kind of seem like voodoo because it's working based on where it assumes things should be. And you can add new files and it will suddenly start working without you changing any other code. It just kind of magically happens. And it's not always clear which file is actually providing the template. So your theme may provide a file, but it might be falling back to something from WooCommerce or it could be your child theme is overriding a template from your master theme. There's a whole bunch of things. So it can be difficult to find out which actual file is providing a piece of template. And the page you see is usually compiled out of a few different template parts. So its first challenge is making the template hierarchy work with roots. Roots in Laravel are effectively how it takes the URL and figures out which part of the code is going to run for that URL, which controller it's going to run. This is the template hierarchy. This is how WordPress decides what is going to be run, what file is going to be used. I don't know how readable it is, but if we go across from the left, say you're looking at an author archive page. First, it goes, OK, I'm looking for an archive page. I'm looking for an author archive. Does the author, is there a file called author-sam.php? If it finds it, it uses that. Great. If there's not, my ID is one. So is there author-1.php? If there is, it uses it. If not, it falls back to author.php. If that's not defined, it's still an archive page, so it'll fall back to archive.php. If that's not defined, it falls back to index.php, and everything falls back to index.php. And some of you can probably guess where I'm going with this. But if you're a bit like me and you see this kind of structure and go, that's a bit messy. Could do better. The template structure kind of looks a lot like this. You don't have to define all of those things. You only have to define your index.php. And conveniently, you remember I said Lumen only has one file and it's index.php. So that makes it really, really easy. So we still have to define a functions.php in a style.css because WordPress expects them because it's magic. But we can do all of our actual routing from the index.php. So we can start using all of the bits and pieces that are in Lumen instead of relying on everything being magic from WordPress. So the request comes into WordPress. That boots up functions.php in our theme. What we do there is we boot up Lumen, registers all its routes, and then WordPress continues on. When it gets to the time when WordPress actually wants to render a page, it goes. And it looks for author named php, can't find it. Author ID, can't find it. Author php, can't find it. Archive php, still can't find it. Index php, oh, we've got that one. So it calls index php, includes it. And that's when we dispatch the route. And we have a route here, which is author name. So we can use that route. We can call the controller author by name. And we can give a response through that way. So we've broken up the index from Lumen into two parts. There's the initialization of the framework in functions. And then there's the actual dispatching of the request in index. And I'm sorry if this is really hard to read. It's not particularly important that you read it. But the first step, we add a filter on to the template hierarchy, and we get every single file that WordPress is trying to find. So it's not finding them, but it's still looking for each of those files in order. So we collect them with a filter. And then when we get to index, we dispatch the route. So we go through and we go and check all of those files that WordPress was trying to find and say, do we have a route that matches this one? If we do, we fire it off, and away we go. So you get a WordPress URL, which looks like the website slash author slash LaraPress that gets routed through to the author name route that gets passed to a controller. And this controller is just dumping the request and dumping the name that we've got. So we can see. And we can see there, as far as Lumen is concerned, we were asked for author dash LaraPress, and we got the username LaraPress. Hooray, we have templates working through routes. So the next challenge is native database access. Yeah? Is that any? Aim it better there. The next problem is native database access. I'll take that off too. So we've got all the routing happening with blade templates, and so far all we've done is effectively replicated Sage in a more complex and terrifying way. We still need to access the database, we still need to pull out objects, and we want to do that with models. So let's just have a quick talk about posts. There is one data type in WordPress, and it is the post. Everything is a post. You see a page? No, it's a post. You see an image or a media object? Nope, it's a post. It is very flexible and also just, it's mind boggling that this is how all of the data types in WordPress work. So posts have very limited information about themselves, and then everything else that's special about a post is extended with post meta, which is another table, and it's all kind of a bit awkward. You can register your own post types, your own custom post types, but because it's WordPress and everything's a little bit magic, if you have a plug-in which registers a book post type, and then you have something else which registers a book post type, one of them will win, and you don't know which one. And post types can be versioned, so there might be multiple copies of the data in a particular object, and it can be difficult to use, find, know which posts or which objects actually exist, and how you're meant to access them. So we have some other hurdles to overcome. Lumen is configured through a .env file, and that's where you're meant to set the database configuration details. Call me crazy, I don't think a theme should have database configuration details stored in it. The other problem is Eloquent uses PDO, which is PHP data objects. It uses it because Eloquent can talk to SQL Lite, it can talk to MySQL, can talk to Postgres, it can talk to a whole bunch of different database languages. WordPress uses MySQL i, which can only talk to MySQL. They are completely different libraries, and while they both do the same thing, their APIs aren't interchangeable. I can't just grab the MySQL i object and hand it to Eloquent and expect it to know what to do. It doesn't work. It's just a bit of a problem. Custom post types, as I said, don't really fit neatly into models, and models are designed to define how you create, how you update, how you access all the data, and all the bits of meta information about the data. It's a massive headache. Except we have Corsale. So the problem with Corsale before was it was built for Laravel and Lumen, and all of those tools. It was built to be used outside of WordPress, except we've just injected Lumen into WordPress. So we have access to this tool, which gives us really nice, native to Lumen access to the WordPress database. So we just use the configuration settings that come from the WP config, and we shove them into Lumen and say, hey, here's how we defined our database. We don't need our own.env. We've already got that all defined, and we can grab a user by the ID, and then we have a nice interface within our templates where we're just calling properties of the model. So we have models working, and now we get to the last problem, which is the loop. I hate the loop. It is the antithesis of good design in modern PHP. This, for anyone who's unaware, is the loop. It changes the global state using a global variable called WPQuery. You call the post, and it loads up the next post, and then you have access to the data on the post through functions like the title and the content. The problem is, if something else calls the post again, it moves it on, and you don't know. So models are a lot better, because once you've got a model, you're accessing all the data directly from the model, and you're not worrying too much about whether the post has been called in some function somewhere, which does happen. So I had a quick look at how the other tools that exist deal with this. Yeah. Sage doesn't deal with the loop. It just uses the loop. As I said before, Sage is adding a nice layer of sugar on top of existing WordPress templates, but it's not actually doing anything special. Timber grabs WPQuery. It's still using the global WPQuery, and it just wraps a nice bunch of sugar around it so it looks like a model, even though it's not really. Yeah. We can do better. Here's a terrible solution. So WordPress has already figured out all the posts that need to be displayed on the page. It's got them all sitting in WPQuery as a loop. So I'm just going to use the loop. I'm just going to get user to grab all the IDs, and then I'm going to build my own collection of eloquent models that I can use across all my templates. This is a terrible solution, but it works. So first we grab the list of posts IDs from the loop, small little piece of code. We create a collection of Corsale post models with posts to find many with the IDs, and then we hide it in a common class. So I just shoved it into the controller class, the base controller class for all of my controllers. So every single controller now has access to collect posts, and it will hand them back a collection of nice Corsale models of all the posts that was meant to display on this page. Could be one, could be 15, who knows. So in the controllers we can just call this collect posts. Hey, look at that, we've got a nice collection of posts. In the templates, we treat it like a collection of posts. We can loop through it with our four reaches. We can access all of the bits. We don't have to worry about calling something that we'll call the post again because we're not using the post functions here anymore. We're using true proper models that we can pass around and pull bits and pieces out of. And the really nice thing about Corsale models is it takes all the WP meta and makes it available from the same model without running extra queries or extra functions. It's all there. So it looks ugly, I haven't done any styling, but here it is rendered. All posts by LaraPress, we've got the author, user nice name, that's our author model. And then we can loop through all the posts and give them a title and spit out the content. So what have we learned? WordPress is incredibly flexible. We can do a lot. It's PHP and that's not everything that you need to know but WordPress itself as software has been written with the right amount of magic and hooks and loops and everything else to be incredibly flexible. Lumen is scarily well-adapted to being a WordPress theme. I thought this was going to take me weeks and it took me a weekend. It kind of all just fell into place really easily and I'm a little bit scared of that. Just because something's legacy doesn't mean that you're trapped there anymore. So that's what projects like Sage and Timber are trying to do. They're trying to give you the modern PHP tools to work with WordPress. And this is maybe taking it a bit far but it's what I was trying to attempt to do. I was trying to give myself everything that I like about a framework but still running in WordPress. You probably shouldn't use this. That's one thing that I learned. You really probably shouldn't use this in production. This is a proof of concept. It's a terrible one and I haven't explored all of the other nasty bits of weird magic in WordPress. No, really don't use this in production unless you already are. So one of the even more terrifying things that I found when I started researching this and I started going, hey guys, wouldn't it be funny if I chucked Laravel in WordPress? A surprising number of people went, oh yeah, we did that. It's done everywhere. If you wanna see this code and play with it, it's very messy. I've literally done the amount of code that was needed for the presentation, pushed it and left it. So you have my few routes that I have there. But yeah, it's open source. It's all up on GitHub if you wanna play with it and see if you can make something actually useful out of it. But you probably shouldn't. So, any questions? All right, we've got some questions already. Have we got a second runner over here? Yeah, so we've got Lady and the Green shirt up the back. It's a race. So does WordPress take note of which files don't exist when it's looking for all the different template files that are there or has it just checked them every single request? I'm assuming that would be quite intensive. Well, it checks every single request anyway. So that filter that I'm hooking into is it gets handed a list of templates that it could possibly be. And then it quite literally goes through and does a file exist for each single one of those. So it's not going to be particularly more intensive than any other template. It's just, it finds none of them except for index PHP and we're collecting the list that it's looking for. Hi, can you describe why it's terrible? You said that a number of times and then people have done it. Did they find it terrible? The people I talked to who did it said their experience was terrible, but I think they were perhaps approaching it from a different direction. I didn't ask too heavily about what they were doing because it was all done within companies. I'm saying this particular implementation is terrible because it's a nasty hack that I built up in a weekend. And like most things that I built up in a weekend, it'll probably find its way into production soon and be there for years. As I said, my single file PHP blog has been running for seven years, which was a nasty weekend hack to be as obnoxious as possible and see if I can make it work. Yeah, it's not terrible in and of itself. It's just this particular implementation isn't great and you're also pulling a lot of extra stuff into WordPress for developer niceness, but I have no idea what effect it'll have on performance in a real production system. Anyone else? Do we have any more questions? Do you have any examples? Yeah, we have a question over here. Do you have a microphone? While we're waiting for the microphone to come down, I have a question for you Sam. Do you have any examples we can look at of where someone has used a similar sort of solution or something else to combine them? There's Sage and Timber are both doing kind of similar things. So I know there are a lot of sites that are built on top of Timber, which is adding, it does add controllers in, it does add a kind of model in, it adds bits of an MPC architecture in terms of examples for places using Laravel in WordPress, I couldn't tell you where they are, simply because you'd probably never know. It's all abstracted away behind and what you get out will probably still look like a WordPress site. So I'm guessing that all works in server side PHP. So it holds all those posts just in RAM. Yep. Well, when you're building the collection, it's pulling them all out from the database. But on the client side, on the server side? Server side. Okay, yeah. So it is a Sydney and RAM on the server. Yes. Rula, did I say it right? Yes, you did. Nailed it. Right, so it's kind of like taking it back to WordPress. I think some of the drawbacks you raised like super important to talk about. So thank you for bringing them up. I took a photo of your slide. If I find out your tweet, I'm gonna be tweeting it at you about that. So thanks for that. I don't actually check Twitter very often. It exists. That's okay. So the question is, if you were gonna bring this to core, you're the captain of the ship, you can make this happen. So what's the first step that you would take to like help WordPress, PHP back end, that architecture we're talking about to start iterating towards being able to have some of these things that you crave and that you need as a developer now? That's a very difficult question because the problem that WordPress faces, and I'm sure you're very well aware of this, is WordPress has to support all of the stuff that's already out there. We can't turn off the loop and provide a nice interface for pulling out posts as a collection because there's tens, hundreds of thousands of things and plugins that don't know how to use that. And if we provide that, which is what's happened with WP Query, it's a wrapper around what was clearly the older functions. But if we provide that and then put backwards compatibility layers like the loop in place, no one's ever gonna use the new stuff because they're just gonna use all of the old stuff. It's a problem which there's no easy solution to it, but I will say it is possible. If you look at Drupal, the Drupal 728 conversion was switching from their own home spun framework to Drupal 8 is symphony. It is a symphony project now. It is using a full-featured current PHP framework. I'm not saying it's any better to develop in. I haven't played with Drupal 8, but I'm saying it is possible, but there has to be a lot of unhappy people and a lot of breaking changes. For sure. Yeah, major version number is definitely relevant there. Thank you. Yeah, so we've got the closing remarks in a couple of minutes, guys. So we'll take one more question, I think. So who's got a burning question? We've got one up the back here. If the questions, why would you do this? It's, I can't answer that. Is this essentially achieving what you would achieve by using WordPress as a headless, CFS and a custom front-end? Um... So WordPress API may be plus custom front-end? Possibly, because you could do it that way, and I've seen plenty of people do it that way where you're using WordPress as a data store and an API. This is still providing you PHP code running on the server so you can build out an application and smart routing and a whole bunch of other bits and pieces. So it's not exactly the same. I'm not saying this is better or worse because I'm still firmly of the opinion that this probably isn't a great idea to do in production, even if it does make it there. But no, it's not exactly the same thing as using WordPress API as a headless CMS. If you were doing this for the purpose of easing custom development, would you be better off just not having WordPress in the mix and just using Laravel or something like it? If that was your own goal? The reason why that doesn't happen and the reason why Corsell exists is development is very much attached from user experience and WordPress still provides a lot of functionality out of the box and with plugins that you can't really just drop into a Laravel application. So we could use this and have a modern development environment for a WooCommerce site or for a BuddyPress site and you've got all of that functionality already still built and running in WordPress but we're just using this as a layer to present it in a more clean, modern way and a more clean, modern way to access and manipulate the data. Thanks. Big round of applause to Sam Levy, everyone.