Сообщения

Редактирование и удаление

Практическое руководство по редактированию и удалению сообщений в Telegram Bot API на PHP: работа с editMessageText, editMessageReplyMarkup, editMessageCaption и deleteMessage.

В ботах динамический интерфейс строится не на отправке десятков новых сообщений, а на изменении уже существующих. В Telegram Bot API для этого предусмотрена группа методов семейства editMessage* и метод deleteMessage. Это позволяет обновлять статус заказа, анимировать процесс обработки, менять кнопки на лету и сохранять чистый чат пользователя без лишнего спама.

editMessageText: изменение текста сообщения

Если сообщение было отправлено через sendMessage, его текст и клавиатуру можно отредактировать с помощью метода editMessageText. Обязательные параметры: text и один из способов идентификации сообщения: пара chat_id + message_id (для обычных чатов) или inline_message_id (для сообщений из инлайн-режима — см. раздел Inline mode).

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

<?php
$token = getenv('TELEGRAM_BOT_TOKEN');
$chatId = 123456789;

// 1. Отправляем начальное сообщение и сохраняем message_id
$sent = telegramApi($token, 'sendMessage', [
'chat_id' => $chatId,
'text' => 'Заявка #142: <b>создана</b>',
'parse_mode' => 'HTML',
]);

$messageId = $sent['result']['message_id'];
echo "Отправлено сообщение ID: {$messageId}\n";

// 2. Имитируем паузу в 2 секунды и редактируем текст
sleep(2);
$edited = telegramApi($token, 'editMessageText', [
'chat_id' => $chatId,
'message_id' => $messageId,
'text' => 'Заявка #142: <b>в работе</b>',
'parse_mode' => 'HTML',
]);

// Выводим ответ API в консоль для проверки
print_r($edited);

Пример ответа Telegram API на вызов editMessageText:

{
"ok": true,
"result": {
"message_id": 57,
"from": {
"id": 987654321,
"is_bot": true,
"first_name": "MyBot",
"username": "my_sample_bot"
},
"chat": {
"id": 123456789,
"first_name": "Ivan",
"type": "private"
},
"date": 1724501234,
"edit_date": 1724501236,
"text": "Заявка #142: в работе",
"entities": [
{
"offset": 13,
"length": 8,
"type": "bold"
}
]
}
}

Разбор JSON-ответа: Поле ok: true подтверждает успешность выполнения запроса. В ключе result приходят актуальные данные объекта Message. Обратите внимание на появление поля edit_date — это UNIX-timestamp времени последнего редактирования. Поле entities подтверждает, что разметка HTML применилась корректно (символы с 13 по 21 стали bold).

editMessageReplyMarkup: изменение только клавиатуры

Когда текст сообщения менять не требуется, а нужно добавить, обновить или полностью убрать инлайн-кнопки под ним, используйте метод editMessageReplyMarkup. Это экономит трафик и избавляет от повторного форматирования основного текста.

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

<?php
$token = getenv('TELEGRAM_BOT_TOKEN');
$chatId = 123456789;
$messageId = 57;

// Добавляем или обновляем клавиатуру под сообщением
telegramApi($token, 'editMessageReplyMarkup', [
'chat_id' => $chatId,
'message_id' => $messageId,
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '✅ Подтвердить', 'callback_data' => 'confirm_142'],
['text' => '❌ Отклонить', 'callback_data' => 'cancel_142'],
],
],
],
]);

// Чтобы полностью удалить клавиатуру — передаём пустой массив inline_keyboard
telegramApi($token, 'editMessageReplyMarkup', [
'chat_id' => $chatId,
'message_id' => $messageId,
'reply_markup' => [
'inline_keyboard' => [],
],
]);

editMessageCaption: подписи к фото и документам

Для медиа-сообщений (картинки, файлы, видео, отправленные через методы из главы Фото, документы, media group) изменить текст методом editMessageText нельзя — API вернёт ошибку. Для них предназначен метод editMessageCaption.

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

<?php
$token = getenv('TELEGRAM_BOT_TOKEN');
$chatId = 123456789;
$photoMessageId = 58;

$response = telegramApi($token, 'editMessageCaption', [
'chat_id' => $chatId,
'message_id' => $photoMessageId,
'caption' => 'Новая подпись к фото с <b>HTML-разметкой</b>',
'parse_mode' => 'HTML',
]);

var_dump($response['ok']); // bool(true)

deleteMessage: удаление сообщений

Метод deleteMessage окончательно удаляет сообщение из чата. Бот может гарантированно удалять собственные сообщения. Сообщения пользователей бот может удалять только в группах и каналах при наличии прав администратора can_delete_messages.

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

<?php
$token = getenv('TELEGRAM_BOT_TOKEN');
$chatId = 123456789;
$messageId = 57;

