Komplett Discord Bot Guide
Del 4: Slash Commands System
📋 Innholdsfortegnelse
- Hva lærer vi i denne delen?
- Steg 1: Forstå Slash Commands
- Steg 2: Lage Vår Første Slash Command
- ⚙️ Steg 3: Command Handler System
- 📡 Steg 4: Command Registration
- 🧪 Steg 5: Test Slash Commands
- ⚡ Steg 6: Guild Commands (Raskere Testing)
- 🎨 Steg 7: Avanserte Command Features
- 📊 Steg 8: Command Kategorier og Hjelp
- ✅ Testing Alt Sammen
- 🛠️ Feilsøking
- 🎉 Gratulerer!
- 🚀 Neste Steg
Del 4: Slash Commands System
Nå skal vi lære å lage moderne Slash Commands! Dette er den nye og profesjonelle måten å lage Discord bot kommandoer på. Slash commands ser mye bedre ut og er enklere for brukere å bruke.
Hva lærer vi i denne delen?
- Forstå Slash Commands - Hvorfor de er bedre enn vanlige commands
- Lage vår første slash command -
/pingkommando - Command registration - Få Discord til å kjenne til commandsene
- Command handler system - Organisere commands i egne filer
- Parameters og options - Lage commands som tar input
- Feilhåndtering - Håndtere når ting går galt
Steg 1: Forstå Slash Commands
Hva er forskjellen?
Gamle commands (som vi laget i del 3):
Bruker skriver: !ping
Bot svarer: Pong!
Nye slash commands:
Bruker skriver: /ping
Discord viser: Autocompletion, hjelpetekst, parametere
Bot svarer: Pong! (med fancy embed)
Fordeler med Slash Commands:
- Autocompletion - Discord foreslår commands mens du skriver
- Hjelpetekst - Brukere ser hva commandet gjør
- Parametere - Tydelige input felter
- Permissions - Lettere å kontrollere hvem som kan bruke hva
- Profesjonelt - Ser ut som offisielle Discord funksjoner
Steg 2: Lage Vår Første Slash Command
2.1: Lag commands mappe struktur
I VS Code, lag disse filene i commands/ mappen:
commands/
├── utility/
│ └── ping.js
└── general/
└── userinfo.js
2.2: Lage ping.js
Åpne commands/utility/ping.js og skriv:
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('ping')
.setDescription('Sjekk bot responstid og status'),
async execute(interaction) {
// Kalkuler responstid
const sent = await interaction.reply({
content: 'Regner ut ping...',
fetchReply: true
});
const ping = sent.createdTimestamp - interaction.createdTimestamp;
const apiPing = Math.round(interaction.client.ws.ping);
// Oppdater melding med riktig info
await interaction.editReply({
content: `🏓 **Pong!**
⏱️ **Responstid:** ${ping}ms
🌐 **API Ping:** ${apiPing}ms
📡 **Status:** ${ping < 100 ? '🟢 Utmerket' : ping < 200 ? '🟡 Bra' : '🔴 Treg'}`
});
},
};
2.3: Lage userinfo.js
Åpne commands/general/userinfo.js:
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('userinfo')
.setDescription('Vis informasjon om en bruker')
.addUserOption(option =>
option
.setName('bruker')
.setDescription('Brukeren du vil se info om')
.setRequired(false)
),
async execute(interaction) {
// Hvis ingen bruker er spesifisert, bruk den som kjører kommandoen
const target = interaction.options.getUser('bruker') || interaction.user;
const member = interaction.guild.members.cache.get(target.id);
// Lag fancy embed
const embed = new EmbedBuilder()
.setColor(0x3498db)
.setTitle(`👤 Bruker Informasjon`)
.setThumbnail(target.displayAvatarURL({ dynamic: true, size: 256 }))
.addFields(
{ name: '📛 Navn', value: target.username, inline: true },
{ name: '🏷️ Tag', value: `#${target.discriminator}`, inline: true },
{ name: '🆔 ID', value: target.id, inline: true },
{ name: '📅 Konto Opprettet', value: `<t:${Math.floor(target.createdTimestamp / 1000)}:F>`, inline: false },
{ name: '🚪 Ble Med Server', value: `<t:${Math.floor(member.joinedTimestamp / 1000)}:F>`, inline: false }
)
.setFooter({
text: `Forespurt av ${interaction.user.username}`,
iconURL: interaction.user.displayAvatarURL()
})
.setTimestamp();
// Legg til roller hvis brukeren har noen
if (member.roles.cache.size > 1) {
const roles = member.roles.cache
.filter(role => role.id !== interaction.guild.id)
.map(role => role.toString())
.slice(0, 10) // Max 10 roller
.join(', ');
embed.addFields({
name: '🎭 Roller',
value: roles || 'Ingen roller',
inline: false
});
}
await interaction.reply({ embeds: [embed] });
},
};
⚙️ Steg 3: Command Handler System
Nå må vi lage et system som laster inn alle commands automatisk.
3.1: Oppdater index.js
Legg til dette øverst i index.js (under andre imports):
const fs = require('fs');
const path = require('path');
Legg til dette etter client.commands = new Collection();:
// Last inn alle commands
const commandsPath = path.join(__dirname, 'commands');
const commandFolders = fs.readdirSync(commandsPath);
for (const folder of commandFolders) {
const folderPath = path.join(commandsPath, folder);
const commandFiles = fs.readdirSync(folderPath).filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const filePath = path.join(folderPath, file);
const command = require(filePath);
if ('data' in command && 'execute' in command) {
client.commands.set(command.data.name, command);
console.log(`✅ Lastet command: ${command.data.name}`);
} else {
console.log(`⚠️ Command ${file} mangler 'data' eller 'execute' egenskaper.`);
}
}
}
3.2: Håndter Slash Command Interactions
Legg til dette event handlerne i index.js:
// Håndter slash command interactions
client.on('interactionCreate', async interaction => {
if (!interaction.isChatInputCommand()) return;
const command = client.commands.get(interaction.commandName);
if (!command) {
console.error(`❌ Ingen command kalt ${interaction.commandName} funnet.`);
return;
}
try {
await command.execute(interaction);
console.log(`✅ ${interaction.user.tag} brukte /${interaction.commandName}`);
} catch (error) {
console.error('❌ Feil ved utføring av command:', error);
const errorMessage = 'Det oppstod en feil ved utføring av denne kommandoen!';
if (interaction.replied || interaction.deferred) {
await interaction.followUp({ content: errorMessage, ephemeral: true });
} else {
await interaction.reply({ content: errorMessage, ephemeral: true });
}
}
});
📡 Steg 4: Command Registration
Discord må vite hvilke slash commands som finnes. Vi lager et eget script for dette.
4.1: Lag deploy-commands.js
Lag en ny fil deploy-commands.js i hovedmappen:
require('dotenv').config();
const { REST, Routes } = require('discord.js');
const fs = require('fs');
const path = require('path');
// Samle alle commands
const commands = [];
const commandsPath = path.join(__dirname, 'commands');
const commandFolders = fs.readdirSync(commandsPath);
for (const folder of commandFolders) {
const folderPath = path.join(commandsPath, folder);
const commandFiles = fs.readdirSync(folderPath).filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const filePath = path.join(folderPath, file);
const command = require(filePath);
if ('data' in command && 'execute' in command) {
commands.push(command.data.toJSON());
console.log(`✅ Lagt til command: ${command.data.name}`);
}
}
}
// Deploy commands til Discord
const rest = new REST().setToken(process.env.BOT_TOKEN);
(async () => {
try {
console.log(`🚀 Starter registrering av ${commands.length} slash commands...`);
// Registrer commands globalt (tar 1 time å oppdatere)
// For raskere testing, bruk guild-spesifikke commands
const data = await rest.put(
Routes.applicationCommands(process.env.CLIENT_ID),
{ body: commands }
);
console.log(`✅ Registrert ${data.length} slash commands globalt!`);
console.log('⏰ NB: Globale commands kan ta opptil 1 time å vises i Discord.');
} catch (error) {
console.error('❌ Feil ved registrering av commands:', error);
}
})();
4.2: Kjør Command Registration
I terminalen:
node deploy-commands.js
Du skal se:
✅ Lagt til command: ping
✅ Lagt til command: userinfo
🚀 Starter registrering av 2 slash commands...
✅ Registrert 2 slash commands globalt!
🧪 Steg 5: Test Slash Commands
5.1: Start Boten
node index.js
5.2: Test i Discord
I Discord serveren din:
- Type
/- Du skal se dine commands i listen - Prøv
/ping- Skal vise responstid - Prøv
/userinfo- Skal vise din brukerinfo - Prøv
/userinfo @noen- Skal vise info om den brukeren
⚡ Steg 6: Guild Commands (Raskere Testing)
For raskere testing, kan du registrere commands bare for din server:
6.1: Lag deploy-guild-commands.js
require('dotenv').config();
const { REST, Routes } = require('discord.js');
const fs = require('fs');
const path = require('path');
// SETT INN DIN SERVER ID HER
const GUILD_ID = 'DIN_SERVER_ID_HER';
// ... samme kode som deploy-commands.js, men bytt ut:
const data = await rest.put(
Routes.applicationGuildCommands(process.env.CLIENT_ID, GUILD_ID),
{ body: commands }
);
Hvor finner du server ID?
- I Discord, høyreklikk på server navnet
- Klikk "Copy Server ID"
- Lim inn som GUILD_ID
Kjør:
node deploy-guild-commands.js
Guild commands oppdateres umiddelbart! 🚀
🎨 Steg 7: Avanserte Command Features
7.1: Command med Flere Options
Lag commands/utility/echo.js:
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('echo')
.setDescription('Få boten til å gjenta det du sier')
.addStringOption(option =>
option.setName('melding')
.setDescription('Meldingen du vil at boten skal gjenta')
.setRequired(true)
.setMaxLength(1000)
)
.addBooleanOption(option =>
option.setName('hemmelig')
.setDescription('Skal meldingen være hemmelig? (bare du ser den)')
.setRequired(false)
),
async execute(interaction) {
const message = interaction.options.getString('melding');
const isSecret = interaction.options.getBoolean('hemmelig') || false;
await interaction.reply({
content: `🔊 **Echo:** ${message}`,
ephemeral: isSecret
});
},
};
7.2: Command med Choices
Lag commands/general/status.js:
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('status')
.setDescription('Endre bot status')
.addStringOption(option =>
option.setName('aktivitet')
.setDescription('Hva skal boten "gjøre"?')
.setRequired(true)
.addChoices(
{ name: '🎮 Spille et spill', value: 'PLAYING' },
{ name: '🎵 Høre på musikk', value: 'LISTENING' },
{ name: '📺 Se på noe', value: 'WATCHING' },
{ name: '🏃 Konkurrere', value: 'COMPETING' }
)
)
.addStringOption(option =>
option.setName('tekst')
.setDescription('Hva skal det stå?')
.setRequired(true)
.setMaxLength(50)
),
async execute(interaction) {
const activityType = interaction.options.getString('aktivitet');
const activityText = interaction.options.getString('tekst');
// Bare admin/eier kan endre status
if (!interaction.member.permissions.has('Administrator')) {
return interaction.reply({
content: '❌ Du må være administrator for å bruke denne kommandoen!',
ephemeral: true
});
}
// Endre bot aktivitet
interaction.client.user.setPresence({
activities: [{
name: activityText,
type: activityType
}],
status: 'online'
});
await interaction.reply({
content: `✅ Bot status endret til: **${activityType.toLowerCase()} ${activityText}**`
});
},
};
📊 Steg 8: Command Kategorier og Hjelp
8.1: Lag help command
Lag commands/general/help.js:
const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('help')
.setDescription('Vis alle tilgjengelige commands'),
async execute(interaction) {
const { commands } = interaction.client;
// Grupper commands etter kategori
const categories = {};
commands.forEach(command => {
// Finn kategori fra fil path
const category = command.data.name.includes('ping') || command.data.name.includes('echo')
? 'Verktøy' : 'Generelt';
if (!categories[category]) categories[category] = [];
categories[category].push(command);
});
const embed = new EmbedBuilder()
.setColor(0x3498db)
.setTitle('📋 Bot Commands')
.setDescription('Her er alle tilgjengelige commands:')
.setThumbnail(interaction.client.user.displayAvatarURL())
.setTimestamp();
// Legg til hver kategori
for (const [category, cmds] of Object.entries(categories)) {
const commandList = cmds.map(cmd =>
`\`/${cmd.data.name}\` - ${cmd.data.description}`
).join('\n');
embed.addFields({
name: `📂 ${category}`,
value: commandList,
inline: false
});
}
embed.setFooter({
text: `Totalt ${commands.size} commands tilgjengelig`,
iconURL: interaction.user.displayAvatarURL()
});
await interaction.reply({ embeds: [embed] });
},
};
✅ Testing Alt Sammen
8.1: Registrer Nye Commands
node deploy-commands.js
8.2: Start Bot
node index.js
8.3: Test Alle Commands
I Discord:
/ping- Sjekk responstid/userinfo- Din info/userinfo @noen- Andres info/echo melding:Hei verden!- Echo command/echo melding:Hemmelig hemmelig:True- Hemmelig echo/help- Se alle commands/status aktivitet:🎮 Spille et spill tekst:Minecraft- Endre bot status (krever admin)
🛠️ Feilsøking
Commands vises ikke i Discord
- Vent 1 time for globale commands
- Bruk guild commands for raskere testing
- Sjekk at CLIENT_ID er riktig
"Interaction failed" i Discord
- Sjekk terminalen for feilmeldinger
- Sjekk at alle commands har
dataogexecute - Sjekk at bot har riktige permissions
Bot svarer ikke på commands
- Sjekk at
interactionCreateevent er lagt til - Sjekk at bot har
applications.commandsscope
🎉 Gratulerer!
Du har nå laget et komplett slash command system! Dette er grunnlaget for alle moderne Discord bots.
Hva har du lært:
- ✅ Lage slash commands med options
- ✅ Command registration system
- ✅ Professional command struktur
- ✅ Embeds og fancy meldinger
- ✅ Permissions og sikkerhet
- ✅ Feilhåndtering
🚀 Neste Steg
I del 5 skal vi lære om Event System! Vi lærer:
- Håndtere når folk kommer inn/forlater serveren
- Lage velkommen meldinger med embeds
- Logging system for all server aktivitet
- Role assignment ved server join
- Message filtering og automod
Klar for å lage en bot som reagerer på alt som skjer?