Templates plugin

This plugin is only available for paid TinyMCE subscriptions.
This feature is only available for TinyMCE 6.4 and later.
As of TinyMCE 7.0, the Advanced Template plugin has been renamed to Templates. When adding Templates in your editor, continue to use advtemplate.

The Templates Premium plugin enables the creation of complex, interactive templates using TinyMCE.

They can also be added to a TinyMCE instance by end-users selecting content in a TinyMCE document and saving the selection as a template via the TinyMCE user-interface.

Templates does not support template editing. To update a particular template; insert the template into an editor; make edits; select the, now edited, content; and then create a new template (using, for example, the Tools > Save as Template… menu item).

Using the Templates plugin

Inserting a template

To insert a template

  1. Select Template… from the Insert menu or Select the Insert template Insert template toolbar button.

  2. Select the template to add to the TinyMCE document from the Templates dialog that presents.

  3. Click Insert or press Return.

Adding a new template

To add a new template

  1. Select the material in the TinyMCE document that is going to be the new template and

  2. Save the template using one of the following methods:

    • Select Save as template… from the Tools menu.

    • Select Save as template… from the context menu.

    • Select the Save as template Save as template toolbar button.

Then, in the New template dialog that presents

  1. Enter a name for the new template in the Template name field;

  2. Select a category for the new template from the Category pop-up menu; and

  3. Click Save or press Return.

Adding a new category

To add a new category

  1. Select Template… from the Insert menu to open the Templates dialog.

  2. Click on the New category button in the dialog footer.

  3. The New category form will pop up within the editor.

  4. In the New category form, enter the name of the new category you want to add.

  5. Click the Save button to submit the form.

  6. After saving, the new category will appear in the Tree component of the Templates dialog.

Searching for templates

To search for a template

  1. Select Template… from the Insert menu to open the Templates dialog.

  2. Enter the name of the template you are searching for in the Search field.

  3. As you type, the displayed list of matching templates updates in real-time in the dialog’s Tree component.

Template list management

To manage the template list

  1. Select Template… from the Insert menu to open the Templates dialog.

  2. Select the template or the category you want to modify.

  3. Click on the three dots menu for the selected item.
    The actions menu will open.

  4. From the actions menu, choose the appropriate operation based on your requirements:

    • Rename category/template.

    • Move template to another category.

    • Move all category items to another category.

    • Delete template/category.

Readonly categories

This feature is only available for TinyMCE 7.4 and later.

Templates categories can be set to read-only in TinyMCE, preventing users from modifying the category or its templates. When a category is set to read-only, users cannot:

  • add new templates to the category

  • delete the category or its templates

  • rename the category or its templates

  • move templates into or out of the category

A lock lock.svg icon visually indicates that a category is read-only, preventing users from modifying the category or its templates through the user interface.

To create a locked (read-only) category, add the locked: true property to the category object in your templates data:

Example of a locked category
{
  title: 'Locked Templates',
  locked: true, // Locks the category as readonly
  items: [
    {
      title: 'How to find model number',
      content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p>...</p>'
    },
    {
      title: 'Support escalation',
      content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p>...</p>'
    }
  ]
}
  • TinyMCE

  • HTML

  • JS

