Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Basic idea behind the project was to be able to easily provide, provision and version content without a database backend. Also quite tempting: The markdown syntax.

Build Status Latest Stable Version Total Downloads Scrutinizer Code Quality phpci build status

What does it do?

You can configure following things:

  • Content directory
  • Markdown parser (php-markdown or parsedown)
  • Type of loader for the files (at the moment only file-loader)
  • And the prefix for your content routes

All URLs are dynamically generated and support subdirectories without limitations. MarkdowncontentBundle also supports translations! If you put your directory structure into a locale directory like content/en_US/ it will be loaded either when using w3c urls with locale or if locale is set in your kernel. If you want locale urls, please enable the config directive.


Some things you need to know!


You can set following things in your app/config.yml:

    content_directory: 'app/Resources/markdown'
    content_loader:    'file-loader'
    route_prefix:      'content'
    markdown_provider: 'php-markdown'
    #locale_url:        false


If you want, you can easily add new markdown parsers or content loaders, even hooks. For each type there's an interface you can build a tagged service upon:



class: 'Asm\MarkdownContentBundle\Content\ContentFileLoader'
    - '%kernel.root_dir%'
    - '%asm_markdown_content.content_directory%'
    - '%asm_markdown_content.content_path_depth%'
    - { name: asm_markdown_content.content_loader, alias: file-loader }



    class: 'Asm\MarkdownContentBundle\Parser\ParsedownParser'
        - { name: asm_markdown_content.parser, alias: parsedown }


Asm\MarkdownContentBundle\Hook\HookDataInterface Asm\MarkdownContentBundle\Hook\HookContentInterface

    class: 'Asm\MarkdownContentBundle\Hook\FrontMatterContentHook'
        - { name: asm_markdown_content.hook, alias: front_matter }

Hook system

The system is based on two events:

  • pre-content conversion
  • post-content conversion

For each registered hook service you have to set the type of hook in the getType() method. It's either 'post' or 'pre'. The hook just has one more interface method workContent() which receives the content array. Pre-hooks receive the file content ($content['content']) as an array of lines, post hook will get the whole stuff as a HTML string, because it's already markdown-converted.

$content = array(
    'content' => array()|string,
    'data'    => array(),

That's also the data structure you're needed to return from workContent(). What you're doing with the data is completely up to you. The main difference between 'pre' and 'post' is the state of either data nodes. In 'pre', all content is still raw markdown, data is maybe already prefilled by other hooks (metadata hook e.g.). 'post' gets the already converted html string from your configured markdown parser. There you have the possibility to change some tags, add classes, whatever you want.


The base layout uses bootstrap3 via CDN and provides some base for your own designs. Just override


in your own Bundle(s). Have a look at the variable names! Content template:


Meta data

Since there is an accepted format for page meta in markdown, I've switched to front matter. The general format is

title: Awesome page title
author: me, myself and I
date: 2014/02/09
sample_data: { some: data, more: data_stuff }

This block needs to be the first thing in your markdown file, no whitespaces or newlines before, and the FrontMatterContentHook will extract the contents as YAML and provide the data within the content array. So you have the opportunity to place virtually everything additional you need witin that block. Besides that, default metadata will be placed in the root of the data array. They are the filled with blank content if not set via front matter:

$defaults= array(
    'title'       => '',
    'description' => '',
    'author'      => '',
    'date'        => '',
    'robots'      => '',
    'content'     => '',
    'name'        => '',
    'keywords'    => '',

The front matter block from above will result in this array:

$data = array(
    'title'       => 'Awesome page title',
    'author'      => 'me, myself and I',
    'date'        => '2014/02/09',
    'description' => '',
    'robots'      => '',
    'content'     => '',
    'name'        => '',
    'keywords'    => '',
    'sample_data' => array(
        'some'    => 'data',
        'more'    => 'data_stuff',

The data array is available in your TWIG template and fill the fields automatically ;-)

Exporting of static pages

If you want to export all your markdown files as HTML, you can do so with following command:

app/console asm:markdown:export <absolute_export_dir> -i <optional_import_dir>

The exporter will use the configured markdown parser and if no import directory is provided, the configured one will be used by default. Your content is then rendered file by file into an equivalent folder stucture within the export directory, based on the provided templates. Keep in mind to add any css/js files to your static content directory :-)


  • precaching for markdown file search on compiler pass
  • caching of markdown content
  • maybe more loader types
  • online editor


AsmMarkdownContentBundle is licensed under the MIT license. See the LICENSE for the full license text.

Free Software, Hell Yeah!


Enables symfony to render markdown files as static content via dynamic router



No packages published