Setting Up Slash Commands For Discord Bot
Swislok-Dev
Posted on June 6, 2022
Getting Started
Having a head start with this bot already we should have certain dependencies install, if not here they are:
npm install @discordjs/builders @discordjs/rest discord-api-types
These will be used in creating the Slash Commands for use in Discord.
This blog assumes you have already read what has been built previously in this post here
You will also need to have generated a new URL that include "bot" and "applications.commands" in order to create commands for the Discord server to used for the bot.
deploy-commands.js
const { SlashCommandBuilder } = require('@discordjs/builders')
const { REST } = require('@discordjs/rest')
const { Routes } = require('discord-api-types/v9')
const { clientId, guildId, token } = require('./config.json')
const rest = new REST({ version: '9' }).setToken(token)
const commands = [
new SlashCommandBuilder()
.setName('ping')
.setDescription('Replies with pong'),
new SlashCommandBuilder()
.setName('server')
.setDescription('Replies with server info'),
new SlashCommandBuilder()
.setName('user')
.setDescription('Replies with user info'),
].map((command) => command.toJSON())
rest
.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
.then(() => console.log('Successfully registered application commands.'))
.catch(console.error())
The clientId
is taken from the developer portal for the bot and the guildId
is which guild you would like to target these commands for.
There is a way to create commands which will omit the guildId in order to pass for all servers that the bot joins.
index.js
The following is to be added after the client has been called on initialization.
clinet.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) return
const { commandName } = interaction
if (commandName === 'ping') {
await interaction.reply('Pong!')
} else if (commandName === 'server') {
await interaction.reply(`
Server name: ${interaction.guild.name}\n
Total members: ${interaction.guild.memberCout}\n
Server created on: ${interaction.guild.createdAt}
`)
} else if (commandName === 'user') {
await interaction.reply(`
Your tag: ${interaction.user.tag}\n
Your id: ${interaction.user.id}
`)
}
})
You should now run node deploy-commands.js
. This will only need to be run once unless you change anything how the command is built or what server you want the commands deployed to.
Running the bot in the server with the guildId that was used, in the text field placing a "/"
should now have commands that you created for use by your bot. Using the slash commands will show the command name and the description
as you have written it.
Refactorize!
If you're like me and tend to add a ton of commands to help out the general moderation of a server then you'll get a bit tired of writing commands out like this. Not to mention how messy things will end up getting.
We can create a few directories and refactor some of the existing ones
Let's start by creating the new files which will ultimately be the new home for all the commands that you wish to have.
Create a new directory called commands
.
Within the command directory the ping
, server
, and user
will become their own ".js" files.
ping.js
// commands/ping.js
const { SlashCommandBuilder } = require('@discordjs/builders')
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Replies with Pong!'),
async execute(interaction) {
await interaction.reply('Pong!')
},
}
server.js
// commands/server.js
const { SlashCommandBuilder } = require('@discordjs/builders')
module.exports = {
data: new SlashCommandBuilder()
.setName('server')
.setDescription('Display info about this server.'),
async execute(interaction) {
return interaction.reply(
`Server name: ${interaction.guild.name}\nTotal members: ${interaction.guild.memberCount}`
)
},
}
user.js
// commands/user.js
const { SlashCommandBuilder } = require('@discordjs/builders')
module.exports = {
data: new SlashCommandBuilder()
.setName('user')
.setDescription('Display info about yourself.'),
async execute(interaction) {
return interaction.reply(
`Your username: ${interaction.user.username}\nYour ID: ${interaction.user.id}`
)
},
}
Next edit the deploy-commands.js and index.js files
deploy-commands.js
// node modules that will be included to existing file
const fs = require('node:fs')
const path = require('node:path')
...
// remove everything inside the commands array and replace with an empty array
const commands = []
const commandsPath = path.join(__dirname, 'commands')
const commandFiles = fs
.readdirSync(commandsPath)
.filter((file) => file.endsWith('.js'))
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file)
const command = require(filePath)
commands.push(command.data.toJSON())
}
...
A similar thing will be done with the index.js file to create all the commands.
index.js
const fs = require('node:fs')
const path = require('node:path')
const { Client, Intents, Collection } = require('discord.js')
const { token } = require('./config.json')
const client = newClient({ intents: [Intents.FLAGS.GUILDS] })
client.commands = new Collection()
const commandsPath = path.join(__dirname, 'commands')
const commandFiles = fs
.readdirSync(commandsPath)
.filter((file) => file.endsWith('.js'))
for (const file of commandFiles) {
const filePath = path.join(commandsPath, file)
const command = require(filePath)
client.commands.set(command.data.name, command)
}
client.once('ready', () => {
console.log('Ready!')
})
client.on('interactionCreate', async (interaction) => {
if (!interaction.isCommand()) return
const command = client.commands.get(interaction.commandName)
if (!command) return
try {
await command.execute(interaction)
} catch (error) {
console.error(error)
await interaction.reply({
content: 'There was an error while executing this command!',
ephemeral: true,
})
}
})
client.login(token)
Now we have cleaned up the index.js and deploy-commands.js, we'll add one more command that will open up the options to add options
on a command.
echo.js
// commands/echo.js
const { SlashCommandBuilder } = require('@discordjs/builders')
module.exports = {
data: new SlashCommandBuilder()
.setName('echo')
.setDescription('Replies with you input!')
.addStringOption((option) =>
option
.setName('input')
.setDescription('The input to echo back')
.setRequired(true)
),
async execute(interaction) {
await interaction.reply({
content: interaction.options.getString('input'),
ephemeral: true,
})
}
}
The .addStringOption()
will allow for an input, in this case to reply what we say, and do something with it. In the event you wish you mute someone on the server you will be able to use /mute @this-noisy-user
and the bot will take of it for you. Setting up for how long they will be muted for is up to you and if your bot stays running to unmute them.
Posted on June 6, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.