<textarea id="readonly-locked-template">
  <h3 style="font-size: 1.5em; margin: 20px 0;">Working with Templates</h3>

  <h4 style="font-size: 1.25em; margin: 15px 0;">Inserting a template</h4>
  <p style="margin: 10px 0;">To insert a template:</p>
  <ol style="margin-left: 20px;">
    <li>Click the <strong>Insert template</strong> toolbar button or select <strong>Insert template...</strong> from the <strong>Insert</strong> menu.</li>
    <li>In the <strong>Templates</strong> dialog, you'll see different categories:
      <ul style="margin-left: 20px;">
        <li>Regular categories with editable templates</li>
        <li>Locked categories (marked with a 🔒 icon) containing read-only templates</li>
      </ul>
    </li>
    <li>Select any template to preview its content.</li>
    <li>Click <strong>Insert</strong> or press <strong>Return</strong> to add the template to your document.</li>
  </ol>
  
  <div style="margin: 15px 0; padding: 10px 15px; border-left: 4px solid #3498db; background-color: #f0f7fb;">
    <p><strong>Note:</strong> Templates in locked categories cannot be modified, but they can still be inserted into your document.</p>
  </div>
  
  <h4 style="font-size: 1.25em; margin: 15px 0;">Adding a new template</h4>
  <p style="margin: 10px 0;">To add a new template:</p>
  <ol style="margin-left: 20px;">
    <li>Select the content in your document that you want to save as a template.</li>
    <li>Click the <strong>Save as template</strong> toolbar button or select <strong>Save as template…</strong> from the <strong>Tools</strong> menu.</li>
    <li>In the <strong>New template</strong> dialog:
      <ol style="margin-left: 20px;">
        <li>Enter a name for your template in the <strong>Template name</strong> field.</li>
        <li>Choose a category from the <strong>Category</strong> dropdown menu.
          <div style="margin: 15px 0; padding: 10px 15px; border-left: 4px solid #e74c3c; background-color: #fdf7f7;">
            <p><strong>Important:</strong> Locked categories (marked with a 🔒 icon) are read-only. You cannot save new templates to these categories.</p>
          </div>
        </li>
        <li>Click <strong>Save</strong> or press <strong>Return</strong>.</li>
      </ol>
    </li>
  </ol>
  
  <h4 style="font-size: 1.25em; margin: 15px 0;">Managing Templates</h4>
  <p style="margin: 10px 0;">When working with templates, keep in mind:</p>
  <ul style="margin-left: 20px;">
    <li>Templates in regular categories can be edited, renamed, or deleted.</li>
    <li>Templates in locked categories (🔒) are read-only and cannot be:
      <ul style="margin-left: 20px;">
        <li>Modified or renamed</li>
        <li>Deleted</li>
        <li>Moved to different categories</li>
      </ul>
    </li>
  </ul>
</textarea>
const headers = {
  'Accept': 'application/json',
  'Content-Type': 'application/json',
};

const handleResponse = (message) => (response) => {
  if (!response.ok) {
    return response.text().then((error) => {
      console.error(error);
      throw new Error(message);
    });
  }
  return response.json();
};

const advtemplate_list = () =>
  fetch('/categories', {
    method: 'GET',
    headers,
  }).then(handleResponse('Failed to get template list'));

const advtemplate_get_template = (id) =>
  fetch(`/templates/${id}`, {
    method: 'GET',
    headers,
  }).then(handleResponse('Failed to get template'));

const advtemplate_create_category = (title) =>
  fetch('/categories', {
    method: 'POST',
    body: JSON.stringify({ title }),
    headers,
  }).then(handleResponse('Failed to create category'));

const advtemplate_create_template = (title, content, categoryId) =>
  fetch('/templates', {
    method: 'POST',
    body: JSON.stringify({ title, content, categoryId }),
    headers,
  }).then(handleResponse('Failed to create template'));

const advtemplate_rename_category = (id, title) =>
  fetch(`/categories/${id}`, {
    method: 'PUT',
    body: JSON.stringify({ title }),
    headers,
  }).then(handleResponse('Failed to rename category'));

const advtemplate_rename_template = (id, title) =>
  fetch(`/templates/${id}`, {
    method: 'PUT',
    body: JSON.stringify({ title }),
    headers,
  }).then(handleResponse('Failed to rename template'));

const advtemplate_delete_template = (id) =>
  fetch(`/templates/${id}`, {
    method: 'DELETE',
    headers,
  }).then(handleResponse('Failed to delete template'));

const advtemplate_delete_category = (id) =>
  fetch(`/categories/${id}`, {
    method: 'DELETE',
    headers,
  }).then(handleResponse('Failed to delete category'));

const advtemplate_move_template = (id, categoryId) =>
  fetch(`/templates/${id}`, {
    method: 'PATCH',
    body: JSON.stringify({ categoryId }),
    headers,
  }).then(handleResponse('Failed to move template'));

const advtemplate_move_category_items = (id, categoryId) =>
  fetch(`/categories/${id}`, {
    method: 'PATCH',
    body: JSON.stringify({ categoryId }),
    headers,
  }).then(handleResponse('Failed to move all templates to new category'));

tinymce.init({
  selector: 'textarea#readonly-locked-template',
  plugins: [
    'advlist', 'anchor', 'autolink', 'charmap', 'code', 'fullscreen',
    'help', 'image', 'insertdatetime', 'link', 'lists', 'media',
    'preview', 'searchreplace', 'table', 'visualblocks', 'advtemplate'
  ],
  contextmenu: 'advtemplate',
  toolbar: 'addtemplate inserttemplate | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',

  advtemplate_list,
  advtemplate_get_template,
  advtemplate_create_category,
  advtemplate_create_template,
  advtemplate_rename_category,
  advtemplate_move_category_items,
  advtemplate_delete_category,
  advtemplate_rename_template,
  advtemplate_move_template,
  advtemplate_delete_template,
});

