Skip to main content

πŸ› οΈ Your First Plugin

Welcome! In this guide, we will walk through the process of creating your first Open Ticket plugin.

By the end of this article, you will have a fully functional plugin that listens for ticket creation events and logs messages to the console. You will learn a lot of the basic functionalities of Open Ticket, so be sure to pay attention. Good luck!

Framework Article

Basic Plugins - Your First Plugin


πŸ“Œ Prerequisites​

Before we start, ensure that you have the following:

  • Node.js installed on your system. (Download)
  • A code editor, such as Visual Studio Code. (Download)
  • A basic understanding of JavaScript/TypeScript and discord.js.
  • An existing & working Open Ticket installation
getting started

If you haven't already done so, it's recommended to read the 🏁 Getting Started guide before starting with this article.


πŸ“‚ Setting Up the Plugin​

Each Open Ticket plugin must be placed inside the ./plugins/ directory. Let's create a folder for our first plugin:

mkdir -p ./plugins/example-plugin
cd ./plugins/example-plugin

plugin.json​

Now, inside this folder, create a plugin.json file. This file contains metadata about the plugin. Please insert the following content:

plugin.json
{
"name":"Example Plugin",
"id":"example-plugin",
"version":"1.0.0",
"startFile":"index.ts",

"enabled":false,
"priority":0,
"events":[],

"npmDependencies":[],
"requiredPlugins":[],
"incompatiblePlugins":[],

"details":{
"author":"<your-username>",
"shortDescription":"A simple template for an Open Ticket v4 plugin!",
"longDescription":"A simple example of an Open Ticket v4 plugin!",
"imageUrl":"",
"projectUrl":"",
"tags":["template","example","default"]
}
}

πŸ” Understanding plugin.json​

  • "name": string - The display name of the plugin.
  • "id": string - The unique identifier of the plugin. This must match the folder name!
  • "version": string - The version of the plugin.
  • "startFile": string - The file which will be executed on startup of the bot.
  • "enabled": boolean - If set to false, the plugin will be ignored by Open Ticket.
  • "priority": number - Plugins with a higher priority will be executed first.
  • Explore Additional Properties...

Now that our plugin is registered, let's create the main script file.

index.ts​

Create a new file called index.js inside the ./plugins/example-plugin/ folder. This file will contain our plugin logic. Make sure it already contains the following lines of code:

index.ts
import {api, opendiscord, utilities} from "#opendiscord"
import * as discord from "discord.js"
if (utilities.project !== "openticket") throw new api.ODPluginError("This plugin only works in Open Ticket!")

declare module "#opendiscord-types" {
//This will be used for autocomplete support while coding
}

πŸ” Understanding index.ts​

