Twig Markdown Integration
Total CMS provides seamless markdown processing through Twig templates using ParsedownExtra, a powerful PHP markdown parser that supports extended markdown syntax.
Overview
Section titled “Overview”The markdown integration allows you to:
- Process markdown content stored in CMS collections
- Use extended markdown features like tables, footnotes, and fenced code blocks
- Safely render user-generated markdown content with built-in XSS protection
- Combine markdown with Twig templating for dynamic content
Markdown Parser
Section titled “Markdown Parser”Total CMS uses ParsedownExtra which extends the standard Parsedown library with additional features:
- Standard Markdown: Headers, paragraphs, lists, links, images, emphasis
- GitHub Flavored Markdown: Fenced code blocks, tables, strikethrough
- Extended Features: Footnotes, definition lists, abbreviations
- Security: Safe mode enabled to prevent XSS attacks
- Line Breaks: Automatic conversion of single line breaks to
<br>tags
Basic Usage
Section titled “Basic Usage”The |markdown Filter
Section titled “The |markdown Filter”Use the |markdown filter to process full markdown content including block elements (paragraphs, headers, lists, etc.):
{# Process markdown content #}{{ content|markdown }}
{# Process markdown from a collection object #}{{ post.content|markdown }}
{# Combine with other filters #}{{ article.body|markdown|raw }}The |markdownInline Filter
Section titled “The |markdownInline Filter”Use |markdownInline when you need to process markdown within existing HTML elements without adding wrapper tags like <p>:
{# In headings - no <p> wrapper added #}<h2>{{ page.title|markdownInline }}</h2>
{# In list items #}<ul> {% for feature in product.features %} <li>{{ feature|markdownInline }}</li> {% endfor %}</ul>
{# In existing paragraphs #}<p class="tagline">{{ product.tagline|markdownInline }}</p>Comparison:
{# markdown filter - adds <p> wrapper #}{{ "Visit our **website**"|markdown }}{# Output: <p>Visit our <strong>website</strong></p> #}
{# markdownInline filter - no wrapper #}{{ "Visit our **website**"|markdownInline }}{# Output: Visit our <strong>website</strong> #}Supported inline syntax: bold (**text**), italic (*text*), code (`code`), links ([text](url)), and images ().
Processing Collection Content
Section titled “Processing Collection Content”When working with blog posts or articles stored in collections:
{# Display a blog post with markdown content #}<article> <h1>{{ post.title }}</h1> <div class="meta"> <time>{{ post.date|date('F j, Y') }}</time> <span>by {{ post.author }}</span> </div> <div class="content"> {{ post.content|markdown }} </div></article>Processing String Properties
Section titled “Processing String Properties”For StringData properties that contain markdown:
{# StringData with markdown content #}<div class="description"> {{ product.description|markdown }}</div>
{# Check if content contains markdown before processing #}{% if article.summary contains '#' or article.summary contains '*' %} {{ article.summary|markdown }}{% else %} <p>{{ article.summary }}</p>{% endif %}Advanced Markdown Features
Section titled “Advanced Markdown Features”Tables
Section titled “Tables”ParsedownExtra supports GitHub-style tables:
| Feature | Status | Notes ||---------|--------|-------|| Headers | ✓ | H1-H6 supported || Tables | ✓ | GitHub style || Footnotes | ✓ | Extended syntax |{# Process table content #}<div class="table-responsive"> {{ specs.comparison_table|markdown }}</div>Code Blocks
Section titled “Code Blocks”Fenced code blocks with syntax highlighting:
```php<?phpecho "Hello World!";```twig{# Code documentation with syntax highlighting #}<div class="code-documentation"> {{ tutorial.code_examples|markdown }}</div>Footnotes
Section titled “Footnotes”Extended footnotes syntax:
This is a text with footnote[^1].
[^1]: This is the footnote content.{# Academic or detailed content with footnotes #}<div class="research-paper"> {{ paper.content|markdown }}</div>Template Examples
Section titled “Template Examples”Blog Template
Section titled “Blog Template”{# blog-post.twig #}{% extends "layouts/main.twig" %}
{% block content %}<div class="blog-post"> <header class="post-header"> <h1>{{ post.title }}</h1> <div class="post-meta"> <time datetime="{{ post.date|date('c') }}"> {{ post.date|date('F j, Y') }} </time> {% if post.author %} <span class="author">by {{ post.author }}</span> {% endif %} {% if post.tags %} <div class="tags"> {% for tag in post.tags %} <span class="tag">{{ tag }}</span> {% endfor %} </div> {% endif %} </div> </header>
<div class="post-content"> {{ post.content|markdown }} </div>
{% if post.excerpt %} <div class="post-excerpt"> <h3>Summary</h3> {{ post.excerpt|markdown }} </div> {% endif %}</div>{% endblock %}Documentation Template
Section titled “Documentation Template”{# documentation.twig #}{% extends "layouts/docs.twig" %}
{% block content %}<div class="documentation"> {% if page.toc %} <aside class="table-of-contents"> {{ page.toc|markdown }} </aside> {% endif %}
<main class="doc-content"> <h1>{{ page.title }}</h1>
{% if page.description %} <div class="description"> {{ page.description|markdown }} </div> {% endif %}
<div class="content"> {{ page.content|markdown }} </div>
{% if page.code_examples %} <section class="examples"> <h2>Examples</h2> {{ page.code_examples|markdown }} </section> {% endif %} </main></div>{% endblock %}Product Listing with Markdown Descriptions
Section titled “Product Listing with Markdown Descriptions”{# products.twig #}<div class="products-grid"> {% for product in cms.collection.objects('products') %} <div class="product-card"> {% if product.image %} <img src="{{ product.image }}" alt="{{ product.title }}"> {% endif %}
<div class="product-info"> <h3>{{ product.title }}</h3>
{% if product.short_description %} <div class="short-description"> {{ product.short_description|markdown }} </div> {% endif %}
<div class="price">${{ product.price }}</div>
<a href="/product/{{ product.slug }}" class="btn"> View Details </a> </div> </div> {% endfor %}</div>Security Considerations
Section titled “Security Considerations”ParsedownExtra runs in safe mode by default, which:
- Prevents execution of raw HTML that could contain malicious scripts
- Filters out dangerous HTML attributes and elements
- Protects against XSS (Cross-Site Scripting) attacks
- Maintains the security of user-generated content
{# Safe processing of user-generated markdown #}<div class="user-content"> {{ user_comment.content|markdown }} {# XSS protection is automatic #}</div>Performance Tips
Section titled “Performance Tips”Caching Processed Content
Section titled “Caching Processed Content”For frequently accessed content, consider caching the processed markdown:
{# Use Twig's cache for expensive operations #}{% set processed_content %} {{ large_document.content|markdown }}{% endset %}
{% cache 'doc_' ~ large_document.id for 3600 %} {{ processed_content }}{% endcache %}Conditional Processing
Section titled “Conditional Processing”Only process content through markdown when necessary:
{# Check if content needs markdown processing #}{% if content contains '#' or content contains '*' or content contains '[' %} {{ content|markdown }}{% else %} <p>{{ content|nl2br }}</p>{% endif %}Combining with Other Features
Section titled “Combining with Other Features”Markdown with Form Builder
Section titled “Markdown with Form Builder”{# Create forms that accept markdown input #}{{ cms.form.textarea('content', { 'label': 'Content', 'help': 'You can use markdown syntax here', 'rows': 10, 'class': 'markdown-editor'}) }}
{# Preview processed markdown #}{% if content %} <div class="markdown-preview"> <h4>Preview:</h4> {{ content|markdown }} </div>{% endif %}Markdown in Email Templates
Section titled “Markdown in Email Templates”{# email-template.twig #}<div class="email-content"> <h1>{{ email.subject }}</h1>
<div class="message"> {{ email.message|markdown }} </div>
{% if email.signature %} <div class="signature"> {{ email.signature|markdown }} </div> {% endif %}</div>Best Practices
Section titled “Best Practices”- Content Structure: Store markdown in StringData properties for automatic sanitization
- Performance: Cache processed markdown for large documents
- User Experience: Provide markdown syntax help for content editors
- Validation: Validate markdown content before saving to collections
- Fallback: Always provide fallback rendering for non-markdown content
Common Use Cases
Section titled “Common Use Cases”- Blog Posts: Article content with rich formatting
- Documentation: Technical documentation with code examples
- Product Descriptions: Rich product information with formatting
- Comments: User-generated content with safe formatting
- Email Templates: Rich email content with markdown formatting
- Static Pages: Content pages with complex formatting needs
The markdown integration in Total CMS provides a powerful yet secure way to handle rich text content while maintaining the flexibility of Twig templating.