Basic setup

To setup the Templates plugin user-interface in the editor:

  • add advtemplate to the plugins option in the editor configuration;

  • add inserttemplate and addtemplate to the toolbar option in the editor configuration;

  • add each Templates option to the editor configuration;

Example
tinymce.init({
  selector: 'textarea',  // change this value according to your html
  plugins: "advtemplate",
  toolbar: "inserttemplate addtemplate",
  contextmenu: "advtemplate",
  // Each of the following options must be defined as
  // a function that returns a Promise.
  // Please find the specific details for each option below.
  advtemplate_list,
  advtemplate_get_template,
  advtemplate_create_category,
  advtemplate_create_template,
  advtemplate_rename_category,
  advtemplate_rename_template,
  advtemplate_delete_template,
  advtemplate_delete_category,
  advtemplate_move_template,
  advtemplate_move_category_items
});
The undefined options in the above example must be defined. See the Options below for specific details on each function.

Interactive examples

There are two approaches to using the Templates Premium plugin: fixed template lists and user-modifiable template lists.

Fixed template lists

For users who work with a fixed template list that does not require modification, you can provide a list directly through the TinyMCE init configuration using the advtemplate_templates option.

The following interactive predefined list example provides guidance for this approach.

Configuring the Templates plugin to use a static list of predefined templates.

  • TinyMCE

  • HTML

  • JS

  • Edit on CodePen

<textarea id="template-predefined">
  <h3>Inserting a template</h3>
  <p>To insert a template:</p>
  <ol>
    <li>select <strong>Template…</strong> from the <strong>Insert</strong> menu or<br />
    select the <strong>Insert template</strong> toolbar button.</li>
    <li>select the template to add to the TinyMCE document from the <strong>Templates</strong> dialog that presents.</li>
    <li>click <strong>Insert</strong> or press <strong>Return</strong>.</li>
  </ol>
</textarea>
const advtemplate_templates = [
  {
    title: 'Quick replies',
    items: [
      {
        title: 'Message received',
        content: '<p dir="ltr">Hey {{Customer.FirstName}}!</p>\n<p dir="ltr">Just a quick note to say we&rsquo;ve received your message, and will get back to you within 48 hours.</p>\n<p dir="ltr">For reference, your ticket number is: {{Ticket.Number}}</p>\n<p dir="ltr">Should you have any questions in the meantime, just reply to this email and it will be attached to this ticket.</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">Regards,</p>\n<p dir="ltr">{{Agent.FirstName}}</p>'
      },
      {
        title: 'Thanks for the feedback',
        content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p dir="ltr">We appreciate you taking the time to provide feedback on {{Product.Name}}.</p>\n<p dir="ltr">It sounds like it wasn&rsquo;t able to fully meet your expectations, for which we apologize. Rest assured our team looks at each piece of feedback and uses it to decide what to focus on next with {{Product.Name}}.</p>\n<p dir="ltr"><strong>&nbsp;</strong></p>\n<p dir="ltr">All the best, and let us know if there&rsquo;s anything else we can do to help.</p>\n<p dir="ltr">-{{Agent.FirstName}}</p>'
      },
      {
        title: 'Still working on case',
        content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p dir="ltr">Just a quick note to let you know we&rsquo;re still working on your case. It&rsquo;s taking a bit longer than we hoped, but we&rsquo;re aiming to get you an answer in the next 48 hours.</p>\n<p dir="ltr">Stay tuned,</p>\n<p dir="ltr">{{Agent.FirstName}}</p>'
      }
    ]
  },
  {
    title: 'Closing tickets',
    items: [
      {
        title: 'Closing ticket',
        content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p dir="ltr">We haven&rsquo;t heard back from you in over a week, so we have gone ahead and closed your ticket number {{Ticket.Number}}.</p>\n<p dir="ltr">If you&rsquo;re still running into issues, not to worry, just reply to this email and we will re-open your ticket.</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">All the best,</p>\n<p dir="ltr">{{Agent.FirstName}}</p>'
      },
      {
        title: 'Post-call survey',
        content: '<p dir="ltr">Hey {{Customer.FirstName}}!</p>\n<p dir="ltr">&nbsp;</p>\n<p dir="ltr">How did we do?</p>\n<p dir="ltr">If you have a few moments, we&rsquo;d love you to fill out our post-support survey: {{Survey.Link}}</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">Thanks in advance!<br>{{Company.Name}} Customer Support</p>'
      }
    ]
  },
  {
    title: 'Product support',
    items: [
      {
        title: 'How to find model number',
        content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">My name is {{Agent.FirstName}} and I will be glad to assist you today.</p>\n<p dir="ltr">To troubleshoot your issue, we first need your model number, which can be found on the underside of your product beneath the safety warning label.&nbsp;</p>\n<p dir="ltr">It should look something like the following: XX.XXXXX.X</p>\n<p dir="ltr">Once you send it over, I will advise on next steps.</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">Thanks!</p>\n<p dir="ltr">{{Agent.FirstName}}</p>'
      },
      {
        title: 'Support escalation',
        content: '<p dir="ltr">Hi {{Customer.FirstName}},</p>\n<p dir="ltr">We have escalated your ticket {{Ticket.Number}} to second-level support.</p>\n<p dir="ltr">You should hear back from the new agent on your case, {{NewAgent.FirstName}}, shortly.</p>\n<p><strong>&nbsp;</strong></p>\n<p dir="ltr">Thanks,</p>\n<p dir="ltr">{{Company.Name}} Customer Support</p>'
      }
    ]
  }
];

