Переклад цього гайду зʼявиться незабаром. Поки що текст доступний російською — перемкніться на RU або читайте нижче. Відкрити російську версію

Клавіатури

Inline Keyboard

Inline-клавиатура (встроенная клавиатура) — это сетка интерактивных кнопок, которая прикрепляется непосредственно к конкретному сообщению. В отличие от обычных Reply-клавиатур (которые заменяют стандартную клавиатуру пользователя внизу экрана), инлайн-кнопки не засоряют интерфейс ввода текста, перемещаются вместе с сообщением при пересылке и могут динамически изменяться «на лету» без отправки новых сообщений.

Существует два основных сценария использования таких кнопок: мгновенный переход по внешней ссылке (кнопки типа url) и отправка скрытого запроса на ваш сервер (кнопки типа callback_data). Второй вариант превращает бота в полноценное интерактивное приложение с мгновенным откликом.

Анатомия параметра reply_markup

Для отправки клавиатуры используется необязательный параметр reply_markup в методе sendMessage (или других методах отправки медиа). В этот параметр передается JSON-строка, описывающая объект клавиатуры.

Ключевое поле здесь — inline_keyboard. Это двумерный массив (массив массивов). Внешний массив представляет собой строки кнопок (rows), а внутренние массивы — сами кнопки в этой строке (columns). Такая структура позволяет гибко настраивать сетку: например, сделать одну большую кнопку на всю ширину, а под ней — две кнопки в ряд.

Каждая кнопка — это ассоциативный массив, содержащий обязательный текст (text) и один из параметров действия. Самые популярные:

  • callback_data — строка до 64 байт, которая вернется вашему боту при нажатии.
  • url — классическая ссылка для перехода в браузер.
  • web_app — ссылка на Mini App, которое откроется прямо внутри Telegram.

Используем функцию telegramApi(), которую мы сделали в главе Первый запрос: getMe. Здесь только вызываем её — реализацию не копируем.

<?php
// Отправка сообщения с инлайн-клавиатурой
$token = getenv('TELEGRAM_BOT_TOKEN');
if (!$token) {
exit("Ошибка: TELEGRAM_BOT_TOKEN не задан в окружении\n");
}

$chatId = 123456789; // Замените на реальный chat_id пользователя
$leadId = bin2hex(random_bytes(4)); // Генерация уникального ID для примера

// Формируем структуру клавиатуры
$keyboard = [
'inline_keyboard' => [
// Первая строка кнопок (две кнопки в ряд)
[
['text' => '✅ Взять в работу', 'callback_data' => 'take_lead:' . $leadId],
['text' => '❌ Отклонить', 'callback_data' => 'reject_lead:' . $leadId],
],
// Вторая строка кнопок (одна кнопка на всю ширину)
[
['text' => '🌐 Перейти на сайт', 'url' => 'https://example.com/leads/' . $leadId],
]
]
];

$params = [
'chat_id' => $chatId,
'text' => "<b>Новая заявка #{$leadId}</b>\nСтатус: Ожидает обработки",
'parse_mode' => 'HTML',
'reply_markup' => json_encode($keyboard) // Обязательно кодируем в JSON!
];

$response = telegramApi($token, 'sendMessage', $params);

// Выводим результат для отладки в терминале
echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . PHP_EOL;

Пример успешного ответа API

В случае успешного выполнения запроса Telegram Bot API вернет JSON-ответ, содержащий объект Message с заполненным полем reply_markup:

{
"ok": true,
"result": {
"message_id": 1502,
"from": {
"id": 987654321,
"is_bot": true,
"first_name": "My Helper Bot",
"username": "my_helper_bot"
},
"chat": {
"id": 123456789,
"first_name": "Иван",
"type": "private"
},
"date": 1710000000,
"text": "Новая заявка #a1b2c3d4\nСтатус: Ожидает обработки",
"reply_markup": {
"inline_keyboard": [
[
{
"text": "✅ Взять в работу",
"callback_data": "take_lead:a1b2c3d4"
},
{
"text": "❌ Отклонить",
"callback_data": "reject_lead:a1b2c3d4"
}
],
[
{
"text": "🌐 Перейти на сайт",
"url": "https://example.com/leads/a1b2c3d4"
}
]
]
}
}
}