Let's break down what we’ve added so far:

  • Importing dependencies:
    • api (#opendiscord) - Contains all Open Ticket classes, objects, interfaces, variables, ...
    • opendiscord (#opendiscord) - This is the Open Ticket bot itself. We will frequently interact with it.
    • utilities (#opendiscord) Additional utility functions to make coding easier.
    • discord (discord.js) - Allows us to interact with Discord’s API, such as sending messages or modifying channels.
  • Ensuring compatibility:
    • The if (utilities.project !== "openticket") check prevents the plugin from running in unsupported environments or different bots.
  • Adding TypeScript autocomplete support:
    • The declare module "#opendiscord-types" block allows us to extend Open Ticket's type definitions, making development easier with improved autocomplete suggestions.

Now that our setup is complete, let's proceed with implementing the rest of the plugin logic. πŸš€


πŸ“ Writing Code (Step by Step)​

Now that we've set up our plugin directory and index.ts file, it's time to write the actual code. Below, we'll go through each section carefully, explaining its purpose and functionality.

1️⃣ TypeScript Autocomplete Support (Optional)​

note

This step is optional but highly recommended for smoother development!

index.ts
declare module "#opendiscord-types" {
export interface ODPluginManagerIds_Default {
"example-plugin": api.ODPlugin
}
export interface ODConfigManagerIds_Default {
"example-plugin:config": api.ODJsonConfig
}
}

πŸ”Ή Why declare these types?​

  • These extend Open Ticket’s type system, providing autocomplete and type safety while coding.
  • ODPluginManagerIds_Default allows our plugin to be recognized under the "example-plugin" ID.
  • ODConfigManagerIds_Default allows our plugin configuration to be recognized under the "example-plugin:config" ID.

2️⃣ Registering a Custom Configuration​

To store plugin settings, we can register a configuration file.

If you want an in-depth guide about this topic, check this article.

index.ts
opendiscord.events.get("onConfigLoad").listen((configManager) => {
configManager.add(new api.ODJsonConfig("example-plugin:config", "config.json", "./plugins/example-plugin/"))

πŸ”Ή What happens here?​

  • onConfigLoad is triggered when the bot loads its configurations.
  • configManager.add(...) registers a new JSON configuration file.
  • ODJsonConfig is the class responsible for managing & reading the JSON file.
  • Parameters explained:
    • "example-plugin:config" β†’ The unique ID for this config.
    • "config.json" β†’ The filename of the config.
    • "./plugins/example-plugin/" β†’ The directory where the file is stored.
config location

Why store configs inside ./plugins/example-plugin/ instead of ./config/?
This keeps all plugin-related files self-contained, avoiding clutter in the main config directory.


3️⃣ Accessing Configuration Data​

Ofcourse we also want to read our plugin settings. This can be done by importing the ODJSonConfig from opendiscord.configs.

index.ts
//you can run this code in any event which has triggered after the config has been loaded!
opendiscord.events.get("someEventYouWantToUseThisConfig").listen(() => {
const ourConfig = opendiscord.configs.get("example-plugin:config")
opendiscord.log("The example config loaded successfully!", "plugin", [
{ key: "var-1", value: ourConfig.data.testVariable1 },
{ key: "var-2", value: ourConfig.data.testVariable2.toString() },
{ key: "var-3", value: ourConfig.data.testVariable3.toString() }
])
})

πŸ”Ή What does this do?​

  • Retrieve our config file using opendiscord.configs.get("example-plugin:config").
  • Access the test variables from the config file.
  • Uses opendiscord.log(...) to print information in the console and logs in a beautiful way.
tips
  • Logging configuration values helps ensure that everything loads correctly.
  • opendiscord.configs works the same as configManager when we registered the config file.

4️⃣ Listening for Ticket Events​

Let's try to react when a user creates a ticket. For this, we can use the same event listeners.

index.ts
opendiscord.events.get("onTicketCreate").listen((creator) => {
opendiscord.log("Ticket is getting created...", "plugin")
})
opendiscord.events.get("afterTicketCreated").listen((ticket, creator, channel) => {
opendiscord.log("Ticket is ready for usage!", "plugin")
})

πŸ”Ή What happens here?​

  • onTicketCreate is triggered before a ticket is created (right after the user clicks the button).
  • afterTicketCreated is fired after the ticket has been created and is assigned to a channel.
  • Logs "Ticket is getting created..." & "Ticket is ready for usage!" to inform us of the events.
  • You can use the ticket, creator and channel variables to execute your own actions.

βš™οΈ Testing Your Plugin​

To test the plugin, make sure the plugin is enabled in plugin.json and restart your Open Ticket bot:

npm start

If everything is set up correctly, you should see the following messages in your bot console when a ticket is created:

[PLUGIN] Ticket is getting created...
[PLUGIN] Ticket is ready for usage!

πŸ” Troubleshooting​

If you don't see these messages, ensure:

  • Your plugin is inside ./plugins/example-plugin/
  • plugin.json has "enabled":true
  • There are no syntax errors in index.ts
  • The bot has been configured correctly
  • The compilation succeeded
  • For more advanced testing, check out the Testing Your Plugin guide.

πŸ’‘ Exercises​

Every article will contain a few Exercise dialogs. Use these to improve your Open Ticket knowledge!

exercises

Now it's your turn! Try to listen for a few other events and react to them accordingly.

Exercises​

  • 🟒 Listen for ticket deletion.
  • 🟠 Listen for after a ticket has been closed.
  • πŸ”΄ Send a message when a ticket is going to get claimed.

πŸ† Summary​

Congratulations! You've successfully built your first Open Ticket plugin!

What did we build in this tutorial?

  • βœ… A plugin with Ensured compatibility with Open Ticket.
  • βœ… TypeScript autocomplete support for a smoother coding experience.
  • βœ… Registered a custom configuration file for our plugin.
  • βœ… Listened for ticket creation events:
    • onTicketCreate β†’ Runs before the ticket is made.
    • afterTicketCreated β†’ Runs after the ticket is created.

This concludes our first Open Ticket plugin! πŸŽ‰ In the next steps, we’ll explore how to test and refine our plugin.

Next Steps​

Learn More​

Go Further​

Useful Resources​