Two ways to bring a design

There are two, and they answer different questions.

The design is You give it It gives you
A template a Word document — a .docx or a .dotx the styleIds of its styles its fonts, colours, spacing, headers and footers, and its letterhead
A theme a directory of YAML nothing a look of your own, in every document that names it

A template is a design somebody made in Word. A theme is a design you write down, and it is the only one of the two that travels with the Markdown rather than with the document.

A Word template

Point the renderer at the styleIds your template defines and it inherits the whole design — fonts, colours, spacing, headers and footers.

use MarkdownWord\Configuration;
use MarkdownWord\Configuration\Styles;
use MarkdownWord\Template\MarkdownTemplate;

$config = Configuration::create()->withStyles([
    Styles::HEADING_1 => 'ReportTitle',   // a styleId in your template
    Styles::PARAGRAPH => 'BodyText',
    Styles::BLOCK_QUOTE => 'PullQuote',
]);

(new MarkdownTemplate('report-template.docx', $config))
    ->insert(file_get_contents('summary.md'))
    ->save('northwind.docx');

A .docx and a .dotx are both accepted, and which one it is makes no difference to the result: a filled-in template is always a document. See What a .dotx costs for why that is worth saying.

Everything a template says is something Word already understands, because a template comes from Word and anything else would have to be invented here:

A value a MERGEFIELD, the field a person inserts with Ctrl+F9
A place for the content a rich-text content control, named body

There is no third thing. A row of records is a table in the Markdown, and the template styles it like any other content — which is why there is no loop to explain.

The values

fields() fills the template's MERGEFIELDs, and the document carries its own values so that the document and everything in it travel together:

(new MarkdownTemplate('report-template.docx'))
    ->fields(['customer' => 'Northwind Ltd'])
    ->insert(file_get_contents('summary.md'))
    ->save('northwind.docx');

Filled fields are unlinked. The value stays and the field goes, which is what Word's own Finish & Merge → Edit Individual Documents produces and what a finished document wants: nothing to refresh with F9, and a value that can hold & or < without becoming an instruction.

The place for the content

body is this library's convention, not Word's. ECMA-376 §17.5.2.36 defines a content control's w:tag as "an arbitrary string which applications can associate with a structured document tag", reserves no value for it, and Word itself never reads one — it round-trips it. So the name collides with nothing Word recognises, and no standard is being missed by not matching one.

The control is matched on its tag, which is the field name Word gives it, rather than on its alias: the alias is the label a person sees in Word's own UI and is the one they will rename while editing the template, whereas the tag is what a program reads. A template that has both is written by something that knows the difference.

A template that names its control something else is asked for that name:

(new MarkdownTemplate('letterhead.docx'))->insert($markdown, 'letter');

Nobody else does this: the templating libraries that exist either use plain text delimiters ({name} in docxtemplater, `` in python-docx-template) or invent their own prefix, and none of them claims body.

A template with no control

A template need not be one this library's generator wrote. A letterhead a company made in Word to be filled in by a person has fields and no control, and refusing those would leave the library able to use only the templates it wrote itself.

So a template with no control of that name takes the content at the end of its body, or says so and refuses. Which one is the contentFallback() setting — ContentFallback::Append or ContentFallback::Error — and the refusal is --require-control on the command line.

Filling the fields is independent of it: a template can have values and nowhere to put the prose.

The same thing from the frontmatter

A document may name its own template, and then nothing has to be supplied from PHP to reproduce it:

---
template_file: ../templates/report.dotx
fields:
  customer: Northwind Ltd
---

template_file: names a .docx or a .dotx, and the path is resolved against the document's own directory. fields: fills the template's MERGEFIELDs, with true and false spelled as strings because that is what Word stores.

The two routes are the same thing reached two ways, and the difference is where the styleIds come from: the frontmatter route cannot name them, so it inherits the template's own styles rather than mapping this library's slots onto them.

What a .dotx costs

Nothing to use one, and one thing to produce from one: the result is a document, not a filled template. That is the only difference between the two, and it is worth saying because the alternative is worse.

A .dotx and a .docx are the same archive with one line of [Content_Types].xml different, and that line is what Word decides a file by. A package typed as a template is opened by creating a new document from it — double-clicking a filled-in .dotx gives you Document1.docx rather than the file you were sent, and anything dispatching on MIME type treats it as a template. So rendering into one writes a document, and says so by writing one:

$template = new MarkdownTemplate('report-template.dotx');
$template->insert('body', $markdown)->save('northwind.docx');   // a .docx, whatever went in

A theme

A theme is a directory: theme.yml — name required, plus description and author — and an optional styles.yml holding the same slot names as the configuration. One key of that file is not a slot: textStyles holds the named styles a document may write a word in.

A document names one with theme:, and the ones that ship are listed with the configuration, on the themes.

A theme may also name the theme.yml itself, in which case the styles.yml beside it is the theme's, and a document that names one by path gets that one.

The command line

mdoffice word to-docx notes.md --template report.dotx --require-control

--template takes a .docx or a .dotx, and --require-control refuses a template with no content control instead of appending to it. The rest of the options are on For word.

Every example on this page was built by the library it documents while this page was built. This page as Markdown.