tinymce.init({
  selector: "textarea#template-predefined",
    plugins: [
        "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", 
        "help", "image", "insertdatetime", "link", "lists", "media", 
        "preview", "searchreplace", "table", "visualblocks", "advtemplate"
    ],
  contextmenu: 'advtemplate',
  toolbar: "inserttemplate undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
  advtemplate_templates
});

User-modifiable template lists

If the intention is for the template list to be end-user modifiable, the Templates plugin should be configured with options to enable communication with a remote Template storage service.

The following interactive remote storage configuration example provides guidance on configuring the Templates plugin to support user-modifiable template lists.

Configuring the Templates plugin to interact with a remote backend service via REST API.

  • TinyMCE

  • HTML

  • JS

<textarea id="template">
  <h3>Inserting a template</h3>
  <p>To insert a template</p>
  <ol>
    <li>select <strong>Insert template...</strong> from the <strong>Insert</strong> menu or<br />
    select the <strong>Insert template</strong> toolbar button.</li>
    <li>select the template to add to the TinyMCE document from the <strong>Templates</strong> dialog that presents.</li>
    <li>click <strong>Insert</strong> or press <strong>Return</strong>.</li>
  </ol>
  <h3>Adding a new template</h3>
  <p>To add a new template</p>
  <ol>
    <li>select the material in the TinyMCE document that is going to be the new template and</li>
    <li>select <strong>Save as template…</strong> from the <strong>Tools</strong> menu or<br />
    select the <strong>Save as template</strong> toolbar button.</li>
  </ol>
  <p>Then, in the <strong>New template</strong> dialog that presents
  <ol>
  <li>enter a name for the new template in the <strong>Template name</strong> field;</li>
  <li>select a category for the new template from the <strong>Category</strong> pop-up menu; and</li>
  <li>click <strong>Save</strong> or press <strong>Return</strong>.</li>
  </ol>
</textarea>
const headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  }
  
  const handleResponse = (message) => (response) => {
    if (!response.ok) {
      response.text().then((message) => console.error(message))
      throw new Error(message);
    } else {
      return response.json();
    }
  }
  
  const advtemplate_list = () => {
    return fetch('/categories', {
        method: 'GET',
        headers,
      })
      .then(handleResponse('Failed to get template list'))
  }
  
  const advtemplate_get_template = (id) => {
    return fetch('/templates/' + id, {
        method: 'GET',
        headers,
      })
      .then(handleResponse('Failed to get template'))
  }
  
  const advtemplate_create_category = (title) => {
    return fetch('/categories', {
        method: 'POST',
        body: JSON.stringify({
          title
        }),
        headers,
      })
      .then(handleResponse('Failed to create category'))
  }
  
  const advtemplate_create_template = (title, content, categoryId) => {
    return fetch('/templates', {
        method: 'POST',
        body: JSON.stringify({
          title,
          content,
          categoryId
        }),
        headers,
      })
      .then(handleResponse('Failed to create template'))
  }
  
  const advtemplate_rename_category = (id, title) => {
    return fetch('/categories/' + id, {
        method: 'PUT',
        body: JSON.stringify({
          title
        }),
        headers,
      })
      .then(handleResponse('Failed to rename category'))
  }
  
  const advtemplate_rename_template = (id, title) => {
    return fetch('/templates/' + id, {
        method: 'PUT',
        body: JSON.stringify({
          title
        }),
        headers,
      })
      .then(handleResponse('Failed to rename template'))
  }
  
  const advtemplate_delete_template = (id) => {
    return fetch('/templates/' + id, {
        method: 'DELETE',
        headers,
      })
      .then(handleResponse('Failed to delete template'))
  }
  
  const advtemplate_delete_category = (id) => {
    return fetch('/categories/' + id, {
        method: 'DELETE',
        headers,
      })
      .then(handleResponse('Failed to delete category'))
  }
  const advtemplate_move_template = (id, categoryId) => {
    return fetch('/templates/' + id, {
        method: 'PATCH',
        body: JSON.stringify({
          categoryId
        }),
        headers,
      })
      .then(handleResponse('Failed to move template'))
  }
  
  const advtemplate_move_category_items = (id, categoryId) => {
    return fetch('/categories/' + id, {
        method: 'PATCH',
        body: JSON.stringify({
          categoryId
        }),
        headers,
      })
      .then(handleResponse('Failed to move all templates to new category'))
  } 

  tinymce.init({
    selector: "textarea#template",
      plugins: [
          "advlist", "anchor", "autolink", "charmap", "code", "fullscreen", 
          "help", "image", "insertdatetime", "link", "lists", "media", 
          "preview", "searchreplace", "table", "visualblocks", "advtemplate"
      ],
    contextmenu: 'advtemplate',
    toolbar: "addtemplate inserttemplate | undo redo | styles | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
    advtemplate_list,
    advtemplate_get_template,
    advtemplate_create_category,
    advtemplate_create_template,
    advtemplate_rename_category,
    advtemplate_rename_template,
    advtemplate_delete_template,
    advtemplate_delete_category,
    advtemplate_move_template,
    advtemplate_move_category_items
  });

