---
title: "Templates plugin"
description: "Create and edit complex templates in TinyMCE for use with TinyMCE."
canonical_url: "https://www.tiny.cloud/docs/tinymce/latest/advanced-templates/"
md_url: "https://www.tiny.cloud/docs/tinymce/latest/advanced-templates/index.md"
version: "latest"
last_updated: "2026-05-07T05:55:46Z"
tokens: 8601
---
# Templates plugin

> **Note:** This plugin is only available for [paid TinyMCE subscriptions](/pricing/).

> **Tip:** 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.

> **Important:** 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](../_images/icons/template.svg)
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](../_images/icons/template-add.svg)
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

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](../_images/icons/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
```js
{
  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>'
    }
  ]
}
```
**Example**

```js
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
```js
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
});
```

> **Note:** For information on bundling this plugin with module bundlers, see [Bundling TinyMCE - Overview](../bundling-guide/).

> **Note:** The undefined options in the above example must be defined. See the [Options](#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`](#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.

**Example**

```js
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.

**Example**

```js
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

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](../mergetags/) plugin knows to ignore this fixed string, making it possible to use the insertion point marker in conjunction with both plugins.

**Example**

```js
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

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.

**Example**

```js
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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise))

**Input parameters:** None

**Return data:** `Array`

#### Example: using `advtemplate_list`

```js
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

```js
[{
    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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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`

```js
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 [`toolbar`](../toolbar-configuration-options/#toolbar) configuration option.
- The [`quickbars_insert_toolbar`](../quickbars/#quickbars_insert_toolbar) configuration option.
- [Custom Context toolbars](../contexttoolbar/).

## Menu items

The Templates plugin provides the following menu items:

| Menu item identifier | [Default Menu Location](../menus-configuration-options/#example-the-tinymce-default-menu-items) | 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:

- The [`menu`](../menus-configuration-options/#menu) configuration option.
- The [`contextmenu`](../menus-configuration-options/#contextmenu) configuration option.
- [Custom Menu toolbar buttons](../custom-menu-toolbar-button/).

## 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
```js
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')
```
