Skip to content

Commit 08daed8

Browse files
HeyItsGilbertclaude
andcommitted
Model site archetypes in Front Matter CMS and ease article submission
Replace the single generic `default` content type with five typed ones (article, podcast, event, page, author) mapped to their content folders, so the Front Matter editor matches what contributors actually write. - frontmatter.json: per-folder content types + mappings, auto date-prefixed filenames, RFC3339 dateFormat, authors custom taxonomy - archetypes: convert default.md to YAML; add articles/podcast/calendar/ authors templates named to match Hugo sections - taxonomyDb.json: seed authors dropdown from existing content - add-article.yml: turn an approved guest-post issue into a front-mattered article file + PR (mirrors add-event.yml) - guest-blog-post.yml: add Description, Category, and Tags inputs - CONTRIBUTING.md: include description in the front matter template Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ddd04b7 commit 08daed8

11 files changed

Lines changed: 588 additions & 5 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{
2+
"taxonomy": {
3+
"tags": [],
4+
"categories": [
5+
"Announcements",
6+
"Books",
7+
"DevOps",
8+
"Events",
9+
"Graph",
10+
"In Case You Missed It",
11+
"News",
12+
"PowerShell Summit",
13+
"PowerShell for Admins",
14+
"PowerShell for Developers",
15+
"Scripting Games",
16+
"Tips and Tricks",
17+
"Tools",
18+
"Training",
19+
"Tutorials"
20+
]
21+
},
22+
"customTaxonomy": [
23+
{
24+
"id": "authors",
25+
"options": [
26+
"Aaron Jensen",
27+
"Adam Bertram",
28+
"Adam Platt",
29+
"Alex Aymonier",
30+
"Art Beane",
31+
"Bartek Bielawski",
32+
"Bjorn Houben",
33+
"Boe Prox",
34+
"Brian Bourque",
35+
"Carlo Mancini",
36+
"Chris Martin",
37+
"Cole McDonald",
38+
"Colyn Via",
39+
"Darren Mar-Elia",
40+
"David Jones",
41+
"David Wilson",
42+
"Don Jones",
43+
"Eli Hess",
44+
"Enrique Puig",
45+
"Eric Brookman (scriptingcaveman)",
46+
"Glenn Sizemore",
47+
"Graham Beer",
48+
"Greg Altman",
49+
"Greg Tate",
50+
"Jaap Brasser",
51+
"Jacob Benson",
52+
"Jacob Moran",
53+
"James Petty",
54+
"Jeffery Hicks",
55+
"Joel Newton",
56+
"John Mello",
57+
"Jonas Sommer Nielsen",
58+
"Jonathan Medd",
59+
"Jonathan Walz",
60+
"June Blender",
61+
"Keith Hill",
62+
"Kirk Munro",
63+
"Liam Kemp",
64+
"Mark Kraus (markekraus)",
65+
"Mark Roloff",
66+
"Mark Wragg",
67+
"Matt Laird",
68+
"Matthew Hodgkins",
69+
"Mike F Robbins",
70+
"Mike Kanakos",
71+
"Mike Roberts",
72+
"Missy Januszko",
73+
"Nathaniel Webb (ArtisanByteCrafter)",
74+
"Nick Rimmer",
75+
"Richard Siddaway",
76+
"Robin Dadswell",
77+
"Stephen Moore",
78+
"Stephen Owen",
79+
"Steve Parankewich",
80+
"Steven Murawski",
81+
"Sunny Chakraborty",
82+
"Terri Donahue",
83+
"Thomas Malkewitz",
84+
"Thomas Rayner, MVP",
85+
"Tim Curwick",
86+
"Timothy Warner",
87+
"WeiYen Tan",
88+
"Will Anderson"
89+
]
90+
}
91+
]
92+
}

.github/ISSUE_TEMPLATE/guest-blog-post.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,48 @@ body:
3636
validations:
3737
required: true
3838

