Перейти к основному контенту

Адаптация Telegram-плагина под VK

Название плагина
Vk Код плагина VKCommon.Integrations.Vk Разработчик Официальные плагины от Metabot АвторАвторы

Илья Зыщик

Metabot Дата создания 3009 ИюляОктября 2026 Последняя дата обновления 3109 ИюляОктября 2026

Описание

Плагин Vk позволяет форматироватьиспользовать текстодин и кнопкитот отправляемыеже скрипт бота в ВК.Telegram, Max и VK. Он не вводит новый класс: плагин «патчит» методы класса TelegramMessage из плагина Common.Integrations.Telegram.

    Если лид пришёл из Telegram — вызывается исходный метод Telegram (или патч Max, если он подключён раньше). Если лид пришёл из Max — срабатывает Max-патч. Если лид пришёл из VK — те же самые методы (send, edit, addReplyToText, removeInlineKeyboard, removeReplyKeyboard, getMessagePayload, debug) отправляют запросы в VK API.

    Плагин поддерживает отправку текстовых сообщений, создание inline-клавиатур (кнопки text и open_link), обработку нажатий и текстового ввода, а также отправку медиагрупп (по одному вложению). PHP-драйвер VK не меняется: часть поведения Telegram/Max в VK осознанно деградирует (см. таблицу совместимости).

    Документация VK API: https://dev.vk.com/method/messages.send

    Подключение

    Сначала подключается Telegram-плагин, затем при необходимости Max, затем — Vk. Порядок важен: Vk патчит уже загруженный класс. Повторное подключение безопасно (патч ставится один раз).

    snippet(let TelegramMessage = require('Business.Common.Integrations.VK'Telegram')
    varrequire('Common.Integrations.Max') // опционально
    require('Common.Integrations.Vk')
    
    let msg = new VkMessage(TelegramMessage()

    Больше ничего в скрипте менять не нужно: проверять канал (if (isVk)) не требуется.

    ИспользованиеОсновные параметры

    Текст
    msg.text = 'Привет'"Ваше сообщение" // Текст сообщения
    msg.send()parse_mode = "HTML" // В VK разметка снимается до plain text
    msg.keyboard = "Да[yes]==Нет[no]" // Создание клавиатуры
    msg.entities = [] // В VK игнорируются (текст очищается так же, как при parse_mode)
    Кнопки
    Параметр Telegram Max VK text text text message (plain) parse_mode parse_mode format (HTML → html, Markdown/MarkdownV2 → markdown) strip → plain keyboard inline-клавиатура вложение inline_keyboard VK keyboard JSON (inline: true) entities entities преобразуются в HTML strip protect_content поддерживается игнорируется игнорируется

    Форматы клавиатуры

    DSL:Формат строки клавиатуры полностью совпадает с Telegram-плагином.

    • Вертикальное разделение — используйте == - новый ряд;
    msg.keyboard = "Кнопка1[btn1]==Кнопка2[btn2]" // Кнопки будут расположены вертикально
      Горизонтальное разделение — используйте ||;
      msg.keyboard = "Кнопка1[btn1]||Кнопка2[btn2]" // Кнопки будут расположены горизонтально
      -
        Комбинированное разделение;
        msg.keyboard = "Кнопка1[btn1]||Кнопка2[btn2]==Кнопка3[btn3]||Кнопка4[btn4]"

        Значение в квадратных скобках для обычной кнопки отправляется в одномVK рядукак action.type=text с payload в виде JSON-строки "btn_static_<значение>" (VK требует валидный JSON, иначе ошибка API 911). В getMessagePayload().callback_data кавычки и префикс снимаются — так же, как в Telegram/Max.

        Специальные типы кнопок

          Запрос контакта (request_contact) в VK не поддерживается: кнопка пропускается, пишется отладочное сообщение:
          msg.keyboard = "Отправить контакт[telegram_contact]"
            Текст[команда]Запрос -локации (request_geo_location) в VK не поддерживается: кнопка пропускается, пишется отладочное сообщение:
            msg.keyboard = "Отправить локацию[telegram_location]"
              Ссылки (open_link):
              Сайт[msg.keyboard = "Посетить сайт[https://example.com]"
                Web App. Запись {https://...]} в VK не поддерживается: кнопка пропускается, пишется отладочное сообщение:
                msg.keyboard = "Открыть приложение{https://webapp-url.com}"
                -
                ссылкаСсылка на пользователя tg://user?id=... в VK не поддерживается: кнопка пропускается, пишется отладочное сообщение. Reply-клавиатура (msg.reply_markup = 'keyboard') в VK эмулируется теми же inline-кнопками; нажатие с payload при _reply_markup == 'keyboard' в getMessagePayload() даёт input_type: 'write'.

                ПодписьЛимит обрезаетсяподписи докнопки 20VK символов,— кнопок40 несимволов больше(плагин 7.обрезает).

                Примеры использования

                Простое меню с обработкой ответов

                callback_dataКод всегдабудет {работать command:корректно "..."только }.в команде JS Callback. Один и тот же код работает для Telegram, Max и VK.

                let TelegramMessage = require('Common.Integrations.Telegram')
                require('Common.Integrations.Max')
                require('Common.Integrations.Vk')
                
                let msg = new TelegramMessage()
                msg.text = "Выберите действие:"
                msg.keyboard = "Информация[info]==Помощь[help]==Настройки[settings]"
                msg.parse_mode = "HTML"
                
                switch (true) {
                case (isFirstImmediateCall):
                    msg.send()
                    return false
                
                case (msg.getMessagePayload()?.callback_data == "info"):
                    msg.addReplyToText()
                    bot.sendMessage("Информация о боте...")
                    return false
                
                case (msg.getMessagePayload()?.callback_data == "help"):
                    msg.addReplyToText()
                    bot.sendMessage("Справка по использованию...")
                    return false
                
                case (msg.getMessagePayload()?.callback_data == "settings"):
                    msg.addReplyToText()
                    bot.runScriptForLead(123, leadId) // Запуск скрипта настроек
                    return false
                }

                Минимальное демо: кнопки + переход дальше

                const TelegramMessage = require('Common.Integrations.Telegram')
                require('Common.Integrations.Max')
                require('Common.Integrations.Vk')
                
                const msg = new TelegramMessage()
                msg.text = 'Меню'VK+Telegram+Max demo\n\nВыберите кнопку:'
                msg.keyboard = 'Да[yes]Кнопка A[a]==Нет[no]Кнопка B[b]'
                msg.parse_mode = 'HTML'
                
                if (isFirstImmediateCall) {
                  msg.send()
                  return false
                }
                
                msg.addReplyToText()
                return true

                В Telegram и Max после нажатия клавиатура исчезнет, а к тексту сообщения добавится строка ➤ Кнопка A. В VK кнопкаподпись частокнопки уже приходит текстомв подписичат как сообщение пользователя (эхо text-кнопки), поэтому addReplyToText() ничего не callback.
                отправляет — только очищает _keyboard и возвращает getMessagePayload().

                Справочник методов

                Основные методы отправки

                  send() — отправка нового сообщения (messages.send). ID сохраняется в атрибуты лида vk_last_message_id и telegram_last_message_id. Клавиатура уходит напрямую в теле messages.send (драйвер VK не передаёт keyboard из sendMessage); edit() — в VK нет редактирования сообщений бота, поэтому отправляется новое сообщение (как send);= addReplyToText() — в VK no-op: сообщение не отправляется (выбор уже виден как эхо подписи кнопки). Возвращает getMessagePayload() и очищает _keyboard; removeInlineKeyboard() — в VK нельзя убрать кнопки из уже отправленного сообщения, поэтому метод только очищает _keyboard и возвращает getMessagePayload(); removeReplyKeyboard() — отправляет текст _remove_keyboard_text через messages.send без клавиатуры (как уведомление в Telegram).

                  Получение информации

                    getMessagePayload() — получение информации о сообщении из вебхука:
                      message_id — ID сообщения VK; text — текст сообщения / подпись кнопки; input_type — тип ввода ('write' / 'press'); callback_data — данные колбэка (без префикса btn_static_); original_reply_markup — какой тип клавиатуры хотели получить (inline_keyboard / keyboard); payload — полные данные вебхука.

                      Обработка ответов пользователя:

                      snippet('Business.Integrations.VK')// varПроверка msgтипа = new VkMessage()
                      var MENU = 'Да[yes]==Нет[no]'
                      
                      msg.keyboard = MENU
                      var p = msg.getMessagePayload()ввода
                      if (!isFirstImmediateCallmsg.getMessagePayload()?.input_type && p.callback_data && p.callback_data !== 'undefined'"write") {
                          bot.runScriptByCodeForLead(p.callback_data,// leadId)Пользователь returnнаписал trueтекст
                      }
                      
                      // Проверка нажатия кнопки
                      if (msg.textgetMessagePayload()?.callback_data == 'Выберите:'"button_id") {
                          // Пользователь нажал кнопку
                      }

                      Структура вебхука VK отличается от Telegram: событие всегда message_new. Сообщение лежит в object.message (API ≥ 5.103) или прямо в object. Нажатие text-кнопки приходит как message_new с полем payload (JSON-строка); плагин декодирует его, ищет кнопку в _keyboard и выставляет input_type=press. Текст без payload — input_type=write; если подпись совпала с кнопкой текущей клавиатуры, callback_data берётся из неё.

                      Отладка

                      msg.debug("Отладочное сообщение")

                      В Telegram при bot_debug_level == 0 используется «тихий» getMe. В VK такого метода нет: при уровне 0 отладка не отправляется пользователю. При ненулевом уровне сообщение уходит в чат (как и в Telegram-плагине).

                      Лучшие практики

                        Всегда проверяйте первый вызов:
                        if (isFirstImmediateCall) {
                            msg.send()
                            return truefalse
                        }

                        Также

                        можноДобавляйте прописыватьобработку номератекстовых кнопок:сообщений:
                        1if (msg.getMessagePayload()?.input_type == "write") {
                            bot.sendMessage('Пожалуйста, используйте кнопки')
                            return false
                        },
                        2
                        Картинки
                        После нажатия кнопки вызывайте addReplyToText() — в Telegram/Max это скроет клавиатуру и файлыдопишет ➤ …, в VK вызов безопасен (отправка)no-op) и сохраняет единый код скрипта:
                        msg.addReplyToText()
                          Подключайте Common.Integrations.Vk сразу после Telegram (и Max, если он нужен) в начале скрипта. Не используйте в тексте кнопок больше 40 символов; payload кнопки VK — до 255 байт. Для кросс-канальных скриптов всё равно задавайте parse_mode = 'HTML': в Telegram/Max форматирование сохранится, в VK плагин снимет разметку сам. В настройках сообщества VK включите «Возможности ботов» — иначе messages.send с клавиатурой вернёт ошибку 912.

                          Форматирование текста и entities

                          ПлагинVK не принимает толькоHTML/Markdown imageв messages.send так же, как Telegram/Max. Если заданы parse_mode или entities, плагин удаляет HTML-теги, типичные entities и file.маркеры ФайлMarkdown должени бытьотправляет указанplain как публичный URL.text.

                          msg.text = 'Фото'"<b>Жирный текст</b>\n<i>Курсив</i>\n<code>Моноширинный текст</code>"
                          msg.filesDataparse_mode = ["HTML"
                          // В VK уйдёт: "Жирный текст\nКурсив\nМоноширинный текст"

                          Работа с entities

                          msg.entities в VK не отправляются. Текст очищается так же, как при parse_mode.

                          let TelegramMessage = require('Common.Integrations.Telegram')
                          require('Common.Integrations.Max')
                          require('Common.Integrations.Vk')
                          
                          let msg = new TelegramMessage()
                          let messageData = lead.getJsonAttr("messageData")
                          
                          msg.text = messageData?.text
                          msg.entities = messageData?.entities
                          
                          // Не используйте одновременно parse_mode и entities

                          Отправка медиагрупп

                          Глобальная функция sendMediaGroup для лидов VK отправляет вложения по одному через bot.sendMessage с { type:type, url }. Типы элементов приводятся так: photo/image → image, document/file → file, video → video, audio → audio. Подпись очищается от разметки. Для Telegram/Max-лидов вызывается исходная (или Max) реализация.

                          Работа с файлами

                          Входящие файлы обрабатываются стандартными методами бота — так же, как в Telegram-плагине. Вы можете получить URL файла и сохранить его в карточку лида.

                          let TelegramMessage = require('Common.Integrations.Telegram')
                          require('Common.Integrations.Max')
                          require('Common.Integrations.Vk')
                          let msg = new TelegramMessage()
                          
                          // Все входящие файлы
                          let attachments = bot.getAllAttachments()
                          
                          if (Boolean(attachments?.[0]?.url)) {
                              let uploadData = bot.downloadFileFromUrl(attachments[0].url)
                          
                              msg.debug('Пользователь отправил файл: 'image' + uploadData.url)
                              lead.setAttr('file', url:uploadData.url)
                          
                              'https://example.com/pic.jpg' Запуск скрипта обработки
                              bot.runScriptByCodeForLead("recieveFile", lead.getData('id'))
                          
                              bot.stop()
                          }
                          ]
                          msg.send()

                          Пример ожидания фото:

                          let TelegramMessage = require('Common.Integrations.Telegram')
                          require('Common.Integrations.Max')
                          require('Common.Integrations.Vk')
                          let msg = new TelegramMessage()
                          
                          msg.text = 'Документ'А теперь жду твоё фото 😉'
                          msg.filesDataparse_mode = ['HTML'
                          
                          { type: 'file', url: 'https://example.com/doc.pdf' }
                          ]
                          msg.send()

                          После send():

                            lead.getJsonAttr('vk_last_send_result') lead.getAttr('vk_last_message_id')
                            Входящие вложения
                            msg.getImages()
                            msg.getFiles()
                            msg.getAllAttachments()

                            Видео из VK сейчас принимать нельзя

                            Исходный код плагина

                            /**
                             * Upload в VK: только image и file (photo/doc).
                             * Текст+кнопки с вложением платформа для VK отправляет раздельно (не как TG/Max).
                             */
                            if (typeof VkMessage === 'undefined') {
                              var vkNormalizeCommand = function (data) {
                                var s
                                var o
                            
                                if (data == null) {
                                  return ''
                                }
                            
                                if (typeoflet data === 'object'bot.getAllAttachments()
                            
                            switch (true) {
                            return String(data.command || data.callback_data || '')
                                }
                            
                                s = String(data)
                                ifcase (s.charAt(0) === '{') {
                                  try {
                                    o = JSON.parse(s)
                                    return String(o.command || o.callback_data || '')
                                  } catch (e) {}
                                }
                            
                                if (s.indexOf('btn_static_') === 0) {
                                  return s.slice('btn_static_'.length)
                                }
                            
                                return s
                              }
                            
                              var vkMakeCallback = function (command) {
                                return { command: String(command) }
                              }
                            
                              var vkSafeCall = function (fn, args) {
                                try {
                                  if (typeof fn !== 'function') {
                                    return []
                                  }
                                  return fn.apply(bot, args || []) || []
                                } catch (e) {
                                  return []
                                }
                              }
                            
                              var vkMapAttachmentType = function (raw) {
                                var t = String(raw || 'file').toLowerCase()
                                if (t === 'photo' || t === 'image' || t === 'sticker') {
                                  return 'image'
                                }
                                if (t === 'document' || t === 'doc' || t === 'file') {
                                  return 'file'
                                }
                                return null
                              }
                            
                              VkMessage = function () {
                                this._text = null
                                this._keyboard = null
                                this._attachments = []
                                this._answer_symbol = '>'
                                this._max_button_label = 20
                                this._max_buttons = 7
                                this._baseServerUrl = 'https://app.metabot24.com/' /*меняем на сервер который будет использоваться для отправки сообщений*/
                                this.webhookPayload = bot.getWebhookPayload()
                              }
                            
                              Object.defineProperty(VkMessage.prototype, 'text', {
                                get: function () {
                                  return this._text
                                },
                                set: function (value) {
                                  this._text = value
                                }
                              })
                            
                              Object.defineProperty(VkMessage.prototype, 'keyboard', {
                                get: function () {
                                  return this._keyboard
                                },
                                set: function (value) {
                                  this._keyboard = value ? this.createVkKeyboard(value) isFirstImmediateCall):
                                null
                                }
                              })
                            
                              Object.defineProperty(VkMessage.prototype, 'answer_symbol', {
                                set: function (value) {
                                  this._answer_symbol = value
                                }
                              })
                            
                              Object.defineProperty(VkMessage.prototype, 'filesData', {
                                get: function () {
                                  return this._attachments
                                },
                                set: function (value) {
                                  var i
                                  var prepared
                                  var item
                                  var list
                            
                                  this._attachments = []
                                  if (!value) {
                                    return
                                  }
                                  if (Object.prototype.toString.call(value) !== '[object Array]') {
                                    this.debug('filesData must be an array')
                                    return
                                  }
                            
                                  list = value
                                  for (i = 0; i < list.length; i++) {
                                    item = list[i]
                                    prepared = this.prepareAttachment(item)
                                    if (prepared) {
                                      this._attachments.push(prepared)
                                    }
                                  }
                                }
                              })
                            
                              Object.defineProperty(VkMessage.prototype, 'baseServerUrl', {
                                set: function (value) {
                                  if (value) {
                                    this._baseServerUrl = String(value)
                                    if (this._baseServerUrl.charAt(this._baseServerUrl.length - 1) !== '/') {
                                      this._baseServerUrl += '/'
                                    }
                                  }
                                }
                              })
                            
                              VkMessage.prototype.createVkKeyboard = function (keyboard) {
                                var rows = String(keyboard).split('==')
                                var result = []
                                var count = 0
                                var i
                                var j
                                var cols
                                var row
                                var item
                                var btn
                                var code
                            
                                for (i = 0; i < rows.length; i++) {
                                  cols = rows[i].split('||')
                                  row = []
                            
                                  for (j = 0; j < cols.length; j++) {
                                    item = String(cols[j] || '').trim()
                                    if (!item) {
                                      continue
                                    }
                                    if (count >= this._max_buttons) {
                                      break
                                    }
                            
                                    btn = null
                                    if (/https?:\/\//.test(item) && /\[[^\[\]]+\]/.test(item)) {
                                      code = item.match(/\[[^\[\]]+\]/)[0].slice(1, -1)
                                      btn = {
                                        text: this._clip(item.replace(/\[[^\[\]]+\]/g, '')),
                                        url: code,
                                        callback_data: vkMakeCallback(code),
                                        text_button_label: String(count + 1)
                                      }
                                    } else if (/\[[^\[\]]+\]/.test(item)) {
                                      code = item.match(/\[[^\[\]]+\]/)[0].slice(1, -1)
                                      btn = {
                                        text: this._clip(item.replace(/\[[^\[\]]+\]/g, '')),
                                        callback_data: vkMakeCallback(code),
                                        text_button_label: String(count + 1)
                                      }
                                    } else {
                                      btn = {
                                        text: this._clip(item),
                                        callback_data: vkMakeCallback(item),
                                        text_button_label: String(count + 1)
                                      }
                                    }
                            
                                    row.push(btn)
                                    count++
                                  }
                            
                                  if (row.length) {
                                    result.push(row)
                                  }
                                }
                            
                                return result
                              }
                            
                              VkMessage.prototype._clip = function (label) {
                                var text = String(label || '').trim()
                                if (text.length > this._max_button_label) {
                                  return text.slice(0, this._max_button_label)
                                }
                                return text
                              }
                            
                              VkMessage.prototype.debug = function (data) {
                                bot.sendMessage(
                                  'VK debug\n\n' + (typeof data === 'string' ? data : JSON.stringify(data))
                                )
                              }
                            
                              VkMessage.prototype.processLocalFile = function (filePath) {
                                var attrs
                                var businessId
                            
                                attrs = bot.getDebugAttributes ? bot.getDebugAttributes() : null
                                businessId = attrs && attrs.business_id != null ? attrs.business_id : ''
                                return this._baseServerUrl + 'uploads/business/' + businessId + '/' + filePath
                              }
                            
                              /**
                               * Готовит вложение для bot.sendMessage(..., attachments).
                               * Поддерживаемые type: image, file (photo как image, document/doc как file).
                               */
                              VkMessage.prototype.prepareAttachment = function (item) {
                                var type
                                var url
                                var out
                            
                                if (!item || typeof item !== 'object') {
                                  return null
                                }
                            
                                type = vkMapAttachmentType(item.type || item.file_type)
                                if (!type) {
                                  this.debug({
                                    error: 'unsupported attachment type for VK upload',
                                    type: item.type || item.file_type,
                                    hint: 'use image or file only'
                                  })
                                  return null
                                }
                            
                                url = item.url || item.file_url || item.file_id || null
                                if (!url && item.file_path) {
                                  url = this.processLocalFile(item.file_path)
                                }
                                if (!url) {
                                  this.debug({
                                    error: 'attachment url missing',
                                    item: item
                                  })
                                  return null
                                }
                            
                                out = {
                                  type: type,
                                  url: String(url)
                                }
                                if (item.caption != null) {
                                  out.caption = String(item.caption)
                                } else if (item.text != null) {
                                  out.caption = String(item.text)
                                }
                                if (item.payload && typeof item.payload === 'object') {
                                  out.payload = item.payload
                                }
                                if (item.file_id && item.file_id !== url) {
                                  out.file_id = item.file_id
                                }
                                return out
                              }
                            
                              VkMessage.prototype.getFiles = function (mimeInclude, mimeExclude) {
                                if (mimeExclude === undefined) {
                                  return vkSafeCall(bot.getFiles, [mimeInclude])
                                }
                                return vkSafeCall(bot.getFiles, [mimeInclude, mimeExclude])
                              }
                            
                              VkMessage.prototype.getImages = function (mimeInclude) {
                                if (mimeInclude === undefined) {
                                  return vkSafeCall(bot.getImages, [])
                                }
                                return vkSafeCall(bot.getImages, [mimeInclude])
                              }
                            
                              VkMessage.prototype.getVideos = function (mimeInclude) {
                                if (mimeInclude === undefined) {
                                  return vkSafeCall(bot.getVideos, [])
                                }
                                return vkSafeCall(bot.getVideos, [mimeInclude])
                              }
                            
                              VkMessage.prototype.getAllAttachments = function (filesMimeExclude) {
                                if (filesMimeExclude === undefined) {
                                  return vkSafeCall(bot.getAllAttachments, [])
                                }
                                return vkSafeCall(bot.getAllAttachments, [filesMimeExclude])
                              }
                            
                              VkMessage.prototype._resolveMessageId = function (resultPayload) {
                                var messageId = null
                            
                                if (typeof bot.getLastMessageId === 'function') {
                                  try {
                                    messageId = bot.getLastMessageId()
                                  } catch (e) {}
                                }
                            
                                if (messageId != null) {
                                  return messageId
                                }
                            
                                if (!resultPayload) {
                                  return null
                                }
                            
                                if (resultPayload.response != null) {
                                  return resultPayload.response
                                }
                                if (resultPayload.message_id != null) {
                                  return resultPayload.message_id
                                }
                                if (resultPayload.result != null && typeof resultPayload.result !== 'object') {
                                  return resultPayload.result
                                }
                                if (resultPayload.result && resultPayload.result.message_id != null) {
                                  return resultPayload.result.message_id
                                }
                                return null
                              }
                            
                              VkMessage.prototype.send = function () {
                                var text
                                var sent
                                var resultPayload
                                var messageId
                                var hasAttachments
                                var keyboard
                            
                                hasAttachments =
                                  Object.prototype.toString.call(this._attachments) === '[object Array]' &&
                                  this._attachments.length > 0
                            
                                if (!this._text && !hasAttachments) {
                                  this.debug('text or filesData is required'msg.send()
                                return false
                            
                            }case text = this._text(Boolean(data?.[0]?.type != null'image')):
                                &&bot.sendMessage('Отправь String(this._text)изображение. !Такой формат не подходит')
                                return false
                            
                            case (Boolean(data?.[0]?.type == '' ? String(this._text) image')):
                                'let '
                                keyboard = this._keyboard && this._keyboard.length ? this._keyboard : null
                            
                                if (hasAttachments) {
                                  sentuploadData = bot.sendMessage(text,downloadFileFromUrl(data[0].url)
                                keyboard,msg.debug('Пользователь this._attachments)отправил } else if (keyboard) {
                                  sent = bot.sendMessage(text, keyboard)
                                } else {
                                  sent = bot.sendMessage(text)
                                }
                            
                                resultPayload = bot.getLastResultPayload()
                                lead.setJsonAttr('vk_last_send_result', {
                                  sent: sent,
                                  has_keyboard: !!keyboard,
                                  has_attachments: hasAttachments,
                                  attachments_count: hasAttachments ? this._attachments.length : 0,
                                  result: resultPayload
                                })
                            
                                messageId = this._resolveMessageId(resultPayload)
                                if (messageId != null) {
                                  lead.setAttr('vk_last_message_id', String(messageId))
                                }
                            
                                if (sent === false || (resultPayload && resultPayload.error)) {
                                  this.debug({
                                    error: 'send failed',
                                    sent: sent,
                                    has_attachments: hasAttachments,
                                    result: resultPayload
                                  })
                                }
                            
                                return this.getMessagePayload()
                              }
                            
                              VkMessage.prototype.addReplyToText = function () {
                                var payload = this.getMessagePayload()
                                if (payload.input_type === 'press' && payload.text) {
                                  this._text = this._text + '\n\n' + this._answer_symbol + 'файл: ' + payload.textuploadData.url)
                                }lead.setAttr('photo', this._keyboarduploadData.url)
                                =bot.sendMessage('Класс! nullФото this._attachments = []загрузил')
                                return this.send(true
                            
                            default:
                                msg.addReplyToText()
                              }
                            
                              VkMessage.prototype._attachIncoming = function (result) {
                                var attachments
                                var hasText
                            
                                attachments = this.getAllAttachments()
                                if (Object.prototype.toString.call(attachments) !== '[object Array]') {
                                  attachments = []
                                }
                                result.attachments = attachments
                            
                                hasText = result.text != null && String(result.text) !== '' && result.text !== 'undefined'
                                if (attachments.length && !hasText && result.input_type !== 'press') {
                                  result.input_type = 'attachment'
                                  if (!result.text || result.text === 'undefined') {
                                    result.text = ''
                                  }
                                }
                                return resulttrue
                            }
                            VkMessage.prototype.getMessagePayload

                            Рекомендации =по functionработе с файлами

                              Всегда проверяйте наличие вложения (attachments?.[0]?.url) перед скачиванием. Сохраняйте URL, который вернул bot.downloadFileFromUrl(), {а varне resultисходный =URL {}канала var— payloadон =может this.webhookPayloadустареть. ||Не {}используйте varTelegram datafile_id varдля midVK: varидентификаторы eventObjвложений varв rawканалах varразные. incoming var

                              Совместимость rс varTelegram-плагином

                              b
                              varrowvarВозможность btnTelegram varMax cmdVK ifКомментарий send() ✅ ✅ ✅ VK: messages.send edit() ✅ ✅ ⚠️ VK: новое сообщение addReplyToText() ✅ ✅ ⚠️ VK: ничего не отправляет (payload.callback_query) { data = payload.callback_query.data mid = null if (payload.callback_query.message) { mid = payload.callback_query.message.message_id } cmd = vkNormalizeCommand(data) result.message_id = mid || lead.getAttr('vk_last_message_id') || null result.callback_data = cmd result.text = this._buttonLabel(cmd) || cmd result.input_type = 'press' result.payload = payload return this._attachIncoming(result) } eventObj = payload.object || payload if ( payload.type === 'message_event' || eventObj.type === 'message_event' || (eventObj.event_id != null && eventObj.payload != null) ) { raw = eventObj.payload cmd = vkNormalizeCommand(raw) result.message_id = eventObj.conversation_message_id || lead.getAttr('vk_last_message_id') || null result.callback_data = cmd result.text = this._buttonLabel(cmd) || cmd result.input_type = 'press' result.payload = payload return this._attachIncoming(result) } incoming = (payload.message && payload.message.text) || (payload.object && payload.object.message && payload.object.message.text) || (payload.object && payload.object.text) || bot.getIncomingMessage() if (incoming != null && String(incoming) !== '') { result.message_id = (payload.message && payload.message.id) || (payload.object && payload.object.message && payload.object.message.id) || (payload.object && payload.object.conversation_message_id) || null result.text = String(incoming) result.input_type = 'write' result.payload = payload if (Object.prototype.toString.call(this._keyboard) === '[object Array]') { for (r = 0; r < this._keyboard.length; r++) { row = this._keyboard[r] for (b = 0; b < row.length; b++) { btn = row[b] if (!btn || !btn.callback_data) { continue } // VK часто шлёт подписьэхо кнопки текстом;уже такжев принимаемчате) номер 1/2/…ifremoveInlineKeyboard() (✅ btn.text✅ ===⚠️ result.textVK: ||ничего String(btn.text_button_labelне ||отправляет '' removeReplyKeyboard() ===✅ result.text⚠️ ⚠️ VK: send _remove_keyboard_text getMessagePayload() {✅ result.callback_data✅ =✅ vkNormalizeCommand(btn.callback_data)
                              result.input_type ='press'debug() return✅ this._attachIncoming(result)✅ }⚠️ }при } } return this._attachIncoming(result) } result.message_id = (payload.message && payload.message.id) || (payload.object && payload.object.message && payload.object.message.id) || (payload.object && payload.object.conversation_message_id) || null result.text = 'undefined' result.input_type = 'undefined' result.callback_data = 'undefined' result.payload = payload return this._attachIncoming(result) } VkMessage.prototype._buttonLabel = function (command) { var needle var r var b var row var btn var cb if ( Object.prototype.toString.call(this._keyboard) !== '[object Array]' || commandbot_debug_level == null0 )— {silent returnno-op null }needleparse_mode = vkNormalizeCommand(command)HTML for✅ (r✅ ❌ strip → plain parse_mode = 0;MarkdownV2 r✅ <⚠️ this._keyboard.length;❌ r+strip → plain entities ✅ ⚠️ ❌ strip Кнопки contact / location ✅ ✅ ❌ кнопка пропускается +) debug Кнопки-ссылки ✅ ✅ ✅ open_link Web App {url} row✅ =⚠️ this._keyboard[r]❌ forкнопка пропускается + debug tg://user?id= ✅ ❌ ❌ кнопка пропускается protect_content ✅ ❌ ❌ игнорируется TelegramPhoto ✅ ❌ ❌ не патчится, используйте sendMediaGroup sendMediaGroup ✅ ✅ ⚠️ по одному вложению Эхо подписи кнопки нет нет да особенность VK text-кнопок

                              Ограничения VK

                                Текст кнопки — до 40 символов, payload кнопки — до 255 байт. payload должен быть валидной JSON-строкой (bплагин =кодирует 0;сам); bиначе <ошибка row.length;911. b++)Для {клавиатур btnв =сообществе row[b]должны cbбыть =включены vkNormalizeCommand(btn.callback_data)«Возможности ifботов»; иначе ошибка 912. Нет in-place edit / снятия inline-клавиатуры без правок PHP-драйвера. Нет message_event (cbcallback ===без needle)эха {подписи) returnбез btn.textправок }PHP-драйвера. }Вебхук }Callback returnAPI nullтребует }публичный }HTTPS URL (для локальной разработки — туннель; APP_URL может оставаться на localhost).