The insertion point marker

This feature is only available for TinyMCE 6.7 and later.

The insertion point marker is a fixed string for adding to any template.

The string to add is as follows: {{mce-cursor}}.

Wherever this string is within a template is where the insertion point appears when that template is added to a TinyMCE document.

Also, and as shown in the interactive demonstration below, the Merge Tags plugin knows to ignore this fixed string, making it possible to use the insertion point marker in conjunction with both plugins.

  • TinyMCE

  • HTML

  • JS

  • Edit on CodePen

<textarea id="template-insertionpoint">
<h3>Using the Insertion Point Marker with Templates (and Merge Tags)<h3>

<h4>To insert a template</h4>
 <ol>
  <li>
    Select <strong>Template…</strong> from the <strong>Insert</strong> menu or<br />
    select the <strong>Insert template</strong> toolbar button.
  </li>
  <li>
  Select the template to add to the TinyMCE document from the <strong>Templates</strong> dialog that presents.
    <ol>
      <li>
      Click the <strong>Without an insertion point marker</strong> category to see and select a template that does not use the <code>{{mce-cursor}}</code> insertion point marker.
      </li>
      <li>
      Click the <strong>With an insertion point marker</strong> category to see and select a template that does use the <code>{{mce-cursor}}</code> insertion point marker.
      </li>
    </ol>
  </li>
<li>click <strong>Insert</strong> or press <strong>Return</strong>.</li>
</ol>

<h4>Noting the difference</h4>

<p>The <em>Name entry prompt</em> template without the <code>{{mce-cursor}}</code> insertion point marker, places the insertion point at the end of the template text.</p>

<p>By contrast, the <em>Name entry prompt</em> template with the <code>{{mce-cursor}}</code> insertion point marker places the insertion point at the right spot for someone to enter their name, as requested.</p>

<p>Similarly, the <em>Letter outline</em> template without the <code>{{mce-cursor}}</code> insertion point marker, places the insertion point at the end of the template text.</p>

<p>And, by equivalent contrast, the <em>Letter outline</em> template with the <code>{{mce-cursor}}</code> insertion point marker places the insertion point at the right spot for someone to start writing a letter.</p>

<h4>Working with Merge Tags</h4>

<p>The second pre-defined template in this demonstration — the <em>Letter outline</em> template — shows the <code>{{mce-cursor}}</code> string working in conjunction with the <a href="https://tiny.cloud/docs/tinymce/6/mergetags/">Merge Tags</a> Premium plugin.</p>

<p>The fixed string that is the Insertion Point Marker uses the same delimiting characters as are used by default by the Merge Tags plugin.</p>

<p>The <strong>Merge Tags</strong> plugin knows nothing about the <code>{{mce-cursor}}</code> being a marker string for the <strong>Templates</strong> plugin. And, if this particular string was used in a Merge Tags configuration, the <strong>Merge Tags</strong> plugin would recognise it and substitute it with whatever contents it was set to substitute, as expected.

