- all_posts/0 now excludes posts where date > today - all_tags/0 computed at runtime from filtered posts - posts_by_tag/1 and recent_posts/1 inherit date filtering - Add unfiltered_posts/0 to Blog macro and FakeBlog - Add all_posts_unfiltered/0 to Registry for dashboard use
125 lines
3.4 KiB
Elixir
125 lines
3.4 KiB
Elixir
defmodule Blogex do
|
|
@moduledoc """
|
|
Blogex — a multi-blog engine for Phoenix apps, powered by NimblePublisher.
|
|
|
|
Blogex lets you host multiple blogs (e.g. engineering blog, release notes)
|
|
from markdown files in your repo. Posts are compiled into the BEAM at build
|
|
time for instant reads with zero runtime I/O.
|
|
|
|
## Quick Start
|
|
|
|
1. Add `blogex` to your dependencies:
|
|
|
|
```elixir
|
|
def deps do
|
|
[
|
|
{:blogex, "~> 0.1.0"}
|
|
]
|
|
end
|
|
```
|
|
|
|
2. Create your markdown posts:
|
|
|
|
```
|
|
priv/blog/engineering/2026/03-10-our-new-architecture.md
|
|
priv/blog/release-notes/2026/03-01-v2-launch.md
|
|
```
|
|
|
|
Each file has frontmatter + content:
|
|
|
|
```markdown
|
|
%{
|
|
title: "Our New Architecture",
|
|
author: "Jane Doe",
|
|
tags: ~w(elixir architecture),
|
|
description: "How we rebuilt our platform"
|
|
}
|
|
---
|
|
Your markdown content here...
|
|
```
|
|
|
|
3. Define blog modules in your app:
|
|
|
|
```elixir
|
|
defmodule Firehose.EngineeringBlog do
|
|
use Blogex.Blog,
|
|
blog_id: :engineering,
|
|
app: :firehose,
|
|
from: "priv/blog/engineering/**/*.md",
|
|
title: "Engineering Blog",
|
|
description: "Deep dives into our tech stack",
|
|
base_path: "/blog/engineering"
|
|
end
|
|
|
|
defmodule Firehose.ReleaseNotes do
|
|
use Blogex.Blog,
|
|
blog_id: :release_notes,
|
|
app: :firehose,
|
|
from: "priv/blog/release-notes/**/*.md",
|
|
title: "Release Notes",
|
|
description: "What's new in our product",
|
|
base_path: "/blog/releases"
|
|
end
|
|
```
|
|
|
|
4. Register blogs in your config:
|
|
|
|
```elixir
|
|
config :blogex,
|
|
blogs: [Firehose.EngineeringBlog, Firehose.ReleaseNotes]
|
|
```
|
|
|
|
5. Mount routes in your Phoenix router:
|
|
|
|
```elixir
|
|
scope "/blog" do
|
|
pipe_through :browser
|
|
|
|
forward "/engineering", Blogex.Router, blog: Firehose.EngineeringBlog
|
|
forward "/releases", Blogex.Router, blog: Firehose.ReleaseNotes
|
|
end
|
|
```
|
|
|
|
6. Enable live reloading in `config/dev.exs`:
|
|
|
|
```elixir
|
|
live_reload: [
|
|
patterns: [
|
|
...,
|
|
~r"priv/blog/*/.*(md)$"
|
|
]
|
|
]
|
|
```
|
|
|
|
## Architecture (Poncho Pattern)
|
|
|
|
Blogex is designed as a "poncho" — it wraps NimblePublisher and provides
|
|
a clean public API while the inner library does the heavy lifting of
|
|
markdown parsing and compilation. The host app's supervision tree is used
|
|
directly; Blogex adds no processes of its own since all data is compiled
|
|
into module attributes at build time.
|
|
|
|
## Modules
|
|
|
|
* `Blogex.Blog` — macro to define a blog context
|
|
* `Blogex.Post` — post struct
|
|
* `Blogex.Registry` — cross-blog queries
|
|
* `Blogex.Feed` — RSS/Atom feed generation
|
|
* `Blogex.SEO` — meta tags and sitemap generation
|
|
* `Blogex.Components` — Phoenix function components
|
|
* `Blogex.Router` — mountable Plug router
|
|
"""
|
|
|
|
@doc "Returns true if draft posts should be visible (dev/test environments)."
|
|
def show_drafts? do
|
|
Application.get_env(:blogex, :show_drafts, false)
|
|
end
|
|
|
|
defdelegate blogs, to: Blogex.Registry
|
|
defdelegate get_blog!(blog_id), to: Blogex.Registry
|
|
defdelegate get_blog(blog_id), to: Blogex.Registry
|
|
defdelegate all_posts, to: Blogex.Registry
|
|
defdelegate all_posts_unfiltered, to: Blogex.Registry
|
|
defdelegate all_tags, to: Blogex.Registry
|
|
end
|