//(These were originally called "hygienic templates", which got confused with hygienic template **[arguments](https://phabricator.wikimedia.org/T114432)**. The latter are now called "heredoc" arguments, and "hygiene" is no more.)//
As described in my [Wikimania 2015 talk](https://wikimania2015.wikimedia.org/wiki/Submissions/Templates_are_dead!_Long_live_templates!) ([starting at slide 27](https://wikimania2015.wikimedia.org/w/index.php?title=File:Templates_are_dead!_Long_live_templates!.pdf&page=27)), there are a number of reasons to mark certain templates as "balanced". Foremost among them: to allow high-performance incremental update of page contents after templates are modified, and to allow safe editing of template uses using HTML-based tools such as Visual Editor or [jsapi](https://doc.wikimedia.org/Parsoid/master/#!/guide/jsapi). More discussion of motivation is at T130567 (and covered in RFC meeting E159).
"Balance" means (roughly) that the output of the template is a complete [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment): every open tag is closed. Furthermore, there are some restrictions on context to ensure there are no open tags which the template will implicitly close, nor nodes which the HTML [adoption agency algorithm](http://dev.w3.org/html5/spec-LC/tree-construction.html#adoptionAgency) will reorder. (More precise details below.)
Template balance is enforced: tags are closed or removed as necessary to ensure that the output satisfies the necessary constraints, regardless of the values of the template arguments or how child templates are expanded.
Properly balanced template inclusion allows efficient update of articles by doing substring substitution for template bodies, without having to expand all templates to wikitext and reparse from scratch. It also guarantees that the template (and surrounding content) will be editable in Visual Editor; mistakes in template arguments won't "leak out" and prevent editing of surrounding content.
**Wikitext Syntax**
After some bikeshedding, we decided that balance should be an "opt-in" property of templates, indicated by adding a `{{#balance:TYPE}}` marker to the content. This syntax leverages the existing "parser function" syntax, and allows for different types of balance to be named where `TYPE` is.
We propose three forms of balance, of which the first and perhaps the second are likely to be implemented initially. Other balancing modes would provide safety in different HTML-parsing contexts, and may be added in the future if there is need.
1. `{{#balance:block}}` (informally) would close any open `<p>`/`<a>`/`<h*>`/`<table>` tags in the article preceding the template insertion site. In the template content all tags left open at the end will be closed, but there is no other restriction. This is similar to how block-level tags work in HTML 5. This is useful for navboxes and other "block" content.
* Formally: in context preceding template, close `p`, `a`, `table`, `h[1-6]`, `style`, `script`, `xmp`, `iframe`, `noembed`, `noframes`, `plaintext`, `noscript`, `textarea`, `select`, `template`, `dd`, `dt`, and `pre`. (Alternatively, close all but `div` and `section`.) After template, close all open tags.
2. `{{#balance:inline}}` would only allow inline (i.e. phrasing) content and silently delete block-level tags seen in the content. But because of this, it //can// be used inside a block-level context without closing active `<p>`/`<a>`/`<h*>` in the article (as `{{#balance:block}}` would). This is useful for simple plain text templates, e.g. age calculation.
* Formally: In context preceding template, close `style`, `script`, `xmp`, `iframe`, `noembed`, `noframes`, `plaintext`, `noscript`, `textarea`, `table`, `ruby`, and `select`, `template`. These are the tags which change tokenizer or parser modes. (`ruby` affects subsequent parsing of `rb`/`rtc`/`rp`/`rt`.) Wrap the template with `<span>...</span>`, in order to trigger [AFE reconstruction](http://w3c.github.io/html/syntax.html#elements-reconstruct-the-active-formatting-element). Inside the template, strip `address`, `article`, `aside`, `blockquote`, `center`, `details`, `dialog`, `dir`, `div`, `dl`, `fieldset`, `figcaption`, `figure`, `footer`, `header`, `hgroup`, `main`, `menu`, `nav`, `ol`, `p`, `section`, `summary`, `ul`, `h[1-6]`, `pre`, `listing`, `form`, `li`, `dd`, `dt`, `plaintext`, `button`, `a`, `nobr`, `hr`, `isindex`, `xmp`, `optgroup`, and `option`. These are the elements which can trigger a close tag to be emitted [in body parsing mode](http://w3c.github.io/html/syntax.html#the-in-body-insertion-mode).
3. `{{#balance:table}}` would allow insertion inside `<table>` and allow `<td>`/`<th>` tags in the content. The exact semantics need to be nailed down; it is possible that the inline mode might be extended to allow safe insertion inside `<td>`/`<th>` elements, which might remove some of the need for a special table mode. Templates which wish to insert rows or sequences of cells might still need a special mode.
We expect `{{#balance:block}}` to be most useful for the large-ish templates whose efficient replacement would make the most impact on performance, and so we propose `{{#balance:}}` as shorthand for `{{#balance:block}}`. (The current wikitext grammar does not allow `{{#balance}}`, since the trailing colon is required in parser function names, but the current patch set accommodates this without too much pain.)
Violations of content restrictions (ie, a `<p>` tag in a `{{#balance:inline}}` template) would be errors, but how these errors would be conveyed is an orthogonal issue. Currently bad tags are stripped silently. Some other options for error reporting include ugly bold text visible to readers (like `{{cite}}`), wikilint-like reports, or inclusion in `[[Category:Balance Errors]]`. Note that errors might not appear immediately: they may only occur when some other included template is edited to newly produce disallowed content, or only when certain values are passed as template arguments.
**Implementation**
Implementation is slightly different in the PHP parser and in Parsoid. Incremental parsing/update would necessarily not be done in the PHP parser, but it does need to enforce equivalent content model constraints for consistency.
PHP parser implementation strategy:
* When a template with `{{#balance}}` is expanded, add a marker to the start of its output.
* In the Sanitizer leave that marker alone, and then just before handling the output to tidy/[depurate](https://phabricator.wikimedia.org/T89331) we'll replace the marker with `</p></table>...etc...`. That pass will close the tags (and discard any irrelevant `</...>` tags). Some care needed to ensure we discard unnecessary close tags, and not html-entity-escape them.
* PHP might not be able to implement `{{#balance:inline}}` or `{{#balance:table}}` quite yet -- there might need to be a special depurate mode, or do it in a DOM-based sanitizer, something like that. We can concentrate on `{{#balance:block}}` initially.
In Parsoid:
* We just need to emit synthetic `</p></table></...>` tokens, the tree builder will take care of closing a tag if necessary or else discarding the token.
* When PHP switches over to a DOM-based sanitizer, it might be able to use this same strategy.
**Deployment**
Unmarked templates are "unbalanced" and will render exactly the same as before, they will just be slower (require more CPU time) than balanced templates.
It is expected that we will profile the "costliest"/"most frequently used/changed" templates on wikimedia projects and attempt to add balance markers first to those templates where the greatest potential performance gain may be achieved. @TStarling noticed that adding a balance marker to [`[[:en:Template:Infobox]]`](https://en.wikipedia.org/wiki/Template:Infobox) could affect over two million pages and have a large immediate effect on performance. We would want to carefully verify first that balance would not affect the appearance of any of those pages, using visual diff or other tools.
Related: {T89331}, {T114072}.
Mailing list discussion: https://lists.wikimedia.org/pipermail/wikitech-l/2015-October/083449.html