<p>The <strong>Templates</strong> plugin removes the Insertion Point Marker before inserting a template containing the string in to a TinyMCE instance, however.</p>

<p>Consequently the <strong>Templates</strong> insertion point marker string is never seen by the <strong>Merge Tags</strong> plugin.</p>

</textarea>
tinymce.init({
  selector: "textarea#template-insertionpoint",
  plugins: [ "advtemplate", "mergetags", ],
  toolbar: "inserttemplate | mergetags",
  advtemplate_templates: [
    {
      title: 'Without an insertion point marker',
      items: [
        {
          title: 'Name entry prompt',
          content: '<p><strong>Enter your name:</strong></p><p><em>Include both your given and family names, in your preferred order.</em></p>'
        },
        {
          title: 'Letter outline',
          content: '<p>{{Current.Date}}</p><p>{{Honorific}} {{Person.Name.Last}},</p><p></p><p>&nbsp;</p><p>Regards,</p><p>{{staff.digital.signature}}</p><p>{{Staff.Name}}</p><p>{{Staff.Email}}</p>'
        },
      ],
    },
    {
      title: 'With an insertion point marker',
      items: [
        {
          title: 'Name entry prompt',
          content: '<p><strong>Enter your name:</strong>{{mce-cursor}}</p><p><em>Include both your given and family names, in your preferred order.</em></p>'
        },
        {
          title: 'Letter outline',
          content: '<p>{{Current.Date}}</p><p>{{Honorific}} {{Person.Name.Last}},</p><p>{{mce-cursor}}&nbsp;</p><p>Regards,</p><p>{{staff.digital.signature}}</p><p>{{Staff.Name}}</p><p>{{Staff.Email}}</p>'
        },
      ],
    },
  ],
  mergetags_list: [
    {
      value: 'Current.Date',
      title: 'Current date in DD/MM/YYYY format'
    },
    {
      value: 'Current.Time',
    },
    {
      value: 'Honorific',
    },
    {
      title: 'Person',
      menu: [
        {
          value: 'Customer.Name.Given',
          title: 'customer first name'
        },
        {
          value: 'Customer.Name.Family',
          title: 'customer family name'
        },
        {
          value: 'Customer.Name.Full',
          title: 'customer full name'
        },
        {
          value: 'Staff.Name.Full',
          title: 'staff full name'
        },
        {
          value: 'Staff.Digital.Signature',
          title: 'staff digital signaure'
        },
        {
          title: 'Email',
          menu: [
            {
              value: 'Customer.Email'
            },
            {
              value: 'Staff.Email'
            }
          ]
        }
      ]
    }
  ]
});

The mce-clipboard marker

This feature is only available for TinyMCE 6.8 and later.

The {{mce-clipboard}} marker is a fixed string for adding to any template.

The string to add is as follows: {{mce-clipboard}}.

Whenever a user inserts a template containing the {{mce-clipboard}} marker, the editor will replace those markers with the actual content from the clipboard.

  • TinyMCE

  • HTML

  • JS

  • Edit on CodePen

<textarea id="template-mce-clipboard">
  <h3>Using the {{mce-clipboard}} Marker with Templates</h3>
  <h4>Before inserting the example template, <strong>type in your name</strong> to the editor, select and copy it to your clipboard by using <strong>Ctrl+C</strong> for Windows users, or <strong>⌘+C</strong> for Mac users</h4>
  <div>
    <ol>
      <li>
        Select <strong>Template…</strong> from the <strong>Insert</strong> menu or by selecting the <strong>Insert template</strong> toolbar button.
      </li>
      <li>
        Select a template to add to the TinyMCE document from the <strong>Templates</strong> dialog that presents.
        <ol>
          <li>
            <p>Click the <strong>Without an <code>{{mce-clipboard}}</code> marker</strong> template.</p>
            <p>The template should be inserted into the editor content regardless of any clipboard content./p>
          </li>
          <li>
            <p>Click the <strong>With a <code>{{mce-clipboard}}</code> marker</strong> template.</p>
            <p><em>When a template <strong>does</strong> contain a valid {{mce-clipboard}} marker, the current content saved in the users clipboard will <strong>replace</strong> the marker when the user inserts the template.</em></p>
          </li>
        </ol>
      </li>
      <li>
        Click <strong>Insert</strong> or press <strong>Return</strong>.
      </li>
    </ol>
  </div>
