I will have hundreds of biographies for characters which consist of some text, markup and image(s).
I want to have a template where you can write e.g. {{Biography|Steven}} and it grabs that biography from a page of all bios where each one is linked to a parameter.
Further, the option to only show part of a bio, e.g. {{Biography|Steven|Personality}}
I know I could make a template for each biography, but then I would have hundreds of templates that editors have to find, and I dont know if thats good performance wise (its kind of ok?).
Then I still wouldnt know how to set up the template to conditionally display on parts of the bio.
I also wonder if I should possibly have some data storage extension, but I dont see how that is possibly faster than text on a page transcluded.
Do I need conditional code using ParserFunctions or my preference, Lua, and use its many possible versions of a switch statement.
I see this template as a good feature because people can just edit any bio on one page, or one page for each character classification, then anyone can transclude it instead of writing out the same content but making errors, wasting time, etc.
This template will use extremely high-use, so its important that it performs well and easy to use for editors.
I'm not asking for someone to write it for me, just advice on how to go about it.
To do this you will need to make your data granular enough to be able to select individual biography fields. There are several ways to do this in MediaWiki.
You can use #switch statements to create a template that will do the job, without adding any extensions. For example, you can have a data module at Template:Biography/data
:
{{#switch: {{{character|}}}
| Steven = {{#switch: {{{trait|}}}
| Personality = Outgoing
| Age = 25
}}
| Dennis = {{#switch: {{{trait|}}}
| Personality = Shy
| Age = 34
}}
}}
You can then call that from Template:Biography
like this:
{{#if: {{{2|}}}
| {{Biography/data|character={{{1|}}}|trait={{{2|}}}}}
|
* Name: {{{1|}}}
* Age: {{Biography/data|character={{{1|}}}|trait=Age}}
* Personality: {{Biography/data|character={{{1|}}}|trait=Personality}}
}}
You can organise this #switch statement in several different ways. For example, you can have the data for each character stored in a different subtemplate of Template:Biography
, like Template:Biography/data/Steven
, Template:Biography/data/Dennis
, etc.
Template:Biography:
{{#if: {{{2|}}}
| {{Biography/data|{{{1|}}}|{{{2|}}}}}
|
* Name: {{{1|}}}
* Age: {{Biography/data|{{{1|}}}|Age}}
* Personality: {{Biography/data|{{{1|}}}|Personality}}
}}
Template:Biography/data
{{Biography/data/{{{1|}}}|trait={{{2|}}}}}
Template:Biography/data/Steven:
{{#switch: {{{trait|}}}
| Personality = Outgoing
| Age = 25
}}
This will be better than our first attempt, as long switch statements are notoriously slow in MediaWiki. However, you still need two levels of subtemplates to make it work, and if you don't specify a trait, you have to call the subtemplates multiple times. So it is still going to be slow.
You can speed things up by writing the template in Lua, via the Scribunto extension. You can write a data module like this (let's say it is called Module:Biography/data
):
return {
['Steven'] = {
Personality = 'Outgoing',
Age = 25,
},
['Dennis'] = {
Personality = 'Shy',
Age = 34,
},
}
Then you can load the data using mw.loadData, which will load the entire table once per page, instead of every time you use the {{Biography}}
template. For example:
local data = mw.loadData('Module:Biography/data')
local p = {}
local BIO_TEMPLATE = [[
* Name: %s
* Age: %d
* Personality: %s]]
-- Trim whitespace from args, and treat blank args as nil
local function preprocessArg(s)
if not s then
return nil
end
s = s:match('^%s*(.-)%s*$') -- trim whitespace
if s == '' then
return nil
else
return s
end
end
function p.main(frame)
local args = frame.args
local character = preprocessArg(args[1])
local trait = preprocessArg(args[2])
-- Check for blank character arguments
if not character then
return ''
end
-- Get the data for the specified character
local characterData = data[character]
if not characterData then
return ''
end
if trait then
-- User specified a trait, so return it
return characterData[trait] or ''
else
-- Return the biography template with all the traits in it
return string.format(
BIO_TEMPLATE,
character,
characterData.Age,
characterData.Personality
)
end
end
return p
You can also split the data pages up by character or by trait, in much the same way as you can with #switch.
The disadvantage of using Lua is that your editors will need to learn Lua syntax as well as wikitext syntax to add entries to the data module(s). Lua syntax is generally harder to master than wikitext, so this may put people off contributing.
The problem of wikitext data being unstructured is a long-standing one, so there have been lots of attempts to fix it over the years. Before settling on pure parser functions or pure Scribunto, you would do well to investigate some of the extensions that have been made to try and address this problem. (Remember that you can access these extensions via templates, and generally, via Scribunto as well.)
For example, the labeled section transclusion extension will allow you to write a normal biography for your character, delimit the different sections, and then transclude those sections individually onto other pages.
There are also more data-focused extensions that can help you to make more granular templates without getting bogged down in switch functions or data modules:
These will store your data fields separately in a database (usually the same one as your MediaWiki installation) so the performance characteristics will depend on how many database accesses you need to generate a page, and how you have your caching set up.
If I were you I would have a look at the available extensions first and see if there is anything that would fit your situation well, then fine-tune that using a template or Scribunto.