When you frequently roll out new features, you need to notify your team, users, and search engines. The latter is important for SEO — Google takes into account whether the product is evolving or abandoned.
Doing this manually after each push becomes a routine that you quickly forget. I set up automation: when deploying, GitHub Actions sends a notification to Telegram and creates a changelog post on the site.
What You’ll Get
- When pushing to production, a message is automatically sent to the Telegram channel
- A post is created in WordPress with the “changelog” category in the desired language
- You can skip notifications by adding
[skip-public]in the commit
Message format:
🏴 Update v1.30
— Added OAuth authentication
— Fixed bug with menu display
— Updated dependencies
How the Git Repository is Structured
The main branch contains the production version of the site. There are other branches where I and other developers work. Auto-deploy is set up: when pushing to main, the project is automatically deployed to production via GitHub Actions.
This is where we’ll integrate automation. In the same workflow, we’ll add steps to gather all commits from the last deploy and send them to the Telegram channel and the site as a post.
Step 1: Create a Telegram Bot
Open @BotFather in Telegram and create a bot with the /newbot command. You’ll get a token like this:
1234567890:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw
Create a channel and add the bot as an administrator. To get the channel’s Chat ID:
- Send any message to the channel
- Open this in the browser:
https://api.telegram.org/bot{TOKEN}/getUpdates - In the JSON response, find
chat.id— this is the Chat ID of the channel (starts with a minus)
Example response:
{
"message": {
"chat": {
"id": -1001234567890,
"title": "My Channel"
}
}
}
Chat ID of the channel: -1001234567890
Step 2: Configure the WordPress REST API
To create posts through the API, you need an Application Password:
- WordPress Admin → Users → your profile
- Scroll down to “Application Passwords”
- Enter a name (e.g., “GitHub Actions”) and click “Add New”
- Copy the generated password — it is shown only once.
Step 3: Add Secrets to GitHub
In the repository: Settings → Secrets and variables → Actions → New repository secret. Add the following:
TELEGRAM_BOT_TOKEN — bot token
TELEGRAM_CHAT_ID — channel ID (with minus, e.g., -1001234567890)
WP_USER — WordPress admin login
WP_APP_PASSWORD — Application Password
WP_SITE_URL — site address (https://example.com)
Step 4: Create a Version File
In the root of the repository, create a VERSION file with the base version:
1.0
GitHub Actions will automatically add the build number: 1.42, 1.43, etc.
Step 5: GitHub Actions Workflow
Create a file .github/workflows/deploy.yml:
name: Deploy
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Needed for git log
- name: Generate version
id: version
run: |
BASE_VERSION=$(cat VERSION)
FULL_VERSION="${BASE_VERSION}.${{ github.run_number }}"
echo "version=$FULL_VERSION" >> $GITHUB_OUTPUT
- name: Send to Telegram
if: ${{ !contains(github.event.head_commit.message, '[skip-public]') }}
env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
run: |
COMMITS=$(git log --pretty=format:"— %s" ${{ github.event.before }}..${{ github.sha }} --no-merges)
if [ -z "$COMMITS" ]; then
echo "No commits to report"
exit 0
fi
VERSION="${{ steps.version.outputs.version }}"
MESSAGE=$(printf "🏴 Update v%s\n\n%s" "$VERSION" "$COMMITS")
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d chat_id="${TELEGRAM_CHAT_ID}" \
-d text="$MESSAGE"
- name: Create changelog post
if: ${{ !contains(github.event.head_commit.message, '[skip-public]') }}
env:
WP_USER: ${{ secrets.WP_USER }}
WP_APP_PASSWORD: ${{ secrets.WP_APP_PASSWORD }}
WP_SITE_URL: ${{ secrets.WP_SITE_URL }}
run: |
COMMITS=$(git log --pretty=format:"— %s" ${{ github.event.before }}..${{ github.sha }} --no-merges)
if [ -z "$COMMITS" ]; then
exit 0
fi
VERSION="${{ steps.version.outputs.version }}"
TITLE="Update v${VERSION}"
# Get or create the changelog category
CAT_ID=$(curl -s -u "${WP_USER}:${WP_APP_PASSWORD}" \
"${WP_SITE_URL}/wp-json/wp/v2/categories?slug=changelog" | jq -r '.[0].id // empty')
if [ -z "$CAT_ID" ]; then
CAT_ID=$(curl -s -u "${WP_USER}:${WP_APP_PASSWORD}" \
-X POST "${WP_SITE_URL}/wp-json/wp/v2/categories" \
-H "Content-Type: application/json" \
-d '{"name":"Changelog","slug":"changelog"}' | jq -r '.id')
fi
# Create the post
curl -s -u "${WP_USER}:${WP_APP_PASSWORD}" \
-X POST "${WP_SITE_URL}/wp-json/wp/v2/posts" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg title "$TITLE" \
--arg content "$COMMITS" \
--argjson categories "[$CAT_ID]" \
'{title: $title, content: $content, status: "publish", categories: $categories}')"
Polylang: Multilingual Support
The site of my product is built on WordPress and it is multilingual — I use the Polylang Pro plugin for this. Therefore, when creating a post, it is necessary to specify the language of the commits.
Polylang adds a lang field to the REST API. We pass it in the JSON request:
curl -X POST ".../wp-json/wp/v2/posts" \
-d '{
"title": "Update v1.30",
"content": "— commit 1",
"lang": "ru"
}'
The language slug (ru, en) can be found in the admin: Languages → Languages → Code column.
In the future, changelog can be automatically translated into all site languages using neural networks — but that’s a topic for a separate article.
Skipping Notifications
Sometimes you need to push technical changes without public notification. Add [skip-public] in the commit message:
git commit -m "Refactor config [skip-public]"
git push origin main
GitHub Actions checks the condition !contains(github.event.head_commit.message, '[skip-public]') and skips the notification steps.
Summary
Now every push to main automatically:
- Generates a version from the VERSION file + build number
- Gathers the list of commits using
git log - Sends a beautiful message to Telegram
- Creates a post on the site in the changelog category
Setting up takes 15-20 minutes and saves time on every release.