</textarea>
tinymce.init({
  selector: "textarea#template-mce-clipboard",
  plugins: [ "advtemplate", "code", "help"],
  toolbar: "undo redo | inserttemplate",
  advtemplate_templates: [
    {
      title: 'Without an mce-clipboard marker',
      content: '<p>Hi , Thank you for visiting this page. We truly appreciate and value your feedback and any feature requests you may have While you are here, take a moment to explore mce-cursor, its another powerful tool designed for Templates</p>'
    },
    {
      title: 'With an mce-clipboard marker',
      content: '<p>Hi {{mce-clipboard}}, Thank you for visiting this page. We truly appreciate and value your feedback and any feature requests you may have While you are here, take a moment to explore mce-cursor {{mce-clipboard}}, its another powerful tool designed for Templates</p>'
    }
  ],
});

Options

The following configuration options affect the behavior of the Templates plugin.

advtemplate_templates

This option lets you specify a static list of predefined templates that can be inserted using the Templates dialog. It is for scenarios where the provided template list is unchangeable. In this use-case, there is no need to set up a persistent template store and provide a more complex plugin configuration.

Type: Array

The template list assigned to the advtemplate_templates option must adhere to the following requirements:

  1. Each item must have a non-empty title value.

  2. Each template item is required to include a non-empty content value.

  3. Each category item is required to include a items sublist, which can be empty.

  4. Category items must not contain nested subcategories.

Example: using advtemplate_templates

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: "advtemplate",
  toolbar: "inserttemplate",
  advtemplate_templates: [
    {
      title: 'Template 1',
      content: 'Template 1 content'
    },
    {
      title: 'Category 2',
      items: [
        {
          title: 'Template 2.1',
          content: 'Template 2.1 content'
        },
        {
          title: 'Template 2.2',
          content: 'Template 2.2 content'
        }
      ]
    }
  ],
});

advtemplate_list

The plugin uses the advtemplate_list asynchronous function to retreive the template list.

Type: Function (Returns a Promise)

Input parameters: None

Return data: Array

Example: using advtemplate_list

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_list: () =>
    fetch('/categories', {
      method: 'GET',
    })
    .then((response) => response.json())
    .then((data) => data)
    .catch((error) => console.log('Failed to get template list\n' + error)),
});

The data returned by advtemplate_list must adhere to the following requirements:

  1. Each list item must have a unique id value.

  2. Each list item must have a non-empty title value.

  3. Each category item is required to include an items sublist, which can be empty.

  4. Category items must not contain nested subcategories.

  5. Template item is not required to include a content value.

Sample advtemplate_list response

[{
    id: '1',
    title: 'Resolving tickets',
  },
  {
    id: '2',
    title: 'Quick replies',
    items: [{
        id: '3',
        title: 'Message received',
      },
      {
        id: '4',
        title: 'Progress update',
      }
    ]
  }
]

advtemplate_get_template

The plugin uses the advtemplate_get_template asynchronous function to get a template.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

id

string

required

The id of the template to get.

Return data:

Field Type Description

id

string

The id of the template.

title

string

The title of the template.

content

string

The content of the template.

Example: using advtemplate_get_template

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_get_template: (id) =>
    fetch('/templates/' + id, {
      method: 'GET',
    })
    .then((response) => response.json())
    .then(({ id, title, content }) => ({id, title, content}))
    .catch((error) => console.log('Failed to get template\n' + error)),
});

advtemplate_create_category

The plugin uses the advtemplate_create_category asynchronous function to create a category.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

title

string

required

The title of the category.

Return data:

Field Type Description

id

string

The id of the newly created category.

Example: using advtemplate_create_category

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_create_category: (title) =>
    fetch('/categories', {
      method: 'POST',
      body: JSON.stringify({
        title
      }),
    })
    .then((response) => response.json())
    .then(({ id }) => ({ id }))
    .catch((error) => console.log('Failed to create category\n' + error)),
});

advtemplate_create_template

The plugin uses the advtemplate_create_template asynchronous function to create a template.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

title

string

required

The title of the template.

content

string

required

The content of the template.

categoryId

string

optional

The parent category id.

Return data:

Field Type Description

id

string

The id of newly created template.

Example: using advtemplate_create_template

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_create_template: (title, content, categoryId) =>
    fetch('/templates', {
      method: 'POST',
      body: JSON.stringify({
        title,
        content,
        categoryId
      }),
    })
    .then((response) => response.json())
    .then(({ id }) => ({ id }))
    .catch((error) => console.log('Failed to create template\n' + error)),
});

advtemplate_rename_category

The plugin uses the advtemplate_rename_category asynchronous function to rename a category.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

id

string

required

The id of the category to rename.

title

string

required

New category title.

