On automating post creation

How to generate Quarto post template
Author
Published

May 14, 2025

Modified

May 14, 2025

Although I am not a big fan of generating entire code using generative AI, I find it helpful to automate repetitive tasks that would otherwise take longer if done manually. In this case, I am creating a Quarto post template using Python. The initial code provided by the LLM was good enough, but I needed to make minor adjustments to fit my needs. While you can also prompt it yourself, you can use the following Python script to generate a Quarto template:

# create_post.py

import os
import datetime
import re
import argparse


def create_slug(title):
    """Generates a URL-friendly slug from a title."""
    slug = title.lower()
    slug = re.sub(r"[^\w\s-]", "", slug)
    slug = re.sub(r"\s+", "-", slug)
    slug = re.sub(r"-+", "-", slug)
    slug = slug.strip("-")
    return slug


def get_user_input(prompt_text, default_value=None):
    """Gets user input with an optional default value."""
    if default_value:
        prompt_with_default = f"{prompt_text} (default: {default_value}): "
    else:
        prompt_with_default = f"{prompt_text}: "

    user_value = input(prompt_with_default).strip()
    return user_value if user_value else default_value


def main():
    parser = argparse.ArgumentParser(description="Create a new Quarto blog post.")
    parser.add_argument(
        "--dir",
        type=str,
        default="posts",
        help="Directory to save the post (e.g., 'posts', '_posts'). Can be set non-interactively.",
    )
    args = parser.parse_args()
    dir = args.dir

    print("Creating a new Quarto blog post...")
    print("-" * 35)

    # Title (Required)
    while True:
        title = input("Post title: ").strip()
        if title:
            break
        print("Title cannot be empty. Please enter a title.")

    default_author = "DEFAULT AUTHOR NAME"
    author = get_user_input("Enter author", default_value=default_author)

    # Description
    description = get_user_input(
        "Enter a short description (optional, press Enter to skip)"
    )

    # Date
    default_date = datetime.date.today().strftime("%Y-%m-%d")
    while True:
        date_str = get_user_input("Enter date (YYYY-MM-DD)", default_value=default_date)
        try:
            datetime.datetime.strptime(date_str, "%Y-%m-%d")
            break
        except ValueError:
            print("Invalid date format. Please use YYYY-MM-DD.")

    # Folder name
    suggested_slug = create_slug(title)
    suggested_foldername = f"{date_str}_{suggested_slug}"
    foldername = get_user_input("Enter folder name", default_value=suggested_foldername)

    # Categories
    categories_input = get_user_input(
        "Enter categories (comma-separated, e.g., news,python,quarto) (optional)"
    )
    categories_yaml_lines = ""
    if categories_input:
        cats = [cat.strip() for cat in categories_input.split(",") if cat.strip()]
        categories_yaml_lines = (
            "categories:\n" + "\n".join(f" - {cat}" for cat in cats) if cats else ""
        )

    # Draft status
    draft_input = get_user_input("Mark as draft? (yes/no)", default_value="no").lower()
    draft = draft_input in ["yes", "y"]

    # Create directory
    post_dir = os.path.join(dir, foldername)
    if os.path.exists(post_dir):
        overwrite = get_user_input(
            f"Warning: Post '{post_dir}' already exists. Overwrite? (yes/no)",
            default_value="no",
        ).lower()
        if overwrite not in ["yes", "y"]:
            print("Post creation cancelled.")
            return
    os.makedirs(post_dir, exist_ok=True)
    output_path = os.path.join(post_dir, "index.qmd")

    # --- Create YAML Header and Content ---
    content = f"""---
title: "{title}"
description: "{description if description else ""}"
date: "{date_str}"
author: "{author}"
date-modified: "{date_str}"
draft: {str(draft).lower()}
{categories_yaml_lines}
---

Your content goes here.
"""
    try:
        with open(output_path, "w", encoding="utf-8") as f:
            f.write(content)
        print("-" * 30)
        print(f"Blog post successfully created: {output_path}")
        print("-" * 30)
    except IOError as e:
        print(f"Error writing file: {e}")


if __name__ == "__main__":
    main()

You can run the Python script from the command line using:

uv run create_post.py
Back to top

Reuse

Citation

For attribution, please cite this work as:
Reynaldo Hutabarat, Farhan. 2025. “On Automating Post Creation.” May 14, 2025. https://weaklyinformative.com/posts/2025-05-14_on-automating-post-creation/.