$result = telegramApi($token, 'deleteMessage', [
'chat_id' => $chatId,
'message_id' => $messageId,
]);

// При успехе Telegram возвращает boolean true в поле result
var_dump($result['result']); // bool(true)

Ответ API при успешном удалении сообщения выглядит так:

{
"ok": true,
"result": true
}

Частые ошибки и их обработка

При активном изменении сообщений Telegram Bot API может возвращать ошибки с HTTP-кодом 400. Рассмотрим самые распространённые:

  • Bad Request: message is not modified — попытка записать в текст или клавиатуру ровно то же самое содержимое, которое там уже лежит. Ошибка не критична, её нужно игнорировать.
  • Bad Request: message can't be edited — прошло более 48 часов с момента отправки сообщения, либо бот пытается отредактировать чужое сообщение.
  • Bad Request: message to edit not found — указан несуществующий message_id или сообщение уже было удалено пользователем.
  • Bad Request: message can't be deleted — сообщение слишком старое или у бота нет прав на удаление сообщений в данном чате.

Безопасная обёртка safeEditMessageText

Чтобы сценарий бота не ломался при повторных кликах пользователей по инлайн-кнопкам, оборачиваем editMessageText в безопасную функцию с обработкой исключений:

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

<?php
function safeEditMessageText(string $token, int $chatId, int $messageId, string $text): bool {
try {
telegramApi($token, 'editMessageText', [
'chat_id' => $chatId,
'message_id' => $messageId,
'text' => $text,
'parse_mode' => 'HTML',
]);
return true;
} catch (RuntimeException $e) {
$errorMessage = $e->getMessage();

// Если контент не изменился — считаем это успехом
if (str_contains($errorMessage, 'message is not modified')) {
return true;
}

// Если отредактировать нельзя (прошло 48ч) — удаляем старое и отправляем новое
if (str_contains($errorMessage, "message can't be edited")) {
try {
telegramApi($token, 'deleteMessage', [
'chat_id' => $chatId,
'message_id' => $messageId,
]);
} catch (Exception $ignored) {}

telegramApi($token, 'sendMessage', [
'chat_id' => $chatId,
'text' => $text,
'parse_mode' => 'HTML',
]);
return true;
}

throw $e;
}
}

Практический паттерн: Интерактивный статус заказа

Ниже приведён законченный PHP-скрипт, который демонстрирует паттерн «одно живое сообщение». Бот публикует заказ, меняет его статус по шагам и аккуратно удаляет кнопки в конце процедуры.

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

<?php
$token = getenv('TELEGRAM_BOT_TOKEN');
$managerChatId = 123456789;
$orderId = 5081;

// Шаг 1: Создаём сообщение о новом заказе с кнопкой
$response = telegramApi($token, 'sendMessage', [
'chat_id' => $managerChatId,
'text' => "📦 <b>Заказ #{$orderId}</b>\nСтатус: <i>Новый</i>",
'parse_mode' => 'HTML',
'reply_markup' => [
'inline_keyboard' => [
[['text' => '🚀 Взять в работу', 'callback_data' => "process_{$orderId}"]],
],
],
]);

$messageId = $response['result']['message_id'];
echo "Сообщение создано: ID {$messageId}\n";

// Симулируем паузу на реакцию менеджера
sleep(3);

// Шаг 2: Менеджер взял заказ — обновляем текст и меняем кнопку
telegramApi($token, 'editMessageText', [
'chat_id' => $managerChatId,
'message_id' => $messageId,
'text' => "📦 <b>Заказ #{$orderId}</b>\nСтатус: ⚙️ <i>В сборке</i>\nОтветственный: Алексей",
'parse_mode' => 'HTML',
'reply_markup' => [
'inline_keyboard' => [
[['text' => '✅ Завершить заказ', 'callback_data' => "finish_{$orderId}"]],
],
],
]);
echo "Статус обновлен: В сборке\n";

// Симулируем процесс сборки
sleep(3);

// Шаг 3: Заказ выполнен — обновляем текст и удаляем клавиатуру
telegramApi($token, 'editMessageText', [
'chat_id' => $managerChatId,
'message_id' => $messageId,
'text' => "📦 <b>Заказ #{$orderId}</b>\nСтатус: ✅ <b>Выполнен</b>\nВремя: " . date('H:i:s'),
'parse_mode' => 'HTML',
]);

telegramApi($token, 'editMessageReplyMarkup', [
'chat_id' => $managerChatId,
'message_id' => $messageId,
'reply_markup' => [
'inline_keyboard' => [],
],
]);
echo "Заказ завершен, кнопки удалены.\n";

Дальше: переходим к детальному разбору создания кнопок в главе Inline Keyboard.