Обратите внимание на поле message_id (в примере — 1502). Его обязательно нужно сохранить в базу данных, если в дальнейшем вы планируете изменять эту клавиатуру или текст сообщения при обработке нажатий.

Жесткое ограничение на callback_data

Самая частая ошибка новичков — попытка упаковать в поле callback_data слишком много информации (например, JSON-строку с параметрами товара). Telegram накладывает строгое ограничение: размер значения callback_data не должен превышать 64 байта.

Если вы попытаетесь отправить кнопку с данными больше 64 байт, API вернет ошибку Bad Request: BUTTON_DATA_INVALID. Чтобы этого избежать, используйте компактные форматы:

  • Сокращайте названия действий до минимума (вместо approve_registration_request пишите appr_reg).
  • Используйте разделители (например, двоеточие :) для разделения действия и ID ресурса: take:452.
  • Храните все тяжелые данные (состояние, полные параметры запроса) в базе данных на вашем сервере, а в кнопку передавайте только первичный ключ (ID записи).

Динамическое изменение клавиатуры

Интерфейс бота выглядит профессионально, когда после нажатия кнопки она меняется на другую или исчезает вовсе. Это предотвращает повторные случайные нажатия (например, когда два менеджера пытаются взять одну и ту же заявку).

Для изменения только сетки кнопок без изменения самого текста сообщения используется метод editMessageReplyMarkup. Если нужно обновить и текст, и кнопки одновременно — используйте метод editMessageText, который мы разбирали в главе Редактирование и удаление.

Используем функцию telegramApi(), которую мы сделали в главе Первый запрос: getMe. Здесь только вызываем её — реализацию не копируем.

<?php
// Удаление клавиатуры или замена её на новую
$token = getenv('TELEGRAM_BOT_TOKEN');
if (!$token) {
exit("Ошибка: TELEGRAM_BOT_TOKEN не задан в окружении\n");
}

$chatId = 123456789;
$messageId = 1502; // ID сообщения, полученный при отправке

// Чтобы полностью удалить клавиатуру, передаем пустой массив inline_keyboard.
// Чтобы изменить кнопки — передаем новую структуру.
$newKeyboard = [
'inline_keyboard' => [
[
['text' => '🔒 Заявка обработана', 'callback_data' => 'done']
]
]
];

$params = [
'chat_id' => $chatId,
'message_id' => $messageId,
'reply_markup' => json_encode($newKeyboard)
];

$response = telegramApi($token, 'editMessageReplyMarkup', $params);

// Проверяем результат выполнения
if (isset($response['ok']) && $response['ok'] === true) {
echo "Клавиатура успешно обновлена!\n";
} else {
echo "Ошибка обновления: " . ($response['description'] ?? 'Неизвестная ошибка') . "\n";
}

Как отлаживать ответы API в терминале

При работе с клавиатурами часто возникают ошибки разметки (неверная вложенность массивов). Чтобы быстро понять, что пошло не так, всегда выводите результат выполнения функции telegramApi(). В CLI-скриптах удобно использовать конструкцию:

echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

Если запрос завершился ошибкой, вы увидите структуру следующего вида:

{
"ok": false,
"error_code": 400,
"description": "Bad Request: message is not modified: specified new reply markup is an exact copy of the current one"
}

Эта конкретная ошибка означает, что вы попытались установить точно такую же клавиатуру, какая уже отображается у пользователя. Telegram Bot API считает это избыточным действием и возвращает ошибку 400.

Другие типы инлайн-кнопок

Помимо callback_data и url, Bot API поддерживает специализированные типы кнопок:

  • Switch inline query (параметры switch_inline_query или switch_inline_query_current_chat) — переключает пользователя в инлайн-режим работы с вашим ботом, автоматически подставляя его юзернейм в поле ввода.
  • Web App (параметр web_app) — открывает полноценное веб-приложение прямо внутри Telegram. Подробнее об этом механизме мы поговорим в главе Mini Apps.

Практическое применение этой схемы подробно разобрано в проекте Заявка с сайта → Telegram.

Дальше: callback_query — обрабатываем нажатия inline-кнопок