Since its release, many and varied extensions have been written and released for Lorekeeper. These modifications to the framework's code allow for a variety of new functionality that (given the inherently opt-in nature of extensions) allows them to serve many and in fact many different potential use cases for Lorekeeper itself.
Should you want to author an extension of your own, there are certain guidelines you should follow in the interest of making the process as smooth as possible for all participants. This article covers these, as well as registering your extension on this wiki and releasing it to the public. Note that this does not cover making the modifications themselves.
Note that this article covers the creation and releasing of extensions; for installing them, see Tutorial: Installing Extensions.
Creating an Extension
Before you begin any work, it's useful to have and/or keep in mind a few things.
- You must have a local instance on which to work.
- This is non-negotiable when making significant changes to Lorekeeper, extension-writing included. Working in a dev environment is inherently more conducive to, well, development; in this case it includes easier display of errors, ability to simply save files and see the modifications reflected on your dev environment (without having to commit+push), and so on.
- Lorekeeper, as of v2.0.0, requires PHP 7.4...
- ... and runs on Laravel 8.
Consequently, the primary prerequisite to working on Lorekeeper in any capacity is having a local test environment set up with PHP 7.4. For more information, see Tutorial: Local Host. If you are unfamiliar with working with PHP and/or Laravel (itself a PHP-based framework), it is recommended that you familiarize yourself with their basic concepts beforehand. Depending on your learning style, you may want to dive right in and look at the existing code, do research, read documentation, or some combination thereof.
Also note that you must be willing to support extensions you author (within reason), fixing bugs and/or handling pull requests as appropriate. If for whatever reason you cannot fulfill this, it is recommended that you hand off maintenance, etc. of the extension, or to be willing to do so if someone steps forward. You are not obligated to make changes to functionality/fulfill feature requests, however.
You will also need a GitHub account, with the Lorekeeper repository forked.
Identifying the Extension's Purpose and Scope
First and foremost, you need an idea as to what your extension will do. Some potential sources of inspiration are:
- Is there a feature or function that would be helpful to you/a site you run that does not currently exist either in Lorekeeper or an extension?
- Does one of the ideas in the Community Feature Request document interest you?
You might also be hired to write an extension to serve a specific purpose.
Once you have an idea of what your extension should do, you should think about how you want to implement it. It can be helpful to think about existing structures in Lorekeeper or extensions that serve similar purposes, or might work a similar way to how your extension could work. Especially if referencing an extension, it may be helpful to consult the extension's author(s) for insight, keeping in mind to be respectful of their time and energy.
However works best for you, it can be helpful to plan out things such as:
- Database modifications
- Creation and/or editing of models
- Creation and/or editing of views
before actually writing any code. While you are doing this, it's important to keep in mind that a good extension is dynamic: it can be configured to serve a variety of potential use cases within its broadly stated purpose. This has implications in what sort of table(s) and columns you make, how they are structured, what data they must be able to hold, and so on and so forth cascading down through models and views. This may introduce complications, so it's important to account for it sooner rather than later-- so that you don't wind up needing to redo work, etc.
However, not all functions are well-suited to being made dynamic, or it would be prohibitively intensive to do so. You can make modifications to a single site just the same, hard-coding values and/or making specific assumptions about the required functionality that you would not be able to make otherwise, and this may be the most practical way to solve a given problem/provide a given functionality. While such modifications have their own merits, they are ultimately unsuited to being made extensions. This does not mean that you cannot publicly distribute the code or portions thereof (circumstances depending), as it may be helpful to others working on similar functions, but it does mean that you should not advertise it as an extension in the sense of the above.
In any case, it is helpful to have a clear idea of the function(s) your extension will have and those it will not-- or rather, to have a clearly defined scope. It is helpful to keep this relatively restricted and not change it majorly over the course of development. Of course, you may discover that it would be very helpful to have some additional minor function midway through; assuming you're willing and it's reasonable to implement it, and it is consistent with the primary purpose of the extension, there's no issue with including things like this. Or you may want to add some new functionality after having developed the extension; the considerations are similar. Rather, you will want to avoid tacking on not only additional work, but also additional functions which may muddy the purpose of your extension. Different functions may serve very different purposes to different people; you may have a whole suite of functions planned, but different sites may have use for only one or two parts of that whole. Developing each discrete function as its own extension and then combining them after the fact-- into an extension pack or simply on your own site/for your own use-- allows you to get the best of both worlds, so to speak. Additionally, it divides what may potentially be a very large amount of work into multiple discrete projects, which is likely to be more manageable to work on.
When you have completed your planning and have a clear idea of the purpose, scope, and necessary modifications required, you can move on to the next step.
All extensions, without exception, must be built upon a clean and unmodified copy of a branch from the Lorekeeper repo. If you have not already, you will want to identify which branch you want to use, depending on the current state of the release cycle.
- If a release branch exists, it is recommended that you build upon it.
- This is practical both because release branches are inherently stable-- only receiving bugfixes-- and because when the release they represent becomes the current version, extensions built upon it will already be up-to-date or close to it.
- Otherwise, it is recommended to use the current release (on master).
While it is not unviable to build on develop, it's not recommended as it incentivizes users toward a fundamentally unstable branch. Using develop, especially for a live site, is only advisable if you know what you're doing-- which users only interested in a given extension's functionality may or may not be well-equipped to handle, putting extra stress on volunteer support.
Once you have identified the branch you're going to build upon, check it out/switch to it, depending. It is now time to make the branch in which you will build your extension. You will want to select a succinct, descriptive name, preferably no more than three or four words, which summarizes the purpose of your extension. You should separate the words in the branch name using dashes
- or underscores
_. You must also browse the Extensions Category and ensure that this name is unique.
- It is strongly recommended that you use the
extension/prefix for extension branches for clarity.
- Do not prefix extension branches with
feature/, as feature branches are intended specifically for merging into core Lorekeeper.
- Encouraging users to pull branches with the
feature/prefix in this way creates conflicting messages and risk of difficulty for regular users, as they should never pull any of these branches due to the risk of unfinished and/or unreviewed code.
- See Contributing to Lorekeeper for more information.
- Encouraging users to pull branches with the
Once you've created your branch, make changes as appropriate.
Note that if your planned extension includes user notifications, you should familiarize yourself with the Community Notification Standard and request a notification block if necessary.
When ready, be sure to add your extension's details to config/lorekeeper/extension_tracker.php.
Releasing the Extension
When you have made modifications as desired and tested them to the best of your ability, you may wish to release these modifications to the public. This is a three-part process:
- Ensure all changes have been committed to your extension branch, and push it to your fork on GitHub
- Create documentation for it on this wiki
- Announce the release in the Lorekeeper Discord server
Creating a Documentation Page
If you have not already, you will need to register for an account on this wiki and request editing permissions via the technical-support channel in the Lorekeeper Discord server or via issue on the GitHub repo. When ready, you can create a documentation page for your extension via this process:
- Enter the name of your extension (the wiki key you specified in the extension_tracker config file, minus any underscores), prefixed by
Extensions:, into the search bar. (i.e. Extensions:Separate Prompts)
- This will bring you to a search results page informing you that there are no results, as the page does not yet exist.
- The title you entered will be present as a red link; click this to be brought to page creation.
- The page will then preload with the following:
- This will apply the Extension Page template once the page is saved.
- To save the page, enter and delete a space or something to that effect, then click "Save changes..." at the top right.
The page will then be created with the full extension page template. You may now fill out the page like so:
- Click "Edit source" in the top right of the page, which will bring you to the editing dialogue
- Fill out the infobox, which contains basic information about the extension
- Information about the template can be found at Template:Extensioninfobox. Brief explanations of each parameter are also included in the page template.
- Fill each section of the page body out as appropriate.
- Most of the body of the page should be self-explanatory; comments are also provided as prompts for each section.
It may be useful to you in filling out the page to make use of Template:Github, particularly if your extension makes use of an additional package. The template's page outlines the particulars of its use as well as parameters.
Announcing the Release
The Lorekeeper Discord server has a dedicated channel for announcing extension releases and updates,
#ext-releases-updates. A release message should contain the following:
- The name of the extension
- Some note that it is being released
- A note of what branch the extension is built on (assuming it is not master)
- A short description of the extension's function
- A link to the documentation page created in the previous step
It may also contain:
- A link to the extension's branch on GitHub
- Install instructions (these must be on the wiki documentation page, but may be included here as well)
Updating Extensions with Lorekeeper
In most cases, Lorekeeper updates will not break extension functionality. However, conflicts may ensue; for this reason, it is recommended to update extensions at minimum to each current release. When updating, make an effort to preserve incoming changes from Lorekeeper updates alongside the changes from your extension.
However, releases may contain certain points of concern or known breaking changes from the previous release. These are noted here in brief.
There are two major factors involved in updating extensions to 2.0.0. The first is that the Laravel version Lorekeeper uses has been upgraded from 5.8 to 8; consequently, some methods have changed.
Arr::only()is now used instead of
getRawOriginal()now serves the purpose
getOriginal()previously served (see for example the loot table display name field)
The second is that extensions which were not developed with modified-main or its component extensions in mind may encounter conflicting changes, especially as a consequence of the changes included Stacked Inventories, that require reworking part of the extension being updated's methods.