Skip to content

Instantly share code, notes, and snippets.

@gtaylor
Last active December 15, 2025 05:58
Show Gist options
  • Select an option

  • Save gtaylor/bdccbd2143c445819222c4ed243e04ee to your computer and use it in GitHub Desktop.

Select an option

Save gtaylor/bdccbd2143c445819222c4ed243e04ee to your computer and use it in GitHub Desktop.
squarespace-to-astro.py
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "feedparser",
# "dateparser",
# "markdownify",
# ]
# ///
"""
Horrible, janky script to migrate posts from Squarespace to Astro.
I hope that this is useful to someone as prior art!
1. Update SQUARESPACE_EXPORT_PATH, OUTPUT_PATH, and TAG_MAP
2. Run: uv run squarespace-to-astro.py
"""
import json
import markdownify
import dateparser
import feedparser
# Replace with your own path or add logic for a command line arg.
SQUARESPACE_EXPORT_PATH = "/Users/gregtaylor/Downloads/Squarespace-Wordpress-Export-12-15-2025.xml"
# The path to write the resulting markdown files to.
OUTPUT_PATH = "src/data/blog/"
# I wanted to clean my tags up as I was moving over. This is the old vs new map.
TAG_MAP = {
"Drone CI": "CI",
"Quay.io": "CI",
"Minecraft": "Gaming",
}
def map_tags(tags):
"""Map tags from Squarespace to our new tag taxonomy."""
new_tags = []
for tag in tags:
new_tags.append(TAG_MAP.get(tag, tag))
return new_tags
def main():
data = feedparser.parse(SQUARESPACE_EXPORT_PATH)
for entry in data['entries']:
# Squarespace pages are included in the XML but are not blog posts.
content = entry.content[0].value
if not content:
continue
# Old (XML) values
tags = getattr(entry, 'tags', [])
slug = entry.link.split('/')[-1]
# New (to be written) values
new_filename = f"{OUTPUT_PATH}{slug}.md"
new_tags = []
for tag in tags:
new_tags.append(tag['term'])
new_tags = list(set(map_tags(new_tags)))
new_tags_json = json.dumps(new_tags)
new_pub_datetime = dateparser.parse(entry.published)
new_pub_datetime_iso = new_pub_datetime.isoformat()
markdown_content = markdownify.markdownify(content, strip=['CDATA', 'caption'])
print("=" * 80)
print(f"Post title: {entry.title}")
print(f"Post content: {content}")
print(f"Post date: {entry.published}")
print(f"Post link: {entry.link}")
print(f"Post tags: {getattr(entry, 'tags', [])}")
print("-" * 80)
print(f"New filename: {new_filename}")
print("-" * 80)
new_contents = f"""---
author: Greg Taylor
pubDatetime: {new_pub_datetime_iso}
modDatetime:
title: {entry.title}
slug: {slug}
featured: false
draft: false
tags: {new_tags_json}
description: ""
---
{markdown_content}
"""
print(new_contents)
print("=" * 80)
print("\r\n")
with open(new_filename, 'w') as f:
f.write(new_contents)
if __name__ == "__main__":
main()

Comments are disabled for this gist.