• Stars
    star
    191
  • Rank 201,626 (Top 4 %)
  • Language
    Python
  • License
    zlib License
  • Created about 9 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Markdown support for Wagtail

wagtail-markdown: Markdown fields and blocks for Wagtail

Build status PyPI black pre-commit.ci status

Tired of annoying rich text editors getting in the way of your content input? Wish Wagtail worked more like a wiki? Well, now it can.

wagtail-markdown provides Markdown field support for Wagtail. Specifically, it provides:

  • A wagtailmarkdown.blocks.MarkdownBlock for use in StreamFields.
  • A wagtailmarkdown.fields.MarkdownField for use in Page models.
  • A wagtailmarkdown.edit_handlers.MarkdownPanel for use in the editor interface.
  • A markdown template tag.

The markdown rendered is based on python-markdown, but with several extensions to make it actually useful in Wagtail:

These are implemented using the python-markdown extension interface.

Installation

Available on PyPI - https://pypi.org/project/wagtail-markdown/.

Install using pip (pip install wagtail-markdown), poetry (poetry add wagtail-markdown) or your package manager of choice.

After installing the package, add wagtailmarkdown to the list of installed apps in your settings file:

# settings.py

INSTALLED_APPS = [
    # ...
    "wagtailmarkdown",
]

Configuration

All wagtail-markdown settings are defined in a single WAGTAILMARKDOWN dictionary in your settings file:

# settings.py

WAGTAILMARKDOWN = {
    "autodownload_fontawesome": False,
    "allowed_tags": [],  # optional. a list of HTML tags. e.g. ['div', 'p', 'a']
    "allowed_styles": [],  # optional. a list of styles
    "allowed_attributes": {},  # optional. a dict with HTML tag as key and a list of attributes as value
    "allowed_settings_mode": "extend",  # optional. Possible values: "extend" or "override". Defaults to "extend".
    "extensions": [],  # optional. a list of python-markdown supported extensions
    "extension_configs": {},  # optional. a dictionary with the extension name as key, and its configuration as value
    "extensions_settings_mode": "extend",  # optional. Possible values: "extend" or "override". Defaults to "extend".
}

Note: allowed_tags, allowed_styles, allowed_attributes, extensions and extension_configs are added to the default wagtail-markdown settings.

Custom FontAwesome Configuration - autodownload_fontawesome

The EasyMDE editor is compatible with FontAwesome 5. By default, EasyMDE will get version 4.7.0 from a CDN. To specify your own version, set

# settings.py

WAGTAILMARKDOWN = {
    # ...
    "autodownload_fontawesome": False,
}

Get the desired FontAwesome version. For the latest version you can use:

curl -H "Content-Type: application/json" \
-d '{ "query": "query { release(version: \"latest\") { version } }" }' \
https://api.fontawesome.com

then add the following to a wagtail_hooks module in a registered app in your application:

# Content of app_name/wagtail_hooks.py
from wagtail import hooks
from django.conf import settings
from django.utils.html import format_html


@hooks.register("insert_global_admin_css")
def import_fontawesome_stylesheet():
    elem = '<link rel="stylesheet" href="{}path/to/font-awesome.min.css">'.format(
        settings.STATIC_URL
    )
    return format_html(elem)

Note that due to the way EasyMDE defines the toolbar icons it is not compatible with Wagtail FontAwesome

Using with django-compressor

You may have your own SCSS sources that you want to precompile on the fly. We can invoke django-compressor to fetch our Font Awesome SCSS sources like this:

# Content of app_name/wagtail_hooks.py
from compressor.css import CssCompressor
from wagtail import hooks
from django.conf import settings
from django.utils.html import format_html


@hooks.register("insert_global_admin_css")
def import_fontawesome_stylesheet():
    elem = '<link rel="stylesheet" type="text/x-scss" href="{}scss/fontawesome.scss">'.format(
        settings.STATIC_URL
    )
    compressor = CssCompressor("css", content=elem)
    output = ""
    for s in compressor.hunks():
        output += s
    return format_html(output)

Markdown extensions - extensions/extension_configs

You can configure wagtail-markdown to use additional Markdown extensions using the extensions setting.

