aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord Botları

Discord Bot Buton ve Select Menü Kullanımı

Bir discord bot buton eklemek, mesajlarını metin yığınından gerçek bir arayüze dönüştürür: kullanıcı tıklar, bot anında tepki verir. discord.js ile butonlar, açılır (string select) menüler ve onları taşıyan ActionRow bileşenleri sayesinde rol seçimi, sayfalama, onay diyalogları veya destek talebi panelleri gibi etkileşimli akışlar kurabilirsin. Bu yazıda bileşenleri sıfırdan oluşturmayı, gönderdikten sonra tıklamaları doğru biçimde dinlemeyi ve sık yapılan hataları nasıl önleyeceğini adım adım göreceksin.

Bileşen modeli: ActionRow, button ve select

Discord'da etkileşimli öğeler doğrudan mesaja değil, satırlara (rows) yerleştirilir. Bir mesajda en fazla 5 ActionRow bulunabilir. Her satır ya beş adede kadar butonu ya da tek bir select menüyü taşır; ikisini aynı satırda karıştıramazsın. discord.js v14'te bu yapıları builder sınıflarıyla kurarsın:

  • ButtonBuilder — tıklanabilir buton; stili, etiketi ve customId'si vardır.
  • StringSelectMenuBuilder — sabit seçenekli açılır menü.
  • ActionRowBuilder — bileşenleri gruplayan kapsayıcı.

Buton stilleri ButtonStyle enum'ı ile gelir: Primary (mavi), Secondary (gri), Success (yeşil), Danger (kırmızı) ve Link. Link butonları bir URL'ye gider ve customId almaz; diğerleri etkileşim üretir.

Discord bot buton oluşturma

Aşağıdaki örnek bir slash komutuna iki buton ekler. customId alanı senin için kritik: tıklama olayını ayırt etmeni sağlayan benzersiz kimliktir ve 100 karaktere kadar olabilir.

const {
  ButtonBuilder,
  ButtonStyle,
  ActionRowBuilder,
} = require('discord.js');

const confirm = new ButtonBuilder()
  .setCustomId('order_confirm')
  .setLabel('Onayla')
  .setStyle(ButtonStyle.Success);

const cancel = new ButtonBuilder()
  .setCustomId('order_cancel')
  .setLabel('İptal')
  .setStyle(ButtonStyle.Danger);

const row = new ActionRowBuilder().addComponents(confirm, cancel);

await interaction.reply({
  content: 'Siparişi onaylıyor musun?',
  components: [row],
});

Mesaj artık iki butonla görünür. Ancak butonlar henüz "ölü"dür: tıklandığında bir şey olması için ayrı bir dinleyici kurman gerekir.

String select menü ekleme

Açılır menü, kullanıcıya birden çok seçenek sunmak istediğinde butonlardan daha derli topludur. Her seçeneğin görünen bir etiketi ve geri dönen bir value'su olur. İsteğe bağlı olarak setMinValues ve setMaxValues ile çoklu seçim de açabilirsin.

const { StringSelectMenuBuilder } = require('discord.js');

const menu = new StringSelectMenuBuilder()
  .setCustomId('role_select')
  .setPlaceholder('Bir rol seç')
  .addOptions(
    { label: 'Geliştirici', value: 'dev', emoji: '💻' },
    { label: 'Tasarımcı', value: 'design', emoji: '🎨' },
    { label: 'Topluluk', value: 'community', emoji: '🤝' },
  );

const menuRow = new ActionRowBuilder().addComponents(menu);
await interaction.reply({ components: [menuRow] });

Bir select menü tek başına bir satırı doldurur; aynı satıra buton koyamazsın. Birden fazla menü veya buton grubu istiyorsan ayrı ActionRowBuilder nesneleri oluştur ve hepsini components dizisine ekle.

Etkileşimleri dinlemek: interactionCreate ve collector

Tıklamaları yakalamanın iki yolu vardır. Kalıcı, her zaman çalışan butonlar için botun ana interactionCreate olayını kullan ve customId'ye göre dallan:

client.on('interactionCreate', async (interaction) => {
  if (interaction.isButton()) {
    if (interaction.customId === 'order_confirm') {
      await interaction.reply({ content: 'Sipariş onaylandı ✅', ephemeral: true });
    }
  }

  if (interaction.isStringSelectMenu() && interaction.customId === 'role_select') {
    const choice = interaction.values[0];
    await interaction.reply({ content: `Seçtiğin: ${choice}`, ephemeral: true });
  }
});

Belirli bir mesaja bağlı, geçici akışlar (örneğin sayfalama veya tek seferlik onay) için createMessageComponentCollector daha pratiktir. Collector belirli bir süre sonra kapanır ve sadece o mesajın bileşenlerini dinler:

const reply = await interaction.fetchReply();
const collector = reply.createMessageComponentCollector({
  time: 60_000,
});

collector.on('collect', async (i) => {
  if (i.user.id !== interaction.user.id) {
    return i.reply({ content: 'Bu menü senin için değil.', ephemeral: true });
  }
  await i.update({ content: `Seçim: ${i.customId}`, components: [] });
});

collector.on('end', () => {
  reply.edit({ components: [] }).catch(() => {});
});

Her etkileşime mutlaka yanıt ver

Discord, bir etkileşime 3 saniye içinde yanıt bekler; aksi halde kullanıcı "Bu etkileşim başarısız oldu" hatası görür. Hızlı yanıt veremiyorsan (veritabanı sorgusu, dış API çağrısı vb.) önce deferUpdate() veya deferReply() çağırıp sonra editReply() ile devam et. Yanıt yöntemlerini şöyle ayır:

  • reply() — yeni bir yanıt gönderir.
  • update() — butona tıklanan orijinal mesajı düzenler (menüleri kapatmak için ideal).
  • deferUpdate() / deferReply() — "düşünüyorum" durumu; uzun işlemlerde süre kazandırır.

ephemeral: true seçeneği yanıtı yalnızca tıklayan kişiye gösterir; rol panelleri ve hata mesajları için kanalı temiz tutar.

Sık Sorulan Sorular

customId neden bu kadar önemli?

Çünkü hangi butona veya menüye tıklandığını yalnızca customId üzerinden anlarsın. Benzersiz ve okunabilir tut; gerekiyorsa ticket_close_12345 gibi araya veri (kullanıcı/mesaj id'si) gömüp tıklama anında ayrıştırabilirsin.

Bir mesajda kaç buton olabilir?

Mesaj başına en fazla 5 ActionRow, her buton satırında en fazla 5 buton vardır; yani toplam 25 butona kadar çıkabilirsin. Bir select menü ise tek başına bir satırı doldurur.

Bot yeniden başlayınca eski butonlar çalışmaz mı?

Collector'lar bota bağlı olduğu için yeniden başlatmada kaybolur. Kalıcı butonlar istiyorsan collector yerine global interactionCreate dinleyicisi ve customId tabanlı yönlendirme kullan; böylece bot her açıldığında tıklamalar yine işlenir.

Etkileşimli bir Discord botu mu lazım? Rol panelleri, destek talebi sistemleri veya özel select menü akışları için temiz ve sürdürülebilir bir kurulum hazırlayabilirim. Benimle iletişime geç ve projeni konuşalım.

Bu kategorideki tüm yazılar →

Devamı için