Static site generator supporting Markdown and reStructuredText
—
Generator classes that process different content types and produce output files through theme rendering, pagination, and content organization. Generators form the core processing pipeline of Pelican's site generation.
Foundation class for all content generators providing common functionality for template rendering, context management, and output generation.
class Generator:
"""
Base class for all content generators.
Parameters:
- context (dict): Shared context between all generators
- settings (dict): Site configuration dictionary
- path (str): Content source directory path
- theme (str): Theme directory path
- output_path (str): Output directory path
- readers_cache_name (str, optional): Cache name for readers
"""
def __init__(
self,
context: dict,
settings: dict,
path: str,
theme: str,
output_path: str,
readers_cache_name: str = "",
**kwargs
): ...
# Core attributes available after initialization
context: dict # Shared context dictionary
settings: dict # Site settings
path: str # Content source path
theme: str # Theme path
output_path: str # Output directory
readers: Readers # Content readers instance
env: Environment # Jinja2 template environment
def generate_context(self) -> None:
"""Generate content and populate context."""
def generate_output(self, writer) -> None:
"""Generate output files using provided writer."""Generates blog articles with automatic categorization, tagging, pagination, and archive creation.
class ArticlesGenerator(CachingGenerator):
"""
Generator for blog articles and related pages.
Processes article content files and generates:
- Individual article pages
- Category pages with article listings
- Tag pages with article listings
- Author pages with article listings
- Archive pages (yearly, monthly, daily)
- Article pagination
- RSS/Atom feeds
"""
# Content collections (populated after generate_context())
articles: list[Article] # Published articles
translations: list[Article] # Article translations
drafts: list[Article] # Draft articles
drafts_translations: list[Article] # Draft translations
hidden_articles: list[Article] # Hidden articles
hidden_translations: list[Article] # Hidden translations
# Organizational collections
categories: list[tuple[Category, list[Article]]] # Categories with articles
tags: list[tuple[Tag, list[Article]]] # Tags with articles
authors: list[tuple[Author, list[Article]]] # Authors with articles
# Date-based archives
dates: list[Article] # Articles sorted by date
def generate_feeds(self) -> None:
"""Generate RSS/Atom feeds for articles."""
def generate_articles(self, write: callable) -> None:
"""Generate individual article pages."""
def generate_period_archives(self, write: callable) -> None:
"""Generate date-based archive pages."""
def generate_direct_templates(self, write: callable) -> None:
"""Generate direct template pages (index, tags, categories, authors, archives)."""
def generate_tags(self, write: callable) -> None:
"""Generate tag pages with article listings."""
def generate_categories(self, write: callable) -> None:
"""Generate category pages with article listings."""
def generate_authors(self, write: callable) -> None:
"""Generate author pages with article listings."""Generates static pages for non-blog content with support for hierarchical organization and custom templates.
class PagesGenerator(CachingGenerator):
"""
Generator for static pages.
Processes page content files and generates:
- Individual page files
- Page hierarchies and navigation
- Custom page templates
"""
# Content collections (populated after generate_context())
pages: list[Page] # Published pages
translations: list[Page] # Page translations
hidden_pages: list[Page] # Hidden pages
hidden_translations: list[Page] # Hidden translations
draft_pages: list[Page] # Draft pages
draft_translations: list[Page] # Draft translations
def generate_pages(self, write: callable) -> None:
"""Generate individual page files."""Handles static files by copying them from source to output directory with optional processing and linking.
class StaticGenerator(Generator):
"""
Generator for static files (images, CSS, JS, etc.).
Copies static files from source directories to output directory.
Handles file modification detection and selective copying.
"""
# File collections (populated after generate_context())
staticfiles: list[Static] # Static file objects
def generate_output(self, writer) -> None:
"""Copy static files to output directory."""Generates pages directly from Jinja2 templates without content files, useful for dynamic pages and special layouts.
class TemplatePagesGenerator(Generator):
"""
Generator for template-based pages.
Generates pages directly from Jinja2 templates specified in TEMPLATE_PAGES setting.
Useful for complex layouts, landing pages, or pages with dynamic content.
"""
def generate_output(self, writer) -> None:
"""Generate pages from templates."""Copies original source files to output directory for transparency and debugging purposes.
class SourceFileGenerator(Generator):
"""
Generator for source file copies.
Copies original content source files to output directory when OUTPUT_SOURCES is enabled.
Useful for debugging, transparency, or allowing readers to view source markup.
"""
def generate_output(self, writer) -> None:
"""Copy source files to output directory."""Base class for generators that support content caching for improved performance on large sites.
class CachingGenerator(Generator, FileStampDataCacher):
"""
Base class for generators with file caching support.
Provides caching functionality to avoid reprocessing unchanged content files.
Used by ArticlesGenerator and PagesGenerator for performance optimization.
"""
def generate_context(self) -> None:
"""Generate content with caching support."""
def check_disabled_readers(self) -> None:
"""Check for disabled readers and warn about unprocessed files."""The generation process follows this sequence:
from pelican.generators import Generator
class CustomGenerator(Generator):
"""Custom generator for special content processing."""
def generate_context(self):
"""Generate custom content and add to context."""
# Process custom content files
custom_content = self.process_custom_files()
# Add to shared context
self.context['custom_content'] = custom_content
def generate_output(self, writer):
"""Generate custom output files."""
for content in self.context['custom_content']:
writer.write_file(
content.save_as,
self.get_template(content.template),
self.context,
content=content
)
def process_custom_files(self):
"""Process custom content files."""
# Custom file processing logic
return []# In a plugin or custom generator
def process_articles_generator(generator):
"""Process articles after generation."""
# Access all articles
for article in generator.articles:
print(f"Article: {article.title}")
print(f"URL: {article.url}")
print(f"Category: {article.category.name}")
# Access categories with articles
for category, articles in generator.categories:
print(f"Category: {category.name} ({len(articles)} articles)")
# Access tags with articles
for tag, articles in generator.tags:
print(f"Tag: {tag.name} ({len(articles)} articles)")
# Register with plugin system
from pelican.plugins import signals
signals.all_generators_finalized.connect(process_articles_generator)# In pelicanconf.py - configure generator behavior
# Article generator settings
ARTICLE_URL = '{date:%Y}/{date:%m}/{slug}.html'
ARTICLE_SAVE_AS = '{date:%Y}/{date:%m}/{slug}.html'
DEFAULT_PAGINATION = 10
PAGINATED_TEMPLATES = {
'index': None,
'tag': None,
'category': None,
'author': None,
}
# Static generator settings
STATIC_PATHS = ['images', 'css', 'js', 'downloads']
STATIC_EXCLUDES = ['.DS_Store']
# Template pages
TEMPLATE_PAGES = {
'special.html': 'special-page.html',
'landing.html': 'index.html'
}
# Source file output
OUTPUT_SOURCES = True
OUTPUT_SOURCES_EXTENSION = '.txt'from pelican.generators import ArticlesGenerator
class EnhancedArticlesGenerator(ArticlesGenerator):
"""Enhanced articles generator with custom processing."""
def generate_context(self):
"""Generate context with custom enhancements."""
super().generate_context()
# Add custom processing
self.process_related_articles()
self.generate_reading_time()
def process_related_articles(self):
"""Add related articles to each article."""
for article in self.articles:
# Find related articles by tags
related = []
for other in self.articles:
if other != article and set(article.tags) & set(other.tags):
related.append(other)
article.related_articles = related[:5] # Limit to 5
def generate_reading_time(self):
"""Calculate reading time for articles."""
for article in self.articles:
word_count = len(article.content.split())
reading_time = max(1, word_count // 200) # ~200 words per minute
article.reading_time = reading_timeInstall with Tessl CLI
npx tessl i tessl/pypi-pelican