For example, to enable the Table of Contents and Sane Lists extensions:

WAGTAILMARKDOWN = {
    # ...
    "extensions": ["toc", "sane_lists"]
}

Extensions can be configured too:

WAGTAILMARKDOWN = {
    # ...
    "extension_configs": {"pymdownx.arithmatex": {"generic": True}}
}

Allowed HTML - allowed_styles / allowed_attributes / allowed_tags

wagtail-markdown uses bleach to sanitise the input. To extend the default bleach configurations, you can add your own allowed tags, styles or attributes:

WAGTAILMARKDOWN = {
    # ...
    "allowed_tags": ["i"],
    "allowed_styles": ["some_style"],
    "allowed_attributes": {"i": ["aria-hidden"]},
}

Syntax highlighting

Syntax highlighting using codehilite is an optional feature, which works by adding CSS classes to the generated HTML. To use these classes, you will need to install Pygments (pip install Pygments), and to generate an appropriate stylesheet. You can generate one as per the Pygments documentation, with:

from pygments.formatters import HtmlFormatter

print(HtmlFormatter().get_style_defs(".codehilite"))

Save the output to a file and reference it somewhere that will be picked up on pages rendering the relevant output, e.g. your base template:

<link rel="stylesheet" type="text/css" href="{% static 'path/to/pygments.css' %}">

EasyMDE configuration

You can customise the EasyMDE options. To do this, create a JavaScript file in your app (for example my_app_name/static/js/easymde_custom.js) and add the following:

window.wagtailMarkdown = window.wagtailMarkdown || {};
window.wagtailMarkdown.options = window.wagtailMarkdown.options || {};
window.wagtailMarkdown.options.spellChecker = false;

This overrides a specific option and leaves any other ones untouched. If you want to override all options, you can do:

window.wagtailMarkdown = window.wagtailMarkdown || {};
window.wagtailMarkdown.options = {
    spellChecker: false,
}

To make sure that your JavaScript is executed, create a hook in my_app_name/wagtail_hooks.py:

from django.templatetags.static import static
from django.utils.html import format_html

from wagtail import hooks


@hooks.register("insert_global_admin_js", order=100)
def global_admin_js():
    """Add /static/js/admin/easymde_custom.js to the admin."""
    return format_html('<script src="{}"></script>', static("js/easymde_custom.js"))

Inline links

wagtail-markdown supports custom inline links syntax:

