StarfieldWiki:MetaTemplate

MetaTemplate provides several template-related parser functions. These features are intended to permit more powerful templates, more legible templates, and data-sharing between articles. Better documentation for some of the features can be found at Magic Words.

Installation
As with all modern extensions, the initial installation is to add  to LocalSettings.php. If data functions (see below) are enabled, you should also run in order to create the required tables and convert the original MetaTemplate data, if it exists. Note that the old MetaTemplate tables will not be deleted at any time; these must be removed by hand. This allows the old ones to remain available if needed.

Once installed, there are four global variables that govern which functions will be available. All of these are set to by default; setting them to  will disable the listed functions. In addition to those four, there is another setting which serves as a sanity check for #listsaved.

Variable Definition
All of the following parser functions alter template variables. Most work within the context of the template they're called from, but #inherit and #return interact instead with "parent" templates or pages in order to allow data to be transferred between them.

Conditional expressions couple particularly well with variable definitions. If the same condition needs to be used multiple times, it can instead be stored in a variable using #define or #local to evaluate the condition once, then you would reuse the variable in each necessary subroutine. For example:
 * ... is both more efficient and more readable as ...

#define
The main purpose of #define is to provide a default value for a template parameter, but the variable will only be created if it doesn't already exist. However, #define tags can be used to do more than simply replace an input argument:
 * The arguments to a #define tag can contain any combination of other wiki code. In particular, any variables that have previously been defined anywhere in the template or the template's arguments will be recognized. Therefore, #define tags can refer to any of the template's input arguments and can be used to combine or process those arguments.
 * The processing required to parse the arguments is only done once no matter how many times the #define'd variable is subsequently used. Therefore, #define'd variables can increase the efficiency of templates by eliminating repetitive code parsing.
 * Using the  option, #define and its derivatives can also be used to allow flexibility in a parameter's capitalization. For example, a parameter might be called  internally but the template call could allow, ,  or any other variation of lower- and upper-case to be used when the template is called. Note that after such a #define, the original values will no longer exist, leaving only the specified case.

Each of the following examples assumes that the #define statement appears in a template named Test, which has been called using the code shown under "Template Call".

