Community Central
Community Central
This blog assumes you are familiar with programming concepts, like variables and conditions. If you aren't, you should find a beginner course for it before learning how to use Lua on Fandom.


If you have been creating templates on your wiki, sooner or later you may have to learn how to use parser functions to create more complex code. Be it either {{#if:}} or {{#switch:}}, these help you to have more powerful building blocks for your content.

However, at some point you may face an issue: using too many #if makes it harder to read the source code. Imagine you wanted to auto-categorize the pages for episodes in your wiki about a TV show with the following rules:

  1. If there is a {{{season}}} parameter, it will add [[Category:Episodes from season {{{season}}}]].
  2. If the {{{season}}} parameter is missing, it will add [[Category:Episodes without a season]] so you can find it easily.

In a template, you would need an #if: as simple as:

{{#if:{{{season|}}}|[[Category:Episodes from season {{{season}}}]]|[[Category:Episodes without a season]]}}


So many {{ }} and [[ ]] may start to look confusing, but it isn't terrible... yet. What if we needed to add a new rule?

  1. If there is a {{{special}}} parameter, which determines whether the episode is a special or a regular episode, it must instead add [[Category:Special episodes from season {{{season}}}]].

How could we do this? Maybe something like:

{{#if:{{{season|}}}|{{#if:{{{special|}}}|[[Category:Special episodes from season {{{season}}}]]|[[Category:Episodes from season {{{season}}}]]}}|[[Category:Episodes with no season]]}}


Now it is getting a little harder to read, isn't it? We just added a single rule to our logic! Parser functions shine at simple checks, but they get more complicated as you try to implement a more complex logic using them. What should we do, then? As a programming language, Lua is a more powerful tool that helps you to add advanced logic to your templates, while being easier to read if you are familiar with it. But before we can convert the previous example, we need to understand what is it and how can you use it on your wikis through modules.

Lua quickstart[]

Lua scripts are available in the Module: namespace in all wikis by default. Just like all of your templates start with Template:, all Lua scripts are in pages that start with Module:. Most modules will look like:

local p = {}

function p.main(frame)
  -- code
end

return p


Let's do a quick summary of the previous example:

  • local p is a variable, which stores an empty table {}. You need it to keep all of your exported functions bundled together so they can be return-ed at the end. Other modules and pages will be able to use anything in the exported table.
  • We are creating a function main inside our table p. frame is an argument all functions receive when they are called from a page; you can read more about the frame object, but for now we only need to know that it allows you to access the parameters used in the page. For example, in "{{Template|First|Second|hello=world}}", it would give you access to First parameter, Second parameter and the value of a parameter named hello, which is world.

Keep in mind: main is just an example! You can use any valid name for your functions.

Creating our module[]

Now, let's get into the actual code! Focus on the new content, which is everything inside the main function.

local p = {}

function p.categorize(frame)
  local args = require('Dev:Arguments').getArgs(frame)
  local season = args.season
  local special = args.special
  
  if season then
    if special then
      return string.format( '[[Category:Special episodes from season %s]]', season )
    else
      return string.format( '[[Category:Episodes from season %s]]', season )
    end
  else
    return '[[Category:Episodes with no season]]'
  end
end

return p


Step by step[]

Let's take a look at what all of this is.

Accessing the parameters
There are other ways to access the parameters passed to your module from the page, but the most recommended one is to use Arguments, a Global Lua Module available in all wikis. It exports a function getArgs that will give you a table with all arguments from your frame object. Using the same template call we had before, "{{Template|First|Second|hello=world}}", it will give you all arguments in a table like:
{
  "First",
  "Second",
  hello = "world"
}
Remember that Lua tables start indexing from 1! So you could access any parameter you need as args[1] (First), args[2] (Second) and args.hello (world). Accessing any key that doesn't exist will return a nil value, equivalent to JavaScript's undefined or Python's None.
Implementing your logic
You should already be familiar with if statements in programming. Lua's syntax may be different, but easy to understand.
Just like we did before using parser functions, we first check if the season parameter was set. If it wasn't, we would have got a nil value from our args table, which would be evaluated as false.
The other part that may have you wondering its meaning is string.format. Lua has different ways to "interpolate" strings, and this is just one of them. The first parameter of this function is your template string, where each instance of %s will be substituted by the following parameters in order (in this case, the value stored in season).
  • If season is set, check if special is also set.
    • If special is set, add a category [[Category:Special episodes from season %s]], where %s will be replaced with the value in season.
    • Else, add a category [[Category:Episodes from season %s]].
  • If season is not set, add a category [[Category:Episodes with no season]].
Just like a template, the value returned from your module will be inserted into the article.

How do I use it?[]

If we had the previous example in Module:Episode, you could call it in any page using {{#invoke:Episode|categorize|season=1}}. However, you should avoid this. Although the syntax is very similar to templates, it might potentially confuse new editors: #invoke? Why categorize? Where is this template?

Usually, your editors will never use modules directly, but instead through templates. For example, in your Template:Episode Infobox you could call your module at the end as: {{#invoke:Episode|categorize}}.

You may be wondering: how will it know the season? Well, your frame object will have access to any parameters passed to {{Episode Infobox}}! And thanks to the Arguments global module we used before, it will give you easy access to these parameters without having to modify your module. Isn't it great?

Summary[]

This blog only gave you an idea of how you can use Lua to simplify the logic in your templates, hopefully you will be able to apply it in better scenarios so they are easier to maintain! Here is a short list of when you should consider using Lua:

  • Your template has many parser functions, especially if they are nested.
  • You need to process any number of parameters. Instead of manually adding {{{parameter 1}}}, {{{parameter 2}}}, {{{parameter 3}}} and so on as you need, you can manage them using Lua.
  • Although centralizing your data is considered a bad practice for wikis, sometimes it may be the best solution for your needs. And the best way to centralize data is through Lua modules.

Keep in mind that Lua modules require someone that knows the language to be able to maintain it. Try to follow good programming practices in your module so other people are able to understand what should it do and easily navigate through it if they need to fix anything. For example: use descriptive variables (local ip doesn't give as much information as local item_price) and split your code into different functions to make it easier to read. And, of course, add some comments to keep it clear for others!

You have at your disposal all the tools available in a programming language to create powerful modules to use in your articles, instead of only relying on parser functions and other basic features.