Link to Syntax Notes
Pages [title](page:PAGE_ID) PAGE_ID is the page ID
Documents [title](doc:DOCUMENT_ID) DOCUMENT_ID is the document ID
Media [title](media:MEDIA_ID) Needs wagtailmedia. MEDIA_ID is the media item ID
Images ![alt text](image:IMAGE_ID) Renders an image tag. IMAGE_ID is the image ID
↳ with class attribute ![alt text](image:IMAGE_ID,class=the-class-name) adds class="the-class-name" to the ` tag
↳ with rendition filter ![alt text](image:IMAGE_ID,filter=fill-200x200&#x7c;format-webp) Uses the same format as generating renditions in Python
↳ class name and filter can be stacked ![alt text](image:IMAGE_ID,class=the-class-name,filter=width-100)

Previously we supported custom link tags that used the target object title. They had the following form:

  • <:My page name|link title> or <:page:My page title>
  • <:doc:My fancy document.pdf>
  • <:image:My pretty image.jpeg>, <:image:My pretty image.jpeg|left> (left classname), <:image:My pretty image.jpeg|right> (right classname), <:image:My pretty image.jpeg|full> (full-name classname), <:image:My pretty image.jpeg|width=123> (outputs a rendition with width-123, and class left)

⚠️ these types of tags are not reliable as titles can and will change. Support for will be removed in the future.

Usage

You can use it as a StreamField block:

from wagtail.blocks import StreamBlock

from wagtailmarkdown.blocks import MarkdownBlock


class MyStreamBlock(StreamBlock):
    markdown = MarkdownBlock(icon="code")
    # ...

Or use as a page field:

from wagtail.admin.panels import FieldPanel
from wagtail.models import Page

from wagtailmarkdown.fields import MarkdownField


class MyPage(Page):
    body = MarkdownField()

    content_panels = [
        FieldPanel("title", classname="full title"),
        FieldPanel("body"),
    ]

And render the content in a template:

{% load wagtailmarkdown %}
<article>
{{ self.body|markdown }}
</article>

Compatibility

wagtail-markdown supports Wagtail 2.15 and above, python-markdown 3.3 and above.

Contributing

All contributions are welcome!

Note that this project uses pre-commit. To set up locally:

# if you don't have it yet
$ pip install pre-commit
# go to the project directory
$ cd wagtail-markdown
# initialize pre-commit
$ pre-commit install

# Optional, run all checks once for this, then the checks will run only on the changed files
$ pre-commit run --all-files

How to run tests

Now you can run tests as shown below:

tox -p

or, you can run them for a specific environment tox -e py311-django3.2-wagtail4.1 or specific test tox -e py311-django3.2-wagtail4.1 tests.testapp.tests.test_admin.TestFieldsAdmin

More Repositories

1

django-recaptcha

New maintainers 🚧 --- Django reCAPTCHA form field/widget integration app.
Python
929
star
2

django-pattern-library

UI pattern libraries for Django templates
Python
359
star
3

django-libsass

A django-compressor filter to compile SASS files using libsass
Python
265
star
4

vagrant-django-template

Skeleton project for a Django app running under Vagrant
Python
240
star
5

wagtailmedia

A Wagtail module for managing video and audio files within the admin
Python
231
star
6

wagtail-grapple

A Wagtail app that makes building GraphQL endpoints a breeze!
Python
152
star
7

wagtail-torchbox

Wagtail build of Torchbox.com
Python
124
star
8

wagtail-headless-preview

Previews for headless Wagtail setups
Python
116
star
9

wagtail-experiments

A/B testing for Wagtail
Python
105
star
10

vagrant-django-base

Vagrant configuration for a base box for Django development
Shell
90
star
11

storybook-django

Develop Django UI components in isolation, with Storybook
JavaScript
83
star
12

cookiecutter-wagtail

Python
54
star
13

k8s-hostpath-provisioner

Network storage provisioner for Kubernetes
Go
52
star
14

kdtool

Kubernetes deployment utility
Python
45
star
15

kube-ldap-authn

Kubernetes LDAP authentication service
Python
42
star
16

wagtail-wordpress-import

A package for Wagtail CMS to import WordPress blog content from an XML file into Wagtail
Python
41
star
17

wagtail-storages

Use AWS S3 with private documents in Wagtail
Python
40
star
18

design-in-browser-bootstrap

An aid to quickly starting Design In the Browser
JavaScript
34
star
19

wagtail-import-export

UNMAINTAINED. Try wagtail-transfer, the evolution of this package: https://github.com/wagtail/wagtail-transfer/
Python
32
star
20

wagtail-content-import

A module for importing page content into Wagtail from third-party sources. Docs:
Python
32
star
21

rustface-py

Python library for detecting faces in images.
Rust
31
star
22

wagtailquickcreate

Wagtail Quick Create offers shortcut links to create objects from models specified in your settings file.
Python
25
star
23

wagtailguide

An app for adding a CMS guide to your Wagtail CMS
Python
23
star
24

k8s-ts-ingress

Kubernetes Ingress controller as a Traffic Server plugin
C
22
star
25

wagtailsurveys

Python
21
star
26

vagrant-thumbor-base

Vagrant box providing a thumbor service over HTTP
Shell
20
star
27

wagtail-footnotes

Python
19
star
28

wagtail-template

A Django template for starting new Wagtail projects with Vagrant. NO LONGER MAINTANED
Python
19
star
29

wagtail-ab-testing

A/B testing for Wagtail
Python
17
star
30

buckup

Creating S3 buckets for your site with ease.
Python
16
star
31

torchbox-frontend

JavaScript
16
star
32

wagtail-appengine-demo

The simplest possible Wagtail site on Google Cloud
CSS
15
star
33

django-basic-auth-ip-whitelist

Hide your Django site behind basic authentication with IP whitelisting support
Python
14
star
34

verdant-rca

Python
13
star
35

docker-php

Docker PHP Images based on official PHP
Shell
12
star
36

longform

A plugin for longform content in Wagtail
CSS
12
star
37

wagtail-purge

A simple Wagtail admin UI for removing individual pages from your CDN's cache
Python
10
star
38

wagtail-webstories

AMP web story support for Wagtail
Python
9
star
39

cloudflare-recipes

Cloudflare service worker recipes
JavaScript
7
star
40

rca-wagtail-2019

Python
7
star
41

trafficserver-ingress-controller

Apache Traffic Server ingress controller for Kubernetes
Perl
7
star
42

tbxforms

A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds.
HTML
6
star
43

stylelint-config-torchbox

Shareable stylelint config for CSS and SCSS, following Torchbox’s code style.
JavaScript
6
star
44

wagtailapi

A module for adding a read only, JSON based web API to your Wagtail site (NO LONGER MAINTAINED! Use Wagtails contrib.wagtailapi module instead)
Python
6
star
45

webstories

Parser for AMP web stories
Python
6
star
46

wagtail-makeup

Wagtail plugin to replace all your broken local images with unsplash ones
Python
6
star
47

samaritans-patterns

HTML
5
star
48

wagtail-bookmarklet

Gives Wagtail editors an 'edit this page' bookmarklet, for scenarios where the user bar isn't available
Python
5
star
49

django-registration

Tweaked Django >=1.6-compatible version of django-registration
Python
5
star
50

careers

Torchbox careers site
TypeScript
4
star
51

ample

Cross-browser audio playback library, with HTML5 and Flash backends
JavaScript
4
star
52

nhs-organisations

Python
3
star
53

wagtail-jotform

A plugin for using jotforms in wagtail
Python
3
star
54

wagtail-bynder

Wagtail + Bynder Digital Asset Management System integration
Python
3
star
55

wagtailapidemo

Wagtaildemo with API enabled
Python
3
star
56

eslint-config-torchbox

Shareable ESLint config following Torchbox’s code style
JavaScript
3
star
57

wagtail-mongodb

Python
3
star
58

dit_directory_cms_poc

Proof-of-concepts for potential improvements to uktrade/directory-cms
Python
2
star
59

christmas-video-2017

CSS
2
star
60

wagtail-related

Python
2
star
61

resourcespace_plugin-api_markasused

API plugin for resourcespace that updates a resourcespace entry
PHP
2
star
62

wagtail-azure-cdn

Use Azure CDN with Wagtail CMS.
Python
2
star
63

heroku-cloudflare-app-domain

Create branded herokuapp.com domains through Cloudflare
Python
2
star
64

demo.wagtail.io

Configuration for demo.wagtail.io
Python
2
star
65

christmaschorus

the 2011 musical christmas card
JavaScript
2
star
66

ngxpurged

nginx cache purge daemon
Python
2
star
67

django-tagging

Fork via PyPI v0.3.4 to maintain Django compatibility. Unmaintained for Django >= 1.10
Python
2
star
68

torchbox.com

Torchbox website 2024 incarnation
Python
2
star
69

resourcespace_plugin-api_resource

API plugin for resourcespace that fetches a resource metadata or a resource file in stream
PHP
2
star
70

docker-rsync

Trivial Docker image containing Alpine Linux with rsync installed
Makefile
1
star
71

heroku-restarter

Restarts Heroku applications based on timeout alerts in Papertrail
Python
1
star
72

django-piston

Fork of the popular REST API mini-framework
Python
1
star
73

kube-registry-proxy

Shell
1
star
74

tate-cms

Tate CMS project’s sprint notes
1
star
75

docker-trafficserver

1
star
76

healtheintent-api-python

Python
1
star
77

raxtool

Rackspace Cloud management tool
Python
1
star
78

ceph-rbd-provisioner

1
star
79

django-importo

A developer-friendly framework for importing data into Django apps
Python
1
star
80

wagtail_picture_proposal

Code snippets for an experimental picture tag for Wagtail. Not intended for reuse
Python
1
star
81

nlbq

Natural language interface to BigQuery
Python
1
star
82

nuffield-nhs-timeline

Nuffield NHS Timeline
HTML
1
star