#local
This function assigns a value directly to a variable. If the value already exists, it will be overridden by the new value. If the value does not (i.e., it wasn't passed to the template), this will create it, making it appear as though it had been passed. It is otherwise identical to #define and has the same benefits as well as two additional ones:
 * You can use #local to set a default value for a parameter that is either not set at all or that might be blank, as is common when copying a blank template call. For example,.
 * It can also be used to sanitize values passed to the template. For example, a parameter that expects a purely numerical width might sanitize the width parameter with something like . From that point forward, it would look like the template had always been passed a purely numerical argument with no further need to check or re-sanitize the value.

#preview
The #preview function works exactly like #local, but only when you are previewing a template. It can be used to test exactly what a template will look like for a given set of input arguments. The advantage of using #preview instead of #local for such tests is that #preview can be saved with the template without affecting how it works.

#unset
It stands to reason that if you can set a variable, you should also be able to clear it, which is exactly what the #unset function does with each variable passed to it, making it appear to the template as though the variable had never been set and/or passed to the template in the first place. If the variable was passed anonymously or by directly assigning it to a numeric position, the  parameter can be used to shift any variables above it down by one.

Variable Passing
Variable passing functions allow a child template to get data directly from, or send data directly to, its parent without needing to save or load it.

#inherit
This tells a nested template to inherit the values for the listed variables from the template(s) that called it. As many variable names as necessary can be listed in an #inherit statement, and it will recognize variables defined by any possible method (#define, #local, #inherit, #return).

will check recursively through the entire stack of templates to find any definition of a requested variable. It starts by checking the template itself (i.e., a #define statement preceding a #inherit statement will take precedence, as will any value provided when calling that specific template). If there are any values remaining that haven't been found yet, it then checks the parent template (the template that called the one containing the #inherit statement), then the grandparent, etc.

#return
This function returns the values of all listed variables to the parent template. If the variable has already been defined in the parent template, #return will override that value. Unlike most programming languages, execution of a template does not stop at a #return statement. In this context, return means "return these values to the calling template", not "return from this template". Likewise, if the specified variables are subsequently altered in the template, the altered values are not copied to the parent template.

Data Sharing
These functions allow template variables from one page to be used on any other page. They provide an efficient mechanism for sharing information between pages, and therefore make it unnecessary to create stub-like subpages (/Description, /Author) for that purpose.

#listsaved
This function calls a template for each page or set of #save'd data that meets specified criteria. Each template is called with the parameters listed below. #load and #inherit should be used to import any additional data required. If these names are present in the #save'd data, you may want to use the name mapping feature to avoid any overlap.
 * , which corresponds to ,
 * , which corresponds to ,
 * , which is used in the #load and #save functions to choose which data set to use.

Options for the #listsaved conditions are intentionally limited. If more complex conditions are necessary for a #listsaved call, then a new #save variable should be created to make the #listsaved call possible. For example, if a list containing both Ayleid Ruins and Forts was needed, it is not possible within #listsaved to request "(type=Ayleid Ruin) OR (type=Fort)". Instead, a new #save variable can be created, for example "alttype=Ruin or Fort".

Note that adding #preload to the template can significantly optimize #listsaved's performance.

Example:  would create a list of all Ayleid Ruins in Oblivion, formatting each place using Place Link.

#load
Loads each of the variables listed from the database unless they're already defined. These can subsequently be used just like any other template variable. Any number of variables can be requested.

Generally speaking, #load will cause a database query every time it's called. For that reason, #load commands should be combined into one to the extent possible. The only time #loads should be separate is if they're loading data from different sets or some of variables should only be loaded conditionally. No data will be loaded if all variables are already defined or if a #preload in the template already covers all the variables needed.

Example: can be found in Book Link, where it loads various information for the requested book.

#preload

 * 1) preload saves metadata to the template page telling it what variables should be pre-loaded when using the #listsaved command. When #listsaved encounters this metadata, it bulk loads all of the named variables before calling the specified template. Because the information is bulk-loaded, rather than a page at a time, when used in a template, it can drastically speed up any #listsaved commands that call that template.

You should add #preload to any template called by #listsaved that also uses #load. If you include a variable list the covers the most frequently #loaded variables, it will no longer need to #load them on the page, resulting in drastic performance improvements.

Unlike #load, #preload should be placed in the &lt;noinclude> section of the template or outside of any inclusion tags.

#save

 * Example: could be placed in Lore Book, which would result in the description and author variables being saved for every book page that directly or indirectly includes the Lore Book template.

Each of the variables listed in the parser function is written to the database. As many (or as few) variables as needed can be listed in the parser function.

Optional arguments for #save are:
 * if and ifnot: enable/disable the entire function, see Conditional Expressions for details.
 * set: can be specified if there are multiple sets of data that need to be #save'd for a single article. If set is not specified, it will default to an empty string, however it's strongly encouraged to use a set name where possible, both for organization purposes and possibly a marginal improvement to #load speeds. Any arbitrary string, up to 50 characters in length, can be used for a set name.

Additional information:
 * The variables are saved after being fully expanded and parsed. Therefore, if the variables contain complex processing, the processing does not need to be redone by any articles that load the variables.


 * #save parser functions are always ignored when saving template pages and special pages. This prevents unwanted entries from being added to the database.
 * #save parser functions can be used on redirect pages, even if the #save function appears after the #REDIRECT command.
 * The actual #save operation (writing the data to the database) is only done once per savefile, no matter how many #save commands appear in the savefile. The #save database operation is done after the wiki has saved the article itself to the database. This ensures that the #save database has the correct file revision ID; it also ensures that #load commands can safely be executed concurrently (in separate apache threads) with #save commands without extended database locks.
 * In prior versions of MetaTemplate, the  parameter was used. For backwards compatibility, this name has been retained, but since no set is subordinate to any other, they are now simply referred to as  . All sets are equal; the default set simply has a blank name.
 * Saved set names and variable names are limited to 50 characters each. There are no such restrictions if the variables are not being saved.

Details

 * #save/#load variables will automatically update as expected in nearly all situations:
 * Changing an article with #save'd data will automatically force any pages that #load the data to update: if the description variable is changed on Lore:King, then Lore:Books_K will automatically retrieve the new description.
 * This is accomplished by making the wiki think that the #save file is transcluded in any files that #load its data. In the above example, Lore:Books_K would be listed in Lore:King's "What Links Here" list as a transcluding article; Lore:King would appear in the list of "Templates used on this page" for Lore:Books K. This is purely a book-keeping trick. Lore:King is not actually transcluded in Lore:Books_K (this can be confirmed by looking at the template processing stats hidden in the HTML for Lore:Books_K; "Template argument size" is much smaller than it would be if actual transclusions were being done).
 * #save'd data is correctly updated if the article is renamed or deleted.
 * #save'd data is always updated if the article is purged.
 * #save'd data is automatically deleted from the database if the #save tag is deleted from the article.
 * #save'd data is automatically updated if any templates on the page are updated.
 * However, there is one slight glitch with automatic updates of variables
 * #save'd data is not automatically recreated if an article is undeleted. The undeleted article needs to be purged or edited to recreate the article's database entries. This is an omission due to laziness: is it really worth coding in undelete functions, especially given that an article is likely to be edited soon after being undeleted?


 * ... tags are stripped within any saved variables, in both the save document and the load document. In other words, the nowiki tags are effectively ignored; the text within the tags will be wikified.
 * However, the nowiki tags are only removed immediately before the variable is saved. Therefore, nowiki tags can be used if there is a need to force specific variables or templates to be expanded after the variables are #loaded.
 * For example, if is used in a saved variable, normally NAMESPACE would always provide the namespace of the original save file—ignoring the namespace of the file that #loads the data.
 * To instead force NAMESPACE to provide the namespace of the final article, even after being loaded, then the original variable definition should use.
 * This behavior is definitely unusual, but it's basically an attempt to make the worst of a bad situation.
 * nowiki tags do not like the #save/#load processing. Without any special treatment, any nowiki'd text would be replaced by mangled nonsense (e.g., "UNIQ69c231c93c7370c8 ") in any #load documents.
 * To make nowiki tags work "as usual" would require special treatment before a variable is saved, then more special treatment after the variable is loaded—special treatment that would require extra processing for every single variable, not just those variables that contain nowiki tags.
 * Effectively, only half of that special treatment has been implemented, namely, the check for nowiki'd text before a variable is #save'd. This unmangles the nowiki'd text before saving it to the database; it does not reinsert the nowiki tags.
 * The decision to not do any special processing after #load'ing the variables is intentional. It is assumed that #load commands may appear multiple times on pages that need a lot of processing, including some traditional "problem" pages (Oblivion:Merchants, Oblivion:Places). Therefore, including extra processing (that is hardly every going to be used) in the #load command may have a noticeable negative impact on site performance. Furthermore, a mechanism was needed for occasionally preserving wiki tags in #save variables (the example is likely to be needed on Lore book pages); other ways of accomplishing that goal would be difficult to implement. The upshot is that processing is improved and a new capability is added—at the expense of eliminating the standard nowiki function within #saved variables.


 * Any other nowiki-like tags that "hide" text from the wiki parser are also broken. For example, ..., $$...$$, ... , and HTML comments.
 * All content within such tags is removed before the value is #save'd. This is the exact same problem that affects nowiki tags, but I'm handling it more simplistically in these cases.
 * The problem is that, during parser processing any such tags get replaced by a mangled "UNIQ...QINU" string (a marker for text that is being hidden from the parser). The original template knows the full context, so it restores the hidden text after parsing is done. But when #load'ed, all information about the hidden text is lost.
 * Instead of even bothering to save the mangled "UNIQ-QINU" string to the database, the code is now completely removing that marker. So in the end there is no visible sign that there was a chunk of problematic text.
 * In general, use of tags like these should be avoided in any templates that are going to be used within #save'd variables
 * However, in some cases, the problem tags can be used completely safely. The basic test is: does the #load'ed value content the correct text, or is it missing a chunk of text?
 * HTML comments can always be safely used in templates (they won't appear in the HTML source code, but presumably they don't need to).
 * If cleanspace tags are being used solely to handle a chunk of initialization (using #local, #define, #preview, etc. to set variables) and does not end up generating any actual text, then cleanspace tags can be used in templates without any problems. Just double-check that the cleanspace tags do not also contain categories.


 * There are actually two database tables associated with these functions:  and  .   stores the actual variables; a numeric index,   identifies the savefile.   contains a single entry for each savefile, translating the savefile name into the numeric ID used in  .   also contains bookkeeping data necessary to ensure that database entries are cleaned up when necessary—namely, the article revision ID and a timestamp.

catpagetemplate
The catpagetemplate tag can be used on category pages to customize the appearance of the listed articles. (MetaTemplate version 1.0)

The contents of the tag should be template code. The code is executed once for each article listed in the category; each time, the parameter 'pagename' is set to the name of the article and 'sortkey' is set to the article's sortkey. By default, the text produced by the code is used for the article's label. In addition, #define statements can be used to customize many other aspects of the category listing.

Examples:
 * The displayed text for each page would no longer contain any disambiguation data (e.g., "Oblivion:Umbra (person)" would be displayed as "Oblivion:Umbra")
 * The displayed text would no longer include the namespace, and the text would be in "sortable" format
 * The first four letters of the articles would be used to create the sections on the category page, instead of just the first letter
 * #save'd data would be loaded to get the previously-determined values for catgroup, catlabel, and catanchor (catanchor would allow the category to link directly to the appropriate section of the page).
 * The first four letters of the articles would be used to create the sections on the category page, instead of just the first letter
 * #save'd data would be loaded to get the previously-determined values for catgroup, catlabel, and catanchor (catanchor would allow the category to link directly to the appropriate section of the page).
 * #save'd data would be loaded to get the previously-determined values for catgroup, catlabel, and catanchor (catanchor would allow the category to link directly to the appropriate section of the page).

To limit wiki processing requirements, complex processing would not be appropriate in a catpagetemplate tag—especially since category pages are never cached. One possibility is to use a #load statement to fill in the variables, allowing any work to be done on the individual pages, instead of within the category.

Parameters with special meaning when #define'd within catpagetemplate:
 * Several parameters combine to create the text displayed for a given article; the result is equivalent to:
 * #|
 * catlabel: the text to use for the article's label; overrides the output text of the tag. The advantage of using catlabel is that the contents of the catpagetemplate tag can then contain extra line breaks or even comments. The disadvantage of using catlabel is that any error messages produced when the template is parsed are lost, making debugging more difficult.
 * cattextpre: text to display before the link to the article; default ''. A space is automatically added in between the text and the link.
 * cattextpost: text to display after the link to the article; default ''. A space is automatically added in between the text and the link.
 * catpage: the full name of the article; defaults to . In most cases, there should be no reason to set this parameter. If it is reset, there could be some minor anomalies because the code does not update various secondary settings based on a new value of catpage (e.g., the code does not check whether the page is valid, so the resulting link will be a standard blue link even if the page is non-existent; if a redirect is replaced with a non-redirect, the link will still be italicized, unless catredirect is also set).
 * catanchor: the section of the article to which the link should point; default ''.
 * catgroup: the group within which the article should be placed; defaults to the first letter of the sort key. catgroup can be a full word, or multiple words; there is no one-letter limitation. Note, however, that the articles are not re-sorted according to their group, therefore catgroup must be some logical derivative of the category sort key.
 * catredirect: is the link a redirect? This can be used to override the italicization of redirects, although normally it probably makes no sense to override the default values.
 * Note, there is no catsortkey parameter; no mechanism has been added for changing the order in which articles appear on the category. The problem is that implementing such a parameter would be incredibly inefficient on large categories (ones with more than 200 articles), because all the articles would have to be read, processed, resorted, and then refiltered to the correct set. It's better to find a way to correctly set the original sortkey.

Input values to catpagetemplate:
 * is the article's full name
 * is the article's sort key
 * In addition, the article is added to the current template stack. This means that,  , and  provide information about the article (unless catpagetemplate calls subtemplates, in which case  and the equivalents could be used).

Other points:
 * This feature has been set up so it doesn't eliminate the category changes introduced by the CategoryTree extension. However (at the moment at least), catpagetemplate cannot be used to customize category trees. The options for displaying subcategories on the page are
 * without a catpagetemplate, CategoryTree will generate the subcategories
 * using, CategoryTree will generate the subcategories
 * otherwise, catpagetemplate will generate the subcategories


 * When #load is used within catpagetemplate, the code will check to see whether there are multiple sets for the page, and if so, will try generating a category page entry for each set. For example, if several sections of the page should each be listed separately in a category, this provides a mechanism for doing so. [Except this is where catsortkey might be needed... I'm still pondering the details of this feature]

NESTLEVEL
In programming terms, NESTLEVEL is the template stack depth. In English, it's how many "nested" templates have been called before getting to NESTLEVEL. So, if you put  directly on a page, it will display 0 since no templates are being called. If you put  inside a template and then use that template on a page, the value of NESTLEVEL is 1 since you have called one template between the original page and NESTLEVEL. If you then call that template from yet another template, the number goes up to 2 and so on. This is most effectively used in templates like FMI to detect whether they're being called from the main Lore page or if they're being transcluded somewhere else.

If you need to test NESTLEVEL at various depths while designing a template, you can use, for example, and it will always display 2. You can also define or pass a variable named. Like with the specified value, any number found in will always be returned, regardless of the actual level of nesting. In the event that both are specified, the first version takes precedence.

Namespace and Pagename

 * NAMESPACE0, PAGENAME0, and FULLPAGENAME0 variables
 * NAMESPACEx, PAGENAMEx, and FULLPAGENAMEx variables (technically these are parser functions, but they are set up to be called as instead of  so that they are as similar as possible to the base variables)

Differences from Previous Version

 * ,, and   are now available on all variable and data-sharing functions.
 * #preview now works in all namespaces.
 * #load now supports "load all from set" functionality.
 * #load and #save no longer inherit or change the  variable; that feature wasn't used significantly and if not understood, it could potentially lead to unintended results.
 * deprecated in favor of  to encourage the idea that all sets are equal and that assigning variables to a specific set is a beneficial.

General Notes
All the functions listed in the Variable Definition and Data Sharing sections support conditional expressions as well as a case-insensitive option, as detailed below.

Name Mapping
Most functions that deal with variables from outside the immediate template allow you to use different names between the source and the destination. For example, you might have a template that saves a Quest ID as simply, but in another template, you want to load that as. To do so, you would use:.

In each case, the mapping direction is. Using  as an example:
 * loads  from the quest page to   in the template.
 * gets  from the template to   in the data saved on the page.
 * inherits  from the parent template to   in the local template.
 * returns   from the current template to   in the parent template.
 * loads  from each page and sends it to the template as.
 * doesn't do anything on its own, but when either &lt;catpagetemplate> or #listsaved find it, they will bulk load the data exactly as noted in #load, above.

Notes
 * Numeric variables are forbidden on both the from and to sides.
 * Safety when moving named variables is left entirely up to the editor. Overlapping mappings, such as  will not produce an error, though they're unlikely to be what the editor intends.

Special:MetaVarsOnPage
This special page allows you to see the #saved variables on a page. Simply enter the full page name and, if desired, the maximum number of items on any given page, and the results will be displayed.

Caution: When paging through data, the page will always start with a full set, even if it was partly displayed on the previous page of data. On pages with large enough sets, you could end up simply paging through the same data repeatedly and will have to increase the number of results returned in order to continue. As of this writing, the default value of 50 is large enough for all but a handful of pages (and any sandboxes that copy these pages):
 * Blades:Blades: Effects (242), Enchanting (56), and Artifacts (56)
 * Morrowind:Morrowind: The Eight Wonders (52), Blessings of the Fourth Corner (52), The Eight Gifts (51)

Special:PagesWithMetaVar
This special page lists all pages containing a specific variable and/or set. Either the set name or a variable name must be provided. If you want to look for a variable within a specific set, both can be entered. You cannot leave the set at "Any" while the variable name is blank.

For the variable drop-down box, the 25 most common variables will be listed. For the namespace drop-down box, only namespaces that have actual #saved data in them are listed. Note: This data is updated every time the special page is viewed, which is not optimal on a large wiki with many users, but should pose no problems for Starfield Wiki.

API
MetaTemplate includes an API property module which allows you to query pages for all d values, or for specific sets or values. The module can be requested using a standard  parameter, using the name. Parameters are listed below. Maximum values are listed as /. On Starfield Wiki, bots and admins both have the high-limits right.

Examples
Query parameters shown are limited to those that matter and separated for readability. Note: the queries below include  to make them more human-readable;   is the preferred format for programmatic use, and is the default in MediaWiki 1.25 and above.