Creating a basic slash command
Creating a basic slash command is very similar to creating a basic command. To create a slash command you will have to
define the registerApplicationCommands
method in the command class.
For example, let's create a ping
command:
- JavaScript
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');class PingCommand extends Command { constructor(context, options) { super(context, { ...options }); } registerApplicationCommands(registry) { registry.registerChatInputCommand((builder) => builder.setName('ping').setDescription('Ping bot to see if it is alive') ); }}module.exports = { PingCommand};
import { Command } from '@sapphire/framework';export class PingCommand extends Command { constructor(context, options) { super(context, { ...options }); } registerApplicationCommands(registry) { registry.registerChatInputCommand((builder) => builder.setName('ping').setDescription('Ping bot to see if it is alive') ); }}
import { Command } from '@sapphire/framework';export class PingCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options }); } public override registerApplicationCommands(registry: ChatInputCommand.Registry) { registry.registerChatInputCommand((builder) => builder.setName('ping').setDescription('Ping bot to see if it is alive') ); }}
The above example will create a slash command (chat input command) called ping
with the description
Ping bot to see if it is alive
. Alternatively, we can also use this.name
and this.description
to pass the name and
description to the builder which will take the data from the passed values in command class.
Example:
- JavaScript
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');class PingCommand extends Command { constructor(context, options) { super(context, { ...options, name: 'ping', description: 'Ping bot to see if it is alive' }); } registerApplicationCommands(registry) { registry.registerChatInputCommand((builder) => builder.setName(this.name).setDescription(this.description)); }}module.exports = { PingCommand};
import { Command } from '@sapphire/framework';export class PingCommand extends Command { constructor(context, options) { super(context, { ...options, name: 'ping', description: 'Ping bot to see if it is alive' }); } registerApplicationCommands(registry) { registry.registerChatInputCommand((builder) => builder.setName(this.name).setDescription(this.description)); }}
import { Command } from '@sapphire/framework';export class PingCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, name: 'ping', description: 'Ping bot to see if it is alive' }); } public override registerApplicationCommands(registry: ChatInputCommand.Registry) { registry.registerChatInputCommand((builder) => builder.setName(this.name).setDescription(this.description)); }}
Creating the chatInputRun
method
To handle the command callback when the context menu command is ran we need to override the chatInputRun
method of
command class.
- JavaScript
- ESM
- TypeScript
const { isMessageInstance } = require('@sapphire/discord.js-utilities');const { Command } = require('@sapphire/framework');class PingCommand extends Command { constructor(context, options) { // ... } async chatInputRun(interaction) { const msg = await interaction.reply({ content: `Ping?`, ephemeral: true, fetchReply: true }); if (isMessageInstance(msg)) { const diff = msg.createdTimestamp - interaction.createdTimestamp; const ping = Math.round(this.container.client.ws.ping); return interaction.editReply(`Pong 🏓! (Round trip took: ${diff}ms. Heartbeat: ${ping}ms.)`); } return interaction.editReply('Failed to retrieve ping :('); }}module.exports = { PingCommand};
import { isMessageInstance } from '@sapphire/discord.js-utilities';import { Command } from '@sapphire/framework';export class PingCommand extends Command { constructor(context, options) { // ... } async chatInputRun(interaction) { const msg = await interaction.reply({ content: `Ping?`, ephemeral: true, fetchReply: true }); if (isMessageInstance(msg)) { const diff = msg.createdTimestamp - interaction.createdTimestamp; const ping = Math.round(this.container.client.ws.ping); return interaction.editReply(`Pong 🏓! (Round trip took: ${diff}ms. Heartbeat: ${ping}ms.)`); } return interaction.editReply('Failed to retrieve ping :('); }}
import { isMessageInstance } from '@sapphire/discord.js-utilities';import { Command } from '@sapphire/framework';export class PingCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { // ... } public async chatInputRun(interaction: Command.ChatInputInteraction) { const msg = await interaction.reply({ content: `Ping?`, ephemeral: true, fetchReply: true }); if (isMessageInstance(msg)) { const diff = msg.createdTimestamp - interaction.createdTimestamp; const ping = Math.round(this.container.client.ws.ping); return interaction.editReply(`Pong 🏓! (Round trip took: ${diff}ms. Heartbeat: ${ping}ms.)`); } return interaction.editReply('Failed to retrieve ping :('); }}
Creating a slash command with subcommands
caution
Currently, progress is still being made on updating the official Sapphire Plugin Subcommands. This section will fully work now, and will continue to work after the plugin is updated. However, once the plugin has been updated creating subcommands will be possible with less code.
To create the slash command with subcommand we need to override the registerApplicationCommands
method of Command
class. This method is called when the Client
collects all the slash commands defined in the command directory on
application startup to register them on the discord API. Let's see a quick example of how to make a slash command with
subcommands.
Example
- JavaScript
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');class SubCommand extends Command { constructor(context, options) { // ... } async chatInputRun(interaction) { // ... } registerApplicationCommands(registry) { registry.registerChatInputCommand((builder) => builder .setName('command') .setDescription('Command with sub commands') .addSubcommand((command) => command.setName('first').setDescription('First sub command')) .addSubcommand((command) => command.setName('second').setDescription('Second sub command')) ); }}module.exports = { SubCommand};
import { Command } from '@sapphire/framework';export class SubCommand extends Command { constructor(context, options) { // ... } async chatInputRun(interaction) { // ... } registerApplicationCommands(registry) { registry.registerChatInputCommand((builder) => builder .setName('command') .setDescription('Command with sub commands') .addSubcommand((command) => command.setName('first').setDescription('First sub command')) .addSubcommand((command) => command.setName('second').setDescription('Second sub command')) ); }}
import { Command } from '@sapphire/framework';export class SubCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { // ... } public async chatInputRun(interaction: Command.ChatInputInteraction) { // ... } public override registerApplicationCommands(registry: Command.Registry) { registry.registerChatInputCommand((builder) => builder .setName('command') .setDescription('Command with sub commands') .addSubcommand((command) => command.setName('first').setDescription('First sub command')) .addSubcommand((command) => command.setName('second').setDescription('Second sub command')) ); }}
The above will create a slash command called command
with the description Command with sub commands
. The command
will have two sub commands, first
and second
with description First sub command
and Second sub command
respectively.
To handle the command callback for the sub command we will have to perform checks in the chatInputRun
method. Let's
see a quick example of how to handle the sub command callback.
- JavaScript
- ESM
- TypeScript
const { Command } = require('@sapphire/framework');class SubCommand extends Command { constructor(context, options) { // ... } async chatInputRun(interaction) { const subcommand = interaction.options.getSubcommand(true); if (subcommand === 'first') { return await this.first(interaction); } else if (subcommand === 'second') { return await this.second(interaction); } return interaction.reply('Invalid sub command'); } async first(interaction) { // private class method to handle the first sub command return interaction.reply('First sub command executed'); } async second(interaction) { // private class method to handle the second sub command return interaction.reply('Second sub command executed'); } registerApplicationCommands(registry) { // ... }}module.exports = { SubCommand};
import { Command } from '@sapphire/framework';export class SubCommand extends Command { constructor(context, options) { // ... } async chatInputRun(interaction) { const subcommand = interaction.options.getSubcommand(true); if (subcommand === 'first') { return await this.first(interaction); } else if (subcommand === 'second') { return await this.second(interaction); } return interaction.reply('Invalid sub command'); } async first(interaction) { // private class method to handle the first sub command return interaction.reply('First sub command executed'); } async second(interaction) { // private class method to handle the second sub command return interaction.reply('Second sub command executed'); } registerApplicationCommands(registry) { // ... }}
import { Command } from '@sapphire/framework';export class SubCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { // ... } public async chatInputRun(interaction: Command.ChatInputInteraction) { const subcommand = interaction.options.getSubcommand(true); if (subcommand === 'first') { return await this.first(interaction); } else if (subcommand === 'second') { return await this.second(interaction); } return interaction.reply('Invalid sub command'); } private async first(interaction: Command.ChatInputInteraction) { // private class method to handle the first sub command return interaction.reply('First sub command executed'); } private async second(interaction: Command.ChatInputInteraction) { // private class method to handle the second sub command return interaction.reply('Second sub command executed'); } public override registerApplicationCommands(registry: Command.Registry) { // ... }}