Return data: Empty object {}

Example: using advtemplate_rename_category

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_rename_category: (id, title) =>
    fetch('/categories/' + id, {
      method: 'PUT',
      body: JSON.stringify({
        title
      }),
    })
    .then(() => ({}))
    .catch((error) => console.log('Failed to rename category\n' + error)),
});

advtemplate_rename_template

The plugin uses the advtemplate_rename_template asynchronous function to rename a template.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

id

string

required

The id of the template to rename.

title

string

required

New template title.

Return data: Empty object {}

Example: using advtemplate_rename_template

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_rename_template: (id, title) =>
    fetch('/templates/' + id, {
      method: 'PUT',
      body: JSON.stringify({
        title
      }),
    })
    .then(() => ({}))
    .catch((error) => console.log('Failed to rename template\n' + error)),
});

advtemplate_delete_template

The plugin uses the advtemplate_delete_template asynchronous function to delete a template.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

id

string

required

The id of the template to delete.

Return data: Empty object {}

Example: using advtemplate_delete_template

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_delete_template: (id) =>
    fetch('/templates/' + id, {
      method: 'DELETE',
    })
    .then(() => ({}))
    .catch((error) => console.log('Failed to delete template\n' + error)),
});

advtemplate_delete_category

The plugin uses the advtemplate_delete_category asynchronous function to delete a category.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

id

string

required

The id of the category to delete.

Return data: Empty object {}

Example: using advtemplate_delete_category

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_delete_category: (id) =>
    fetch('/categories/' + id, {
      method: 'DELETE',
    })
    .then(() => ({}))
    .catch((error) => console.log('Failed to delete category\n' + error)),
});

advtemplate_move_template

The plugin uses the advtemplate_move_template asynchronous function to move the template to another category.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

templateId

string

required

The id of the template to move .

newCategoryId

string

optional

The id of the destination category.

Return data: Empty object {}

Example: using advtemplate_move_template

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_move_template: (templateId) =>
    fetch('/templates/' + templateId, {
      method: 'PATCH',
      body: JSON.stringify({
        newCategoryId
      }),
    })
    .then(() => ({}))
    .catch((error) => console.log('Failed to move template\n' + error)),
});

advtemplate_move_category_items

The plugin uses the advtemplate_move_category_items asynchronous function to move all templates from a given category to the another one.

Type: Function (Returns a Promise)

Input parameters:

Field Type Required? Description

oldCategoryId

string

required

The id of the source category .

newCategoryId

string

optional

The id of the destination category.

Return data: Empty object {}

Example: using advtemplate_move_category_itmes

tinymce.init({
  selector: 'textarea#advtemplate',  // change this value according to your html
  plugins: ["advtemplate"],
  advtemplate_move_category_items: (oldCategoryId, newCategoryId) =>
    fetch('/categories/' + oldCategoryId, {
      method: 'PATCH',
      body: JSON.stringify({
        newCategoryId
      }),
    })
    .then(() => ({}))
    .catch((error) => console.log('Failed to move category items\n' + error)),
});

Toolbar buttons

The Templates plugin provides the following toolbar buttons:

Toolbar button identifier Description

inserttemplate

Opens the Templates dialog which presents all templates available to the particular TinyMCE instance for selection and insertion.

addtemplate

Open the New template dialog, allowing for the selected text to be saved as a named template and placed in an already-set category. If there is no selection current in the TinyMCE editor, this button is disabled.

These toolbar buttons can be added to the editor using:

The Templates plugin provides the following menu items:

Menu item identifier Default Menu Location Description

inserttemplate

Insert

Opens the Templates dialog which presents all templates available to the particular TinyMCE instance for selection and insertion.

addtemplate

Tools

Open the New template dialog, allowing for the selected text to saved as a named template and placed in an already-set category. If there is no selection current in the TinyMCE editor, this menu item is disabled.

These menu items can be added to the editor using:

Commands

The Templates plugin provides the following TinyMCE commands.

Command Description

AdvTemplateAddDialog

Opens the Add Template dialog, allowing the current selection to be added as a template.

AdvTemplateInsertDialog

Opens the Insert Template dialog, allowing a template to be inserted at the current selection

AdvTemplateInsertTemplateById

Adds a new template specified by the value of its ID.

Example
tinymce.activeEditor.execCommand('AdvTemplateAddDialog');
tinymce.activeEditor.execCommand('AdvTemplateInsertDialog');

// Adds a new template, which ID is 122, to the document.
tinymce.activeEditor.execCommand('AdvTemplateInsertTemplateById', false, '122')