Редактируем сообщение через Телеграм Бот

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

Мы все ближе и ближе подходим к реализации интересного проекта. В моих планах написать цикл статей по построению бота по продаже товаров или услуг, своего рода интернет-магазин в Телеграме. У меня уже даже есть настроенная Яндекс.Касса. Но для этого нам нужно понимание процессов, которые будут происходить в работе такого бота. Мы уже многое умеем, и сегодня пополним свои знания в части редактирования и удаления сообщений.

Для того чтобы произвести какие-либо действия с сообщением нам нужно знать его message_id и chat_id. Эти данные мы можем получить в объекте, который будет нам отправлен в ответ на нашу публикацию сообщения от Bot API,  далее для удобства можем сохранить их в удобном для нас виде, или можем получить их через объект CallbackQuery при событии через кнопку встроенной клавиатуры.

В своем примере я продемонстрирую работу через встроенную клавиатуру. Заодно еще познакомимся с объектом ForceReply

* * *

Создаем тестовое сообщение

В качестве теста, я создал простое, текстовое сообщение с кнопками "Редактировать" и "Удалить".  Приводить весь код скрипта я не буду, он повторяется из предыдущих статей, и в прикрепленном в конце статьи исходном коде он также будет присутствовать. 

<?php
        // готовим кнопки
        $inlineBtn = [
            ['text' => 'Редактировать', 'callback_data' => 'edit_msg'],
            ['text' => 'Удалить', 'callback_data' => 'del_msg'],
        ];
        $btns = $this->setInlineButton($inlineBtn);

        // готовим данные для отправки
        $content = [
            'chat_id' => $chat_id,
            'text' => 'Сообщение для редактирования',
                'reply_markup' => $btns,
            ];
        // отправляем сообщение
        $this->sendMessage($content);
?>

* * *

Редактируем сообщение

Редактирование здесь будет происходить в 2 этапа. Сначала мы предложим пользователю ввести новый текст сообщения, потом произведем действие по замене текста. Хранение данных организовывать не будем, все будем делать на лету. В связи с этим возникает вопрос: как передать message_id на втором шаге?

При нажатии на кнопку "Редактировать" нам приходит объект CallbackQuery, в котором содержится message_id нужного нам сообщения, он находится в ['callback_query']['message']['message_id'].  Сформируем текстовое сообщение-запрос, зашьем в него полученный message_id, и отправим пользователю. Дополнительно к сообщению прикрепим объект ForceReply

Объект ForceReply позволяет выполнить в автоматическом режиме действие, если бы пользователь через контекстное меню вызвал команду "Ответить". То есть мы сразу предлагаем пользователю ответить на наше сообщение, это удобно, ведь если по нашему сценарию нам нужно запросить от пользователя какие-то данные, то в тексте сообщения мы напишем "Укажите вашу фамилию", автоматом ставим его на ответ, и при отправке пользователем Фамилии, и после проверок, что это ответ на наш запрос, получаем ожидаемые данные.

Пользователь отправит нам в ответ новый текст для редактирования, также под ключом reply_to_message будет наш сформированный текст с message_id нужного нам сообщения. Достаем его и передаем в метод editMessageText.

<?php
// если запрос на редактирование
if (preg_match("~^edit_msg~", $data['callback_query']['data'])) {
    //готовим данные
    $content = [
        'chat_id' => $callback_chat_id,
        // зашиваем id сообщения которое надо отредактировать
        'text' => "Ваш новый текст для сообщения - " 
            . $data['callback_query']['message']['message_id'],
        // автоматически подставляем для ответа
        'reply_markup' => json_encode(['force_reply' => true], true),
        ];
        // отправляем сообщение
        $this->sendMessage($content);
}

// ... //
} elseif (array_key_exists('reply_to_message', $data['message'])) {
    // если это ответ на сообщение

    // берем id сообщения которое надо отредактировать
     // зашито в тексте для примера
    preg_match("~([0-9])+$~", $data['message']['reply_to_message']['text'], $matches);

    // готовим данные
    $content = [
    'chat_id' => $chat_id,
    'message_id' => $matches[0],
    'reply_markup' => $btns,
    'text' => $data['message']['text'], // текст который отправили
    ];
    // редактируем сообщение
    $this->requestToTelegram($content, "editMessageText");
}
?>

* * *

Удаляем сообщение

Удалять сообщение как ни странно проще некуда. При нажатии на кнопку также передается объект CallbackQuery из которого берем message_id передаем его вместе с chat_id в метод deleteMessage

<?php
// ... //
} elseif (preg_match("~^del_msg~", $data['callback_query']['data'])) {
    //  если пришел запрос на удаление

    // готовим данные
    $content = [
        'chat_id' => $callback_chat_id,
        'message_id' => $data['callback_query']['message']['message_id'],
    ];
    // отправляем запрос на удаление
    $this->requestToTelegram($content, "deleteMessage");
}
?>

* * *

Подводим итоги

Теперь мы еще на один шаг стали ближе к большому проекту. Исходный код примеров этой статьи вы можете скачать по этой ссылке.

editDelete.php.zip
2.6
3 комментария
Авторизуйтесь через Telegram, чтобы оставить комментарий.
Откройте по ссылке или QR бот @iMakeBot, нажмите кнопку Старт/Start.
Следуйте инструкциям бота.

  • Denis DeN [2 года назад]

    ЗдОрово. Но есть такая проблема. Если бот находится в группе, он рассылает предложение ответить вообще всем участникам, а не только тому, кто нажал на кнопку.

    То есть ForceReply срабатывает для всех.

    Вижу, что есть параметр $selective, но я не понял, как им пользоваться. Ставил true, тогда reply вообще не срабатывает.

  • iMakeBots [2 года назад → Denis DeN]

    Насколько я понимаю, то если параметр selective в значении true, будет предложено ответить только участникам, которые отмечены по @username в контексте сообщения, или же если это сообщение имеет информацию с reply_to_message_id, то будет предложено ответить автору сообщения.

  • Андрей [10 месяцев назад]

    Привет