[Tutorial] How to make a proper punishment command - without a mistake you probably have done (Discord.JS V12)

Hey! I haven’t been here for a while, but here I am with a tutorial for the lusty Discord Bot Developers!

I will have to admit, my last tutorial really wasn’t that great, as it would have quite a few errors. But now that I’ve learnt a lot more, I am here once again to create another tutorial!

But now, what do I mean with “How to make a proper punishment command”? Well, it is actually not only for punishment commands, but in fact for all commands that uses mentions!

But now, let’s get into this!

As an example, I will be using a ban command. You should already have a command handler, and if not, I strongly suggest you make one. If you don’t know how, here is a official Discord.JS guide for it.

I will not be using data storing in this tutorial, but if you’d like that, feel free to let me know and I’ll make another tutorial entirely based on data storing.

So, first off, let’s start up by setting up the command to the command handler. You may have it different from me, based of your command handler, but I will be using mine.

const Discord = require('discord.js');

module.exports = {
    name: "ban",
    description: "Ban a member.",
    aliases: ["b"],
    usage: "<mention or id> [reason]",
    guildOnly: true,


    code(client, message, args) {

    }
}

Ok so, now that we have the command file set up, it is time to start coding the command!
First off, make sure the member has permissions, to avoid exploits, and make sure the bot has permissions, to avoid errors.

const Discord = require('discord.js');

module.exports = {
    name: "ban",
    description: "Ban a member.",
    aliases: ["b"],
    usage: "<mention or id> [reason]",
    guildOnly: true,


    code(client, message, args) {
        if (!message.member.hasPermission(`BAN_MEMBERS`)) return message.reply(`I am sorry, but you can not use this command.`); // Denies people, without the BAN_MEMBERS permission, to use the ban command.
        if (!message.guild.me.hasPermission(`BAN_MEMBERS`)) return message.reply(`I am sorry, but I can not ban members.`); // guild.me is the client user as a guild member, which makes us easily able to check if we have permission to ban or not. If not, it will inform the user and not return an error to the console.
    }
}

Alright, so now that we’ve done these checks, we can now move on to getting the member to ban. And now, this is where most people mess up.

const Discord = require('discord.js');

module.exports = {
    name: "ban",
    description: "Ban a member.",
    aliases: ["b"],
    usage: "<mention or id> [reason]",
    guildOnly: true,


    code(client, message, args) {
        if (!message.member.hasPermission(`BAN_MEMBERS`)) return message.reply(`I am sorry, but you can not use this command.`); // Denies people, without the BAN_MEMBERS permission, to use the ban command.
        if (!message.guild.me.hasPermission(`BAN_MEMBERS`)) return message.reply(`I am sorry, but I can not ban members.`); // guild.me is the client user as a guild member, which makes us easily able to check if we have permission to ban or not. If not, it will inform the user and not return an error to the console.

        function getUser(mention) {
            if (!mention) return; // Checking if something was specified

            if (mention.startsWith(`<@`) && mention.endsWith(`>`)) { // Checking if it is a mention
                mention = mention.slice(2, -1); // Since it is a mention, we slice away the mention part.

                if (mention.startsWith(`!`)) { // Sometimes, mentions doesn't have the !, but in the cases when they do, we check for it here
                    mention = mention.slice(1); // And here we remove the !, leaving us with only the User ID
                }

                return client.users.cache.get(mention); // Fetching the User ID to a User Object by getting it from the client's cache, and then returning it to the rest of the code.
            } else return client.users.cache.get(mention); // It was not a mention, so we just use the User ID and return the User Object.
        }
        let user = getUser(args[0]); // Here we are running the function and grabbing our User Object into the user variable.
        if (!user) return message.channel.send(`Member not found. Please specify a valid User ID or mention the person you would like to ban.`); // Checking if the user exist in the client's cache.
        let member = message.guild.member(user);
        if (!member) return message.channel.send(`User not found. Please specify a valid User ID or mention the person you would like to ban.`); // Checking if the user is a member of the server.
    }
}

Now, you may be wondering why I am using a function to fetch the user and not message.mentions.members.first();. Well, a brief explanation, Discord sends the mentions from lowest id to highest id, so for example !ban <@!2> They bully <@!1> would ban <@!1> since that is the id Discord sends first, so that is taken as the first mention. So then, we are only checking for a mention on the first argument, using that function. If you’d like a more in depth explanation on it, go here.

Now to get the reason and finish off the command by banning the member.

const Discord = require('discord.js');

module.exports = {
    name: "ban",
    description: "Ban a member.",
    aliases: ["b"],
    usage: "<mention or id> [reason]",
    guildOnly: true,


    code(client, message, args) {
        if (!message.member.hasPermission(`BAN_MEMBERS`)) return message.reply(`I am sorry, but you can not use this command.`); // Denies people, without the BAN_MEMBERS permission, to use the ban command.
        if (!message.guild.me.hasPermission(`BAN_MEMBERS`)) return message.reply(`I am sorry, but I can not ban members.`); // guild.me is the client user as a guild member, which makes us easily able to check if we have permission to ban or not. If not, it will inform the user and not return an error to the console.

        function getUser(mention) {
            if (!mention) return; // Checking if something was specified

            if (mention.startsWith(`<@`) && mention.endsWith(`>`)) { // Checking if it is a mention
                mention = mention.slice(2, -1); // Since it is a mention, we slice away the mention part.

                if (mention.startsWith(`!`)) { // Sometimes, mentions doesn't have the !, but in the cases when they do, we check for it here
                    mention = mention.slice(1); // And here we remove the !, leaving us with only the User ID
                }

                return client.users.cache.get(mention); // Fetching the User ID to a User Object by getting it from the client's cache, and then returning it to the rest of the code.
            } else return client.users.cache.get(mention); // It was not a mention, so we just use the User ID and return the User Object.
        }
        let user = getUser(args[0]); // Here we are running the function and grabbing our User Object into the user variable.
        if (!user) return message.channel.send(`Member not found. Please specify a valid User ID or mention the person you would like to ban.`); // Checking if the user exist in the client's cache.
        let member = message.guild.member(user);
        if (!member) return message.channel.send(`User not found. Please specify a valid User ID or mention the person you would like to ban.`); // Checking if the user is a member of the server.

        let reason = args.slice(1).join(' ');
        if (!reason) reason = `No reason specified.`;

        member.ban(`Banned by ${message.author.tag} (${message.author.id}) with reason ${reason}`).then(() => message.channel.send(`${user.tag} was successfully banned by ${message.author.tag} with reason ${reason}`)).catch(err => {message.channel.send(err); console.log(err);})
    }
}

And now, there it is! A proper ban command without the common mistake of using message.mentions

I hope this helped you out, and I will see you all next time! Have an amazing day!

10 Likes

Good work, but there is still a few things that could’ve changed.

Functions should be defined in the root scope, not inside of other functions.

Use proper async/await or handle promises if something goes wrong!

Agreed. But then again. I do all my commands on a “global basis” meaning they are bot bans, not server bans, to each their own