Auto-Sync Markdown Front Matter Image Links with Python
1. Background
When editing Markdown blog posts, it’s common to set both og_image
(for social media sharing) and thumbnail
(for blog card display). Maintaining these two fields manually is time-consuming and error-prone—especially when image filenames are designed to match post slugs. With a simple Python script, you can batch-update the og_image
and thumbnail
fields in your posts’ Front Matter to ensure they correctly point to the corresponding image files, significantly improving maintenance efficiency.
2. Requirements
- Blog posts are stored in the
_posts
folder, with filenames like: 2025-06-20-my-post.md - Corresponding images are located in assets/img/blog/, with filenames like: my-post.webp
- Each post’s
og_image
andthumbnail
fields should point to: /assets/img/blog/my-post.webp - If the fields do not exist, automatically insert
og_image
first, thenthumbnail
- Only modify Front Matter, not the main content
- Preserve the existing path prefix and only replace the image filename
3. Solution
Use a Python script to loop through all posts, find the matching image file, and update the relevant Front Matter fields.
Steps:
- Strip the date prefix (e.g.
2025-06-20
) from the post filename to extract the slug. - Check whether a
.webp
image file named with that slug exists in the image folder. - Parse the YAML Front Matter, detect or insert the
og_image
andthumbnail
fields. - Update or insert the fields, ensuring correct order and path format.
- Save the updated file without modifying the main content.
4. Final Script update_thumbnail.py
import os
import re
# === Set directories ===
posts_dir = './_posts'
img_dir = './assets/img/blog'
# Get all Markdown files, sorted alphabetically
post_files = sorted([f for f in os.listdir(posts_dir) if f.endswith('.md')])
for post_file in post_files:
post_name = os.path.splitext(post_file)[0]
# Remove the date prefix to get the slug
slug = re.sub(r'^\d{4}-\d{2}-\d{2}-', '', post_name)
expected_img = slug + ".webp"
img_path = os.path.join(img_dir, expected_img)
# Skip if image doesn't exist
if not os.path.exists(img_path):
print(f"Missing image: {expected_img}, skipping {post_file}")
continue
img_web_path = f"/assets/img/blog/{expected_img}"
# Read the post file
post_path = os.path.join(posts_dir, post_file)
with open(post_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
# Detect YAML Front Matter block
in_front_matter = False
front_matter_end_idx = 0
for idx, line in enumerate(lines):
if line.strip() == '---':
if not in_front_matter:
in_front_matter = True
else:
front_matter_end_idx = idx
break
fm_lines = lines[1:front_matter_end_idx]
new_fm_lines = []
og_image_found = False
thumbnail_found = False
for line in fm_lines:
m = re.match(r'^(thumbnail:|og_image:)\s*(.+)$', line)
if m:
field_name = m.group(1)
old_path = m.group(2).strip()
prefix_match = re.match(r'(.*/)', old_path)
prefix = prefix_match.group(1) if prefix_match else "/assets/img/blog/"
new_path = prefix + expected_img
new_fm_lines.append(f"{field_name} {new_path}\n")
if field_name == "og_image:":
og_image_found = True
elif field_name == "thumbnail:":
thumbnail_found = True
else:
new_fm_lines.append(line)
# Insert missing fields
if not og_image_found:
new_fm_lines.append(f"og_image: {img_web_path}\n")
if not thumbnail_found:
new_fm_lines.append(f"thumbnail: {img_web_path}\n")
# Write back to file
new_lines = ['---\n'] + new_fm_lines + ['---\n'] + lines[front_matter_end_idx + 1:]
with open(post_path, 'w', encoding='utf-8') as f:
f.writelines(new_lines)
print(f"Updated Front Matter: {post_file} → image {expected_img}")
5. Usage
Save the script as update_thumbnail.py and place it in the root directory (e.g., xx
).
Ensure the following folder structure:
xx/
├── update_thumbnail.py
├── _posts/
│ ├── 2025-06-20-my-post.md
│ └── ...
└── assets/
└── img/
└── blog/
├── my-post.webp
└── ...
Run the script:
cd ~/Desktop/xx
python3 update_thumbnail.py
6. Example
Original Front Matter:
---
layout: post
title: Example
date: 2025-06-20
---
After running the script:
---
layout: post
title: Example
date: 2025-06-20
og_image: /assets/img/blog/my-post.webp
thumbnail: /assets/img/blog/my-post.webp
---