$message Message. * @param array $config Channel config. * @return true|WP_Error */ public function send( array $message, array $config ) { $text = '' . $this->escape( (string) $message['title'] ) . ''; if ( '' !== (string) ( $message['intro'] ?? '' ) ) { $text .= "\n" . $this->escape( (string) $message['intro'] ); } $lines = $this->item_lines( $message ); if ( $lines ) { $text .= "\n\n" . implode( "\n", array_map( fn( $l ) => '• ' . $this->escape( $l ), $lines ) ); } $text .= "\n\n" . sprintf( '%s · %s', esc_url( (string) $message['url'] ), $this->escape( (string) $message['link_label'] ), $this->escape( (string) $message['site'] ) ); $result = $this->post_json( // The token is validated on save to [0-9A-Za-z:_-], so it is URL-safe as is. 'https://api.telegram.org/bot' . (string) $config['bot_token'] . '/sendMessage', array( 'chat_id' => (string) $config['chat_id'], 'text' => mb_substr( $text, 0, 4000 ), 'parse_mode' => 'HTML', 'disable_web_page_preview' => true, ) ); // Never surface the bot token (it is part of the URL) in an error. if ( is_wp_error( $result ) ) { return new WP_Error( $result->get_error_code(), str_replace( (string) $config['bot_token'], '•••', $result->get_error_message() ), $result->get_error_data() ); } return $result; } /** * Escape text for Telegram's HTML parse mode. * * @param string $text Text. */ private function escape( string $text ): string { return htmlspecialchars( $text, ENT_NOQUOTES, 'UTF-8' ); } }