Newsletters
**Referenced Files in This Document** - [.eleventy.js](file://.eleventy.js) - [newsletters.njk](file://src/newsletters.njk) - [curabitur-ullamcorper-ultricies-nisi.md](file://src/content/newsletters/curabitur-ullamcorper-ultricies-nisi.md) - [newsletters.11tydata.json](file://src/content/newsletters/newsletters.11tydata.json) - [newsletter-signup.njk](file://src/_includes/macros/newsletter-signup.njk) - [newsletter-spam-protection.js](file://src/assets/js/modules/newsletter-spam-protection.js) - [newsletter-signup-component.css](file://src/assets/css/modules/42-newsletter-signup-component.css) - [config.yml](file://src/admin/config.yml) - [site.json](file://src/_data/site.json) - [base.njk](file://src/_includes/layouts/base.njk)Table of Contents
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
Introduction
This document explains the Newsletter content collection system used to manage, render, and distribute Ace Strategies’ monthly market intelligence and strategic insights. It covers the frontmatter schema, content assembly pipeline, archive presentation, opt-in integration via ConvertKit, spam protection, and operational guidance for creating, organizing, and measuring newsletter engagement.
Project Structure
The newsletter system spans content, configuration, templating, and client-side protections:
- Content: Markdown files under src/content/newsletters define individual issues.
- Collections: Eleventy builds a sorted “newsletters” collection from these files.
- Rendering: A dedicated Nunjucks template renders the archive page and includes a signup component.
- Opt-in: Forms submit to ConvertKit using a configured form ID.
- Spam protection: A small client-side script adds a honeypot and submission guard.
- Admin: TinaCMS defines the editorial schema for newsletter entries.
graph TB
subgraph "Content"
MD["Markdown Issue Files<br/>src/content/newsletters/*.md"]
CFG["Collection Config<br/>.eleventy.js"]
end
subgraph "Rendering"
TPL["Archive Template<br/>src/newsletters.njk"]
MAC["Signup Macro<br/>src/_includes/macros/newsletter-signup.njk"]
LAYOUT["Footer Layout<br/>src/_includes/layouts/base.njk"]
end
subgraph "Admin"
TINA["Tina Config<br/>src/admin/config.yml"]
SITE["Site Settings<br/>src/_data/site.json"]
end
subgraph "Client-Side"
JS["Spam Protection<br/>src/assets/js/modules/newsletter-spam-protection.js"]
CSS["Signup Styles<br/>src/assets/css/modules/42-newsletter-signup-component.css"]
end
MD --> CFG
CFG --> TPL
TPL --> MAC
LAYOUT --> MAC
TINA --> SITE
SITE --> MAC
SITE --> LAYOUT
JS --> MAC
CSS --> MAC
Diagram sources
- [.eleventy.js:181-185](file://.eleventy.js#L181-L185)
- [newsletters.njk:20-71](file://src/newsletters.njk#L20-L71)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
- [newsletter-signup-component.css:6-137](file://src/assets/css/modules/42-newsletter-signup-component.css#L6-L137)
- [config.yml:92-105](file://src/admin/config.yml#L92-L105)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
- [base.njk:207-216](file://src/_includes/layouts/base.njk#L207-L216)
Section sources
- [.eleventy.js:181-185](file://.eleventy.js#L181-L185)
- [newsletters.njk:1-72](file://src/newsletters.njk#L1-L72)
- [config.yml:92-105](file://src/admin/config.yml#L92-L105)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
- [newsletter-signup-component.css:6-137](file://src/assets/css/modules/42-newsletter-signup-component.css#L6-L137)
- [base.njk:207-216](file://src/_includes/layouts/base.njk#L207-L216)
Core Components
- Newsletter collection: Sorted by publication date, newest first.
- Archive page: Presents chronological listings with optional links to PDF and online archives.
- Frontmatter schema: Defines metadata per issue.
- Opt-in signup: Inline and footer variants powered by ConvertKit.
- Spam protection: Client-side honeypot and timing guard.
Section sources
- [.eleventy.js:181-185](file://.eleventy.js#L181-L185)
- [newsletters.njk:20-71](file://src/newsletters.njk#L20-L71)
- [curabitur-ullamcorper-ultricies-nisi.md:1-10](file://src/content/newsletters/curabitur-ullamcorper-ultricies-nisi.md#L1-L10)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
Architecture Overview
The newsletter workflow integrates authoring, rendering, and distribution:
sequenceDiagram
participant Author as "Editor (TinaCMS)"
participant FS as "Markdown Files<br/>src/content/newsletters/*.md"
participant Eleventy as "Eleventy Build<br/>.eleventy.js"
participant Site as "Archive Page<br/>src/newsletters.njk"
participant User as "Subscriber"
participant CK as "ConvertKit"
Author->>FS : Create/Edit issue frontmatter
Eleventy->>FS : Read *.md with frontmatter
Eleventy->>Eleventy : Build "newsletters" collection<br/>sorted by date
Eleventy->>Site : Render archive with items
User->>Site : Visit archive page
User->>CK : Submit email via ConvertKit form
CK-->>User : Confirmation/opt-in acknowledged
Diagram sources
- [.eleventy.js:181-185](file://.eleventy.js#L181-L185)
- [newsletters.njk:20-71](file://src/newsletters.njk#L20-L71)
- [curabitur-ullamcorper-ultricies-nisi.md:1-10](file://src/content/newsletters/curabitur-ullamcorper-ultricies-nisi.md#L1-L10)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
Detailed Component Analysis
Newsletter Collection and Sorting
- Source: Eleventy reads all Markdown files under src/content/newsletters and sorts them by date descending.
- Purpose: Ensures the archive page lists the most recent issues first.
flowchart TD
A["Glob *.md in src/content/newsletters"] --> B["Build collection"]
B --> C["Sort by item.data.date desc"]
C --> D["Expose as collections.newsletters"]
Diagram sources
- [.eleventy.js:181-185](file://.eleventy.js#L181-L185)
Section sources
- [.eleventy.js:181-185](file://.eleventy.js#L181-L185)
Archive Page Rendering
- Template: src/newsletters.njk renders the archive with:
- Hero header
- Chronological list of issues
- Optional links to PDF and online archive
- Embedded newsletter signup component
- Data binding: Iterates over collections.newsletters and uses item.data.title, item.data.date, item.data.excerpt, and optional links.
sequenceDiagram
participant TPL as "newsletters.njk"
participant Coll as "collections.newsletters"
participant Item as "Issue Item"
participant Macro as "newsletter-signup macro"
TPL->>Coll : Fetch newsletter items
loop For each item
TPL->>Item : Read title, date, excerpt, links
TPL-->>TPL : Render list row
end
TPL->>Macro : Include signup component
Diagram sources
- [newsletters.njk:20-71](file://src/newsletters.njk#L20-L71)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
Section sources
- [newsletters.njk:1-72](file://src/newsletters.njk#L1-L72)
Frontmatter Schema and Fields
The frontmatter supports the following keys for each newsletter issue:
- title: Display title of the newsletter.
- date: Publication timestamp; drives sorting and display.
- excerpt: Short description shown in the archive.
- pdf_link: Optional URL to a downloadable PDF.
- archive_link: Optional URL to an online archive view.
- featured: Boolean flag for prominence.
- draft: Boolean flag to exclude from live collections.
These fields are defined in both the content file and the Tina admin configuration.
Section sources
- [curabitur-ullamcorper-ultricies-nisi.md:1-10](file://src/content/newsletters/curabitur-ullamcorper-ultricies-nisi.md#L1-L10)
- [config.yml:92-105](file://src/admin/config.yml#L92-L105)
Opt-In Integration with ConvertKit
- Form endpoint: Both the archive page and the footer use ConvertKit’s subscription endpoint with a configurable form ID.
- Configuration: The form ID is stored in site settings and injected into the templates/macros.
- Submission: The form posts to ConvertKit, enabling subscribers to join the audience.
sequenceDiagram
participant User as "Visitor"
participant Page as "Archive/Footer"
participant Macro as "newsletter-signup macro"
participant SiteCfg as "site.json"
participant CK as "ConvertKit"
User->>Page : Fill email (and optionally name)
Page->>Macro : Render form with action URL
Macro->>SiteCfg : Resolve convertkit_form_id
User->>CK : POST to ConvertKit form endpoint
CK-->>User : Confirmation message
Diagram sources
- [newsletters.njk:62-69](file://src/newsletters.njk#L62-L69)
- [newsletter-signup.njk:6-24](file://src/_includes/macros/newsletter-signup.njk#L6-L24)
- [base.njk:211-214](file://src/_includes/layouts/base.njk#L211-L214)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
Section sources
- [newsletters.njk:62-69](file://src/newsletters.njk#L62-L69)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [base.njk:207-216](file://src/_includes/layouts/base.njk#L207-L216)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
Newsletter Signup Component
- Macro: Provides two variants—full and compact—to suit page layouts.
- Styling: Dedicated CSS module styles both variants responsively.
- Accessibility: Includes placeholders, aria-labels, and required attributes.
classDiagram
class Macro {
+signup(title, description, buttonText, variant, formId)
}
class Styles {
+newsletter-signup
+footer-newsletter
}
Macro --> Styles : "renders styled markup"
Diagram sources
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [newsletter-signup-component.css:6-137](file://src/assets/css/modules/42-newsletter-signup-component.css#L6-L137)
Section sources
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [newsletter-signup-component.css:6-137](file://src/assets/css/modules/42-newsletter-signup-component.css#L6-L137)
Spam Protection
- Mechanism: Adds a hidden honeypot field and prevents submission if the field is filled or if the form is submitted too quickly after page load.
- Scope: Targets forms whose action includes the ConvertKit domain.
flowchart TD
Start(["Form Load"]) --> Inject["Inject honeypot input"]
Inject --> Wait["Wait for user"]
Wait --> Submit{"Submit event"}
Submit --> |Too fast or honeypot filled| Block["Prevent default"]
Submit --> |Valid| Allow["Allow submission"]
Diagram sources
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
Section sources
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
Archive Organization and Presentation
- Chronological ordering: Newest issues appear first.
- Display fields: Title, formatted date, optional excerpt, and optional links to PDF and online archive.
- Empty state: Friendly messaging when no issues are present.
flowchart TD
A["collections.newsletters"] --> B{"Has items?"}
B -- Yes --> C["Render rows with title/date/excerpt"]
C --> D{"Has pdf_link?"}
C --> E{"Has archive_link?"}
D -- Yes --> F["Show download link"]
E -- Yes --> G["Show view online link"]
B -- No --> H["Show empty state"]
Diagram sources
- [newsletters.njk:20-71](file://src/newsletters.njk#L20-L71)
Section sources
- [newsletters.njk:20-71](file://src/newsletters.njk#L20-L71)
Dependency Analysis
- Content depends on frontmatter fields defined in both the Markdown files and the Tina admin schema.
- Rendering depends on the “newsletters” collection built by Eleventy.
- Templates depend on site settings for the ConvertKit form ID.
- Client-side scripts depend on the presence of ConvertKit forms on the page.
graph LR
MD["*.md frontmatter"] --> COL["Eleventy newsletters collection"]
COL --> TPL["newsletters.njk"]
CFG["site.json convertkit_form_id"] --> TPL
TPL --> MAC["newsletter-signup macro"]
MAC --> CSS["newsletter-signup-component.css"]
MAC --> JS["newsletter-spam-protection.js"]
Diagram sources
- [.eleventy.js:181-185](file://.eleventy.js#L181-L185)
- [newsletters.njk:20-71](file://src/newsletters.njk#L20-L71)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
- [newsletter-signup-component.css:6-137](file://src/assets/css/modules/42-newsletter-signup-component.css#L6-L137)
Section sources
- [.eleventy.js:181-185](file://.eleventy.js#L181-L185)
- [newsletters.njk:20-71](file://src/newsletters.njk#L20-L71)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
- [newsletter-signup-component.css:6-137](file://src/assets/css/modules/42-newsletter-signup-component.css#L6-L137)
Performance Considerations
- Keep frontmatter concise; avoid heavy computations in templates.
- Limit the number of newsletter issues rendered per page if pagination becomes necessary.
- Minimize external redirects by linking directly to hosted assets where possible.
- Ensure the ConvertKit form endpoint remains reliable and fast.
Troubleshooting Guide
- Form does not submit:
- Verify the ConvertKit form ID exists in site settings.
- Confirm the form action URL is present and correct.
- Check browser console for errors.
- Spam protection blocks legitimate signups:
- Ensure users wait briefly after page load before submitting.
- Avoid filling the hidden honeypot field.
- Archive shows no items:
- Confirm frontmatter includes a valid date and that the file is placed under the newsletters directory.
- Check that the draft flag is not set to true unintentionally.
Section sources
- [site.json:13-13](file://src/_data/site.json#L13-L13)
- [newsletter-spam-protection.js:18-22](file://src/assets/js/modules/newsletter-spam-protection.js#L18-L22)
- [curabitur-ullamcorper-ultricies-nisi.md:1-10](file://src/content/newsletters/curabitur-ullamcorper-ultricies-nisi.md#L1-L10)
- [newsletters.11tydata.json:1-2](file://src/content/newsletters/newsletters.11tydata.json#L1-L2)
Conclusion
The newsletter system combines a straightforward frontmatter schema, a robust Eleventy collection, and a ConvertKit-powered opt-in flow. The archive page organizes content chronologically, while the signup component and spam protection improve usability and reduce noise. By following the editorial and formatting guidelines below, teams can maintain a consistent, scalable newsletter program.
Appendices
Practical Examples and Formatting Guidelines
- Creating a new newsletter issue:
- Place a Markdown file under src/content/newsletters with the required frontmatter fields.
- Use a publication date in the filename or frontmatter to ensure correct chronological ordering.
- Formatting tips:
- Keep excerpts concise and scannable.
- Provide clear links for PDF and online archive when available.
- Use the “featured” flag sparingly to highlight standout issues.
- Opt-in placement:
- Use the full variant in the archive page and the compact variant in the footer.
- Ensure the form ID is configured in site settings.
Section sources
- [curabitur-ullamcorper-ultricies-nisi.md:1-10](file://src/content/newsletters/curabitur-ullamcorper-ultricies-nisi.md#L1-L10)
- [newsletters.njk:57-70](file://src/newsletters.njk#L57-L70)
- [base.njk:207-216](file://src/_includes/layouts/base.njk#L207-L216)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
Relationship with Newsletter Signup Component and Opt-In Processes
- The archive page embeds the signup component, and the footer includes a compact variant.
- Both derive the ConvertKit form ID from site settings and submit to ConvertKit.
Section sources
- [newsletters.njk:57-70](file://src/newsletters.njk#L57-L70)
- [newsletter-signup.njk:1-27](file://src/_includes/macros/newsletter-signup.njk#L1-L27)
- [base.njk:207-216](file://src/_includes/layouts/base.njk#L207-L216)
- [site.json:13-13](file://src/_data/site.json#L13-L13)
Guidance on Segmentation, Personalization, and Engagement Tracking
- Segmentation:
- Use ConvertKit tags/lists to segment subscribers by interest or engagement level.
- Personalization:
- Tailor subject lines and preview text in ConvertKit campaigns to reflect issue themes.
- Engagement and conversion:
- Track open and click-through rates via ConvertKit analytics.
- Attribute conversions to specific newsletter issues by tagging or UTM parameters in archive links.
[No sources needed since this section provides general guidance]