December 23, 2023: My First Extension
D minus nine days and counting.
So, my number one priority to get done before the hard launch is to finally implement the Gamespace and all the other namespaces (and subspaces) that I want the Wongery to have. This will be a nontrivial matter, because it will involve creating custom extensions to the MediaWiki code, and I've never created a MediaWiki extension before, or an extension to any software. As I've mentioned multiple times, I'm not much of a programmer; I have enough mostly self-taught programming knowledge to have muddled through setting the site up, but I have no professional programming experience, and creating a MediaWiki extension is something completely new to me.
Although now I suppose perhaps I can put some of that in the past tense. I had never created a MediaWiki extension before; creating a MediaWiki extension was something completely new to me. Because as of this morning, I have now created my first MediaWiki extension. It doesn't do much, but it does do something. And when I say it does do something, I mean, uh, something other than crash the wiki. It does something it's actually supposed to do. It doesn't yet do everything it's supposed to do, but it does do part of it.
Maybe it would have done everything it was supposed to do, had I spent more time on it, because, well, this was not what I spent most of my time yesterday doing. Maybe it should have been, but it wasn't. For one thing, I was working yesterday, though that will probably be my last workday until 2024. While I sometimes have a little downtime during work when I can pursue my own projects, I don't of course have my computer with me. I do have some laptops, but they're cheap laptops with relatively little processing power (I learned my lesson after having a couple of pricier laptops broken because of the wear and tear of being toted around so much), and while I do have VS Code installed on the slightly less incapable of my two cheap laptops, I don't have Wampserver installed on it, so even if I did have the time for it I couldn't really run my code there. What I can do is read through the MediaWiki documentation and try to figure out what I need to do, and I did do that, but I had to wait until I got home to actually write and test the code.
But even when I got home that evening (well, I guess technically it was late afternoon), I still didn't focus on working on the extension. I mentioned a couple of days ago that I was owed more than four thousand dollars by one company I worked for this month, and I wasn't sure whether I was going to get the money before January. Well, at least there's some good news, because I did. Most of it, anyway; the remainder I'm sure won't come till January; but I did receive almost four thousand dollars. Not only does this mean I'm going to be able to pay my rent on time next month after all, and not only does it mean that I will have the money for at least some of what I'd hoped to do for the hard launch, but I actually have a bit left over. And, uh... I may have spent some of that money not entirely wisely.
As it happens, a couple of the RPGs that I'd hoped to have support for on the Wongery by the hard launch released new editions during the period of time when the industry I worked for was going through some trouble and work was slow and I didn't have the money to spare to buy the new books. Specifically, Chaosium released this spring a new edition of Basic Roleplaying, and in a bit of fallout from the OGL debacle at the beginning of this year, Paizo is in the middle of releasing its "remastered" rules for Pathfinder. In both cases, the changes are apparently relatively minor; Paizo insists that the Remaster Project is not a new edition and "does not change the fundamental core system design of Pathfinder", and I have the impression that the biggest change in the latest edition of BRP is the licensing. (The previous edition of BRP, released in 2020, which I do have a copy of, was released under a cobbled-together custom license that came with a lot of troublesome conditions and exclusions; the latest edition uses the much more open and creator-friendly Open RPG Creative License spearheaded by Paizo.) Still, if I was going to have material for these systems on the Wongery, I wanted it to be for the latest editions of the systems, and even if the changes were relatively minor, I should still take them into account... which I couldn't do without having the most recent books.
Well, now that I did have a little money to spare, I went ahead and bought those books, and also the core books for another RPG I didn't already have but that I wanted to have content for on the Wongery: Pinnacle Entertainment Group's Savage Worlds. (Unrelated, I also bought books for another RPG I was interested in, Talislanta, not because I plan to have content for it on the Wongery—it's not released under an open license, although its setting may be a possible candidate for a World of the Week when and if that feature is up and going again—but because it had just released a new edition through a crowdfunding campaign that had completed but was still taking late pledges, and I didn't know how much longer that would be the case or whether the books would be available anywhere after the campaign closed and was afraid if I waited to get it it might be too late.) And so I spent a lot of time yesterday reading through those books. This was, perhaps, not the best use of either my money or my time. Yes, the reason I bought those books now (Talislanta excepted) was because of the Wongery; I would have wanted them eventually anyway, but were it not for my hope to be able to make content for them for the Wongery Gamespace before the hard launch in January there wouldn't have been as much urgency in my acquiring them, and I probably would have waited a few more months until I was in a slightly better financial situation. (I definitely won't have the physical books I ordered before the hard launch, of course, since they'll take a while to ship, but I got the PDFs immediately. (Both Chaosium and Pinnacle throw in the PDFs for free if you order physical books; Paizo makes you order the PDFs separately. Poor show, Paizo.)) But realistically, even now that I have the books it seems unlikely I'm going to have time to do anything with them before the hard launch. Maybe I'll have time to finish reading them (or maybe not; I have a lot else to do and I'm not an especially fast reader), but even if I do there's not going to be time to make much content. I probably could have waited to get those books.
So, anyway, those are the things I was doing yesterday that weren't working on the extension. But I did spend some time working on the extension, and that's what this post is mostly about. (Or was intended to be mostly about; as usual, I managed to spend multiple paragraphs rambling about other matters.)
When I say "the extension", though, I don't mean the extension that adds the additional namespaces and subspaces to the Wongery. I figured that never having written a MediaWiki extension before, I should maybe start with something simpler. And, as it happened, there was another extension that I'd wanted to have anyway, and that seemed like it might be a lot less involved.
The main page of the Wongery site has a sidebar that shows a random article from the Central Wongery. (The site is way overdue for a serious redesign—yet another thing I really want to get done before the hard launch, but we'll see whether it actually happens—but that random article sidebar is something that I'd still want to have in any redesigned version.) Sometimes, though, the random article that it pulls up is a disambiguation page, or it's an article about real-world topics like trees or governments, or a general topic like magic or transformation. These aren't the kinds of articles I really want to showcase in that sidebar; I'd prefer it only showed articles that pertained to specific imaginary worlds. The most straightforward way I could think of to do so was to put a template, say, "{{Unlisted}}", on articles I wanted to exclude from the random page selection (said template could be transcluded in other templates like the {{disambig}} template for disambiguation pages), and then make an extension that executes that exclusion.
So, since this seemed substantially simpler than the subspace extension, I figured this would make a good first extension for me. Even though what I really wanted for my purposes was for it to exclude articles that linked to a specific template, though, I figured I'd make it a little more general in its application in case other people found other uses for it. In particular, I decided on the following:
- Rather than it being tied to a specific template, you can specify the template or templates to be excluded in the extension settings
- In addition to having it exclude pages that include specific template, you can also have it exclude pages in a certain category or categories
- Depending on the settings, rather than have it exclude pages with specific templates or categories, you can alternatively have it pull random pages only from those with the specified templates or categories
I was going to call the extension RandomExclude, but it turns out there's already an extension called ExcludeRandom, so I figured that would be confusing. I couldn't just use ExcludeRandom because it was no longer actively maintained and may not work with current versions of MediaWiki, and even if it did it didn't really do what I needed; it let you list specific pages to be excluded rather than excluding pages by category or template. So anyway, I decided to call my custom extension RandomRules.
And then I had to figure out the basics of just how to even get started with making a MediaWiki extension, which wasn't easy, because while there is some documentation, it's confusing and elliptical. Or very possibly it's perfectly complete and straightforward to a capable PHP programmer who knows what they're doing, and it's only my inexperience and ineptitude that kept me from understanding it. MediaWiki does supply a dummy sample extension called BoilerPlate that you can use as an example and starting point, which helped, but even with that I had a hard time figuring out what to do. In any case, eventually I worked out that you make an extension by specifying what hooks it responds to (basically, particular places in the MediaWiki code that you can have trigger your own functions) and writing the code to be called by those hooks. It still took a bit of trial and error to get everything lined up and get the code to call the correct functions at the correct times, but eventually I managed to create an extension that worked, in the sense of not crashing the wiki. It didn't do anything, but it didn't crash the wiki. That was a good starting point.
However, when I tried to get it to do something, I quickly found that I seemed to be using the wrong hook. I was having the function go off a hook called RandomPageQueryHook, but with some experimentation I found that this hook was triggered by the Random Page feature on the wiki, but not by the main page's API call to select a random page. I looked for other triggers that might apply, but without success, and eventually figured that if I wanted my extension to apply both to the Random Page feature and to API calls for random pages—which I did"I'd have to use two separate hooks, and write two separate functions. So that's what I ended up doing, the other hook being the sesquipedal ApiQueryBaseBeforeQuery.
Now, what my function apparently had to do was modify the query that would be sent to the MySQL database to pull the words, and it had to do so by changing or appending to the values of specific variables representing the conditions and join conditions that would be included in that query. The format of those variables, however, seemed impossibly arcane, and their documentation hopelessly inadequate. I tried looking in the MediaWiki code itself at the functions surrounding the hook to see if I could figure out what they were doing, but their functionality was to me completely opaque. My struggles were only slackened when I finally noticed that when I hovered the cursor over the name of the function in Visual Studio Code, a tooltip appeared with more detailed documentation that finally explained the format of these parameters. I have no idea where Visual Studio Code is pulling that documentation from. It has to be pulling it from somewhere, but neither a websearch for the text in that tooltip nor a search for that text in the MediaWiki files turned anything up. My best guess is that the text it's pulling from is somewhere in the MediaWiki files, but it's in some format that prevents it from showing up in a simple text search, but I don't know. This should be obvious, and I'm probably just being very stupid. But, in any case, unable to find this documentation anywhere else, I read it in the tooltip, and—with a bit more trial and error, with a heavy emphasis on the error"worked out how to do what I needed to do.
At least, I worked out what I needed to do for about one eighth of the things the extension is supposed to do. The extension will, if directed, restrict the pull of random pages for the wiki's Random Page function to those belonging to specific categories. It doesn't apply yet to templates, it doesn't apply yet to API calls, and it doesn't yet have the ability to exclude pages belonging to specific categories. That last will be my next task, though I'm not yet sure how to go about it; it seems that excluding certain categories may require a more complicated query than including them did. Regardless, even if it doesn't yet do all or even most of what it's supposed to do, the fact that the extension even does part of what it's supposed to do I'm going to chalk up as a success. Maybe by tomorrow I'll have it fully functional. Maybe not; I guess we'll see.
Of course, I do want to make this extension publicly accessible so that others could use it. I'm going to put it up on Github. The only reason it's not there yet is because I haven't figured out how to put it there. Github is another thing I really don't know much about or have much experience with; I did purchase a Udemy course about Github that I plan to take, but that'll be after I complete the Udemy course on PHP, and maybe the Udemy course on Lua (which I'm taking because it turns out MediaWiki uses Lua for some template scripting of a sort I think I'm eventually going to have to do to format statblocks in the Gamespace), and that may be a while. Regardless, the HTML/CSS and Javascript courses I took on Udemy did make some use of Github, so I at least know the basics of pushing projects to Github, even if I don't know the details. But when I tried to push my extension to Github, I ran into a problem. I created a new Github account as Clay Salvage for the code projects I'm creating for the Wongery, but of course I was using a different Github account for the Udemy lessons, and, uh, apparently I'm still signed into that account on Visual Studio, so when I tried pushing the extension to Github, being signed into the wrong account I got a HTTP 403 permission error. I'm sure there must be a very simple way to sign out of my other Github account and sign in to my new account, but I haven't figured it out yet. As I have emphasized several times before, I have no idea what I'm doing. But I'll get there. In the meantime, I do have the Github repository for the extension set up—it's at https://github.com/ClaySalvage/RandomRules—but I haven't been able to push the code to the repository, so at the time I'm writing this there's nothing there yet.
So. Anyway. I guess that's my next step: figuring out how to switch Github accounts so I can push my code to Github. Then I'll try to get the rest of the extension's functionality working, and... well, eventually I've still got to tackle that more complex subspace extension. I've got a lot of work ahead of me.
D minus nine days and counting.