# Customize Discord Templates

{% hint style="warning" %}
This functionality is only available from version 1.16.48 of the discord plugin
{% endhint %}

{% hint style="danger" %}
This is an advanced configuration section. A certain level of technical knowledge is required depending on how much you want to change.
{% endhint %}

## Introduction

To create your own custom discord messages you will need some knowledge of \
[The discord API](https://discord.com/developers/docs/resources/webhook#execute-webhook) and the [JEXL](https://commons.apache.org/proper/commons-jexl/) (Java Expression Language) [syntax](https://commons.apache.org/proper/commons-jexl/reference/syntax.html)\
\
Basically we are doing a REST call to the webhook URL and sending a JSON body with it.\
The JSON bodies are build from template files which can be found inside your **plugin directory** underneath a folder "**discordtemplates**". There are different template packs. **"default"** is enabled by default. Every [template pack](https://wiki.staffplusplus.org/integrations/discord-integration/template-packs) contains all the template files needed.

These files are a combination of JSON and JEXL.&#x20;

## Configuring a template

{% hint style="info" %}
To easily change and test templates, edit the template and execute the `/staffplusplusdiscord reload` command
{% endhint %}

Start by setting the "**updateTemplates**" property inside the **config.yml** file to **false**. This will prevent Staff++ Discord from overwriting the template files at startup.

Copy paste the **default** templates directory into a new directory with your template name:

![](https://3621425798-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MPQohtcLxhXAvpSXOMt%2F-MVRMBBPkIxSQdGvzcS0%2F-MVRTaxDHyVAqWF1XZk9%2Ftemplates.png?alt=media\&token=749441d6-da7f-48f5-8e7e-8376f422dd42)

Change the **template** configuration property inside the **config.yml**

```yaml
StaffPlusPlusDiscord:
  templatePack: mycustomtemplates
```

S++ Discord will now start using the templates defined in the "**mycustomtemplates"** directory. Change these templates how you like. You can always switch back to another template pack by change the configuration property.

#### Example: discordtemplates/mycustomtemplates/reports/report-rejected.json

````javascript
// Context:
// report: IReport => https://github.com/garagepoort/StaffPlusPlus/blob/master/StaffPlusAPI/src/main/java/net/shortninja/staffplus/unordered/IReport.java
// timestamp: String
{
    "content": "Report update from Staff++",
    "embeds": [
        {
            "title": "Report rejected by ${report.staffName}",
            "url": "https://www.spigotmc.org/resources/staff.83562/",
            "color": "16601379",
            "timestamp": "${timestamp}",
            "footer": {
                "text": "Provided by Staff++",
                "icon_url": "https://cdn.discordapp.com/embed/avatars/0.png"
            },
            "fields": [
                {
                    "name": "Reporter",
                    "value": "${report.reporterName}\n[${report.reporterUuid}]",
                    "inline": true
                },
                {
                    "name": "Culprit",
                    "value": "${report.culpritUuid != null ? report.culpritName + '\\\\n[' + report.culpritUuid + ']' : '[Unknown]'}",
                    "inline": true
                },
                {
                    "name": "Staff",
                    "value": "${report.staffName}\n[${report.staffUuid}]",
                    "inline": false
                },
                {
                    "name": "Reason",
                    "value": "```${report.reason}```",
                    "inline": false
                },
                #IF report.closeReason != null
                {
                    "name": "Reason for closing",
                    "value": "```${report.closeReason}```",
                    "inline": false
                },
                #ENDIF
                {
                    "name": "Status",
                    "value": "**${report.reportStatus}**",
                    "inline": true
                },
                {
                    "name": "Location",
                    "value": "${report.location.isPresent() ? utils:parseLocation(report.serverName, report.location.get()) : 'Unknown'}",
                    "inline": true
                }
            ]
        }
    ]
}
````

The above shows the default template for a rejection of a report. This is a fairly good example because it contains most of what you might need. In theory you can completely overwrite the contents of this file as long as it will result in a valid JSON request body for the Discord Webhook API.

### JSON

Notice how most of the template is just a JSON body. The entirety of the body is constructed so it will be parsed into a valid request body that can be send to the discord webhook.\
I won't go into detail on the JSON structure because this is defined by the [Discord webhook API](https://discord.com/developers/docs/resources/webhook#execute-webhook).\
In the default templates I always use [Discord Embeds](https://discord.com/developers/docs/resources/channel#embed-object)

### JEXL

Before the above gets send to discord it gets parsed by the S++ Discord plugin.  It allows you to use JEXL expressions within the template.\
Everything inside the template between **"${}"** signs gets parsed as a JEXL expression.

**Context**

```javascript
// Context:
// report: IReport => https://github.com/garagepoort/StaffPlusPlus/blob/master/StaffPlusAPI/src/main/java/net/shortninja/staffplus/unordered/IReport.java
// timestamp: String
```

At the top of every template you will notice the context definition. This describes what properties are placed on the JEXL context for this template. A timestamp will always be provided.\
Besides, the timestamp you also get an object of type IReport. The type definition can be viewed on [Github](https://github.com/garagepoort/staffplusplus-discord). Now that we know what properties we can access, we can write a JEXL expressions like this:

```javascript
"value": "${report.reporterName}\n[${report.reporterUuid}]"
```

In the above string literal we have 2 jexl expressions:

* ${report.reporterName}
* ${report.reporterUuid}

After the template is parsed and the Discord API is called your channel will receive a message looking like this:

![](https://3621425798-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MPQohtcLxhXAvpSXOMt%2F-MTtzR6eLxf6hzGSP9Ir%2F-MTuHkrBz7eX2GKPPqwK%2Freject_report.png?alt=media\&token=708ae72f-6a54-430d-baa4-ac493ce99735)

## Conditional JSON

In the example template you will notice there is a section surrounded by an if statement.

````javascript
#IF report.closeReason != null
{
    "name": "Reason for closing",
    "value": "```${report.closeReason}```",
    "inline": false
},
#ENDIF
````

You can use the **#IF \<jexl expression> #ENDIF** syntax to allow certain parts of the JSON body to be in- or excluded. In this case only a closing reason section will be send to discord if there is actually a closing reason inside the IReport object.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.staffplusplus.org/integrations/discord-integration/customize-discord-templates.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
