The blog is managed from one CLI:
python3 scripts/blog.pyRunning it without a command opens the interactive manager.
Each post is one Markdown file:
content/blog/fa/<slug>.md
content/blog/en/<slug>.md
Each post has its own media directory:
public/blog/fa/<slug>/
public/blog/en/<slug>/
A Persian post named install-parch therefore uses:
content/blog/fa/install-parch.md
public/blog/fa/install-parch/cover.webp
public/blog/fa/install-parch/01-installer.webp
Its public image URLs are:
/blog/fa/install-parch/cover.webp
/blog/fa/install-parch/01-installer.webp
python3 scripts/blog.pyThe menu includes listing and searching, creating posts, editing metadata, opening Markdown in your editor, adding images, publishing or returning to draft, renaming slugs, moving language, deleting posts, validation, statistics and WordPress import.
Interactive:
python3 scripts/blog.py newDirect:
python3 scripts/blog.py new \
--locale fa \
--title "آموزش نصب پارچ" \
--slug install-parch \
--description "راهنمای نصب پارچ گنو/لینوکس" \
--category "آموزش" \
--tags "پارچ,لینوکس,نصب"New posts are drafts unless --publish is passed.
python3 scripts/blog.py list
python3 scripts/blog.py list --locale fa
python3 scripts/blog.py list --status draft
python3 scripts/blog.py list --search "gnome"ls is an alias for list.
python3 scripts/blog.py show fa install-parchIt prints the file, media directory, route, status, title, date, category, tags, author, cover, featured state and word count.
Interactive metadata editor:
python3 scripts/blog.py edit fa install-parchSet individual fields without prompts:
python3 scripts/blog.py edit fa install-parch \
-f 'category=آموزش' \
-f 'tags=پارچ,نصب,لینوکس' \
-f 'featured=true'Set an editor once in your shell:
export EDITOR="code --wait"Then:
python3 scripts/blog.py write fa install-parchThe complete Markdown file opens in the editor.
python3 scripts/blog.py image fa install-parch ~/Pictures/cover.webp --coverThe image is copied into the post media directory and image: in frontmatter is updated automatically.
python3 scripts/blog.py image fa install-parch ~/Pictures/installer.webp --alt "نصاب پارچ"The CLI copies and names the image, then prints the exact Markdown to paste where the image should appear:
To append it to the end of the article automatically:
python3 scripts/blog.py image fa install-parch ~/Pictures/installer.webp --alt "نصاب پارچ" --appendSee all media belonging to one post:
python3 scripts/blog.py media fa install-parchpython3 scripts/blog.py status fa install-parch published
python3 scripts/blog.py status fa install-parch draftFeatured state can be changed at the same time:
python3 scripts/blog.py status fa install-parch published --featured
python3 scripts/blog.py status fa install-parch published --not-featuredpython3 scripts/blog.py rename fa install-parch parch-installationThe CLI renames the Markdown file, renames the media directory and rewrites media URLs inside the post and frontmatter.
python3 scripts/blog.py move fa install-parch --to enThe Markdown file, media directory and media URLs move together.
python3 scripts/blog.py delete fa install-parchIt asks for the slug before deleting. To delete without confirmation:
python3 scripts/blog.py delete fa install-parch --forceKeep the media directory if needed:
python3 scripts/blog.py delete fa install-parch --keep-mediapython3 scripts/blog.py validateAliases:
python3 scripts/blog.py check
python3 scripts/blog.py doctorValidation checks required metadata, dates, content language, missing covers, missing inline images, image alt text, media paths, accidental H1 headings and orphan media directories.
Normalize frontmatter formatting and create missing media directories:
python3 scripts/blog.py validate --fixOne post:
python3 scripts/blog.py format fa install-parchAll posts:
python3 scripts/blog.py format --allpython3 scripts/blog.py statsIt reports total posts, published posts, drafts, featured posts, covers, word count, language totals, categories and top tags.
Use the manager instead of calling the converter directly:
python3 scripts/blog.py import-wordpress wordpress-export.xmlThe importer detects Persian and English separately and skips existing slugs by default.
Download WordPress images into the same organized media structure and rewrite Markdown URLs:
python3 scripts/blog.py import-wordpress wordpress-export.xml --download-imagesInclude drafts:
python3 scripts/blog.py import-wordpress wordpress-export.xml --include-draftsConflict modes:
python3 scripts/blog.py import-wordpress wordpress-export.xml --conflict skip
python3 scripts/blog.py import-wordpress wordpress-export.xml --conflict overwrite
python3 scripts/blog.py import-wordpress wordpress-export.xml --conflict suffixThe interactive manager asks whether WordPress images should be downloaded and organized.
---
title: "عنوان مقاله"
description: "توضیح کوتاه و دقیق"
date: "2026-08-14"
category: "آموزش"
tags: ["پارچ", "لینوکس"]
author: "Parch GNU/Linux"
image: "/blog/fa/install-parch/cover.webp"
featured: false
draft: true
---
مقدمه مقاله.
## بخش اول
متن مقاله.

## بخش دوم
متن بیشتر.Use ## for top-level sections inside the article. The page title already provides the H1.
new → image --cover → write → image → validate → status published
For migrated content:
import-wordpress --download-images → validate → edit/write where needed → publish