diff --git a/.github/AGENTS.md b/.github/AGENTS.md index 4992d69..52595d5 100644 --- a/.github/AGENTS.md +++ b/.github/AGENTS.md @@ -14,7 +14,7 @@ CI, deployment, and repository automation under `.github/`. | File | Purpose | |------|---------| -| [dependabot.yml](dependabot.yml) | Weekly GitHub Actions version updates | +| [dependabot.yml](dependabot.yml) | Weekly GitHub Actions and pip (requirements-docs.txt) updates | | [lychee.toml](lychee.toml) | External link checker settings | | [ISSUE_TEMPLATE/](ISSUE_TEMPLATE/) | Issue form for content problems | | [PULL_REQUEST_TEMPLATE.md](PULL_REQUEST_TEMPLATE.md) | PR checklist for contributors | @@ -23,7 +23,7 @@ CI, deployment, and repository automation under `.github/`. - Pin actions to major version tags (e.g. `@v7`), consistent with existing files. - CI must stay fast: this repo is markdown-only. -- Pages workflow runs `scripts/prepare-mkdocs.py` before building; do not commit `docs/CONTRIBUTING.md`. +- Pages workflow runs `scripts/prepare-mkdocs.py` before building; do not commit `docs/CONTRIBUTING.md`, `docs/index.md`, or `docs/*/index.md`. - Required permissions: `contents: read` for CI; add `pages: write` and `id-token: write` for Pages deploy. ## Dependabot PRs diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5de3438..809d270 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,4 +8,4 @@ - [ ] Links are relative and resolve (`python scripts/check-internal-links.py`) - [ ] Markdown lint passes (`npx markdownlint-cli2 "**/*.md"`) -- [ ] Updated `docs/README.md` / root `README.md` if pages were added or moved +- [ ] New pages have an H1 (optional `nav_order` comment). Do not edit `mkdocs.yml` nav. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8004983..d3cf7c5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,3 +5,8 @@ updates: schedule: interval: weekly open-pull-requests-limit: 5 + - package-ecosystem: pip + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 diff --git a/.github/lychee.toml b/.github/lychee.toml index 98f3cd4..85f4578 100644 --- a/.github/lychee.toml +++ b/.github/lychee.toml @@ -8,4 +8,9 @@ user_agent = "Awesome-Ads-Link-Checker/1.0" exclude = [ "https://adespresso.com/wp-content/*", + "https://upload.wikimedia.org/*", + "https://www.canva.com/*", + "https://www.pexels.com/*", + "https://www.adobe.com/*", + "https://unsplash.com/*", ] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 57dc7f7..fa87d82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,9 +47,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 + with: + fetch-depth: 0 - uses: actions/setup-python@v7 with: python-version: "3.12" - run: pip install -r requirements-docs.txt + - run: python -m unittest scripts.test_catalog - run: python scripts/prepare-mkdocs.py - run: mkdocs build --strict diff --git a/.github/workflows/link-check-scheduled.yml b/.github/workflows/link-check-scheduled.yml index 7ec58b9..b3eeca3 100644 --- a/.github/workflows/link-check-scheduled.yml +++ b/.github/workflows/link-check-scheduled.yml @@ -14,6 +14,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: "3.12" + - name: Prepare generated docs + run: python scripts/prepare-mkdocs.py - uses: lycheeverse/lychee-action@v2 with: args: --config .github/lychee.toml "**/*.md" diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 41719c1..ee64b72 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -20,6 +20,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 + with: + fetch-depth: 0 - uses: actions/setup-python@v7 with: diff --git a/.gitignore b/.gitignore index 3765016..e411adf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,15 @@ research/ # MkDocs build output and generated site files site/ docs/CONTRIBUTING.md +docs/index.md +docs/channels/index.md +docs/resources/index.md +docs/ad-templates/index.md +docs/meta/index.md + +# Python +__pycache__/ +*.py[cod] # Secrets and local environment files .env diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc index 6de715b..791d1c2 100644 --- a/.markdownlint-cli2.jsonc +++ b/.markdownlint-cli2.jsonc @@ -2,6 +2,11 @@ "config": ".markdownlint.json", "ignores": [ "docs/CONTRIBUTING.md", + "docs/index.md", + "docs/channels/index.md", + "docs/resources/index.md", + "docs/ad-templates/index.md", + "docs/meta/index.md", "research/**" ] } diff --git a/AGENTS.md b/AGENTS.md index 4e7a7f4..1be5e11 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ Instructions for AI coding agents working in the Awesome Ads repository. ## Purpose -This repository is a **markdown documentation project**. There is no application runtime beyond GitHub Pages (MkDocs Material). Your job is usually to edit, add, or reorganize guides and keep links, CI, and navigation consistent. +This repository is a **markdown documentation project**. There is no application runtime beyond GitHub Pages (MkDocs Material). Your job is usually to edit, add, or reorganize guides. Keep links valid. Site navigation is generated from the docs folders at build time. ## Repository layout @@ -31,12 +31,7 @@ Each directory has its own `AGENTS.md` with scope-specific rules. Read the neare - **Audience:** Small-business owners and marketers. Write clearly; avoid jargon without explanation. - **Links:** Use relative paths only so pages work on GitHub and GitHub Pages. - **Filenames:** Keep existing UPPERCASE names for channel/resource files (e.g. `SEA.md`, `BUDGETING.md`). -- **Navigation:** When adding or renaming a page, update: - - [mkdocs.yml](mkdocs.yml) (site sidebar navigation) - - [docs/README.md](docs/README.md) - - [README.md](README.md) (if the page is linked from the landing page) - - [docs/index.md](docs/index.md) (if the page should appear on the site home page) - - [docs/meta/REPO_OUTLINE.md](docs/meta/REPO_OUTLINE.md) when structure changes +- **Navigation:** Add or rename a page by placing a markdown file in the right folder with an H1. Optional `` on the line after the H1 controls sidebar order. The GitHub Pages nav and indexes are generated at build time. Do not edit a page list in [mkdocs.yml](mkdocs.yml). - **Style:** No emojis in prose unless already present in a file you are not rewriting. Prefer complete sentences. Avoid em dashes in new copy; use commas, periods, or hyphens instead. - **Scope:** Do not expand scope into code, apps, or infrastructure unless explicitly requested. @@ -46,6 +41,7 @@ Run before opening a PR: ```bash npx markdownlint-cli2 "**/*.md" +python -m unittest scripts.test_catalog python scripts/check-public-repo-hygiene.py python scripts/check-internal-links.py python scripts/prepare-mkdocs.py @@ -61,11 +57,11 @@ Site config lives in [mkdocs.yml](mkdocs.yml). The [Deploy GitHub Pages](.github ## Do not - Commit secrets, credentials, API keys, tokens, or private keys. -- Commit local-only paths: `research/`, `site/`, `docs/CONTRIBUTING.md`, `.env`, or other generated build output. +- Commit local-only paths: `research/`, `site/`, `docs/CONTRIBUTING.md`, generated `docs/index.md` and `docs/*/index.md`, `.env`, or other generated build output. - Commit draft research, internal notes, or machine-local paths unless the user explicitly asks to publish them. - Use `git add -A` or `git add .` without reviewing the staged file list first. - Add unrelated tooling (frameworks, package.json, etc.) without explicit request. -- Break relative links or leave orphaned files out of the table of contents. +- Break relative links. - Run destructive git commands unless the user explicitly asks. - Push to the remote unless the user explicitly asks. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 11e0384..621880c 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,4 +2,6 @@ This project follows the [Community Guidelines](docs/meta/COMMUNITY_GUIDELINES.md). -Report unacceptable behavior via [GitHub Issues](https://github.com/TMHSDigital/Awesome-Ads/issues). +Report content problems via [GitHub Issues](https://github.com/TMHSDigital/Awesome-Ads/issues). + +Report harassment or other conduct violations privately. Do not open a public Issue for that. Contact the repository owner through their GitHub profile, or use GitHub's report-abuse tools. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 437dc88..07d2c82 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,7 +14,7 @@ We welcome contributions from the community! Follow these guidelines to help us └── scripts/ # Maintenance scripts (link checker) ``` -Add new channel guides under `docs/channels/`. Add cross-cutting topics under `docs/resources/`. Update [docs/README.md](docs/README.md) and the root [README.md](README.md) when adding pages. +Add new channel guides under `docs/channels/`. Add cross-cutting topics under `docs/resources/`. The site nav is generated at build time from those folders. Start each page with an H1. Optional `` on the next line controls sidebar order. ## How to contribute @@ -32,6 +32,7 @@ Add new channel guides under `docs/channels/`. Add cross-cutting topics under `d 5. **Verify locally** ```bash npx markdownlint-cli2 "**/*.md" + python -m unittest scripts.test_catalog python scripts/check-public-repo-hygiene.py python scripts/check-internal-links.py python scripts/prepare-mkdocs.py @@ -61,7 +62,7 @@ Open the local URL printed by `mkdocs serve` (typically port 8000). - Write clear, accurate prose aimed at small-business readers. - Use relative links so pages work on GitHub and GitHub Pages. - End markdown files with a single trailing newline. -- Update the table of contents when adding or renaming pages. +- The published site catalog is generated from the docs folders. Do not maintain a second page list. ## Issues and bug reports diff --git a/README.md b/README.md index 82dbb8c..94b4f4c 100644 --- a/README.md +++ b/README.md @@ -8,36 +8,11 @@ Awesome Ads is an open reference for planning, launching, and refining campaigns | | | |---|---| -| **Full index** | [docs/README.md](docs/README.md) | | **Published site** | [tmhsdigital.github.io/Awesome-Ads](https://tmhsdigital.github.io/Awesome-Ads/) | +| **Source** | [docs/](docs/) | | **Contributing** | [CONTRIBUTING.md](CONTRIBUTING.md) | -## Channels - -Guides for each major advertising channel, from setup through optimization. - -| Channel | Guide | Channel | Guide | -|---------|-------|---------|-------| -| Search (SEA) | [SEA](docs/channels/SEA.md) | Social | [SOCIAL](docs/channels/SOCIAL.md) | -| Display | [DISPLAY](docs/channels/DISPLAY.md) | Video | [VIDEO](docs/channels/VIDEO.md) | -| Email | [EMAIL](docs/channels/EMAIL.md) | Native | [NATIVE](docs/channels/NATIVE.md) | -| Affiliate | [AFFILIATE](docs/channels/AFFILIATE.md) | Influencer | [INFLUENCER](docs/channels/INFLUENCER.md) | -| Print | [PRINT](docs/channels/PRINT.md) | Broadcast | [BROADCAST](docs/channels/BROADCAST.md) | -| Out-of-home | [OOH](docs/channels/OOH.md) | Direct mail | [DIRECT_MAIL](docs/channels/DIRECT_MAIL.md) | -| Event sponsorship | [EVENT](docs/channels/EVENT.md) | | | - -## Resources - -Cross-cutting topics that apply across channels. - -| Topic | Guide | -|-------|-------| -| Analytics and reporting | [ANALYTICS](docs/resources/ANALYTICS.md) | -| Budgeting and planning | [BUDGETING](docs/resources/BUDGETING.md) | -| Legal and ethical considerations | [LEGAL](docs/resources/LEGAL.md) | -| Campaign examples | [EXAMPLES](docs/resources/EXAMPLES.md) | -| FAQ and troubleshooting | [FAQ](docs/resources/FAQ.md) | -| Templates and design | [TEMPLATES](docs/ad-templates/TEMPLATES.md) | +The GitHub Pages sidebar, home page, and section indexes are generated at build time from the markdown files under `docs/channels/`, `docs/resources/`, `docs/ad-templates/`, and `docs/meta/`. Add a file with an H1 and it appears on the next deploy. ## For contributors and agents diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 2938afa..bf32b43 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -13,7 +13,7 @@ You are working inside the `docs/` tree. All user-facing guides live here. ## Index -[README.md](README.md) is the canonical table of contents for this folder. Keep it in sync when adding or removing pages. Also update [mkdocs.yml](../mkdocs.yml) navigation and [index.md](index.md) when the change affects the published site. +[README.md](README.md) points at the published site. Home and section indexes are generated at build time from the markdown files in each subdirectory. Do not hand-edit `index.md` files under `docs/`. ## Link conventions @@ -21,18 +21,15 @@ Links between docs should be **relative to the current file**: - From `docs/README.md` to a channel: `channels/SEA.md` - From `docs/channels/SEA.md` to a resource: `../resources/ANALYTICS.md` -- From `docs/ad-templates/SOCIAL_MEDIA.md` to the hub: `TEMPLATES.md` +- From `docs/ad-templates/TEMPLATES.md` to a channel: `../channels/SOCIAL.md` Links from the root [README.md](../README.md) use the `docs/` prefix (e.g. `docs/channels/SEA.md`). ## Adding a new page 1. Place the file in the correct subdirectory (`channels/`, `resources/`, or `ad-templates/`). -2. Add an entry to [README.md](README.md) and [mkdocs.yml](../mkdocs.yml). -3. Update the root [README.md](../README.md) if the page should appear on the landing page. -4. Update [index.md](index.md) if the page should appear on the site home page. -5. Update [meta/REPO_OUTLINE.md](meta/REPO_OUTLINE.md) for structural changes. -6. Run validation from the repo root (see [CONTRIBUTING.md](../CONTRIBUTING.md)). +2. Start the file with an H1. Optional `` on the next line controls sidebar order. +3. Run validation from the repo root (see [CONTRIBUTING.md](../CONTRIBUTING.md)). ## Content standards diff --git a/docs/README.md b/docs/README.md index 9534350..a063956 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,35 +1,10 @@ # Awesome Ads — Documentation -## Advertising channels +Source files for the published site live in the subfolders of this directory. The live catalog is generated at build time. -1. [Search Engine Advertising (SEA)](channels/SEA.md) -2. [Social Media Advertising](channels/SOCIAL.md) -3. [Display Advertising](channels/DISPLAY.md) -4. [Video Advertising](channels/VIDEO.md) -5. [Email Marketing](channels/EMAIL.md) -6. [Native Advertising](channels/NATIVE.md) -7. [Affiliate Marketing](channels/AFFILIATE.md) -8. [Influencer Marketing](channels/INFLUENCER.md) -9. [Print Advertising](channels/PRINT.md) -10. [Broadcast Advertising](channels/BROADCAST.md) -11. [Out-of-Home (OOH) Advertising](channels/OOH.md) -12. [Direct Mail](channels/DIRECT_MAIL.md) -13. [Event Sponsorship](channels/EVENT.md) +Browse the guides at [tmhsdigital.github.io/Awesome-Ads](https://tmhsdigital.github.io/Awesome-Ads/). -## Additional resources - -1. [Analytics and Reporting](resources/ANALYTICS.md) -2. [Ad Budgeting and Planning](resources/BUDGETING.md) -3. [Legal and Ethical Considerations](resources/LEGAL.md) -4. [Examples of Successful Ad Campaigns](resources/EXAMPLES.md) -5. [Ad Templates and Design Resources](ad-templates/TEMPLATES.md) - - [Social Media Ad Templates](ad-templates/SOCIAL_MEDIA.md) - - [Display Ad Templates](ad-templates/DISPLAY_ADS.md) - - [Video Ad Templates](ad-templates/VIDEO_ADS.md) - - [Email Marketing Templates](ad-templates/EMAIL_MARKETING.md) -6. [FAQ and Troubleshooting](resources/FAQ.md) - -## Meta - -- [Repository outline](meta/REPO_OUTLINE.md) -- [Community guidelines](meta/COMMUNITY_GUIDELINES.md) +- [channels/](channels/) — one guide per advertising channel +- [resources/](resources/) — analytics, budgeting, legal, examples, FAQ +- [ad-templates/](ad-templates/) — templates and design resources +- [meta/](meta/) — repository outline and community guidelines diff --git a/docs/ad-templates/AGENTS.md b/docs/ad-templates/AGENTS.md index eec9e64..1539b6b 100644 --- a/docs/ad-templates/AGENTS.md +++ b/docs/ad-templates/AGENTS.md @@ -1,32 +1,16 @@ # Agents: Templates -Ad template overviews and format-specific companion pages. The hub is [TEMPLATES.md](TEMPLATES.md); child pages drill into social, display, video, and email formats. - -## Files - -| File | Role | -|------|------| -| `TEMPLATES.md` | Hub: template types, design tools, stock assets, high-level design tips | -| `SOCIAL_MEDIA.md` | Social media ad templates | -| `DISPLAY_ADS.md` | Display ad templates | -| `VIDEO_ADS.md` | Video ad templates | -| `EMAIL_MARKETING.md` | Email marketing templates | +Ad template overviews. The hub is [TEMPLATES.md](TEMPLATES.md). Additional format-specific pages in this folder are picked up by the catalog automatically. ## Structure -- **Hub (`TEMPLATES.md`):** Broad coverage of tools (Canva, Adobe, stock libraries) and design principles. May include image assets via external URLs. -- **Child pages:** Shorter format-specific summaries that link back to the hub with `[TEMPLATES.md](TEMPLATES.md)`. - -## When editing - -- Keep sibling pages roughly consistent in length and depth. -- Prefer linking to the hub for shared design advice rather than duplicating "Tools and Resources" lists. -- External image URLs (Wikimedia, vendor CDNs) are intentional; do not replace with broken local paths. +- **Hub (`TEMPLATES.md`):** Tools and design principles. Prefer official vendor URLs over hotlinked logos. +- **Optional companions:** Format-specific pages should link back to the hub with `[TEMPLATES.md](TEMPLATES.md)`. ## When adding a template category -1. Add `NEW_FORMAT.md` in this directory. -2. Add a bullet under ad-templates in [../README.md](../README.md), [mkdocs.yml](../../mkdocs.yml), and the root [README.md](../../README.md). +1. Add `NEW_FORMAT.md` in this directory with an H1. +2. Optional `` on the next line. 3. Cross-link from [TEMPLATES.md](TEMPLATES.md). ## Parent context diff --git a/docs/ad-templates/DISPLAY_ADS.md b/docs/ad-templates/DISPLAY_ADS.md deleted file mode 100644 index 097ffc0..0000000 --- a/docs/ad-templates/DISPLAY_ADS.md +++ /dev/null @@ -1,11 +0,0 @@ -# Display Ad Templates - -Templates for banner, rich media, and interstitial display advertising. - -## Formats - -- Static and animated banner ads -- Interactive rich media ads -- Full-screen interstitial ads - -See [Ad Templates and Design Resources](TEMPLATES.md) for design tools and tips. diff --git a/docs/ad-templates/EMAIL_MARKETING.md b/docs/ad-templates/EMAIL_MARKETING.md deleted file mode 100644 index 5320edd..0000000 --- a/docs/ad-templates/EMAIL_MARKETING.md +++ /dev/null @@ -1,11 +0,0 @@ -# Email Marketing Templates - -Templates for newsletters, promotions, and transactional email campaigns. - -## Formats - -- Newsletter templates for regular updates -- Promotional emails for offers and announcements -- Transactional emails for orders and shipping - -See [Ad Templates and Design Resources](TEMPLATES.md) for design tools and tips. diff --git a/docs/ad-templates/SOCIAL_MEDIA.md b/docs/ad-templates/SOCIAL_MEDIA.md deleted file mode 100644 index 4162fe1..0000000 --- a/docs/ad-templates/SOCIAL_MEDIA.md +++ /dev/null @@ -1,11 +0,0 @@ -# Social Media Ad Templates - -Templates and examples for social media advertising across major platforms. - -## Platforms - -- Facebook and Instagram image, video, carousel, and story ads -- Twitter promoted tweets and video ads -- LinkedIn sponsored content and InMail - -See [Ad Templates and Design Resources](TEMPLATES.md) for design tools and tips. diff --git a/docs/ad-templates/TEMPLATES.md b/docs/ad-templates/TEMPLATES.md index 8512983..7840dab 100644 --- a/docs/ad-templates/TEMPLATES.md +++ b/docs/ad-templates/TEMPLATES.md @@ -1,13 +1,15 @@ # Ad Templates and Design Resources + -Accessing high-quality ad templates and design resources can significantly streamline the creation of effective advertisements. +High-quality templates and design tools speed up ad production without requiring a full creative team. ## Types of Ad Templates ### 1. Social Media Ad Templates -- **Facebook and Instagram:** Templates for image, video, carousel, and story ads. -- **Twitter:** Templates for promoted tweets and video ads. -- **LinkedIn:** Templates for sponsored content and InMail. +- **Facebook and Instagram:** Image, video, carousel, story, and Reels ads. +- **X:** Promoted posts and video ads. +- **LinkedIn:** Sponsored content and Message Ads. +- **TikTok:** In-feed and Spark Ads in vertical 9:16. ### 2. Display Ad Templates - **Banner Ads:** Static and animated templates. @@ -15,62 +17,44 @@ Accessing high-quality ad templates and design resources can significantly strea - **Interstitial Ads:** Full-screen ad templates. ### 3. Video Ad Templates -- **YouTube Ads:** In-stream and discovery ad templates. -- **Social Media Video Ads:** Templates for Facebook, Instagram, and TikTok videos. +- **YouTube Ads:** In-stream, Shorts, and in-feed ad templates. +- **Social video:** Templates for Meta Reels, TikTok, and YouTube Shorts. ### 4. Email Marketing Templates -- **Newsletters:** Customizable templates for regular updates. -- **Promotional Emails:** Templates for special offers and announcements. -- **Transactional Emails:** Templates for order confirmations and shipping notifications. +- **Newsletters:** Regular updates and education. +- **Promotional Emails:** Offers and announcements. +- **Transactional Emails:** Orders, shipping, and account messages. ## Design Resources -### 1. Graphic Design Tools -- **Canva:** Easy-to-use online design tool. - - ![Canva](https://upload.wikimedia.org/wikipedia/commons/3/33/Canva_Logo.png) - - [Canva](https://www.canva.com/) -- **Adobe Creative Cloud:** Professional design suite. - - ![Adobe Creative Cloud](https://upload.wikimedia.org/wikipedia/commons/3/31/Adobe_Creative_Cloud_Logo.svg) - - [Adobe Creative Cloud](https://www.adobe.com/creativecloud.html) - -### 2. Stock Images and Videos -- **Unsplash:** Free high-quality images. - - ![Unsplash](https://upload.wikimedia.org/wikipedia/commons/4/4a/Unsplash-logo.png) - - [Unsplash](https://unsplash.com/) -- **Pexels:** Free stock photos and videos. - - ![Pexels](https://upload.wikimedia.org/wikipedia/commons/e/e5/Pexels_logo.png) - - [Pexels](https://www.pexels.com/) - -### 3. Icon Libraries -- **Font Awesome:** Extensive icon library. - - ![Font Awesome](https://upload.wikimedia.org/wikipedia/commons/d/d7/Font_Awesome_Logo.svg) - - [Font Awesome](https://fontawesome.com/) -- **Material Icons:** Google's icon library. - - ![Material Icons](https://upload.wikimedia.org/wikipedia/commons/3/34/Material_Icons_logo.png) - - [Material Icons](https://material.io/resources/icons/) +### Graphic Design Tools +- [Canva](https://www.canva.com/) +- [Adobe Creative Cloud](https://www.adobe.com/creativecloud.html) + +### Stock Images and Videos +- [Unsplash](https://unsplash.com/) +- [Pexels](https://www.pexels.com/) + +### Icon Libraries +- [Font Awesome](https://fontawesome.com/) +- [Google Fonts Icons (Material)](https://fonts.google.com/icons) ## High-Level Design Tips -### 1. Keep It Simple -- **Clear Messaging:** Ensure your message is concise and clear. -- **Minimalist Design:** Avoid clutter and focus on key elements. - -### 2. Visual Hierarchy -- **Attention-Grabbing Headlines:** Use bold headlines to draw attention. -- **Strong CTAs:** Make your call-to-action (CTA) prominent and compelling. - -### 3. Consistency -- **Brand Colors and Fonts:** Use consistent colors and fonts to reinforce brand identity. -- **Layout Consistency:** Maintain a consistent layout across all ads. - -### 4. Mobile Optimization -- **Responsive Design:** Ensure your ads look great on all devices. -- **Fast Loading:** Optimize images and videos for quick loading times. - -## Tools and Resources -- [Canva](https://www.canva.com/) ![Canva](https://upload.wikimedia.org/wikipedia/commons/3/33/Canva_Logo.png) -- [Adobe Creative Cloud](https://www.adobe.com/creativecloud.html) ![Adobe Creative Cloud](https://upload.wikimedia.org/wikipedia/commons/3/31/Adobe_Creative_Cloud_Logo.svg) -- [Unsplash](https://unsplash.com/) ![Unsplash](https://upload.wikimedia.org/wikipedia/commons/4/4a/Unsplash-logo.png) -- [Pexels](https://www.pexels.com/) ![Pexels](https://upload.wikimedia.org/wikipedia/commons/e/e5/Pexels_logo.png) -- [Font Awesome](https://fontawesome.com/) ![Font Awesome](https://upload.wikimedia.org/wikipedia/commons/d/d7/Font_Awesome_Logo.svg) -- [Material Icons](https://material.io/resources/icons/) ![Material Icons](https://upload.wikimedia.org/wikipedia/commons/3/34/Material_Icons_logo.png) +### Keep It Simple +- **Clear messaging:** One idea per ad. +- **Minimalist design:** Drop clutter. Keep the product and CTA visible. + +### Visual Hierarchy +- **Headlines first:** Bold type that reads at thumbnail size. +- **Strong CTAs:** The action should be obvious on mobile. + +### Consistency +- **Brand colors and fonts:** Reuse the same kit across channels. +- **Layout consistency:** Same structure, swapped offers. + +### Mobile Optimization +- **Responsive design:** Check every size the platform actually serves. +- **Fast loading:** Compress images and keep video under platform file limits. + +See [Social Media Advertising](../channels/SOCIAL.md), [Display Advertising](../channels/DISPLAY.md), [Video Advertising](../channels/VIDEO.md), and [Email Marketing](../channels/EMAIL.md) for channel-specific formats. diff --git a/docs/ad-templates/VIDEO_ADS.md b/docs/ad-templates/VIDEO_ADS.md deleted file mode 100644 index ad488aa..0000000 --- a/docs/ad-templates/VIDEO_ADS.md +++ /dev/null @@ -1,10 +0,0 @@ -# Video Ad Templates - -Templates for video advertising on YouTube and social platforms. - -## Formats - -- YouTube in-stream and discovery ads -- Facebook, Instagram, and TikTok video ads - -See [Ad Templates and Design Resources](TEMPLATES.md) for design tools and tips. diff --git a/docs/channels/AFFILIATE.md b/docs/channels/AFFILIATE.md index 21c20fe..e445c42 100644 --- a/docs/channels/AFFILIATE.md +++ b/docs/channels/AFFILIATE.md @@ -1,4 +1,5 @@ # Affiliate Marketing + Affiliate marketing partners with third-party publishers who promote your products or services in exchange for a commission tied to specific outcomes. The model has evolved significantly: **payment structures are shifting to recurring and tiered models**, and traditional 30-day last-click attribution has become largely obsolete. @@ -28,7 +29,7 @@ Traditional 30-day last-click attribution relied on browser cookies to credit th **Impact:** Affiliates with long consideration cycles (editorial reviewers, comparison sites) are being undercredited, while coupon and cashback browser extensions that intercept buyers at checkout are being over-credited. -**Solution — Tiered Commission Structures:** Modern networks like [Impact](https://impact.com/) and [ShareASale](https://www.shareasale.com/) support tiered commission structures. This allows you to reward mid-funnel content creators who drive early consideration at a higher rate while reducing payouts to last-touch coupon interceptors. +**Solution: tiered commissions.** Modern networks like [Impact](https://impact.com/) and [Awin](https://www.awin.com/) (ShareASale now redirects here) support tiered commission structures. Reward mid-funnel creators who drive consideration at a higher rate and reduce payouts to last-touch coupon interceptors. --- @@ -63,8 +64,13 @@ Traditional 30-day last-click attribution relied on browser cookies to credit th ## Tools and Resources - [Impact](https://impact.com/) — advanced attribution and tiered commission support -- [ShareASale](https://www.shareasale.com/) - [CJ Affiliate](https://www.cj.com/) - [Rakuten Advertising](https://rakutenadvertising.com/) - [Awin](https://www.awin.com/) - [Amazon Associates](https://affiliate-program.amazon.com/) + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/AGENTS.md b/docs/channels/AGENTS.md index c248c6f..615397e 100644 --- a/docs/channels/AGENTS.md +++ b/docs/channels/AGENTS.md @@ -2,23 +2,7 @@ This directory contains **one guide per advertising channel**. Each file is a standalone reference for small businesses evaluating or running that channel. -## Files - -| File | Topic | -|------|-------| -| `SEA.md` | Search engine advertising (Google Ads, Bing Ads) | -| `SOCIAL.md` | Social media advertising | -| `DISPLAY.md` | Display and banner advertising | -| `VIDEO.md` | Video advertising | -| `EMAIL.md` | Email marketing | -| `NATIVE.md` | Native advertising | -| `AFFILIATE.md` | Affiliate marketing | -| `INFLUENCER.md` | Influencer marketing | -| `PRINT.md` | Print advertising | -| `BROADCAST.md` | Television and radio | -| `OOH.md` | Out-of-home advertising | -| `DIRECT_MAIL.md` | Direct mail | -| `EVENT.md` | Event sponsorship | +The markdown files in this directory are the catalog. Site nav is generated from them at build time. Keep UPPERCASE names (`SEA.md`, `SOCIAL.md`). ## Expected structure @@ -37,13 +21,14 @@ You may add sections when the channel warrants it, but keep the same tone and de - Preserve filename casing (`SEA.md`, not `sea.md`). - Link to related **resources** with relative paths: `../resources/BUDGETING.md`, `../resources/LEGAL.md`. - Link to **ad-templates** when relevant: `../ad-templates/TEMPLATES.md`. -- Do not move channel files out of this directory without updating all indexes and CI. +- Do not move channel files out of this directory without updating links that point here. ## When adding a new channel -1. Create `NEWCHANNEL.md` in this directory. -2. Update [../README.md](../README.md), [../../README.md](../../README.md), and [../meta/REPO_OUTLINE.md](../meta/REPO_OUTLINE.md). -3. Run the internal link checker. +1. Create `NEWCHANNEL.md` in this directory with an H1 on line 1. +2. Optional: `` on the next line. Omit it to sort last in the section. +3. Link to [BUDGETING.md](../resources/BUDGETING.md), [ANALYTICS.md](../resources/ANALYTICS.md), and [LEGAL.md](../resources/LEGAL.md). +4. Run the validation commands in [CONTRIBUTING.md](../../CONTRIBUTING.md). ## Parent context diff --git a/docs/channels/AMAZON.md b/docs/channels/AMAZON.md new file mode 100644 index 0000000..0ecd7a9 --- /dev/null +++ b/docs/channels/AMAZON.md @@ -0,0 +1,68 @@ +# Amazon Ads + + +Amazon Ads are table stakes for product brands that sell on Amazon. Shoppers who search a category often never leave the marketplace, so if you are not in the sponsored slots you are invisible. Rising CPCs punish weak listings. Fix the product detail page before you scale spend. + +This is retail media, not a general awareness buy. Pair it with [Search Engine Advertising (SEA)](SEA.md) only when you also need off-Amazon demand. + +## Ad types + +### Sponsored Products +- Keyword-targeted placements on search and product pages. +- Start with exact and phrase match on converting queries. Add negatives weekly. + +### Sponsored Brands +- Headline search and detail-page custom images for the brand, not a single SKU. +- Use when you have several related ASINs and a storefront. + +### Sponsored Display +- Audience and product-targeting on and off Amazon. +- Useful for retargeting detail-page viewers. Do not treat it as cheap display. + +### Amazon DSP +- Programmatic audiences across Amazon properties. Minimums and complexity are higher. Most SMBs should master Sponsored Products first. + +## Listing and search hygiene + +Ads will not save a weak PDP. Before you raise bids: + +- Hero images and A+ content that match the query. +- Title and bullets that include the long-tail phrases people actually search. +- Reviews and Q&A that do not contradict the ad claim. +- Inventory and buy-box control. Ads that land on an out-of-stock or competitor buy box burn cash. + +Treat listing copy as Answer Engine Optimization: shoppers and Amazon's ranking both reward specific, scannable answers. + +## 2026 cost posture + +Amazon search CPCs have climbed with competition. Run ads in parallel with organic ranking work. Use long-tail terms first. Broad match without negatives is an expensive way to learn. + +Track TACOS (total ad cost of sales) and organic rank, not only ACOS on the ad campaign. Ads can lift rank, then you can taper bids. + +## Benefits + +- High purchase intent inside a checkout environment. +- Closed-loop sales reporting in Amazon. +- Defend brand terms so competitors cannot sit on your name. + +## Setting Up Amazon Ads + +1. **Register in Amazon Ads** and connect the seller or vendor account. +2. **Fix the PDP** for your hero ASINs. +3. **Launch a small Sponsored Products campaign** on exact match converting keywords. +4. **Add negatives** from search term reports twice a week at first. +5. **Expand** to Sponsored Brands once conversion is stable. +6. **Export** reports into your own sheet. Do not rely on Amazon's UI as the only source of truth. See [Analytics and Reporting](../resources/ANALYTICS.md). + +## Tools and Resources + +- [Amazon Ads](https://advertising.amazon.com/) +- [Amazon Seller Central](https://sellercentral.amazon.com/) +- [Amazon Associates](https://affiliate-program.amazon.com/) for off-Amazon affiliate traffic + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) +- [Search Engine Advertising (SEA)](SEA.md) diff --git a/docs/channels/BROADCAST.md b/docs/channels/BROADCAST.md index d8a0629..c150b7e 100644 --- a/docs/channels/BROADCAST.md +++ b/docs/channels/BROADCAST.md @@ -1,4 +1,5 @@ # Broadcast Advertising + Broadcast advertising covers television and radio. Linear broadcast has seen persistent budget redirection as small businesses shift toward measurable, programmatic alternatives. The most important development for SMBs: **Connected TV (CTV) has become a performance channel accessible from $50**, fundamentally changing what "TV advertising" means for small businesses. @@ -30,6 +31,8 @@ Programmatic CTV has crossed a critical structural milestone: - **[Roku Ads Manager](https://advertising.roku.com/):** Access to Roku's streaming inventory. - **[Tatari](https://www.tatari.tv/):** TV buying and measurement for growth-stage brands. +YouTube in-stream, Shorts, and shoppable CTV units are covered in [Video Advertising](VIDEO.md). + --- ## Traditional Television Ads @@ -94,3 +97,10 @@ See [Spotify Advertising](https://ads.spotify.com/) for self-serve audio options - [Spotify Advertising](https://ads.spotify.com/) - [Ad Agencies: Ogilvy, Wieden+Kennedy] — for linear broadcast production - [Production Services: Fiverr, Upwork] — for affordable local radio and video spots + +## Related guides + +- [Video Advertising](VIDEO.md) +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/DIRECT_MAIL.md b/docs/channels/DIRECT_MAIL.md index 30f8aee..46f76e7 100644 --- a/docs/channels/DIRECT_MAIL.md +++ b/docs/channels/DIRECT_MAIL.md @@ -1,4 +1,5 @@ # Direct Mail Advertising + Direct mail involves sending physical promotional materials to potential or existing customers. The channel has evolved in two directions: **programmatic retargeting** (automated physical mail triggered by digital behavior) and **traditional bulk mail** (geographic saturation via EDDM). Programmatic direct mail in particular has demonstrated strong ROI in high-ticket service categories. @@ -91,3 +92,9 @@ Most programmatic mail platforms handle NCOA/CASS automatically. For self-manage - [Vistaprint](https://www.vistaprint.com/) / [Moo](https://www.moo.com/) — print design and production - [PostcardMania](https://www.postcardmania.com/) — full-service direct mail campaigns - [Adobe InDesign](https://www.adobe.com/products/indesign.html) / [Canva](https://www.canva.com/) — design tools + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/DISPLAY.md b/docs/channels/DISPLAY.md index e13b41a..fc3b152 100644 --- a/docs/channels/DISPLAY.md +++ b/docs/channels/DISPLAY.md @@ -1,4 +1,5 @@ # Display Advertising + Display advertising uses visual ads — banners, graphics, and rich media — shown across websites, apps, and ad networks. Traditional display faces reduced conversion stability due to browser-level cookie blocking; the channel is undergoing a structural pivot toward contextual and first-party audience targeting. @@ -63,3 +64,9 @@ Display maintains cheap cost-per-click relative to high-intent search, making it - [AdRoll](https://www.adroll.com/) - [StackAdapt](https://www.stackadapt.com/) - [Media.net](https://www.media.net/) + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/EMAIL.md b/docs/channels/EMAIL.md index c1140f5..29fa0c3 100644 --- a/docs/channels/EMAIL.md +++ b/docs/channels/EMAIL.md @@ -1,36 +1,59 @@ # Email Marketing + -Email marketing involves sending promotional messages or newsletters to a list of subscribers via email. +Email is owned audience infrastructure, not another rented ad auction. For small businesses, it is the cheapest retention and nurturing channel once a permissioned list exists. Treat it as first-party data, not a blast tool. + +Commercial email is regulated. Read [Legal and Ethical Considerations](../resources/LEGAL.md) before you send a promotional campaign. ## Types of Email Marketing ### 1. Newsletters -- **Regular Updates:** Share news, tips, and updates with subscribers. -- **Educational Content:** Provide valuable information to your audience. +- Regular updates, tips, and education that keep the list warm. +- Best cadence is one you can sustain. Weekly is not required. ### 2. Promotional Emails -- **Special Offers:** Discounts, sales, or limited-time offers. -- **Product Announcements:** Introduce new products or services. +- Offers, launches, and seasonal campaigns. +- Segment by purchase history and recency. Do not send the same discount to everyone. + +### 3. Lifecycle and transactional +- Welcome series, abandoned cart or quote follow-up, post-purchase, win-back. +- Transactional messages (order and shipping) convert well when they stay useful and still include a clear unsubscribe on any marketing add-on. + +### 4. SMS as a companion +- If you collect mobile numbers with separate consent, use SMS for time-sensitive offers. Keep email as the long-form channel. Budget 5 to 10 percent of a small media mix for email and SMS tools combined. + +## 2026 operating notes -### 3. Transactional Emails -- **Order Confirmations:** Details of purchases. -- **Shipping Notifications:** Updates on shipping status. +- Lists beat pixels. Browser tracking is weaker every year, so an opted-in email list is a primary conversion asset. See [Analytics and Reporting](../resources/ANALYTICS.md). +- Consent is not a pre-checked box. Collect emails through a form that states what people will receive. +- Deliverability depends on list hygiene. Remove hard bounces and chronic non-openers instead of buying lists. ## Benefits -- **Direct Communication:** Reach subscribers directly. -- **Personalized Content:** Tailor messages to individual preferences. -- **Measurable Results:** Track open rates, clicks, and conversions. + +- Direct reach to people who already said yes. +- Personalization from first-party data you control. +- Measurable opens, clicks, and revenue when UTMs and conversion events are set up. ## Setting Up Email Marketing -1. **Build an Email List:** Collect email addresses through sign-ups. -2. **Create Engaging Content:** Develop compelling and relevant emails. -3. **Segment Your Audience:** Group subscribers based on behavior and preferences. -4. **Monitor and Optimize:** Track performance and adjust strategies. + +1. **Choose a platform** that supports double opt-in, unsubscribe, and a physical address footer (CAN-SPAM). +2. **Build the list** from your site, checkout, and in-store. Never buy lists. +3. **Write one welcome flow** before you write a newsletter. Most revenue sits in automation. +4. **Segment** by source, purchase, and engagement. +5. **Authenticate** the domain (SPF, DKIM, DMARC) so providers do not junk you. +6. **Monitor** bounce rate, complaint rate, and unsubscribe rate weekly. ## Tools and Resources + +- [Brevo](https://www.brevo.com/) (formerly Sendinblue) +- [Klaviyo](https://www.klaviyo.com/) - [Mailchimp](https://mailchimp.com/) -- [Constant Contact](https://www.constantcontact.com/) -- [SendinBlue](https://www.sendinblue.com/) -- [HubSpot](https://www.hubspot.com/products/marketing/email) -- [AWeber](https://www.aweber.com/) +- [HubSpot Email](https://www.hubspot.com/products/marketing/email) +- [FTC CAN-SPAM guide](https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business) + +## Related guides +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) +- [Ad Templates and Design Resources](../ad-templates/TEMPLATES.md) diff --git a/docs/channels/EVENT.md b/docs/channels/EVENT.md index 656e5c4..66764b1 100644 --- a/docs/channels/EVENT.md +++ b/docs/channels/EVENT.md @@ -1,4 +1,5 @@ # Event Sponsorship + Event sponsorship involves supporting events financially or through in-kind contributions in exchange for brand exposure and audience access. The model has shifted from passive logo placement to **value-driven, experiential partnerships** with verified attendee profiles. Nearly **60% of event organizers** still evaluate sponsorship ROI inconsistently — creating both a challenge and an opportunity for sponsors who demand clear deliverables upfront. @@ -89,3 +90,9 @@ Use unique promo codes, dedicated landing page URLs, or QR codes at your booth t - [SponsorMyEvent](https://www.sponsormyevent.com/) — sponsorship marketplace - [Bizzabo](https://www.bizzabo.com/) — event management with attendee analytics - [Local Chambers of Commerce] — introductions to community events + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/INFLUENCER.md b/docs/channels/INFLUENCER.md index 36bb873..68f8a84 100644 --- a/docs/channels/INFLUENCER.md +++ b/docs/channels/INFLUENCER.md @@ -1,4 +1,5 @@ # Influencer Marketing + Influencer marketing involves partnering with individuals who have established audiences on social platforms to promote your products or services. The industry has matured significantly — pricing now reflects format complexity and engagement quality over follower counts, and compliance enforcement has intensified. @@ -90,3 +91,9 @@ Small businesses running influencer campaigns must maintain a written disclosure 4. **Set terms in writing:** Deliverables, timeline, usage rights (especially for repurposing as paid ads), and disclosure requirements. 5. **Brief but don't script:** Provide talking points, key claims, and brand guidelines — over-scripting kills authenticity. 6. **Track performance:** Use unique UTM links or discount codes; request creator analytics screenshots post-campaign. + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/NATIVE.md b/docs/channels/NATIVE.md index adc356b..9121f7f 100644 --- a/docs/channels/NATIVE.md +++ b/docs/channels/NATIVE.md @@ -1,38 +1,57 @@ # Native Advertising + -Native advertising involves creating ads that blend seamlessly with the content on the platform where they appear, providing a non-disruptive user experience. +Native ads match the look of the surrounding content so they feel like part of the page or feed. That is also why they are a compliance risk. If a reader cannot tell it is paid, you are offside of FTC native advertising rules. Label it "Sponsored" or "Advertisement" in the unit itself, not only in a footer. + +Promoted product listings on Amazon are a different channel. See [Amazon Ads](AMAZON.md). ## Types of Native Advertising -### 1. Sponsored Content -- **Articles:** Branded content published on news sites or blogs. -- **Videos:** Branded videos that appear in the feed of social media platforms. +### 1. Sponsored content +- Branded articles or videos on publisher sites. +- Must not mimic an independent editorial if the commercial relationship is hidden. + +### 2. In-feed ads +- Units inside social or content feeds. Treat Meta, LinkedIn, and similar placements as native in-feed, but run them from those platforms' ad managers. See [Social Media Advertising](SOCIAL.md). -### 2. In-Feed Ads -- **Social Media Feeds:** Ads that appear in the feed of social platforms like Facebook, Twitter, Instagram, and LinkedIn. +### 3. Recommendation widgets +- "Around the web" modules from Taboola, Outbrain, and similar networks. +- Traffic quality varies. Start with a tight allowlist of publishers and watch bounce rate. -### 3. Recommendation Widgets -- **Content Recommendations:** Appear at the end of articles or within the content, suggesting related content. +### 4. Search and promoted listings +- Retail media and marketplace listings. Amazon, Etsy, and similar surfaces belong with those product catalogs, not a generic native buy. -### 4. Search and Promoted Listings -- **Search Ads:** Ads that appear at the top of search engine results pages. -- **Promoted Listings:** Ads that appear on e-commerce platforms like Amazon or Etsy. +## Disclosure + +- Use unambiguous labels: Sponsored, Advertisement, or Paid content. +- Platform UI badges are not enough if the body copy still reads as independent journalism. +- Influencer-style native posts follow the same FTC rules as [Influencer Marketing](INFLUENCER.md). ## Benefits -- **Non-Disruptive:** Ads blend with the content, enhancing user experience. -- **Higher Engagement:** Users interact more with native ads compared to traditional ads. -- **Trust Building:** Provides value through informative content. + +- Higher engagement than banner inventory when the content is actually useful. +- Less interruptive than interstitials. +- Useful for education-heavy offers (B2B, health, home services) if disclosure is clean. ## Setting Up Native Ads -1. **Choose the Platform:** Select platforms that align with your audience. -2. **Create Relevant Content:** Develop content that matches the platform’s style and user expectations. -3. **Define Target Audience:** Use targeting options to reach the right audience. -4. **Monitor and Optimize:** Track performance and refine the ads for better results. + +1. **Pick the surface:** publisher network vs in-feed social vs marketplace. +2. **Write to the host format**, then add the paid label before the first scroll. +3. **Send traffic to a matching landing page.** A clickbait headline into an unrelated offer wastes the click. +4. **Cap frequency** and kill placements with high bounce and zero conversion. +5. **Track with UTMs** and, where possible, server-side events. See [Analytics and Reporting](../resources/ANALYTICS.md). ## Tools and Resources + - [Taboola](https://www.taboola.com/) - [Outbrain](https://www.outbrain.com/) -- [Nativo](https://www.nativo.com/) - [Sharethrough](https://www.sharethrough.com/) - [Revcontent](https://www.revcontent.com/) +- [FTC advertising and marketing guidance](https://www.ftc.gov/business-guidance/advertising-marketing) + +## Related guides +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) +- [Amazon Ads](AMAZON.md) diff --git a/docs/channels/OOH.md b/docs/channels/OOH.md index 46f8d74..0cb3e52 100644 --- a/docs/channels/OOH.md +++ b/docs/channels/OOH.md @@ -1,4 +1,5 @@ # Out-of-Home (OOH) Advertising + Out-of-Home (OOH) advertising reaches consumers in physical locations during their daily activities. The channel has been transformed by **programmatic Digital OOH (DOOH)**, which allows small businesses to bid on digital screen inventory in specific contexts with flexible budgets — eliminating the traditional requirement for long-term static billboard contracts. @@ -84,3 +85,9 @@ The most viable OOH entry point for small businesses is **programmatic DOOH** vi - [Geopath](https://geopath.org/) — OOH audience measurement - [Nielsen](https://www.nielsen.com/) — OOH reach and frequency data - [Canva](https://www.canva.com/) / [Adobe Creative Cloud](https://www.adobe.com/) — creative production + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/PRINT.md b/docs/channels/PRINT.md index 6d1288d..0eb10f6 100644 --- a/docs/channels/PRINT.md +++ b/docs/channels/PRINT.md @@ -1,35 +1,54 @@ # Print Advertising + -Print advertising involves placing ads in physical publications like newspapers, magazines, brochures, and flyers. +Print still works in narrow cases: local trust, high-consideration purchases, and catalogs people keep. It is not a default channel. About a quarter of SMB advertisers planned to cut traditional media in 2026. Measure it or skip it. + +For physical mail that is triggered by digital behavior, use [Direct Mail](DIRECT_MAIL.md) instead of a newspaper insertion. ## Types of Print Advertising -### 1. Newspaper Ads -- **Classified Ads:** Small ads in specific sections. -- **Display Ads:** Larger ads with images and graphics. +### 1. Newspaper ads +- **Classifieds:** Small, local, and cheap. Useful for hiring and hyperlocal services. +- **Display ads:** Larger placements. Demand a unique phone number, URL, or QR so you can see if anyone responded. + +### 2. Magazine ads +- Full page, half page, or advertorials in a niche title whose readers match your buyer. +- Advertorials must be labeled. See native disclosure rules in [Legal and Ethical Considerations](../resources/LEGAL.md). + +### 3. Brochures and flyers +- In-store, trade shows, and door drops. Pair with [Event Sponsorship](EVENT.md) or [Out-of-Home](OOH.md) when the same audience is already in the venue. + +## When print is worth it -### 2. Magazine Ads -- **Full-Page Ads:** Entire page dedicated to the ad. -- **Half-Page Ads:** Half of the page space. -- **Advertorials:** Sponsored content designed to look like an editorial. +- You sell locally and the publication's paid circulation actually matches your service area. +- The piece has a long shelf life (menus, lookbooks, installation guides). +- You need a tactile leave-behind that digital does not replace. -### 3. Brochures and Flyers -- **Informational Brochures:** Detailed information about products or services. -- **Promotional Flyers:** Quick and eye-catching promotions. +Skip national consumer magazines unless you have a brand budget and a tracking plan. Auction channels in [Search Engine Advertising (SEA)](SEA.md) and [Social Media Advertising](SOCIAL.md) will usually spend more efficiently. ## Benefits -- **Targeted Reach:** Reach specific demographics based on publication readership. -- **Tangible Impact:** Physical ads can have a lasting impression. -- **Local Focus:** Effective for reaching local audiences. + +- Tangible and hard to skip the way a feed ad is skipped. +- Strong for older and local audiences that still read print. +- Complements digital when the same offer uses a unique code. ## Setting Up Print Ads -1. **Select Publications:** Choose newspapers or magazines that align with your target audience. -2. **Design the Ad:** Create visually appealing and informative ads. -3. **Define Placement:** Decide on the size and placement of the ad. -4. **Monitor and Optimize:** Track response rates and adjust future campaigns. + +1. **Ask for circulation and geographic data**, not just a rate card. +2. **Design for scanning:** one offer, one CTA, large type. +3. **Put tracking on the ad:** unique URL, QR, or promo code. +4. **Print a small run first** and kill the next insertion if the code does not move. ## Tools and Resources -- [Local Newspapers and Magazines] -- [Graphic Design Tools: Canva, Adobe InDesign] -- [Print Services: Vistaprint, Moo] +- [Canva](https://www.canva.com/) +- [Adobe InDesign](https://www.adobe.com/products/indesign.html) +- [Vistaprint](https://www.vistaprint.com/) +- [Moo](https://www.moo.com/) + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) +- [Direct Mail](DIRECT_MAIL.md) diff --git a/docs/channels/SEA.md b/docs/channels/SEA.md index e68111d..e120269 100644 --- a/docs/channels/SEA.md +++ b/docs/channels/SEA.md @@ -1,4 +1,5 @@ # Search Engine Advertising (SEA) + Search Engine Advertising (SEA) involves placing ads on search engine results pages (SERPs). This method allows businesses to target users actively searching for specific keywords. @@ -61,3 +62,9 @@ AI Max achieves efficiency through three coordinated layers: - [Microsoft Advertising](https://ads.microsoft.com/) - [Google AI Max documentation](https://support.google.com/google-ads/answer/15910187) - [WordStream PPC Benchmarks](https://www.wordstream.com/ppc-benchmarks) + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/SOCIAL.md b/docs/channels/SOCIAL.md index 08062d5..70b43b4 100644 --- a/docs/channels/SOCIAL.md +++ b/docs/channels/SOCIAL.md @@ -1,4 +1,5 @@ # Social Media Advertising + Social media advertising leverages various platforms to target specific audiences with tailored ads. The landscape has shifted from detailed interest-based targeting to autonomous AI optimization driven by conversion signals. @@ -115,7 +116,13 @@ Bluesky surpassed 41 million users in 2025 but **does not support paid advertisi - [Meta Ads Manager](https://www.facebook.com/business/ads) - [TikTok Ads](https://www.tiktok.com/business/en-US/ads) -- [LinkedIn Campaign Manager](https://business.linkedin.com/marketing-solutions/ads) -- [Pinterest Ads](https://business.pinterest.com/ads) -- [X Ads](https://ads.twitter.com/) +- [LinkedIn Campaign Manager](https://business.linkedin.com/advertise/ads) +- [Pinterest Ads](https://business.pinterest.com/ads/) +- [X Ads](https://ads.x.com/) - [Reddit Ads](https://www.reddit.com/advertising/) + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/channels/VIDEO.md b/docs/channels/VIDEO.md index e7dc341..c99bd6d 100644 --- a/docs/channels/VIDEO.md +++ b/docs/channels/VIDEO.md @@ -1,4 +1,5 @@ # Video Advertising + Video advertising promotes products and services through video content across streaming, social, and connected TV surfaces. The landscape has consolidated into three primary viewing contexts: **mobile/desktop in-stream**, **vertical short-form** (YouTube Shorts, TikTok, Reels), and **Connected TV (CTV)**. @@ -70,6 +71,12 @@ CTV is now a viable channel for small businesses running local awareness and geo - [Adwave (CTV self-serve)](https://adwave.com/) - [Roku Ads Manager](https://advertising.roku.com/) - [Spotify Advertising](https://ads.spotify.com/) -- [Meta Video Ads](https://www.facebook.com/business/ads/video) -- [LinkedIn Video Ads](https://business.linkedin.com/marketing-solutions/ads/video-ads) +- [Meta Ads](https://www.facebook.com/business/ads) +- [LinkedIn Ads](https://business.linkedin.com/advertise/ads) - [TikTok Ads](https://www.tiktok.com/business/en-US/ads) + +## Related guides + +- [Analytics and Reporting](../resources/ANALYTICS.md) +- [Ad Budgeting and Planning](../resources/BUDGETING.md) +- [Legal and Ethical Considerations](../resources/LEGAL.md) diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index d61274f..0000000 --- a/docs/index.md +++ /dev/null @@ -1,40 +0,0 @@ -# Awesome Ads - -**A practical advertising playbook for small businesses.** - -Awesome Ads is an open reference for planning, launching, and refining campaigns across digital and traditional channels. Each guide stands on its own: read cover to cover or jump straight to the channel you need. - -## Channels - -Guides for each major advertising channel, from setup through optimization. - -| Channel | Guide | Channel | Guide | -|---------|-------|---------|-------| -| Search (SEA) | [SEA](channels/SEA.md) | Social | [SOCIAL](channels/SOCIAL.md) | -| Display | [DISPLAY](channels/DISPLAY.md) | Video | [VIDEO](channels/VIDEO.md) | -| Email | [EMAIL](channels/EMAIL.md) | Native | [NATIVE](channels/NATIVE.md) | -| Affiliate | [AFFILIATE](channels/AFFILIATE.md) | Influencer | [INFLUENCER](channels/INFLUENCER.md) | -| Print | [PRINT](channels/PRINT.md) | Broadcast | [BROADCAST](channels/BROADCAST.md) | -| Out-of-home | [OOH](channels/OOH.md) | Direct mail | [DIRECT_MAIL](channels/DIRECT_MAIL.md) | -| Event sponsorship | [EVENT](channels/EVENT.md) | | | - -## Resources - -Cross-cutting topics that apply across channels. - -| Topic | Guide | -|-------|-------| -| Analytics and reporting | [ANALYTICS](resources/ANALYTICS.md) | -| Budgeting and planning | [BUDGETING](resources/BUDGETING.md) | -| Legal and ethical considerations | [LEGAL](resources/LEGAL.md) | -| Campaign examples | [EXAMPLES](resources/EXAMPLES.md) | -| FAQ and troubleshooting | [FAQ](resources/FAQ.md) | -| Templates and design | [TEMPLATES](ad-templates/TEMPLATES.md) | - -## Contributing - -Human contributors should start with [Contributing](CONTRIBUTING.md) and [Community Guidelines](meta/COMMUNITY_GUIDELINES.md). Automated agents should read the repository [AGENTS.md](https://github.com/TMHSDigital/Awesome-Ads/blob/main/AGENTS.md) before editing. - -## License - -Apache License 2.0. See [LICENSE](https://github.com/TMHSDigital/Awesome-Ads/blob/main/LICENSE). diff --git a/docs/meta/AGENTS.md b/docs/meta/AGENTS.md index 03ace1f..a174508 100644 --- a/docs/meta/AGENTS.md +++ b/docs/meta/AGENTS.md @@ -6,12 +6,12 @@ Repository documentation and community policy. These files describe the project | File | Purpose | |------|---------| -| `REPO_OUTLINE.md` | Structure map and brief description of every content file | +| `REPO_OUTLINE.md` | Folder layout and how the site catalog is generated | | `COMMUNITY_GUIDELINES.md` | Conduct expectations for contributors and discussions | ## When editing -- **REPO_OUTLINE.md:** Update whenever files move, rename, or are added under `docs/channels/`, `docs/resources/`, or `docs/ad-templates/`. Paths in this file are relative to `docs/meta/` (use `../channels/SEA.md`, etc.). +- **REPO_OUTLINE.md:** Describe folder layout and catalog generation. Do not maintain a per-file bullet list. - **COMMUNITY_GUIDELINES.md:** Keep aligned with [../../CODE_OF_CONDUCT.md](../../CODE_OF_CONDUCT.md), which points here. Use the canonical repo URL: `https://github.com/TMHSDigital/Awesome-Ads`. ## Tone diff --git a/docs/meta/COMMUNITY_GUIDELINES.md b/docs/meta/COMMUNITY_GUIDELINES.md index a7d318b..d48ea3d 100644 --- a/docs/meta/COMMUNITY_GUIDELINES.md +++ b/docs/meta/COMMUNITY_GUIDELINES.md @@ -1,4 +1,5 @@ # Community Guidelines + To ensure a positive and respectful environment, please follow these community guidelines when contributing to the Awesome Ads repository. @@ -16,13 +17,11 @@ To ensure a positive and respectful environment, please follow these community g - Be open to feedback and willing to learn from others. ## Reporting Issues -- Report any inappropriate behavior or violations of these guidelines to the repository maintainers. -- Use the [Issues](https://github.com/TMHSDigital/Awesome-Ads/issues) section to report any problems with the content or conduct within the community. +- Report content problems via [GitHub Issues](https://github.com/TMHSDigital/Awesome-Ads/issues). +- Report conduct or harassment privately. Do not file a public Issue for that. Contact the repository owner through their GitHub profile, or use GitHub's report-abuse tools. ## Consequences - Violations of these guidelines may result in being banned from contributing to the repository. - Repeated offenses or severe violations will lead to further action as deemed necessary by the repository maintainers. -Thank you for helping us maintain a welcoming and collaborative environment! - -![GitHub](https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg) +Thank you for helping us maintain a welcoming and collaborative environment. diff --git a/docs/meta/REPO_OUTLINE.md b/docs/meta/REPO_OUTLINE.md index 59e0429..141baaf 100644 --- a/docs/meta/REPO_OUTLINE.md +++ b/docs/meta/REPO_OUTLINE.md @@ -1,45 +1,31 @@ # Repository Outline: Awesome Ads -Overview of the repository structure and content. + + +Overview of how documentation is laid out and how the published site is generated. ## Layout ``` docs/ ├── channels/ # Per-channel advertising guides -├── resources/ # Cross-cutting topics (analytics, legal, FAQ, …) +├── resources/ # Cross-cutting topics (analytics, legal, FAQ) ├── ad-templates/ # Ad template and design resources └── meta/ # Repo documentation ``` -## Advertising channels - -- [SEA.md](../channels/SEA.md) — Search engine advertising (Google Ads, Bing Ads) -- [SOCIAL.md](../channels/SOCIAL.md) — Facebook, Instagram, Twitter, LinkedIn, Pinterest, TikTok -- [DISPLAY.md](../channels/DISPLAY.md) — Banner, rich media, and interstitial ads -- [VIDEO.md](../channels/VIDEO.md) — YouTube and social video ads -- [EMAIL.md](../channels/EMAIL.md) — Newsletters, promotional, and transactional email -- [NATIVE.md](../channels/NATIVE.md) — Sponsored content, in-feed ads, recommendation widgets -- [AFFILIATE.md](../channels/AFFILIATE.md) — Pay-per-sale, pay-per-click, pay-per-lead -- [INFLUENCER.md](../channels/INFLUENCER.md) — Influencer partnerships and campaigns -- [PRINT.md](../channels/PRINT.md) — Newspaper, magazine, brochures, flyers -- [BROADCAST.md](../channels/BROADCAST.md) — Television and radio advertising -- [OOH.md](../channels/OOH.md) — Billboards, transit ads, street furniture -- [DIRECT_MAIL.md](../channels/DIRECT_MAIL.md) — Postcards, catalogs, brochures, flyers -- [EVENT.md](../channels/EVENT.md) — Local, industry, sports, and cultural event sponsorship - -## Additional resources - -- [ANALYTICS.md](../resources/ANALYTICS.md) — Tracking and analyzing ad performance -- [BUDGETING.md](../resources/BUDGETING.md) — Budgeting strategies and tools -- [LEGAL.md](../resources/LEGAL.md) — Regulations and ethical advertising -- [EXAMPLES.md](../resources/EXAMPLES.md) — Successful campaign case studies -- [TEMPLATES.md](../ad-templates/TEMPLATES.md) — Ad templates and design resources - - [SOCIAL_MEDIA.md](../ad-templates/SOCIAL_MEDIA.md) - - [DISPLAY_ADS.md](../ad-templates/DISPLAY_ADS.md) - - [VIDEO_ADS.md](../ad-templates/VIDEO_ADS.md) - - [EMAIL_MARKETING.md](../ad-templates/EMAIL_MARKETING.md) -- [FAQ.md](../resources/FAQ.md) — Common questions and troubleshooting +Each user-facing guide is a markdown file in one of those folders. `AGENTS.md` files are agent instructions and are excluded from the site. + +## How the site catalog is built + +MkDocs does not keep a handwritten page list. At build time: + +1. `scripts/prepare-mkdocs.py` scans the folders above and writes home and section indexes. +2. `scripts/mkdocs_hooks.py` builds the sidebar from the same scan. + +Title comes from the first H1. Optional `` on the line after the H1 controls order. Files without `nav_order` sort last, then by title. + +Adding a guide means adding the markdown file. Do not edit `mkdocs.yml` nav or regenerate indexes by hand. ## Contributing @@ -51,4 +37,4 @@ See [Community Guidelines](COMMUNITY_GUIDELINES.md). ## License -Apache License 2.0 — see [LICENSE](https://github.com/TMHSDigital/Awesome-Ads/blob/main/LICENSE). +Apache License 2.0. See [LICENSE](https://github.com/TMHSDigital/Awesome-Ads/blob/main/LICENSE). diff --git a/docs/resources/AGENTS.md b/docs/resources/AGENTS.md index 72f2ff3..97cab60 100644 --- a/docs/resources/AGENTS.md +++ b/docs/resources/AGENTS.md @@ -23,13 +23,13 @@ Cross-cutting guides that apply across multiple advertising channels. These file - Link to channel guides when mentioning a specific medium: `[Social Media Advertising](../channels/SOCIAL.md)`. - Link to ad-templates for creative help: `../ad-templates/TEMPLATES.md`. -- Keep infographics and image URLs valid; flag placeholder URLs (e.g. `example.com`) if you see them. +- Keep image URLs valid. Do not use placeholder hosts like example.com. ## When adding a new resource 1. Add the file here, not under `channels/`, unless the topic is truly single-channel. -2. Update [../README.md](../README.md), [../../README.md](../../README.md), and [../meta/REPO_OUTLINE.md](../meta/REPO_OUTLINE.md). -3. Run `python scripts/check-internal-links.py`. +2. Start with an H1. Optional `` on the next line controls order. +3. Run `python scripts/check-internal-links.py` from the repo root. ## Parent context diff --git a/docs/resources/ANALYTICS.md b/docs/resources/ANALYTICS.md index 1b081cd..9bd1218 100644 --- a/docs/resources/ANALYTICS.md +++ b/docs/resources/ANALYTICS.md @@ -1,4 +1,5 @@ # Analytics and Reporting + Accurate measurement is the foundation of every advertising decision. The collapse of third-party cookie-based tracking has forced a structural split in web analytics: **GA4 remains the default for Google-integrated stacks**, while a growing ecosystem of **cookieless, privacy-first alternatives** captures 40–50% more traffic data by bypassing browser-level restrictions entirely. @@ -88,5 +89,5 @@ As browser-side identifiers erode, small businesses must build structured first- - [Fathom Analytics](https://usefathom.com/) - [Matomo](https://matomo.org/) - [PostHog](https://posthog.com/) -- [Meta Business Suite Insights](https://www.facebook.com/business/insights/tools) +- [Meta Business Help](https://www.facebook.com/business/help) - [Google Tag Manager](https://tagmanager.google.com/) diff --git a/docs/resources/BUDGETING.md b/docs/resources/BUDGETING.md index e1a46c0..fdefe6c 100644 --- a/docs/resources/BUDGETING.md +++ b/docs/resources/BUDGETING.md @@ -1,4 +1,5 @@ # Ad Budgeting and Planning + Effective budgeting maximizes return on limited ad spend. For small businesses under **$5,000/month**, the core principle is **concentration over coverage**: feed a small number of campaigns enough conversion volume to exit algorithmic learning phases rather than spreading thinly across every channel. diff --git a/docs/resources/EXAMPLES.md b/docs/resources/EXAMPLES.md index 80e953d..625517d 100644 --- a/docs/resources/EXAMPLES.md +++ b/docs/resources/EXAMPLES.md @@ -1,68 +1,40 @@ # Examples of Successful Ad Campaigns + -This section provides detailed case studies of successful ad campaigns across various channels. Learn what made these campaigns successful and the lessons that can be applied to your own advertising efforts. +Use these as pattern libraries, not scripts to copy. Big-brand production budgets do not transfer to a local shop. The useful part is the mechanism. -## Case Studies +## Patterns that still work -### 1. Old Spice: "The Man Your Man Could Smell Like" -- **Channel:** Television, Social Media -- **Objective:** Rebrand Old Spice to appeal to a younger demographic. -- **Strategy:** A humorous and memorable ad featuring a charismatic spokesman. -- **Results:** Increased sales by 125% in one month. -- ![Old Spice](https://upload.wikimedia.org/wikipedia/commons/8/8c/Old_spice_logo.svg) -- [Read More](https://www.campaignlive.co.uk/article/case-study-old-spice-rebrands-man-your-man-smell-like/995453) +### 1. One sharp demonstration +- **Pattern:** Show the product doing the job in the first seconds. Dollar Shave Club's launch video did this with a warehouse walk-through and a blunt offer. +- **SMB version:** A 15-second phone video of the service in situ, then a single price or CTA. Run it as a Spark Ad or Reels ad. See [Video Advertising](../channels/VIDEO.md). -### 2. Dollar Shave Club: "Our Blades Are F***ing Great" -- **Channel:** Online Video, Social Media -- **Objective:** Increase brand awareness and disrupt the razor market. -- **Strategy:** A viral video with a humorous and irreverent tone. -- **Results:** 12,000 new customers within 48 hours of the video launch. -- ![Dollar Shave Club](https://upload.wikimedia.org/wikipedia/commons/4/4f/Dollar_Shave_Club_logo.png) -- [Read More](https://www.forbes.com/sites/michellegreenwald/2018/07/20/how-dollar-shave-club-changed-the-marketing-game-forever/) +### 2. Reposition an old category +- **Pattern:** Old Spice rebuilt a stale brand by changing who the ad was "for" without changing the SKU overnight. +- **SMB version:** Speak to the buyer who actually pays (the partner, the office manager, the parent), not the category cliche. -### 3. Airbnb: "We Are Here" -- **Channel:** Social Media, Content Marketing -- **Objective:** Increase brand trust and highlight community experiences. -- **Strategy:** User-generated content showcasing authentic travel experiences. -- **Results:** Significant increase in engagement and bookings. -- ![Airbnb](https://upload.wikimedia.org/wikipedia/commons/6/69/Airbnb_Logo_B%C3%A9lo.svg) -- [Read More](https://www.businessinsider.com/airbnb-we-are-here-campaign-2015-7) +### 3. Proof from real customers +- **Pattern:** Airbnb-style UGC beats studio lifestyle when trust is the objection. +- **SMB version:** Collect photo and video reviews with written permission and FTC-safe captions. Boost the best as Spark Ads. See [Influencer Marketing](../channels/INFLUENCER.md). -### 4. Always: "#LikeAGirl" -- **Channel:** Television, Social Media -- **Objective:** Challenge gender stereotypes and empower women. -- **Strategy:** A powerful video campaign that redefined the phrase "like a girl." -- **Results:** Over 85 million views on YouTube and significant brand uplift. -- ![Always](https://upload.wikimedia.org/wikipedia/commons/8/84/Always_logo.png) -- [Read More](https://www.forbes.com/sites/avidan/2015/12/17/always-likeagirl-lessons-from-an-award-winning-campaign/) +### 4. A line people repeat +- **Pattern:** Always's "Like a Girl" and Nike's long-running "Just Do It" work because the line is the strategy. +- **SMB version:** One sentence that names the job to be done. Put it on search headlines, the landing page H1, and the email from-name test. -### 5. Nike: "Just Do It" -- **Channel:** Television, Print, Digital -- **Objective:** Reinforce Nike's brand message and connect with a broad audience. -- **Strategy:** Inspirational messaging featuring athletes overcoming challenges. -- **Results:** Significant increase in brand recognition and sales. -- ![Nike](https://upload.wikimedia.org/wikipedia/commons/a/a6/Logo_NIKE.svg) -- [Read More](https://www.entrepreneur.com/article/312676) +### 5. Constrained, measurable tests +- **Pattern:** The campaigns above look like brand theater. The operators still watched sales, search lift, or sign-ups. +- **SMB version:** Unique URLs, promo codes, and a weekly read of [Analytics and Reporting](ANALYTICS.md). Kill what does not pay. -## Lessons Learned -1. **Creativity and Humor:** Engage audiences with memorable and entertaining content. -2. **Authenticity:** Use real stories and user-generated content to build trust. -3. **Empowerment:** Address social issues and inspire your audience. -4. **Consistency:** Maintain a consistent brand message across all channels. -5. **Data-Driven:** Use analytics to measure success and optimize campaigns. +## Lessons to steal -## Tools and Resources -- [Case Study Research](https://www.campaignlive.com/) -- [Marketing Week](https://www.marketingweek.com/) -- [Ad Age](https://adage.com/) - -## Visual Elements and Infographics +1. **Specific beats clever.** If the joke needs a paragraph, the ad is too long. +2. **Authenticity is a permission problem.** Get usage rights and disclose paid posts. +3. **Consistency across channels.** Same offer in search, social, and email. +4. **Creative fatigue is real.** Plan replacements before the CTR dies. +5. **Budget follows proof.** See [Ad Budgeting and Planning](BUDGETING.md). -### 1. Campaign Impact -![Campaign Impact](https://example.com/campaign-impact-infographic.png) +## Further reading -### 2. Engagement Metrics -![Engagement Metrics](https://example.com/engagement-metrics-infographic.png) - -### 3. ROI Analysis -![ROI Analysis](https://example.com/roi-analysis-infographic.png) +- [Marketing Week](https://www.marketingweek.com/) +- [Ad Age](https://adage.com/) +- [Campaign](https://www.campaignlive.com/) diff --git a/docs/resources/FAQ.md b/docs/resources/FAQ.md index 72763dc..6402bef 100644 --- a/docs/resources/FAQ.md +++ b/docs/resources/FAQ.md @@ -1,65 +1,57 @@ # FAQ and Troubleshooting + -This section provides answers to common questions and solutions to frequent issues related to ad campaigns. +Practical answers for small-business campaigns. Platform UIs change. Prefer official help centers for click-by-click setup. ## Frequently Asked Questions -### 1. How do I choose the right platform for my ads? -- **Answer:** Consider your target audience and where they spend most of their time online. Use platform-specific demographics and user behavior data to guide your decision. For instance, younger audiences may be more active on Instagram and TikTok, while professionals might engage more on LinkedIn. +### How do I choose a platform? -### 2. What is the best ad format for my campaign? -- **Answer:** The best format depends on your campaign goals. For brand awareness, video and display ads work well. For direct response, search and social media ads are effective. Each format has its strengths; for example, video ads are great for storytelling, while search ads capture intent. +Match the job to the channel. Search captures demand that already exists ([SEA](../channels/SEA.md), [Amazon Ads](../channels/AMAZON.md)). Social and video create demand ([Social](../channels/SOCIAL.md), [Video](../channels/VIDEO.md)). Email keeps people you already have ([Email](../channels/EMAIL.md)). If the monthly budget is under $5,000, run at most one or two campaigns per platform so the algorithm can leave learning. -### 3. How can I track the performance of my ads? -- **Answer:** Use analytics tools provided by the ad platforms (e.g., Google Analytics, Facebook Insights) to monitor key metrics like CTR, conversion rate, and ROAS. Setting up UTM parameters can help track the effectiveness of specific campaigns in Google Analytics. +### What ad format should I use? -### 4. How do I optimize my ad campaigns? -- **Answer:** Continuously test different ad creatives, target audiences, and bidding strategies. Use A/B testing and analyze performance data to make informed adjustments. Regularly update and refresh your creatives to avoid ad fatigue. +Awareness: video and CTV. Direct response: search, shopping, and social conversion campaigns. Retargeting: short video or a simple offer. Format follows the outcome, not the trend. -### 5. What budget should I allocate to my ad campaigns? -- **Answer:** Start with a small budget and scale up based on performance. Allocate more budget to high-performing channels and campaigns. Using a flexible budget approach allows you to adjust spending based on real-time results. +### How do I track performance? -### 6. How do I create engaging ad creatives? -- **Answer:** Focus on clear, compelling messaging and high-quality visuals. Use strong CTAs and tailor your message to your target audience. Incorporate elements like storytelling and emotional appeal to connect with viewers. +Use the platform's conversion events plus your own analytics. For Google-heavy stacks that is GA4. For privacy-first sites, add a cookieless tool. Implement Meta Conversions API or Google server-side tagging when browser pixels degrade. Details: [Analytics and Reporting](ANALYTICS.md). -### 7. What is retargeting and how can it benefit my campaigns? -- **Answer:** Retargeting involves showing ads to users who have previously visited your website or engaged with your content. It helps increase conversions by reminding potential customers of your products or services. Tools like Facebook Pixel and Google Remarketing Tags can help set up retargeting campaigns. +UTM parameters on every paid URL. Compare platform-reported conversions to your analytics. They will not match exactly. -## Troubleshooting +### How do I optimize? + +Refresh creative before you rebuild targeting. On Meta, keep 15 or more active creative combinations. On Google, mine search terms and add negatives. Kill placements with spend and no conversions after a statistically boring amount of data, not after two days. -### 1. Low Click-Through Rate (CTR) -- **Solution:** Improve ad creatives by making them more engaging. Test different headlines, images, and CTAs. Ensure your ads are relevant to the target audience. Consider refining your targeting to reach a more interested audience. +### What budget should I start with? -### 2. High Cost-Per-Click (CPC) -- **Solution:** Refine your targeting to focus on high-intent audiences. Adjust your bidding strategy and test different ad formats. Optimize ad quality to improve relevance scores. Lower your bids on keywords that are not performing well and increase bids on high-performing ones. +Enough to exit learning. Fragmented $10/day campaigns across five ad sets usually fail. Consolidate. Then scale what converts. See [Ad Budgeting and Planning](BUDGETING.md). -### 3. Low Conversion Rate -- **Solution:** Ensure your landing page is optimized for conversions. Test different page designs, headlines, and CTAs. Simplify the conversion process and remove any friction points. Use heatmaps and user recordings to identify issues on the landing page. +### How do I stay legal with creators and affiliates? -### 4. Ad Disapproval -- **Solution:** Review the ad policies of the platform and ensure your ads comply. Common reasons for disapproval include inappropriate content, misleading claims, and poor image quality. Make necessary adjustments and resubmit your ads. +Written disclosure policy, `#ad` or `Sponsored by [Brand]`, and dual disclosure on video. Platform partnership tags are not enough. See [Legal and Ethical Considerations](LEGAL.md) and [Influencer Marketing](../channels/INFLUENCER.md). -### 5. Poor Ad Performance -- **Solution:** Analyze performance data to identify underperforming ads. Test different ad creatives and targeting options. Consider running a campaign audit to identify areas for improvement. Look into external factors that might be affecting performance, such as seasonal trends. +## Troubleshooting -## Best Practices +### Low CTR +Rewrite the first line and the image. Tighten the audience only after the creative is clear. -### 1. Regular Monitoring -- **Tip:** Consistently track ad performance and make data-driven adjustments. Set up alerts for significant changes in key metrics. Use automated rules in ad platforms to manage bids and budgets efficiently. +### High CPC +Add negatives, raise relevance, and stop bidding on vanity terms. On Amazon, fix the listing before you raise bids. -### 2. Audience Segmentation -- **Tip:** Segment your audience based on demographics, behavior, and interests. Create tailored ad creatives for each segment to increase relevance and engagement. Use lookalike audiences to find new potential customers similar to your existing ones. +### Low conversion rate +The landing page is usually the problem: slow, off-offer, or missing the next step. Heatmaps help. So does matching the ad promise in the headline. -### 3. A/B Testing -- **Tip:** Continuously test different ad elements to find the best-performing combinations. Test one variable at a time for clear insights. Use statistically significant data to make informed decisions. +### Ad disapproval +Read the current policy for that placement. Common causes: misleading claims, before/after health claims, and poor image quality. -### 4. Ad Scheduling -- **Tip:** Schedule your ads to run at times when your target audience is most active. Use dayparting to allocate your budget more effectively and increase ad visibility during peak times. +### Pixel or conversion mismatch +Ad blockers, iOS ATT, and consent mode cut browser events. Move conversion firing server-side and keep a first-party email list. ## Resources -- [Google Ads Help Center](https://support.google.com/google-ads/) ![Google Ads](https://upload.wikimedia.org/wikipedia/commons/1/1d/Google_Ads_logo.svg) -- [Facebook Business Help Center](https://www.facebook.com/business/help) ![Facebook](https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_(2019).svg) -- [LinkedIn Marketing Solutions Help](https://www.linkedin.com/help/linkedin/answer/71834) ![LinkedIn](https://upload.wikimedia.org/wikipedia/commons/0/01/LinkedIn_Logo.svg) -- [Twitter Ads Help Center](https://business.twitter.com/en/help.html) ![Twitter](https://upload.wikimedia.org/wikipedia/en/6/60/Twitter_Logo_as_of_2021.svg) -- [Canva](https://www.canva.com/) ![Canva](https://upload.wikimedia.org/wikipedia/commons/3/33/Canva_Logo.png) -- [Adobe Creative Cloud](https://www.adobe.com/creativecloud.html) ![Adobe Creative Cloud](https://upload.wikimedia.org/wikipedia/commons/3/31/Adobe_Creative_Cloud_Logo.svg) + +- [Google Ads Help](https://support.google.com/google-ads/) +- [Meta Business Help](https://www.facebook.com/business/help) +- [LinkedIn Advertising Help](https://www.linkedin.com/help/linkedin) +- [X Ads Help](https://business.x.com/en/help.html) +- [Amazon Ads Help](https://advertising.amazon.com/library) diff --git a/docs/resources/LEGAL.md b/docs/resources/LEGAL.md index 8d04219..7ba13cc 100644 --- a/docs/resources/LEGAL.md +++ b/docs/resources/LEGAL.md @@ -1,4 +1,5 @@ # Legal and Ethical Considerations + Advertising compliance has become significantly more complex and higher-stakes. FTC penalties have increased, browser privacy protections have proliferated, and state-level consumer protection laws have expanded. This guide covers the critical requirements as of 2026. @@ -37,7 +38,7 @@ The FTC has civil penalty authority to target: - Undisclosed employee testimonials. - Review suppression (hiding or blocking negative reviews). -[FTC Advertising Guidelines](https://www.ftc.gov/tips-advice/business-center/advertising-and-marketing) +[FTC Advertising Guidelines](https://www.ftc.gov/business-guidance/advertising-marketing) --- @@ -78,7 +79,7 @@ The FTC has civil penalty authority to target: - **Opt-out mechanism:** Every commercial email must include a functioning unsubscribe link that processes requests within 10 business days. - **Physical address:** Commercial emails must include your current physical postal address. -[CAN-SPAM Compliance Guide](https://www.ftc.gov/tips-advice/business-center/guidance/can-spam-act-compliance-guide-business) +[CAN-SPAM Compliance Guide](https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business) --- @@ -121,8 +122,8 @@ This applies to any advertiser promoting subscription-based products or services ## Tools and Resources -- [FTC Advertising Guidelines](https://www.ftc.gov/tips-advice/business-center/advertising-and-marketing) +- [FTC Advertising Guidelines](https://www.ftc.gov/business-guidance/advertising-marketing) - [GDPR.eu Overview](https://gdpr.eu/) -- [CAN-SPAM Act Compliance Guide](https://www.ftc.gov/tips-advice/business-center/guidance/can-spam-act-compliance-guide-business) +- [CAN-SPAM Act Compliance Guide](https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business) - [IAB Legal Guidelines](https://www.iab.com/guidelines/) - [Google Consent Mode documentation](https://support.google.com/google-ads/answer/10000067) diff --git a/mkdocs.yml b/mkdocs.yml index 87473c2..6f31ed5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -6,38 +6,8 @@ repo_url: https://github.com/TMHSDigital/Awesome-Ads repo_name: TMHSDigital/Awesome-Ads edit_uri: edit/main/docs/ -nav: - - Home: index.md - - Channels: - - Search Engine Advertising (SEA): channels/SEA.md - - Social Media Advertising: channels/SOCIAL.md - - Display Advertising: channels/DISPLAY.md - - Video Advertising: channels/VIDEO.md - - Email Marketing: channels/EMAIL.md - - Native Advertising: channels/NATIVE.md - - Affiliate Marketing: channels/AFFILIATE.md - - Influencer Marketing: channels/INFLUENCER.md - - Print Advertising: channels/PRINT.md - - Broadcast Advertising: channels/BROADCAST.md - - Out-of-Home (OOH): channels/OOH.md - - Direct Mail: channels/DIRECT_MAIL.md - - Event Sponsorship: channels/EVENT.md - - Resources: - - Analytics and Reporting: resources/ANALYTICS.md - - Ad Budgeting and Planning: resources/BUDGETING.md - - Legal and Ethical Considerations: resources/LEGAL.md - - Campaign Examples: resources/EXAMPLES.md - - FAQ and Troubleshooting: resources/FAQ.md - - Templates: - - Overview: ad-templates/TEMPLATES.md - - Social Media Ad Templates: ad-templates/SOCIAL_MEDIA.md - - Display Ad Templates: ad-templates/DISPLAY_ADS.md - - Video Ad Templates: ad-templates/VIDEO_ADS.md - - Email Marketing Templates: ad-templates/EMAIL_MARKETING.md - - Meta: - - Repository Outline: meta/REPO_OUTLINE.md - - Community Guidelines: meta/COMMUNITY_GUIDELINES.md - - Contributing: CONTRIBUTING.md +hooks: + - scripts/mkdocs_hooks.py exclude_docs: | **/AGENTS.md @@ -62,11 +32,30 @@ theme: - navigation.instant - navigation.sections - navigation.expand + - navigation.indexes + - navigation.footer + - navigation.tracking - navigation.top - search.suggest - search.highlight - content.code.copy - content.action.edit + - content.action.view + +plugins: + - search + - git-revision-date-localized: + enable_creation_date: true + fallback_to_build_date: true + enable_git_follow: false + strict: false + exclude: + - index.md + - CONTRIBUTING.md + - channels/index.md + - resources/index.md + - ad-templates/index.md + - meta/index.md markdown_extensions: - admonition diff --git a/requirements-docs.txt b/requirements-docs.txt index f1f3d66..764a489 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1 +1,2 @@ -mkdocs-material>=9.5.0 +mkdocs-material==9.7.6 +mkdocs-git-revision-date-localized-plugin==1.5.4 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..12514f2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +-r requirements-docs.txt diff --git a/scripts/AGENTS.md b/scripts/AGENTS.md index 8c8ae3f..2aaee47 100644 --- a/scripts/AGENTS.md +++ b/scripts/AGENTS.md @@ -6,9 +6,12 @@ Maintenance utilities for repository quality checks. | File | Purpose | |------|---------| +| `catalog.py` | Scans `docs/` folders, titles, and `nav_order` comments for nav and indexes | +| `mkdocs_hooks.py` | MkDocs `on_config` hook that sets `nav` from `catalog.py` | +| `test_catalog.py` | Stdlib unit tests for the catalog | | `check-internal-links.py` | Validates that relative `markdown` links resolve to existing files | | `check-public-repo-hygiene.py` | Fails if local-only paths or secret-like content are tracked in git | -| `prepare-mkdocs.py` | Generates `docs/CONTRIBUTING.md` with site-relative links for MkDocs builds | +| `prepare-mkdocs.py` | Generates `docs/CONTRIBUTING.md` and section/home indexes for MkDocs | ## check-internal-links.py @@ -16,7 +19,7 @@ Maintenance utilities for repository quality checks. - Resolves relative link targets from the containing file's directory. - Skips `http://`, `https://`, `mailto:`, `#`, and `ftp://` URLs. - Exit code `0` on success, `1` when broken links are found. -- Runs `prepare-mkdocs.py` first so generated files such as `docs/CONTRIBUTING.md` exist before link resolution. +- Runs `prepare-mkdocs.py` first so generated files such as `docs/CONTRIBUTING.md` and section indexes exist before link resolution. Run from the repository root: diff --git a/scripts/catalog.py b/scripts/catalog.py new file mode 100644 index 0000000..9cc807c --- /dev/null +++ b/scripts/catalog.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +"""Filesystem catalog for MkDocs nav and generated indexes.""" + +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path +import re + +H1_RE = re.compile(r"^#\s+(.+)$", re.MULTILINE) +NAV_ORDER_RE = re.compile(r"") +SKIP_NAMES = frozenset({"AGENTS.md", "README.md", "CONTRIBUTING.md", "index.md"}) +GENERATED_MARKER = "" + +SECTIONS: tuple[tuple[str, str], ...] = ( + ("channels", "Channels"), + ("resources", "Resources"), + ("ad-templates", "Templates"), + ("meta", "Meta"), +) + +SECTION_INTROS: dict[str, str] = { + "channels": "Guides for each major advertising channel, from setup through optimization.", + "resources": "Cross-cutting topics that apply across channels.", + "ad-templates": "Ad templates and design resources.", + "meta": "Repository documentation and community policy.", +} + +HOME_INTRO = """**A practical advertising playbook for small businesses.** + +Awesome Ads is an open reference for planning, launching, and refining campaigns across digital and traditional channels. Each guide stands on its own: read cover to cover or jump straight to the channel you need.""" + +LICENSE_URL = "https://github.com/TMHSDigital/Awesome-Ads/blob/main/LICENSE" +AGENTS_URL = "https://github.com/TMHSDigital/Awesome-Ads/blob/main/AGENTS.md" + + +@dataclass(frozen=True) +class Page: + rel: str + title: str + nav_order: int | None + stem: str + + +def parse_page(path: Path, docs: Path) -> Page: + text = path.read_text(encoding="utf-8") + heading = H1_RE.search(text) + if heading is None: + raise ValueError(f"{path} has no H1") + order_match = NAV_ORDER_RE.search(text) + nav_order = int(order_match.group(1)) if order_match else None + rel = path.relative_to(docs).as_posix() + return Page(rel=rel, title=heading.group(1).strip(), nav_order=nav_order, stem=path.stem) + + +def _sort_key(page: Page) -> tuple[bool, int, str]: + return (page.nav_order is None, page.nav_order or 0, page.title.lower()) + + +def list_section(docs: Path, folder: str) -> list[Page]: + directory = docs / folder + if not directory.is_dir(): + return [] + pages: list[Page] = [] + for path in directory.glob("*.md"): + if path.name in SKIP_NAMES: + continue + pages.append(parse_page(path, docs)) + pages.sort(key=_sort_key) + return pages + + +def scan_docs(docs: Path) -> dict[str, list[Page]]: + return {folder: list_section(docs, folder) for folder, _title in SECTIONS} + + +def render_index_markdown( + title: str, + intro: str, + pages: list[Page], + link_prefix: str, +) -> str: + lines = [ + GENERATED_MARKER, + "", + f"# {title}", + "", + intro, + "", + "| Guide |", + "| --- |", + ] + for page in pages: + filename = Path(page.rel).name + href = f"{link_prefix}{filename}" if link_prefix else filename + lines.append(f"| [{page.title}]({href}) |") + lines.append("") + return "\n".join(lines) + + +def render_home_markdown(docs: Path) -> str: + scanned = scan_docs(docs) + lines = [ + GENERATED_MARKER, + "", + "# Awesome Ads", + "", + HOME_INTRO, + "", + ] + for folder, title in SECTIONS: + pages = scanned[folder] + lines.append(f"## {title}") + lines.append("") + lines.append(SECTION_INTROS[folder]) + lines.append("") + lines.append("| Guide |") + lines.append("| --- |") + for page in pages: + lines.append(f"| [{page.title}]({page.rel}) |") + lines.append("") + lines.extend( + [ + "## Contributing", + "", + "Human contributors should start with [Contributing](CONTRIBUTING.md) " + "and [Community Guidelines](meta/COMMUNITY_GUIDELINES.md). " + f"Automated agents should read the repository [AGENTS.md]({AGENTS_URL}) " + "before editing.", + "", + "## License", + "", + f"Apache License 2.0. See [LICENSE]({LICENSE_URL}).", + "", + ] + ) + return "\n".join(lines) + + +def mkdocs_nav(docs: Path) -> list: + scanned = scan_docs(docs) + nav: list = [{"Home": "index.md"}] + for folder, title in SECTIONS: + entries: list = [{title: f"{folder}/index.md"}] + for page in scanned[folder]: + entries.append({page.title: page.rel}) + nav.append({title: entries}) + nav.append({"Contributing": "CONTRIBUTING.md"}) + return nav diff --git a/scripts/check-public-repo-hygiene.py b/scripts/check-public-repo-hygiene.py index 4d160c0..7c75a01 100644 --- a/scripts/check-public-repo-hygiene.py +++ b/scripts/check-public-repo-hygiene.py @@ -14,6 +14,11 @@ "research/", "site/", "docs/CONTRIBUTING.md", + "docs/index.md", + "docs/channels/index.md", + "docs/resources/index.md", + "docs/ad-templates/index.md", + "docs/meta/index.md", ) FORBIDDEN_TRACKED_SUFFIXES = ( diff --git a/scripts/mkdocs_hooks.py b/scripts/mkdocs_hooks.py new file mode 100644 index 0000000..00c2959 --- /dev/null +++ b/scripts/mkdocs_hooks.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +"""MkDocs hook: build nav from the filesystem catalog.""" + +from __future__ import annotations + +import sys +from pathlib import Path + +_SCRIPTS = Path(__file__).resolve().parent +if str(_SCRIPTS) not in sys.path: + sys.path.insert(0, str(_SCRIPTS)) + +from catalog import mkdocs_nav # noqa: E402 + + +def on_config(config): + docs = Path(config["docs_dir"]) + config["nav"] = mkdocs_nav(docs) + return config diff --git a/scripts/prepare-mkdocs.py b/scripts/prepare-mkdocs.py index d8e10c7..ea41c41 100644 --- a/scripts/prepare-mkdocs.py +++ b/scripts/prepare-mkdocs.py @@ -3,11 +3,25 @@ from __future__ import annotations +import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent +SCRIPTS = ROOT / "scripts" +if str(SCRIPTS) not in sys.path: + sys.path.insert(0, str(SCRIPTS)) + +from catalog import ( # noqa: E402 + SECTIONS, + SECTION_INTROS, + render_home_markdown, + render_index_markdown, + scan_docs, +) + CONTRIBUTING_SRC = ROOT / "CONTRIBUTING.md" CONTRIBUTING_DST = ROOT / "docs" / "CONTRIBUTING.md" +DOCS = ROOT / "docs" def prepare_contributing() -> None: @@ -23,8 +37,29 @@ def prepare_contributing() -> None: print(f"Wrote {CONTRIBUTING_DST.relative_to(ROOT)}") +def prepare_indexes() -> None: + home = DOCS / "index.md" + home.write_text(render_home_markdown(DOCS), encoding="utf-8") + print(f"Wrote {home.relative_to(ROOT)}") + + scanned = scan_docs(DOCS) + for folder, title in SECTIONS: + path = DOCS / folder / "index.md" + path.write_text( + render_index_markdown( + title, + SECTION_INTROS[folder], + scanned[folder], + "", + ), + encoding="utf-8", + ) + print(f"Wrote {path.relative_to(ROOT)}") + + def main() -> int: prepare_contributing() + prepare_indexes() return 0 diff --git a/scripts/test_catalog.py b/scripts/test_catalog.py new file mode 100644 index 0000000..8ebd4ba --- /dev/null +++ b/scripts/test_catalog.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python3 +"""Tests for the filesystem catalog.""" + +from __future__ import annotations + +from pathlib import Path +import sys +import tempfile +import unittest + +sys.path.insert(0, str(Path(__file__).resolve().parent)) + +from catalog import ( + mkdocs_nav, + parse_page, + render_index_markdown, + scan_docs, +) + + +def _write(path: Path, content: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + + +def _docs_tree(root: Path) -> Path: + docs = root / "docs" + for folder in ("channels", "resources", "ad-templates", "meta"): + (docs / folder).mkdir(parents=True) + return docs + + +class CatalogTests(unittest.TestCase): + def test_sea_title_from_h1(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + docs = _docs_tree(Path(tmp)) + _write( + docs / "channels" / "SEA.md", + "# Search Engine Advertising (SEA)\n\nBody.\n", + ) + pages = scan_docs(docs)["channels"] + self.assertEqual(len(pages), 1) + self.assertEqual(pages[0].title, "Search Engine Advertising (SEA)") + self.assertEqual(pages[0].rel, "channels/SEA.md") + self.assertEqual(pages[0].stem, "SEA") + + def test_skips_agents_and_readme(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + docs = _docs_tree(Path(tmp)) + _write(docs / "channels" / "SEA.md", "# Search\n") + _write(docs / "channels" / "AGENTS.md", "# Agents\n") + _write(docs / "channels" / "README.md", "# Readme\n") + pages = scan_docs(docs)["channels"] + self.assertEqual([page.stem for page in pages], ["SEA"]) + + def test_skips_generated_index(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + docs = _docs_tree(Path(tmp)) + _write(docs / "channels" / "SEA.md", "# Search\n") + _write(docs / "channels" / "index.md", "# Channels\n") + pages = scan_docs(docs)["channels"] + self.assertEqual([page.stem for page in pages], ["SEA"]) + + def test_nav_order_before_unordered(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + docs = _docs_tree(Path(tmp)) + _write(docs / "channels" / "ZETA.md", "# Zeta\n") + _write( + docs / "channels" / "ALPHA.md", + "# Alpha\n\n\n", + ) + pages = scan_docs(docs)["channels"] + self.assertEqual([page.stem for page in pages], ["ALPHA", "ZETA"]) + + def test_unordered_sorts_by_title(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + docs = _docs_tree(Path(tmp)) + _write(docs / "channels" / "B.md", "# Bravo\n") + _write(docs / "channels" / "A.md", "# Alpha\n") + pages = scan_docs(docs)["channels"] + self.assertEqual([page.title for page in pages], ["Alpha", "Bravo"]) + + def test_missing_h1_raises(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + docs = _docs_tree(Path(tmp)) + path = docs / "channels" / "EMPTY.md" + _write(path, "No heading here.\n") + with self.assertRaises(ValueError) as ctx: + parse_page(path, docs) + self.assertIn(str(path), str(ctx.exception)) + + def test_mkdocs_nav_shape(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + docs = _docs_tree(Path(tmp)) + _write( + docs / "channels" / "SEA.md", + "# Search Engine Advertising (SEA)\n\n\n", + ) + _write(docs / "resources" / "LEGAL.md", "# Legal\n") + nav = mkdocs_nav(docs) + self.assertEqual(nav[0], {"Home": "index.md"}) + self.assertEqual(nav[-1], {"Contributing": "CONTRIBUTING.md"}) + keys = [next(iter(item)) for item in nav] + self.assertEqual( + keys, + ["Home", "Channels", "Resources", "Templates", "Meta", "Contributing"], + ) + channels = nav[1]["Channels"] + self.assertEqual(channels[0], {"Channels": "channels/index.md"}) + self.assertEqual( + channels[1], + {"Search Engine Advertising (SEA)": "channels/SEA.md"}, + ) + resources = nav[2]["Resources"] + self.assertEqual(resources[0], {"Resources": "resources/index.md"}) + templates = nav[3]["Templates"] + self.assertEqual(templates[0], {"Templates": "ad-templates/index.md"}) + meta = nav[4]["Meta"] + self.assertEqual(meta[0], {"Meta": "meta/index.md"}) + + def test_render_index_uses_prefix(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + docs = _docs_tree(Path(tmp)) + _write(docs / "channels" / "SEA.md", "# Search\n") + pages = scan_docs(docs)["channels"] + rendered = render_index_markdown( + "Channels", + "Channel guides.", + pages, + "channels/", + ) + self.assertIn("# Channels", rendered) + self.assertIn("[Search](channels/SEA.md)", rendered) + self.assertIn("Generated by scripts/prepare-mkdocs.py", rendered) + + +if __name__ == "__main__": + unittest.main()