39+
- type: input
40+
id: description
41+
attributes:
42+
label: Description
43+
description: "A 1-2 sentence summary used for SEO, social cards, and the article list."
44+
placeholder: "Learn how to enable and customize PSReadLine predictive IntelliSense for a faster console."
45+
validations:
46+
required: true
47+
48+
- type: dropdown
49+
id: category
50+
attributes:
51+
label: Category
52+
description: "Pick the category that best fits your article."
53+
options:
54+
- "Announcements"
55+
- "Books"
56+
- "DevOps"
57+
- "Events"
58+
- "Graph"
59+
- "In Case You Missed It"
60+
- "News"
61+
- "PowerShell Summit"
62+
- "PowerShell for Admins"
63+
- "PowerShell for Developers"
64+
- "Scripting Games"
65+
- "Tips and Tricks"
66+
- "Tools"
67+
- "Training"
68+
- "Tutorials"
69+
validations:
70+
required: true
71+
72+
- type: input
73+
id: tags
74+
attributes:
75+
label: Tags (optional)
76+
description: "Comma-separated keywords, e.g. psreadline, console, productivity."
77+
placeholder: "psreadline, console, productivity"
78+
validations:
79+
required: false
80+
3981
- type: textarea
4082
id: summary
4183
attributes:

.github/workflows/add-article.yml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
name: Add Guest Article
2+
3+
on:
4+
issues:
5+
types: [labeled]
6+
7+
jobs:
8+
add-article:
9+
if: |
10+
github.event.label.name == 'approved' &&
11+
contains(github.event.issue.labels.*.name, 'article')
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: write
15+
pull-requests: write
16+
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
21+
- name: Parse issue and create article content file
22+
id: parse
23+
env:
24+
ISSUE_BODY: ${{ github.event.issue.body }}
25+
ISSUE_NUMBER: ${{ github.event.issue.number }}
26+
ISSUE_TITLE: ${{ github.event.issue.title }}
27+
run: |
28+
python3 - <<'PYEOF'
29+
import os, re, datetime, yaml
30+
31+
body = os.environ['ISSUE_BODY']
32+
33+
def field(label):
34+
m = re.search(rf'### {re.escape(label)}\s+(.+?)(?=\n###|\Z)', body, re.DOTALL)
35+
if not m:
36+
return ''
37+
val = m.group(1).strip()
38+
return '' if val in ('_No response_', '') else val
39+
40+
title = field('Article Title')
41+
author = field('Author Name')
42+
description = field('Description')
43+
category = field('Category')
44+
tags_raw = field('Tags (optional)')
45+
content = field('Article Content (Markdown)')
46+
47+
# The Article Content field is rendered as a ```markdown fenced block — unwrap it.
48+
content = re.sub(r'^```[a-zA-Z]*\n', '', content)
49+
content = re.sub(r'\n```$', '', content).strip()
50+
51+
if not title:
52+
raise SystemExit('No article title found; aborting.')
53+
if not content:
54+
# A pitch with no draft — nothing to publish yet.
55+
print('No article content provided (pitch only); skipping file creation.')
56+
with open(os.environ['GITHUB_OUTPUT'], 'a') as out:
57+
out.write('skip=true\n')
58+
raise SystemExit(0)
59+
60+
tags = [t.strip() for t in re.split(r'[,\n]', tags_raw) if t.strip()]
61+
62+
today = datetime.datetime.now(datetime.timezone.utc)
63+
date_str = today.strftime('%Y-%m-%dT%H:%M:%S+00:00')
64+
65+
slug = re.sub(r'[^a-z0-9]+', '-', title.lower()).strip('-')
66+
filename = f"{today.strftime('%Y-%m-%d')}-{slug}.md"
67+
68+
fm = {
69+
'title': title,
70+
'author': author,
71+
'authors': [author] if author else [],
72+
'date': date_str,
73+
'description': description,
74+
}
75+
if category:
76+
fm['categories'] = [category]
77+
if tags:
78+
fm['tags'] = tags
79+
80+
front = yaml.safe_dump(fm, default_flow_style=False, allow_unicode=True, sort_keys=False)
81+
document = '---\n' + front + '---\n\n' + content + '\n'
82+
83+
filepath = f'content/articles/{filename}'
84+
os.makedirs('content/articles', exist_ok=True)
85+
with open(filepath, 'w', encoding='utf-8') as f:
86+
f.write(document)
87+
88+
with open(os.environ['GITHUB_OUTPUT'], 'a') as out:
89+
out.write(f'skip=false\n')
90+
out.write(f'slug={slug}\n')
91+
out.write(f'filepath={filepath}\n')
92+
out.write(f'article_title={title}\n')
93+
94+
print(f'Created {filepath}')
95+
PYEOF
96+
97+
- name: Open PR
98+
if: steps.parse.outputs.skip == 'false'
99+
env:
100+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
101+
SLUG: ${{ steps.parse.outputs.slug }}
102+
FILEPATH: ${{ steps.parse.outputs.filepath }}
103+
ARTICLE_TITLE: ${{ steps.parse.outputs.article_title }}
104+
ISSUE_NUMBER: ${{ github.event.issue.number }}
105+
run: |
106+
BRANCH="article/issue-${ISSUE_NUMBER}-${SLUG}"
107+
git config user.name "github-actions[bot]"
108+
git config user.email "github-actions[bot]@users.noreply.github.com"
109+
git checkout -b "$BRANCH"
110+
git add "$FILEPATH"
111+
git commit -m "Add article: ${ARTICLE_TITLE} (closes #${ISSUE_NUMBER})"
112+
git push origin "$BRANCH"
113+
gh pr create \
114+
--title "Add article: ${ARTICLE_TITLE}" \
115+
--body "Closes #${ISSUE_NUMBER}
116+
117+
Auto-generated from guest blog post submission. Please review front matter and content before merging." \
118+
--base main \
119+
--head "$BRANCH"

CONTRIBUTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ If you're not comfortable with Git, you can pitch or submit your article through
2727
```yaml
2828
---
2929
title: "Your Article Title"
30+
description: "A 1-2 sentence summary used for SEO, social cards, and the article list."
3031
author: Your Name
3132
authors:
3233
- Your Name
@@ -41,6 +42,11 @@ If you're not comfortable with Git, you can pitch or submit your article through
4142
Your article content in Markdown goes here.
4243
```
4344

45+
> Tip: If you have the [Front Matter CMS](https://frontmatter.codes/) extension
46+
> installed in VS Code, run **"Create content"** in the `content/articles`
47+
> folder — it scaffolds the file name (`YYYY-MM-DD-slug.md`) and all of the
48+
> front matter fields above for you.
49+
4450
5. Submit a pull request with a brief description of your article
4551

4652
### Writing Tips

archetypes/articles.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
3+
description: ""
4+
author: ""
5+
authors:
6+
- ""
7+
date: '{{ .Date }}'
8+
categories: []
9+
tags: []
10+
draft: true
11+
---

archetypes/authors.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
3+
description: ""
4+
layout: "authors"
5+
website: ""
6+
twitter: ""
7+
github: ""
8+
---

archetypes/calendar.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
3+
startDate: '{{ .Date | dateFormat "2006-01-02" }}'
4+
endDate: ""
5+
where: ""
6+
externalUrl: ""
7+
virtual: false
8+
---

archetypes/default.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
+++
2-
date = '{{ .Date }}'
3-
draft = true
4-
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
5-
+++
1+
---
2+
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
3+
date: '{{ .Date }}'
4+
draft: true
5+
---

archetypes/podcast.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
3+
description: ""
4+
author: ""
5+
authors:
6+
- ""
7+
date: '{{ .Date }}'
8+
podcast_url: ""
9+
draft: true
10+
---

0 commit comments

Comments
 (0)