Installing Pelican
Pelican currently runs best on >=3.8.1; earlier versions of Python are not supported.
You can install Pelican via several different methods. The simplest is via Pip:
python -m pip install pelican
Or, if you plan on using Markdown:
python -m pip install "pelican[markdown]"
(Keep in mind that some operating systems will require you to prefix the above
command with sudo
in order to install Pelican system-wide.)
While the above is the simplest method, the recommended approach is to create a
virtual environment for Pelican via virtualenv before installing Pelican.
Assuming you have virtualenv installed, you can then open a new terminal
session and create a new virtual environment for Pelican:
virtualenv ~/virtualenvs/pelican
cd ~/virtualenvs/pelican
source bin/activate
Once the virtual environment has been created and activated, Pelican can be
installed via python -m pip install pelican
as noted above. Alternatively, if you
have the project source, you can install Pelican using the distutils method:
cd path-to-Pelican-source
python setup.py install
If you have Git installed and prefer to install the latest bleeding-edge
version of Pelican rather than a stable release, use the following command:
python -m pip install -e "git+https://github.com/getpelican/pelican.git#egg=pelican"
Once Pelican is installed, you can run pelican --help
to see basic usage
options. For more detail, refer to the Publish section.
Optional packages
If you plan on using Markdown as a
markup format, you can install Pelican with Markdown support:
python -m pip install "pelican[markdown]"
Typographical enhancements can be enabled in your settings file, but first the
requisite Typogrify library must be
installed:
python -m pip install typogrify
Dependencies
When Pelican is installed, the following dependent Python packages should be
automatically installed without any action on your part:
feedgenerator, to generate the
Atom feeds
jinja2, for templating support
pygments, for syntax highlighting
docutils, for supporting
reStructuredText as an input format
blinker, an object-to-object and
broadcast signaling system
unidecode, for ASCII
transliterations of Unicode text
utilities
MarkupSafe, for a markup-safe
string implementation
python-dateutil, to read
the date metadata
Upgrading
If you installed a stable Pelican release via Pip and wish to upgrade to
the latest stable release, you can do so by adding --upgrade
:
python -m pip install --upgrade pelican
If you installed Pelican via distutils or the bleeding-edge method, simply
perform the same step to install the most recent version.
Kickstart your site
Once Pelican has been installed, you can create a skeleton project via the
pelican-quickstart
command, which begins by asking some questions about
your site:
If run inside an activated virtual environment, pelican-quickstart
will
look for an associated project path inside $VIRTUAL_ENV/.project
. If that
file exists and contains a valid directory path, the new Pelican project will
be saved at that location. Otherwise, the default is the current working
directory. To set the new project path on initial invocation, use:
pelican-quickstart --path /your/desired/directory
Once you finish answering all the questions, your project will consist of the
following hierarchy (except for pages — shown in parentheses below — which
you can optionally add yourself if you plan to create non-chronological
content):
yourproject/
├── content
│ └── (pages)
├── output
├── tasks.py
├── Makefile
├── pelicanconf.py # Main settings file
└── publishconf.py # Settings to use when ready to publish
The next step is to begin to adding content to the content folder that has
been created for you.
Writing content
Articles and pages
Pelican considers “articles” to be chronological content, such as posts on a
blog, and thus associated with a date.
The idea behind “pages” is that they are usually not temporal in nature and are
used for content that does not change very often (e.g., “About” or “Contact”
pages).
You can find sample content in the repository at samples/content/
.
File metadata
Pelican tries to be smart enough to get the information it needs from the
file system (for instance, about the category of your articles), but some
information you need to provide in the form of metadata inside your files.
If you are writing your content in reStructuredText format, you can provide
this metadata in text files via the following syntax (give your file the
.rst
extension):
My super title
##############
:date: 2010-10-03 10:20
:modified: 2010-10-04 18:40
:tags: thats, awesome
:category: yeah
:slug: my-super-post
:authors: Alexis Metaireau, Conan Doyle
:summary: Short version for index and feeds
Author and tag lists may be semicolon-separated instead, which allows
you to write authors and tags containing commas:
:tags: pelican, publishing tool; pelican, bird
:authors: Metaireau, Alexis; Doyle, Conan
Pelican implements an extension to reStructuredText to enable support for the
abbr
HTML tag. To use it, write something like this in your post:
This will be turned into :abbr:`HTML (HyperText Markup Language)`.
You can also use Markdown syntax (with a file ending in .md
, .markdown
,
.mkd
, or .mdown
). Markdown generation requires that you first
explicitly install the Python-Markdown package, which can be done via pip
install Markdown
.
Pelican also supports Markdown Extensions, which might have to be installed
separately if they are not included in the default Markdown
package and can
be configured and loaded via the MARKDOWN
setting.
Metadata syntax for Markdown posts should follow this pattern:
Title: My super title
Date: 2010-12-03 10:20
Modified: 2010-12-05 19:30
Category: Python
Tags: pelican, publishing
Slug: my-super-post
Authors: Alexis Metaireau, Conan Doyle
Summary: Short version for index and feeds
This is the content of my super blog post.
You can also have your own metadata keys (so long as they don’t conflict with
reserved metadata keywords) for use in your templates. The following table
contains a list of reserved metadata keywords:
Metadata |
Description |
title
|
Title of the article or page |
date
|
Publication date (e.g., YYYY-MM-DD HH:SS ) |
modified
|
Modification date (e.g., YYYY-MM-DD HH:SS ) |
tags
|
Content tags, separated by commas |
keywords
|
Content keywords, separated by commas (HTML content only) |
category
|
Content category (one only — not multiple) |
slug
|
Identifier used in URLs and translations |
author
|
Content author, when there is only one |
authors
|
Content authors, when there are multiple |
summary
|
Brief description of content for index pages |
lang
|
Content language ID (en , fr , etc.) |
translation
|
If content is a translation of another (true or false ) |
status
|
Content status: draft , hidden , or published |
template
|
Name of template to use to generate content (without extension) |
save_as
|
Save content to this relative file path |
url
|
URL to use for this article/page |
Readers for additional formats (such as AsciiDoc) are available via plugins,
which you can find via the Pelican Plugins collection as well as the legacy
pelican-plugins repository.
Pelican can also process HTML files ending in .html
and .htm
. Pelican
interprets the HTML in a very straightforward manner, reading metadata from
meta
tags, the title from the title
tag, and the body out from the
body
tag:
<html>
<head>
<title>My super title</title>
<meta name="tags" content="thats, awesome" />
<meta name="date" content="2012-07-09 22:28" />
<meta name="modified" content="2012-07-10 20:14" />
<meta name="category" content="yeah" />
<meta name="authors" content="Alexis Métaireau, Conan Doyle" />
<meta name="summary" content="Short version for index and feeds" />
</head>
<body>
This is the content of my super blog post.
</body>
</html>
With HTML, there is one simple exception to the standard metadata: tags can be
specified either via the tags
metadata, as is standard in Pelican, or via
the keywords
metadata, as is standard in HTML. The two can be used
interchangeably.
Note that, aside from the title, none of this content metadata is mandatory:
if the date is not specified and DEFAULT_DATE
is set to 'fs'
, Pelican
will rely on the file’s “mtime” timestamp, and the category can be determined
by the directory in which the file resides. For example, a file located at
python/foobar/myfoobar.rst
will have a category of foobar
. If you would
like to organize your files in other ways where the name of the subfolder would
not be a good category name, you can set the setting USE_FOLDER_AS_CATEGORY
to False
. When parsing dates given in the page metadata, Pelican supports
the W3C’s suggested subset ISO 8601.
So the title is the only required metadata. If that bothers you, worry not.
Instead of manually specifying a title in your metadata each time, you can use
the source content file name as the title. For example, a Markdown source file
named Publishing via Pelican.md
would automatically be assigned a title of
Publishing via Pelican. If you would prefer this behavior, add the following
line to your settings file:
FILENAME_METADATA = '(?P<title>.*)'
Note
When experimenting with different settings (especially the metadata
ones) caching may interfere and the changes may not be visible. In
such cases disable caching with LOAD_CONTENT_CACHE = False
or
use the --ignore-cache
command-line switch.
modified
should be last time you updated the article, and defaults to
date
if not specified. Besides you can show modified
in the templates,
feed entries in feed readers will be updated automatically when you set
modified
to the current date after you modified your article.
authors
is a comma-separated list of article authors. If there’s only one
author you can use author
field.
If you do not explicitly specify summary metadata for a given post, the
SUMMARY_MAX_LENGTH
setting can be used to specify how many words from the
beginning of an article are used as the summary.
You can also extract any metadata from the filename through a regular
expression to be set in the FILENAME_METADATA
setting. All named groups
that are matched will be set in the metadata object. The default value for the
FILENAME_METADATA
setting will only extract the date from the filename. For
example, if you would like to extract both the date and the slug, you could set
something like: '(?P<date>\d{4}-\d{2}-\d{2})_(?P<slug>.*)'
Please note that the metadata available inside your files takes precedence over
the metadata extracted from the filename.
Pages
If you create a folder named pages
inside the content folder, all the
files in it will be used to generate static pages, such as About or
Contact pages. (See example filesystem layout below.)
You can use the DISPLAY_PAGES_ON_MENU
setting to control whether all those
pages are displayed in the primary navigation menu. (Default is True
.)
If you want to exclude any pages from being linked to or listed in the menu,
then add a status: hidden
attribute to its metadata. This is useful for
things like making error pages that fit the generated theme of your site.
Static content
Static files are files other than articles and pages that are copied to the
output folder as-is, without processing. You can control which static files
are copied over with the STATIC_PATHS
setting of the project’s
pelicanconf.py
file. Pelican’s default configuration includes the
images
directory for this, but others must be added manually. In addition,
static files that are explicitly linked to are included (see below).
Note
In the default configuration, all files with a valid content file suffix
(.html
, .rst
, .md
, …) get processed by the article and page
generators before the static generator. This is avoided by altering the
*_EXCLUDE
settings appropriately.
Mixed content in the same directory
Starting with Pelican 3.5, static files can safely share a source directory
with page source files, without exposing the page sources in the generated
site. Any such directory must be added to both STATIC_PATHS
and
PAGE_PATHS
(or STATIC_PATHS
and ARTICLE_PATHS
). Pelican will
identify and process the page source files normally, and copy the remaining
files as if they lived in a separate directory reserved for static files.
Note: Placing static and content source files together in the same source
directory does not guarantee that they will end up in the same place in the
generated site. The easiest way to do this is by using the {attach}
link
syntax (described below). Alternatively, the STATIC_SAVE_AS
,
PAGE_SAVE_AS
, and ARTICLE_SAVE_AS
settings (and the corresponding
*_URL
settings) can be configured to place files of different types
together, just as they could in earlier versions of Pelican.
Linking to internal content
From Pelican 3.1 onwards, it is now possible to specify intra-site links to
files in the source content hierarchy instead of files in the generated
hierarchy. This makes it easier to link from the current post to other content
that may be sitting alongside that post (instead of having to determine where
the other content will be placed after site generation).
To link to internal content (files in the content
directory), use the
following syntax for the link target: {filename}path/to/file
.
Note: forward slashes, /
,
are the required path separator in the {filename}
directive
on all operating systems, including Windows.
For example, a Pelican project might be structured like this:
website/
├── content
│ ├── category/
│ │ └── article1.rst
│ ├── article2.md
│ └── pages
│ └── about.md
└── pelican.conf.py
In this example, article1.rst
could look like this:
The first article
#################
:date: 2012-12-01 10:02
See below intra-site link examples in reStructuredText format.
`a link relative to the current file <{filename}../article2.md>`_
`a link relative to the content root <{filename}/article2.md>`_
and article2.md
:
Title: The second article
Date: 2012-12-01 10:02
See below intra-site link examples in Markdown format.
[a link relative to the current file]({filename}category/article1.rst)
[a link relative to the content root]({filename}/category/article1.rst)
Linking to static files
You can link to static content using {static}path/to/file
. Files linked to
with this syntax will automatically be copied to the output directory, even if
the source directories containing them are not included in the STATIC_PATHS
setting of the project’s pelicanconf.py
file.
For example, a project’s content directory might be structured like this:
content
├── images
│ └── han.jpg
├── pdfs
│ └── menu.pdf
└── pages
└── test.md
test.md
would include:

[Our Menu]({static}/pdfs/menu.pdf)
Site generation would then copy han.jpg
to output/images/han.jpg
,
menu.pdf
to output/pdfs/menu.pdf
, and write the appropriate links
in test.md
.
If you use {static}
to link to an article or a page, this will be turned
into a link to its source code.
Attaching static files
Starting with Pelican 3.5, static files can be “attached” to a page or article
using this syntax for the link target: {attach}path/to/file
. This works
like the {static}
syntax, but also relocates the static file into the
linking document’s output directory. If the static file originates from a
subdirectory beneath the linking document’s source, that relationship will be
preserved on output. Otherwise, it will become a sibling of the linking
document.
This only works for linking to static files.
For example, a project’s content directory might be structured like this:
content
├── blog
│ ├── icons
│ │ └── icon.png
│ ├── photo.jpg
│ └── testpost.md
└── downloads
└── archive.zip
pelicanconf.py
would include:
PATH = 'content'
ARTICLE_PATHS = ['blog']
ARTICLE_SAVE_AS = '{date:%Y}/{slug}.html'
ARTICLE_URL = '{date:%Y}/{slug}.html'
testpost.md
would include:
Title: Test Post
Category: test
Date: 2014-10-31


[Downloadable File]({attach}/downloads/archive.zip)
Site generation would then produce an output directory structured like this:
output
└── 2014
├── archive.zip
├── icons
│ └── icon.png
├── photo.jpg
└── test-post.html
Notice that all the files linked using {attach}
ended up in or beneath
the article’s output directory.
If a static file is linked multiple times, the relocating feature of
{attach}
will only work in the first of those links to be processed.
After the first link, Pelican will treat {attach}
like {static}
.
This avoids breaking the already-processed links.
Be careful when linking to a file from multiple documents:
Since the first link to a file finalizes its location and Pelican does
not define the order in which documents are processed, using {attach}
on a
file linked by multiple documents can cause its location to change from one
site build to the next. (Whether this happens in practice will depend on the
operating system, file system, version of Pelican, and documents being added,
modified, or removed from the project.) Any external sites linking to the
file’s old location might then find their links broken. It is therefore
advisable to use {attach} only if you use it in all links to a file, and only
if the linking documents share a single directory. Under these conditions,
the file’s output location will not change in future builds. In cases where
these precautions are not possible, consider using {static}
links instead
of {attach}
, and letting the file’s location be determined by the project’s
STATIC_SAVE_AS
and STATIC_URL
settings. (Per-file save_as
and
url
overrides can still be set in EXTRA_PATH_METADATA
.)
Note
When using {attach}
, any parent directory in *_URL
/ *_SAVE_AS
settings should match each other. See also: URL settings
Deprecated internal link syntax
To remain compatible with earlier versions, Pelican still supports vertical
bars (||
) in addition to curly braces ({}
) for internal links. For
example: |filename|an_article.rst
, |tag|tagname
, |category|foobar
.
The syntax was changed from ||
to {}
to avoid collision with Markdown
extensions or reST directives. Similarly, Pelican also still supports linking
to static content with {filename}
. The syntax was changed to {static}
to allow linking to both generated articles and pages and their static sources.
Support for the old syntax may eventually be removed.
Including other files
Both Markdown and reStructuredText syntaxes provide mechanisms for this.
Following below are some examples for reStructuredText using the include directive:
Include a fragment of a file delimited by two identifiers, highlighted as C++ (slicing based on line numbers is also possible):
.. include:: main.cpp
:code: c++
:start-after: // begin
:end-before: // end
Include a raw HTML file (or an inline SVG) and put it directly into the output without any processing:
.. raw:: html
:file: table.html
For Markdown, one must rely on an extension. For example, using the mdx_include plugin:
```html
{! template.html !}
```
Importing an existing site
It is possible to import your site from several other blogging sites
(like WordPress, Tumblr, ..) using a simple script. See Importing an existing site.
Translations
It is possible to translate articles. To do so, you need to add a lang
meta
attribute to your articles/pages and set a DEFAULT_LANG
setting (which is
English [en] by default). With those settings in place, only articles with the
default language will be listed, and each article will be accompanied by a list
of available translations for that article.
Note
This core Pelican functionality does not create sub-sites
(e.g. example.com/de
) with translated templates for each
language. For such advanced functionality the i18n_subsites
plugin can be used.
By default, Pelican uses the article’s URL “slug” to determine if two or more
articles are translations of one another. (This can be changed with the
ARTICLE_TRANSLATION_ID
setting.) The slug can be set manually in the file’s
metadata; if not set explicitly, Pelican will auto-generate the slug from the
title of the article.
Here is an example of two articles, one in English and the other in French.
The English article:
Foobar is not dead
##################
:slug: foobar-is-not-dead
:lang: en
That's true, foobar is still alive!
And the French version:
Foobar n'est pas mort !
#######################
:slug: foobar-is-not-dead
:lang: fr
Oui oui, foobar est toujours vivant !
Post content quality notwithstanding, you can see that only item in common
between the two articles is the slug, which is functioning here as an
identifier. If you’d rather not explicitly define the slug this way, you must
then instead ensure that the translated article titles are identical, since the
slug will be auto-generated from the article title.
If you do not want the original version of one specific article to be detected
by the DEFAULT_LANG
setting, use the translation
metadata to specify
which posts are translations:
Foobar is not dead
##################
:slug: foobar-is-not-dead
:lang: en
:translation: true
That's true, foobar is still alive!
Syntax highlighting
Pelican can provide colorized syntax highlighting for your code blocks.
To do so, you must use the following conventions inside your content files.
For reStructuredText, use the code-block
directive to specify the type
of code to be highlighted (in these examples, we’ll use python
):
.. code-block:: python
print("Pelican is a static site generator.")
For Markdown, which utilizes the CodeHilite extension to provide syntax
highlighting, include the language identifier just above the code block,
indenting both the identifier and the code:
There are two ways to specify the identifier:
:::python
print("The triple-colon syntax will *not* show line numbers.")
To display line numbers, use a path-less shebang instead of colons:
#!python
print("The path-less shebang syntax *will* show line numbers.")
The specified identifier (e.g. python
, ruby
) should be one that
appears on the list of available lexers.
When using reStructuredText the following options are available in the
code-block directive:
Option |
Valid values |
Description |
anchorlinenos |
N/A |
If present, wrap line numbers in <a> tags. |
classprefix |
string |
String to prepend to token class names |
hl_lines |
numbers |
List of lines to be highlighted, where
line numbers to highlight are separated
by a space. This is similar to
emphasize-lines in Sphinx, but it
does not support a range of line numbers
separated by a hyphen, or comma-separated
line numbers. |
lineanchors |
string |
Wrap each line in an anchor using this
string and -linenumber. |
linenos |
string |
If present or set to “table”, output line
numbers in a table; if set to
“inline”, output them inline. “none” means
do not output the line numbers for this
table. |
linenospecial |
number |
If set, every nth line will be given the
‘special’ CSS class. |
linenostart |
number |
Line number for the first line. |
linenostep |
number |
Print every nth line number. |
lineseparator |
string |
String to print between lines of code,
‘n’ by default. |
linespans |
string |
Wrap each line in a span using this and
-linenumber. |
nobackground |
N/A |
If set, do not output background color for
the wrapping element |
nowrap |
N/A |
If set, do not wrap the tokens at all. |
tagsfile |
string |
ctags file to use for name definitions. |
tagurlformat |
string |
format for the ctag links. |
Note that, depending on the version, your Pygments module might not have
all of these options available. Refer to the HtmlFormatter section of the
Pygments documentation for more
details on each of the options.
For example, the following code block enables line numbers, starting at 153,
and prefixes the Pygments CSS classes with pgcss to make the names
more unique and avoid possible CSS conflicts:
.. code-block:: identifier
:classprefix: pgcss
:linenos: table
:linenostart: 153
<indented code block goes here>
It is also possible to specify the PYGMENTS_RST_OPTIONS
variable in your
Pelican settings file to include options that will be automatically applied to
every code block.
For example, if you want to have line numbers displayed for every code block
and a CSS prefix, you would set this variable to:
PYGMENTS_RST_OPTIONS = {'classprefix': 'pgcss', 'linenos': 'table'}
If specified, settings for individual code blocks will override the defaults in
your settings file.
Publishing drafts
If you want to publish an article or a page as a draft (for friends to review
before publishing, for example), you can add a Status: draft
attribute to
its metadata. That article will then be output to the drafts
folder and not
listed on the index page nor on any category or tag page.
If your articles should be automatically published as a draft (to not
accidentally publish an article before it is finished), include the status in
the DEFAULT_METADATA
:
DEFAULT_METADATA = {
'status': 'draft',
}
To publish a post when the default status is draft
, update the post’s
metadata to include Status: published
.
Hidden Posts
Like pages, posts can also be marked as hidden
with the Status: hidden
attribute. Hidden posts will be output to ARTICLE_SAVE_AS
as expected, but
are not included by default in tag, category, and author indexes, nor in the
main article feed. This has the effect of creating an “unlisted” post.
Publish your site
Site generation
Once Pelican is installed and you have some content (e.g., in Markdown or reST
format), you can convert your content into HTML via the pelican
command,
specifying the path to your content and (optionally) the path to your
settings file:
pelican /path/to/your/content/ [-s path/to/your/settings.py]
The above command will generate your site and save it in the output/
folder, using the default theme to produce a simple site. The default theme
consists of very simple HTML without styling and is provided so folks may use
it as a basis for creating their own themes.
You can also tell Pelican to watch for your modifications, instead of manually
re-running it every time you want to see your changes. To enable this, run the
pelican
command with the -r
or --autoreload
option. On non-Windows
environments, this option can also be combined with the -l
or --listen
option to simultaneously both auto-regenerate and serve the output at
http://localhost:8000:
pelican --autoreload --listen
Pelican has other command-line switches available. Have a look at the help to
see all the options you can use:
Viewing the generated files
The files generated by Pelican are static files, so you don’t actually need
anything special to view them. You can use your browser to open the generated
HTML files directly:
firefox output/index.html
Because the above method may have trouble locating your CSS and other linked
assets, running Pelican’s simple built-in web server will often provide a more
reliable previewing experience:
Once the web server has been started, you can preview your site at:
http://localhost:8000/
Deployment
After you have generated your site, previewed it in your local development
environment, and are ready to deploy it to production, you might first
re-generate your site with any production-specific settings (e.g., analytics,
feeds, etc.) that you may have defined:
pelican content -s publishconf.py
To base your publish configuration on top of your pelicanconf.py
, you can
import your pelicanconf
settings by including the following line in your
publishconf.py
:
from pelicanconf import *
If you have generated a publishconf.py
using pelican-quickstart
, this
line is included by default.
The steps for deploying your site will depend on where it will be hosted. If
you have SSH access to a server running Nginx or Apache, you might use the
rsync
tool to transmit your site files:
rsync -avc --delete output/ host.example.com:/var/www/your-site/
There are many other deployment options, some of which can be configured when
first setting up your site via the pelican-quickstart
command. See the
Tips page for detail on publishing via GitHub Pages.
Automation
While the pelican
command is the canonical way to generate your site,
automation tools can be used to streamline the generation and publication flow.
One of the questions asked during the pelican-quickstart
process pertains
to whether you want to automate site generation and publication. If you
answered “yes” to that question, a tasks.py
and Makefile
will be
generated in the root of your project. These files, pre-populated with certain
information gleaned from other answers provided during the
pelican-quickstart
process, are meant as a starting point and should be
customized to fit your particular needs and usage patterns. If you find one or
both of these automation tools to be of limited utility, these files can
be deleted at any time and will not affect usage of the canonical pelican
command.
Following are automation tools that “wrap” the pelican
command and can
simplify the process of generating, previewing, and uploading your site.
Invoke
The advantage of Invoke is that it is written in Python and thus can be used
in a wide range of environments. The downside is that it must be installed
separately. Use the following command to install Invoke, prefixing with
sudo
if your environment requires it:
python -m pip install invoke
Take a moment to open the tasks.py
file that was generated in your project
root. You will see a number of commands, any one of which can be renamed,
removed, and/or customized to your liking. Using the out-of-the-box
configuration, you can generate your site via:
If you’d prefer to have Pelican automatically regenerate your site every time a
change is detected (which is handy when testing locally), use the following
command instead:
To serve the generated site so it can be previewed in your browser at
http://localhost:8000/:
To serve the generated site with automatic browser reloading every time a
change is detected, first python -m pip install livereload
, then use the
following command:
If during the pelican-quickstart
process you answered “yes” when asked
whether you want to upload your site via SSH, you can use the following command
to publish your site via rsync over SSH:
These are just a few of the commands available by default, so feel free to
explore tasks.py
and see what other commands are available. More
importantly, don’t hesitate to customize tasks.py
to suit your specific
needs and preferences.
Make
A Makefile
is also automatically created for you when you say “yes” to the
relevant question during the pelican-quickstart
process. The advantage of
this method is that the make
command is built into most POSIX systems and
thus doesn’t require installing anything else in order to use it. The downside
is that non-POSIX systems (e.g., Windows) do not include make
, and
installing it on those systems can be a non-trivial task.
If you want to use make
to generate your site using the settings in
pelicanconf.py
, run:
To generate the site for production, using the settings in publishconf.py
,
run:
If you’d prefer to have Pelican automatically regenerate your site every time a
change is detected (which is handy when testing locally), use the following
command instead:
To serve the generated site so it can be previewed in your browser at
http://localhost:8000/:
Normally you would need to run make regenerate
and make serve
in two
separate terminal sessions, but you can run both at once via:
The above command will simultaneously run Pelican in regeneration mode as well
as serve the output at http://localhost:8000.
When you’re ready to publish your site, you can upload it via the method(s) you
chose during the pelican-quickstart
questionnaire. For this example, we’ll
use rsync over ssh:
That’s it! Your site should now be live.
(The default Makefile
and devserver.sh
scripts use the python
and
pelican
executables to complete its tasks. If you want to use different
executables, such as python3
, you can set the PY
and PELICAN
environment variables, respectively, to override the default executable names.)
Settings
Pelican is configurable thanks to a settings file you can pass to the command
line:
pelican content -s path/to/your/pelicanconf.py
If you used the pelican-quickstart
command, your primary settings file will
be named pelicanconf.py
by default.
You can also specify settings via -e
/ --extra-settings
option
flags. It will override default settings as well as any defined within the
setting file. Note that values must follow JSON notation:
pelican content -e SITENAME='"A site"' READERS='{"html": null}' CACHE_CONTENT=true
Environment variables can also be used here but must be escaped appropriately:
pelican content -e API_KEY=''\"$API_KEY\"''
Note
When experimenting with different settings (especially the metadata ones)
caching may interfere and the changes may not be visible. In such cases
disable caching with LOAD_CONTENT_CACHE = False
or use the
--ignore-cache
command-line switch.
Settings are configured in the form of a Python module (a file). There is an
example settings file
available for reference.
To see a list of current settings in your environment, including both default
and any customized values, run the following command (append one or more
specific setting names as arguments to see values for those settings only):
All the setting identifiers must be set in all-caps, otherwise they will not be
processed. Setting values that are numbers (5, 20, etc.), booleans (True,
False, None, etc.), dictionaries, or tuples should not be enclosed in
quotation marks. All other values (i.e., strings) must be enclosed in
quotation marks.
Unless otherwise specified, settings that refer to paths can be either absolute
or relative to the configuration file. The settings you define in the
configuration file will be passed to the templates, which allows you to use
your settings to add site-wide content.
Here is a list of settings for Pelican:
Basic settings
-
USE_FOLDER_AS_CATEGORY = True
When you don’t specify a category in your post metadata, set this setting to
True
, and organize your articles in subfolders, the subfolder will
become the category of your post. If set to False
, DEFAULT_CATEGORY
will be used as a fallback.
-
DEFAULT_CATEGORY = 'misc'
The default category to fall back on.
-
DISPLAY_PAGES_ON_MENU = True
Whether to display pages on the menu of the template. Templates may or may
not honor this setting.
-
DISPLAY_CATEGORIES_ON_MENU = True
Whether to display categories on the menu of the template. Templates may or
not honor this setting.
-
DOCUTILS_SETTINGS = {}
Extra configuration settings for the docutils publisher (applicable only to
reStructuredText). See Docutils Configuration settings for more details.
-
DELETE_OUTPUT_DIRECTORY = False
Delete the output directory, and all of its contents, before generating
new files. This can be useful in preventing older, unnecessary files from
persisting in your output. However, this is a destructive setting and
should be handled with extreme care.
-
OUTPUT_RETENTION = []
A list of filenames that should be retained and not deleted from the output
directory. One use case would be the preservation of version control data.
Example:
OUTPUT_RETENTION = [".hg", ".git", ".bzr"]
-
JINJA_ENVIRONMENT = {'trim_blocks': True, 'lstrip_blocks': True}
A dictionary of custom Jinja2 environment variables you want to use. This
also includes a list of extensions you may want to include. See Jinja
Environment documentation.
-
JINJA_FILTERS = {}
A dictionary of custom Jinja2 filters you want to use. The dictionary
should map the filtername to the filter function.
Example:
import sys
sys.path.append('to/your/path')
from custom_filter import urlencode_filter
JINJA_FILTERS = {'urlencode': urlencode_filter}
See: Jinja custom filters documentation.
-
JINJA_GLOBALS = {}
A dictionary of custom objects to map into the Jinja2 global environment
namespace. The dictionary should map the global name to the global
variable/function. See: Jinja global namespace documentation.
-
JINJA_TESTS = {}
A dictionary of custom Jinja2 tests you want to use. The dictionary should
map test names to test functions. See: Jinja custom tests documentation.
-
LOG_FILTER = []
A list of tuples containing the logging level (up to warning
) and the
message to be ignored.
Example:
LOG_FILTER = [(logging.WARN, 'TAG_SAVE_AS is set to False')]
-
READERS = {}
A dictionary of file extensions / Reader classes for Pelican to process or
ignore.
For example, to avoid processing .html files, set:
To add a custom reader for the foo
extension, set:
READERS = {'foo': FooReader}
-
IGNORE_FILES = ['.#*']
A list of glob patterns. Files and directories matching any of these
patterns will be ignored by the processor. For example, the default
['.#*']
will ignore emacs lock files, and ['__pycache__']
would
ignore Python 3’s bytecode caches.
-
MARKDOWN = {...}
Extra configuration settings for the Markdown processor. Refer to the Python
Markdown documentation’s Options section for a complete
list of supported options. The extensions
option will be automatically
computed from the extension_configs
option.
Defaults to:
MARKDOWN = {
'extension_configs': {
'markdown.extensions.codehilite': {'css_class': 'highlight'},
'markdown.extensions.extra': {},
'markdown.extensions.meta': {},
},
'output_format': 'html5',
}
Note
The dictionary defined in your settings file will replace this default
one.
-
OUTPUT_PATH = 'output/'
Where to output the generated files. This should correspond to your web
server’s virtual host root directory.
-
PATH
Path to content directory to be processed by Pelican. If undefined, and
content path is not specified via an argument to the pelican
command,
Pelican will use the current working directory.
-
PAGE_PATHS = ['pages']
A list of directories and files to look at for pages, relative to PATH
.
-
PAGE_EXCLUDES = []
A list of directories to exclude when looking for pages in addition to
ARTICLE_PATHS
.
-
ARTICLE_PATHS = ['']
A list of directories and files to look at for articles, relative to
PATH
.
-
ARTICLE_EXCLUDES = []
A list of directories to exclude when looking for articles in addition to
PAGE_PATHS
.
-
OUTPUT_SOURCES = False
Set to True if you want to copy the articles and pages in their original
format (e.g. Markdown or reStructuredText) to the specified OUTPUT_PATH
.
-
OUTPUT_SOURCES_EXTENSION = '.text'
Controls the extension that will be used by the SourcesGenerator. Defaults
to .text
. If not a valid string the default value will be used.
-
PLUGINS = None
The list of plugins to load. See Plugins.
-
PLUGIN_PATHS = []
A list of directories where to look for plugins. See Plugins.
-
SITENAME = 'A Pelican Blog'
Your site name
-
SITEURL
Base URL of your web site. Not defined by default, so it is best to specify
your SITEURL; if you do not, feeds will not be generated with
properly-formed URLs. If your site is available via HTTPS, this setting
should begin with https://
— otherwise use http://
. Then append your
domain, with no trailing slash at the end. Example: SITEURL =
'https://example.com'
-
STATIC_PATHS = ['images']
A list of directories (relative to PATH
) in which to look for static
files. Such files will be copied to the output directory without
modification. Articles, pages, and other content source files will normally
be skipped, so it is safe for a directory to appear both here and in
PAGE_PATHS
or ARTICLE_PATHS
. Pelican’s default settings include the
“images” directory here.
-
STATIC_EXCLUDES = []
A list of directories to exclude when looking for static files.
-
STATIC_EXCLUDE_SOURCES = True
If set to False, content source files will not be skipped when copying files
found in STATIC_PATHS
. This setting is for backward compatibility with
Pelican releases before version 3.5. It has no effect unless
STATIC_PATHS
contains a directory that is also in ARTICLE_PATHS
or
PAGE_PATHS
. If you are trying to publish your site’s source files,
consider using the OUTPUT_SOURCES
setting instead.
-
STATIC_CREATE_LINKS = False
Create links instead of copying files. If the content and output directories
are on the same device, then create hard links. Falls back to symbolic
links if the output directory is on a different filesystem. If symlinks are
created, don’t forget to add the -L
or --copy-links
option to rsync
when uploading your site.
-
STATIC_CHECK_IF_MODIFIED = False
If set to True
, and STATIC_CREATE_LINKS
is False
, compare mtimes
of content and output files, and only copy content files that are newer than
existing output files.
-
TYPOGRIFY = False
If set to True, several typographical improvements will be incorporated into
the generated HTML via the Typogrify library, which can be installed
via: python -m pip install typogrify
-
TYPOGRIFY_IGNORE_TAGS = []
A list of tags for Typogrify to ignore. By default Typogrify will ignore
pre
and code
tags. This requires that Typogrify version 2.0.4 or
later is installed
-
TYPOGRIFY_DASHES = 'default'
This setting controls how Typogrify sets up the Smartypants filter to
interpret multiple dash/hyphen/minus characters. A single ASCII dash
character (-
) is always rendered as a hyphen. The default
setting
does not handle en-dashes and converts double-hyphens into em-dashes. The
oldschool
setting renders both en-dashes and em-dashes when it sees two
(--
) and three (---
) hyphen characters, respectively. The
oldschool_inverted
setting turns two hyphens into an em-dash and three
hyphens into an en-dash.
-
SUMMARY_MAX_LENGTH = 50
When creating a short summary of an article, this will be the default length
(measured in words) of the text created. This only applies if your content
does not otherwise specify a summary. Setting to None
will cause the
summary to be a copy of the original content.
-
SUMMARY_END_SUFFIX = '…'
When creating a short summary of an article and the result was truncated to
match the required word length, this will be used as the truncation suffix.
-
WITH_FUTURE_DATES = True
If disabled, content with dates in the future will get a default status of
draft
. See Reading only modified content for caveats.
-
INTRASITE_LINK_REGEX = '[{|](?P<what>.*?)[|}]'
Regular expression that is used to parse internal links. Default syntax when
linking to internal files, tags, etc., is to enclose the identifier, say
filename
, in {}
or ||
. Identifier between {
and }
goes
into the what
capturing group. For details see
Linking to internal content.
-
PYGMENTS_RST_OPTIONS = []
A list of default Pygments settings for your reStructuredText code blocks.
See Syntax highlighting for a list of supported options.
-
CACHE_CONTENT = False
If True
, saves content in caches. See
Reading only modified content for details about caching.
-
CONTENT_CACHING_LAYER = 'reader'
If set to 'reader'
, save only the raw content and metadata returned by
readers. If set to 'generator'
, save processed content objects.
-
CACHE_PATH = 'cache'
Directory in which to store cache files.
-
GZIP_CACHE = True
If True
, use gzip to (de)compress the cache files.
-
CHECK_MODIFIED_METHOD = 'mtime'
Controls how files are checked for modifications.
If set to 'mtime'
, the modification time of the file is
checked.
If set to a name of a function provided by the hashlib
module, e.g. 'md5'
, the file hash is checked.
-
LOAD_CONTENT_CACHE = False
If True
, load unmodified content from caches.
-
FORMATTED_FIELDS = ['summary']
A list of metadata fields containing reST/Markdown content to be parsed and
translated to HTML.
-
PORT = 8000
The TCP port to serve content from the output folder via HTTP when pelican
is run with –listen
-
BIND = ''
The IP to which to bind the HTTP server.
URL settings
The first thing to understand is that there are currently two supported methods
for URL formation: relative and absolute. Relative URLs are useful when
testing locally, and absolute URLs are reliable and most useful when
publishing. One method of supporting both is to have one Pelican configuration
file for local development and another for publishing. To see an example of
this type of setup, use the pelican-quickstart
script as described in the
Installation section, which will produce two separate
configuration files for local development and publishing, respectively.
You can customize the URLs and locations where files will be saved. The
*_URL
and *_SAVE_AS
variables use Python’s format strings. These
variables allow you to place your articles in a location such as
{slug}/index.html
and link to them as {slug}
for clean URLs (see
example below). These settings give you the flexibility to place your articles
and pages anywhere you want.
Note
If a *_SAVE_AS
setting contains a parent directory that doesn’t match
the parent directory inside the corresponding *_URL
setting, this may
cause Pelican to generate unexpected URLs in a few cases, such as when
using the {attach}
syntax.
If you don’t want that flexibility and instead prefer that your generated
output paths mirror your source content’s filesystem path hierarchy, try the
following settings:
PATH_METADATA = '(?P<path_no_ext>.*)\..*'
ARTICLE_URL = ARTICLE_SAVE_AS = PAGE_URL = PAGE_SAVE_AS = '{path_no_ext}.html'
Otherwise, you can use a variety of file metadata attributes within URL-related
settings:
slug
date
lang
author
category
Example usage:
ARTICLE_URL = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/'
ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html'
PAGE_URL = 'pages/{slug}/'
PAGE_SAVE_AS = 'pages/{slug}/index.html'
This would save your articles into something like
/posts/2011/Aug/07/sample-post/index.html
, save your pages into
/pages/about/index.html
, and render them available at URLs of
/posts/2011/Aug/07/sample-post/
and /pages/about/
, respectively.
Note
If you specify a datetime
directive, it will be substituted using the
input files’ date metadata attribute. If the date is not specified for a
particular file, Pelican will rely on the file’s mtime
timestamp. Check
the Python datetime documentation for more information.
-
RELATIVE_URLS = False
Defines whether Pelican should use document-relative URLs or not. Only set
this to True
when developing/testing and only if you fully understand
the effect it can have on links/feeds.
-
ARTICLE_URL = '{slug}.html'
The URL to refer to an article.
-
ARTICLE_SAVE_AS = '{slug}.html'
The place where we will save an article.
-
ARTICLE_LANG_URL = '{slug}-{lang}.html'
The URL to refer to an article which doesn’t use the default language.
-
ARTICLE_LANG_SAVE_AS = '{slug}-{lang}.html'
The place where we will save an article which doesn’t use the default
language.
-
DRAFT_URL = 'drafts/{slug}.html'
The URL to refer to an article draft.
-
DRAFT_SAVE_AS = 'drafts/{slug}.html'
The place where we will save an article draft.
-
DRAFT_LANG_URL = 'drafts/{slug}-{lang}.html'
The URL to refer to an article draft which doesn’t use the default language.
-
DRAFT_LANG_SAVE_AS = 'drafts/{slug}-{lang}.html'
The place where we will save an article draft which doesn’t use the default
language.
-
PAGE_URL = 'pages/{slug}.html'
The URL we will use to link to a page.
-
PAGE_SAVE_AS = 'pages/{slug}.html'
The location we will save the page. This value has to be the same as
PAGE_URL or you need to use a rewrite in your server config.
-
PAGE_LANG_URL = 'pages/{slug}-{lang}.html'
The URL we will use to link to a page which doesn’t use the default
language.
-
PAGE_LANG_SAVE_AS = 'pages/{slug}-{lang}.html'
The location we will save the page which doesn’t use the default language.
-
DRAFT_PAGE_URL = 'drafts/pages/{slug}.html'
The URL used to link to a page draft.
-
DRAFT_PAGE_SAVE_AS = 'drafts/pages/{slug}.html'
The actual location a page draft is saved at.
-
DRAFT_PAGE_LANG_URL = 'drafts/pages/{slug}-{lang}.html'
The URL used to link to a page draft which doesn’t use the default
language.
-
DRAFT_PAGE_LANG_SAVE_AS = 'drafts/pages/{slug}-{lang}.html'
The actual location a page draft which doesn’t use the default language is
saved at.
-
AUTHOR_URL = 'author/{slug}.html'
The URL to use for an author.
-
AUTHOR_SAVE_AS = 'author/{slug}.html'
The location to save an author.
-
CATEGORY_URL = 'category/{slug}.html'
The URL to use for a category.
-
CATEGORY_SAVE_AS = 'category/{slug}.html'
The location to save a category.
-
TAG_URL = 'tag/{slug}.html'
The URL to use for a tag.
-
TAG_SAVE_AS = 'tag/{slug}.html'
The location to save the tag page.
Note
If you do not want one or more of the default pages to be created (e.g.,
you are the only author on your site and thus do not need an Authors page),
set the corresponding *_SAVE_AS
setting to ''
to prevent the
relevant page from being generated.
Pelican can optionally create per-year, per-month, and per-day archives of your
posts. These secondary archives are disabled by default but are automatically
enabled if you supply format strings for their respective _SAVE_AS
settings. Period archives fit intuitively with the hierarchical model of web
URLs and can make it easier for readers to navigate through the posts you’ve
written over time.
Example usage:
YEAR_ARCHIVE_SAVE_AS = 'posts/{date:%Y}/index.html'
YEAR_ARCHIVE_URL = 'posts/{date:%Y}/'
MONTH_ARCHIVE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/index.html'
MONTH_ARCHIVE_URL = 'posts/{date:%Y}/{date:%b}/'
With these settings, Pelican will create an archive of all your posts for the
year at (for instance) posts/2011/index.html
and an archive of all your
posts for the month at posts/2011/Aug/index.html
. These can be accessed
through the URLs posts/2011/
and posts/2011/Aug/
, respectively.
Note
Period archives work best when the final path segment is index.html
.
This way a reader can remove a portion of your URL and automatically arrive
at an appropriate archive of posts, without having to specify a page name.
-
YEAR_ARCHIVE_SAVE_AS = ''
The location to save per-year archives of your posts.
-
YEAR_ARCHIVE_URL = ''
The URL to use for per-year archives of your posts. You should set this if
you enable per-year archives.
-
MONTH_ARCHIVE_SAVE_AS = ''
The location to save per-month archives of your posts.
-
MONTH_ARCHIVE_URL = ''
The URL to use for per-month archives of your posts. You should set this if
you enable per-month archives.
-
DAY_ARCHIVE_SAVE_AS = ''
The location to save per-day archives of your posts.
-
DAY_ARCHIVE_URL = ''
The URL to use for per-day archives of your posts. You should set this if
you enable per-day archives.
DIRECT_TEMPLATES
work a bit differently than noted above. Only the
_SAVE_AS
settings are available, but it is available for any direct
template.
-
ARCHIVES_SAVE_AS = 'archives.html'
The location to save the article archives page.
-
AUTHORS_SAVE_AS = 'authors.html'
The location to save the author list.
-
CATEGORIES_SAVE_AS = 'categories.html'
The location to save the category list.
-
TAGS_SAVE_AS = 'tags.html'
The location to save the tag list.
-
INDEX_SAVE_AS = 'index.html'
The location to save the list of all articles.
URLs for direct template pages are theme-dependent. Some themes use
corresponding *_URL
setting as string, while others hard-code them:
'archives.html'
, 'authors.html'
, 'categories.html'
,
'tags.html'
.
-
SLUGIFY_SOURCE = 'title'
Specifies from where you want the slug to be automatically generated. Can be
set to title
to use the “Title:” metadata tag or basename
to use the
article’s file name when creating the slug.
-
SLUGIFY_USE_UNICODE = False
Allow Unicode characters in slugs. Set True
to keep Unicode characters
in auto-generated slugs. Otherwise, Unicode characters will be replaced
with ASCII equivalents.
-
SLUGIFY_PRESERVE_CASE = False
Preserve uppercase characters in slugs. Set True
to keep uppercase
characters from SLUGIFY_SOURCE
as-is.
-
SLUG_REGEX_SUBSTITUTIONS = [
-
(r'[^\\w\\s-]', ''), # remove non-alphabetical/whitespace/'-' chars
-
(r'(?u)\\A\\s*', ''), # strip leading whitespace
-
(r'(?u)\\s*\\Z', ''), # strip trailing whitespace
-
(r'[-\\s]+', '-'), # reduce multiple whitespace or '-' to single '-'
-
]
Regex substitutions to make when generating slugs of articles and pages.
Specified as a list of pairs of (from, to)
which are applied in order,
ignoring case. The default substitutions have the effect of removing
non-alphanumeric characters and converting internal whitespace to dashes.
Apart from these substitutions, slugs are always converted to lowercase
ascii characters and leading and trailing whitespace is stripped. Useful for
backward compatibility with existing URLs.
-
AUTHOR_REGEX_SUBSTITUTIONS = SLUG_REGEX_SUBSTITUTIONS
Regex substitutions for author slugs. Defaults to
SLUG_REGEX_SUBSTITUTIONS
.
-
CATEGORY_REGEX_SUBSTITUTIONS = SLUG_REGEX_SUBSTITUTIONS
Regex substitutions for category slugs. Defaults to
SLUG_REGEX_SUBSTITUTIONS
.
-
TAG_REGEX_SUBSTITUTIONS = SLUG_REGEX_SUBSTITUTIONS
Regex substitutions for tag slugs. Defaults to SLUG_REGEX_SUBSTITUTIONS
.
Time and Date
-
TIMEZONE
The timezone used in the date information, to generate Atom and RSS feeds.
If no timezone is defined, UTC is assumed. This means that the generated
Atom and RSS feeds will contain incorrect date information if your locale is
not UTC.
Pelican issues a warning in case this setting is not defined, as it was not
mandatory in previous versions.
Have a look at the wikipedia page to get a list of valid timezone values.
-
DEFAULT_DATE = None
The default date you want to use. If 'fs'
, Pelican will use the file
system timestamp information (mtime) if it can’t get date information from
the metadata. If given any other string, it will be parsed by the same
method as article metadata. If set to a tuple object, the default datetime
object will instead be generated by passing the tuple to the
datetime.datetime
constructor.
-
DEFAULT_DATE_FORMAT = '%a %d %B %Y'
The default date format you want to use.
-
DATE_FORMATS = {}
If you manage multiple languages, you can set the date formatting here.
If no DATE_FORMATS
are set, Pelican will fall back to
DEFAULT_DATE_FORMAT
. If you need to maintain multiple languages with
different date formats, you can set the DATE_FORMATS
dictionary using
the language name (lang
metadata in your post content) as the key.
In addition to the standard C89 strftime format codes that are listed in
Python datetime documentation, you can use the -
character between
%
and the format character to remove any leading zeros. For example,
%d/%m/%Y
will output 01/01/2014
whereas %-d/%-m/%Y
will result
in 1/1/2014
.
DATE_FORMATS = {
'en': '%a, %d %b %Y',
'jp': '%Y-%m-%d(%a)',
}
It is also possible to set different locale settings for each language by
using a (locale, format)
tuple as a dictionary value which will override
the LOCALE
setting:
# On Unix/Linux
DATE_FORMATS = {
'en': ('en_US','%a, %d %b %Y'),
'jp': ('ja_JP','%Y-%m-%d(%a)'),
}
# On Windows
DATE_FORMATS = {
'en': ('usa','%a, %d %b %Y'),
'jp': ('jpn','%Y-%m-%d(%a)'),
}
-
LOCALE
Change the locale . A list of locales can be provided here or a single
string representing one locale. When providing a list, all the locales will
be tried until one works.
You can set locale to further control date format:
LOCALE = ('usa', 'jpn', # On Windows
'en_US', 'ja_JP' # On Unix/Linux
)
For a list of available locales refer to locales on Windows or on
Unix/Linux, use the locale -a
command; see manpage
locale(1) for more information.
Template pages
-
TEMPLATE_PAGES = None
A mapping containing template pages that will be rendered with the blog
entries.
If you want to generate custom pages besides your blog entries, you can
point any Jinja2 template file with a path pointing to the file and the
destination path for the generated file.
For instance, if you have a blog with three static pages — a list of books,
your resume, and a contact page — you could have:
TEMPLATE_PAGES = {'src/books.html': 'dest/books.html',
'src/resume.html': 'dest/resume.html',
'src/contact.html': 'dest/contact.html'}
-
TEMPLATE_EXTENSIONS = ['.html']
The extensions to use when looking up template files from template names.
-
DIRECT_TEMPLATES = ['index', 'authors', 'categories', 'tags', 'archives']
List of templates that are used directly to render content. Typically direct
templates are used to generate index pages for collections of content (e.g.,
category and tag index pages). If the author, category and tag collections are not
needed, set DIRECT_TEMPLATES = ['index', 'archives']
DIRECT_TEMPLATES
are searched for over paths maintained in
THEME_TEMPLATES_OVERRIDES
.
Feed settings
By default, Pelican uses Atom feeds. However, it is also possible to use RSS
feeds if you prefer.
Pelican generates category feeds as well as feeds for all your articles. It
does not generate feeds for tags by default, but it is possible to do so using
the TAG_FEED_ATOM
and TAG_FEED_RSS
settings:
-
FEED_DOMAIN = None, i.e. base URL is "/"
The domain prepended to feed URLs. Since feed URLs should always be
absolute, it is highly recommended to define this (e.g.,
“https://feeds.example.com”). If you have already explicitly defined SITEURL
(see above) and want to use the same domain for your feeds, you can just
set: FEED_DOMAIN = SITEURL
.
-
FEED_ATOM = None, i.e. no Atom feed
The location to save the Atom feed.
-
FEED_ATOM_URL = None
Relative URL of the Atom feed. If not set, FEED_ATOM
is used both for
save location and URL.
-
FEED_RSS = None, i.e. no RSS
The location to save the RSS feed.
-
FEED_RSS_URL = None
Relative URL of the RSS feed. If not set, FEED_RSS
is used both for save
location and URL.
-
FEED_ALL_ATOM = 'feeds/all.atom.xml'
The location to save the all-posts Atom feed: this feed will contain all
posts regardless of their language.
-
FEED_ALL_ATOM_URL = None
Relative URL of the all-posts Atom feed. If not set, FEED_ALL_ATOM
is
used both for save location and URL.
-
FEED_ALL_RSS = None, i.e. no all-posts RSS
The location to save the the all-posts RSS feed: this feed will contain all
posts regardless of their language.
-
FEED_ALL_RSS_URL = None
Relative URL of the all-posts RSS feed. If not set, FEED_ALL_RSS
is used
both for save location and URL.
-
CATEGORY_FEED_ATOM = 'feeds/{slug}.atom.xml'
The location to save the category Atom feeds.
-
CATEGORY_FEED_ATOM_URL = None
Relative URL of the category Atom feeds, including the {slug}
placeholder. If not set, CATEGORY_FEED_ATOM
is used both for save
location and URL.
-
CATEGORY_FEED_RSS = None, i.e. no RSS
The location to save the category RSS feeds, including the {slug}
placeholder.
-
CATEGORY_FEED_RSS_URL = None
Relative URL of the category RSS feeds, including the {slug}
placeholder. If not set, CATEGORY_FEED_RSS
is used both for save
location and URL.
-
AUTHOR_FEED_ATOM = 'feeds/{slug}.atom.xml'
The location to save the author Atom feeds.
-
AUTHOR_FEED_ATOM_URL = None
Relative URL of the author Atom feeds, including the {slug}
placeholder.
If not set, AUTHOR_FEED_ATOM
is used both for save location and
URL.
-
AUTHOR_FEED_RSS = 'feeds/{slug}.rss.xml'
The location to save the author RSS feeds.
-
AUTHOR_FEED_RSS_URL = None
Relative URL of the author RSS feeds, including the {slug}
placeholder.
If not set, AUTHOR_FEED_RSS
is used both for save location and URL.
-
TAG_FEED_ATOM = None, i.e. no tag feed
The location to save the tag Atom feed, including the {slug}
placeholder.
-
TAG_FEED_ATOM_URL = None
Relative URL of the tag Atom feed, including the {slug}
placeholder.
-
TAG_FEED_RSS = None, i.e. no RSS tag feed
Relative URL to output the tag RSS feed, including the {slug}
placeholder. If not set, TAG_FEED_RSS
is used both for save location and
URL.
-
FEED_MAX_ITEMS = 100
Maximum number of items allowed in a feed. Setting to None
will cause the
feed to contains every article. 100 if not specified.
-
RSS_FEED_SUMMARY_ONLY = True
Only include item summaries in the description
tag of RSS feeds. If set
to False
, the full content will be included instead. This setting
doesn’t affect Atom feeds, only RSS ones.
If you don’t want to generate some or any of these feeds, set the above
variables to None
.
Translations
Pelican offers a way to translate articles. See the Content
section for more information.
-
DEFAULT_LANG = 'en'
The default language to use.
-
ARTICLE_TRANSLATION_ID = 'slug'
The metadata attribute(s) used to identify which articles are translations
of one another. May be a string or a collection of strings. Set to None
or False
to disable the identification of translations.
-
PAGE_TRANSLATION_ID = 'slug'
The metadata attribute(s) used to identify which pages are translations of
one another. May be a string or a collection of strings. Set to None
or
False
to disable the identification of translations.
-
TRANSLATION_FEED_ATOM = 'feeds/all-{lang}.atom.xml'
The location to save the Atom feed for translations.
-
TRANSLATION_FEED_ATOM_URL = None
Relative URL of the Atom feed for translations, including the {lang}
placeholder. If not set, TRANSLATION_FEED_ATOM
is used both for
save location and URL.
-
TRANSLATION_FEED_RSS = None, i.e. no RSS
Where to put the RSS feed for translations.
-
TRANSLATION_FEED_RSS_URL = None
Relative URL of the RSS feed for translations, including the {lang}
placeholder. If not set, TRANSLATION_FEED_RSS
is used both for save
location and URL.
Ordering content
-
NEWEST_FIRST_ARCHIVES = True
Order archives by newest first by date. (False: orders by date with older
articles first.)
-
REVERSE_CATEGORY_ORDER = False
Reverse the category order. (True: lists by reverse alphabetical order;
default lists alphabetically.)
-
ARTICLE_ORDER_BY = 'reversed-date'
Defines how the articles (articles_page.object_list
in the template) are
sorted. Valid options are: metadata as a string (use reversed-
prefix
to reverse the sort order), special option 'basename'
which will use
the basename of the file (without path), or a custom function to extract the
sorting key from articles. Using a value of 'date'
will sort articles in
chronological order, while the default value, 'reversed-date'
, will sort
articles by date in reverse order (i.e., newest article comes first).
-
PAGE_ORDER_BY = 'basename'
Defines how the pages (pages
variable in the template) are sorted.
Options are same as ARTICLE_ORDER_BY
. The default value, 'basename'
will sort pages by their basename.
Themes
Creating Pelican themes is addressed in a dedicated section (see
Themes). However, here are the settings that are related to
themes.
-
THEME
Theme to use to produce the output. Can be a relative or absolute path to a
theme folder, or the name of a default theme or a theme installed via
pelican-themes (see below).
-
THEME_STATIC_DIR = 'theme'
Destination directory in the output path where Pelican will place the files
collected from THEME_STATIC_PATHS. Default is theme.
-
THEME_STATIC_PATHS = ['static']
Static theme paths you want to copy. Default value is static, but if your
theme has other static paths, you can put them here. If files or directories
with the same names are included in the paths defined in this settings, they
will be progressively overwritten.
-
THEME_TEMPLATES_OVERRIDES = []
A list of paths you want Jinja2 to search for templates before searching the
theme’s templates/
directory. Allows for overriding individual theme
template files without having to fork an existing theme. Jinja2 searches in
the following order: files in THEME_TEMPLATES_OVERRIDES
first, then the
theme’s templates/
.
You can also extend templates from the theme using the {% extends %}
directive utilizing the !theme
prefix as shown in the following example:
{% extends '!theme/article.html' %}
-
CSS_FILE = 'main.css'
Specify the CSS file you want to load.
By default, two themes are available. You can specify them using the THEME
setting or by passing the -t
option to the pelican
command:
There are a number of other themes available at
https://github.com/getpelican/pelican-themes. Pelican comes with
pelican-themes, a small script for managing themes.
You can define your own theme, either by starting from scratch or by
duplicating and modifying a pre-existing theme. Here is a guide on how to
create your theme.
Following are example ways to specify your preferred theme:
# Specify name of a built-in theme
THEME = "notmyidea"
# Specify name of a theme installed via the pelican-themes tool
THEME = "chunk"
# Specify a customized theme, via path relative to the settings file
THEME = "themes/mycustomtheme"
# Specify a customized theme, via absolute path
THEME = "/home/myuser/projects/mysite/themes/mycustomtheme"
The built-in simple
theme can be customized using the following settings.
-
STYLESHEET_URL
The URL of the stylesheet to use.
The built-in notmyidea
theme can make good use of the following settings.
Feel free to use them in your themes as well.
-
SITESUBTITLE
A subtitle to appear in the header.
Pelican can handle Disqus comments. Specify the Disqus sitename identifier
here.
-
GITHUB_URL
Your GitHub URL (if you have one). It will then use this information to
create a GitHub ribbon.
-
ANALYTICS
Put any desired analytics scripts in this setting in publishconf.py
.
Example:
ANALYTICS = """
<script src="/theme/js/primary-analytics.js"></script>
<script>
[ … in-line Javascript code for secondary analytics … ]
</script>
"""
A list of tuples (Title, URL) for additional menu items to appear at the
beginning of the main menu.
-
LINKS
A list of tuples (Title, URL) for links to appear on the header.
-
SOCIAL
A list of tuples (Title, URL) to appear in the “social” section.
Allows for adding a button to articles to encourage others to tweet about
them. Add your Twitter username if you want this button to appear.
-
LINKS_WIDGET_NAME
Allows override of the name of the links widget. If not specified, defaults
to “links”.
-
SOCIAL_WIDGET_NAME
Allows override of the name of the “social” widget. If not specified,
defaults to “social”.
In addition, you can use the “wide” version of the notmyidea
theme by
adding the following to your configuration:
Logging
Sometimes, a long list of warnings may appear during site generation. Finding
the meaningful error message in the middle of tons of annoying log output
can be quite tricky. In order to filter out redundant log messages, Pelican
comes with the LOG_FILTER
setting.
LOG_FILTER
should be a list of tuples (level, msg)
, each of them being
composed of the logging level (up to warning
) and the message to be
ignored. Simply populate the list with the log messages you want to hide, and
they will be filtered out.
For example:
import logging
LOG_FILTER = [(logging.WARN, 'TAG_SAVE_AS is set to False')]
It is possible to filter out messages by a template. Check out source code to
obtain a template.
For example:
import logging
LOG_FILTER = [(logging.WARN, 'Empty alt attribute for image %s in %s')]
Warning
Silencing messages by templates is a dangerous feature. It is possible to
unintentionally filter out multiple message types with the same template
(including messages from future Pelican versions). Proceed with caution.
Note
This option does nothing if --debug
is passed.
Reading only modified content
To speed up the build process, Pelican can optionally read only articles and
pages with modified content.
When Pelican is about to read some content source file:
The hash or modification time information for the file from a
previous build are loaded from a cache file if LOAD_CONTENT_CACHE
is
True
. These files are stored in the CACHE_PATH
directory. If the
file has no record in the cache file, it is read as usual.
The file is checked according to CHECK_MODIFIED_METHOD
:
If set to 'mtime'
, the modification time of the file is
checked.
If set to a name of a function provided by the hashlib
module, e.g. 'md5'
, the file hash is checked.
If set to anything else or the necessary information about the
file cannot be found in the cache file, the content is read as usual.
If the file is considered unchanged, the content data saved in a
previous build corresponding to the file is loaded from the cache, and the
file is not read.
If the file is considered changed, the file is read and the new
modification information and the content data are saved to the cache if
CACHE_CONTENT
is True
.
If CONTENT_CACHING_LAYER
is set to 'reader'
(the default), the raw
content and metadata returned by a reader are cached. If this setting is
instead set to 'generator'
, the processed content object is cached. Caching
the processed content object may conflict with plugins (as some reading related
signals may be skipped) and the WITH_FUTURE_DATES
functionality (as the
draft
status of the cached content objects would not change automatically
over time).
Checking modification times is faster than comparing file hashes, but it is not
as reliable because mtime
information can be lost, e.g., when copying
content source files using the cp
or rsync
commands without the
mtime
preservation mode (which for rsync
can be invoked by passing the
--archive
flag).
The cache files are Python pickles, so they may not be readable by different
versions of Python as the pickle format often changes. If such an error is
encountered, it is caught and the cache file is rebuilt automatically in the
new format. The cache files will also be rebuilt after the GZIP_CACHE
setting has been changed.
The --ignore-cache
command-line option is useful when the whole cache needs
to be regenerated, such as when making modifications to the settings file that
will affect the cached content, or just for debugging purposes. When Pelican
runs in autoreload mode, modification of the settings file will make it ignore
the cache automatically if AUTORELOAD_IGNORE_CACHE
is True
.
Note that even when using cached content, all output is always written, so the
modification times of the generated *.html
files will always change.
Therefore, rsync
-based uploading may benefit from the --checksum
option.
Example settings
AUTHOR = "Alexis Métaireau"
SITENAME = "Alexis' log"
SITESUBTITLE = "A personal blog."
SITEURL = "http://blog.notmyidea.org"
TIMEZONE = "Europe/Paris"
# can be useful in development, but set to False when you're ready to publish
RELATIVE_URLS = True
GITHUB_URL = "http://github.com/ametaireau/"
DISQUS_SITENAME = "blog-notmyidea"
REVERSE_CATEGORY_ORDER = True
LOCALE = "C"
DEFAULT_PAGINATION = 4
DEFAULT_DATE = (2012, 3, 2, 14, 1, 1)
FEED_ALL_RSS = "feeds/all.rss.xml"
CATEGORY_FEED_RSS = "feeds/{slug}.rss.xml"
LINKS = (
("Biologeek", "http://biologeek.org"),
("Filyb", "http://filyb.info/"),
("Libert-fr", "http://www.libert-fr.com"),
("N1k0", "http://prendreuncafe.com/blog/"),
("Tarek Ziadé", "http://ziade.org/blog"),
("Zubin Mithra", "http://zubin71.wordpress.com/"),
)
SOCIAL = (
("twitter", "http://twitter.com/ametaireau"),
("lastfm", "http://lastfm.com/user/akounet"),
("github", "http://github.com/ametaireau"),
)
# global metadata to all the contents
DEFAULT_METADATA = {"yeah": "it is"}
# path-specific metadata
EXTRA_PATH_METADATA = {
"extra/robots.txt": {"path": "robots.txt"},
}
# static paths will be copied without parsing their contents
STATIC_PATHS = [
"images",
"extra/robots.txt",
]
# custom page generated with a jinja2 template
TEMPLATE_PAGES = {"pages/jinja2_template.html": "jinja2_template.html"}
# there is no other HTML content
READERS = {"html": None}
# code blocks with line numbers
PYGMENTS_RST_OPTIONS = {"linenos": "table"}
# foobar will not be used, because it's not in caps. All configuration keys
# have to be in caps
foobar = "barbaz"
Plugins
Beginning with version 3.0, Pelican supports plugins. Plugins are a way to add
features to Pelican without having to directly modify the Pelican core.
How to use plugins
Starting with version 4.5, Pelican moved to a new plugin structure utilizing
namespace packages that can be easily installed via Pip. Plugins supporting
this structure will install under the namespace package pelican.plugins
and
can be automatically discovered by Pelican. To see a list of Pip-installed
namespace plugins that are active in your environment, run:
If you leave the PLUGINS
setting as default (None
), Pelican will
automatically discover namespace plugins and register them. If, on the other
hand, you specify a PLUGINS
setting as a list of plugins, this
auto-discovery will be disabled. At that point, only the plugins you specify
will be registered, and you must explicitly list any namespace plugins as well.
If you are using the PLUGINS
setting, you can specify plugins in two ways.
The first method specifies plugins as a list of strings. Namespace plugins can
be specified either by their full names (pelican.plugins.myplugin
) or by
their short names (myplugin
):
PLUGINS = ['package.myplugin',
'namespace_plugin1',
'pelican.plugins.namespace_plugin2']
Alternatively, you can import them in your settings file and pass the modules:
from package import myplugin
from pelican.plugins import namespace_plugin1, namespace_plugin2
PLUGINS = [myplugin, namespace_plugin1, namespace_plugin2]
Note
When experimenting with different plugins (especially the ones that deal
with metadata and content) caching may interfere and the changes may not be
visible. In such cases disable caching with LOAD_CONTENT_CACHE = False
or use the --ignore-cache
command-line switch.
If your plugins are not in an importable path, you can specify a list of paths
via the PLUGIN_PATHS
setting. As shown in the following example, paths in
the PLUGIN_PATHS
list can be absolute or relative to the settings file:
PLUGIN_PATHS = ["plugins", "/srv/pelican/plugins"]
PLUGINS = ["assets", "liquid_tags", "sitemap"]
Where to find plugins
Namespace plugins can be found in the pelican-plugins organization as
individual repositories. Legacy plugins are located in the pelican-plugins
repository and will be gradually phased out in favor of the namespace
versions.
Please note that while we do our best to review and maintain these plugins,
they are submitted by the Pelican community and thus may have varying levels of
support and interoperability.
How to create plugins
Plugins are based on the concept of signals. Pelican sends signals, and plugins
subscribe to those signals. The list of available signals is documented in a
subsequent section.
The only rule to follow for plugins is to define a register
callable, in
which you map the signals to your plugin logic. Let’s take a simple example:
import logging
from pelican import signals
log = logging.getLogger(__name__)
def test(sender):
log.debug("%s initialized !!", sender)
def register():
signals.initialized.connect(test)
Note
Signal receivers are weakly-referenced and thus must not be defined within
your register
callable or they will be garbage-collected before the
signal is emitted.
If multiple plugins connect to the same signal, plugins will be executed in the
order they are connected. With PLUGINS
setting, order will be as defined in
the setting. If you rely on auto-discovered namespace plugins, no PLUGINS
setting, they will be connected in the same order they are discovered (same
order as pelican-plugins
output). If you want to specify the order
explicitly, disable auto-discovery by defining PLUGINS
in the desired order.
Namespace plugin structure
Namespace plugins must adhere to a certain structure in order to function
properly. They need to be installable (i.e. contain setup.py
or equivalent)
and have a folder structure as follows:
myplugin
├── pelican
│ └── plugins
│ └── myplugin
│ ├── __init__.py
│ └── ...
├── ...
└── setup.py
It is crucial that pelican
or pelican/plugins
folder not
contain an __init__.py
file. In fact, it is best to have those folders
empty besides the listed folders in the above structure and keep your
plugin related files contained solely in the pelican/plugins/myplugin
folder to avoid any issues.
To easily set up the proper structure, a cookiecutter template for plugins
is provided. Refer to that project’s README for instructions on how to use it.
List of signals
Here is the list of currently implemented signals:
Signal |
Arguments |
Description |
initialized |
pelican object |
|
finalized |
pelican object |
invoked after all the generators are executed and just before pelican exits
useful for custom post processing actions, such as:
- minifying js/css assets.
- notify/ping search engines with an updated sitemap. |
generator_init |
generator |
invoked in the Generator.__init__ |
all_generators_finalized |
generators |
invoked after all the generators are executed and before writing output |
readers_init |
readers |
invoked in the Readers.__init__ |
article_generator_context |
article_generator, metadata |
|
article_generator_preread |
article_generator |
invoked before a article is read in ArticlesGenerator.generate_context;
use if code needs to do something before every article is parsed |
article_generator_init |
article_generator |
invoked in the ArticlesGenerator.__init__ |
article_generator_pretaxonomy |
article_generator |
invoked before categories and tags lists are created
useful when e.g. modifying the list of articles to be generated
so that removed articles are not leaked in categories or tags |
article_generator_finalized |
article_generator |
invoked at the end of ArticlesGenerator.generate_context |
article_generator_write_article |
article_generator, content |
invoked before writing each article, the article is passed as content |
article_writer_finalized |
article_generator, writer |
invoked after all articles and related pages have been written, but before
the article generator is closed. |
get_generators |
pelican object |
invoked in Pelican.get_generator_classes,
can return a Generator, or several
generators in a tuple or in a list. |
get_writer |
pelican object |
invoked in Pelican.get_writer,
can return a custom Writer. |
page_generator_context |
page_generator, metadata |
|
page_generator_preread |
page_generator |
invoked before a page is read in PageGenerator.generate_context;
use if code needs to do something before every page is parsed. |
page_generator_init |
page_generator |
invoked in the PagesGenerator.__init__ |
page_generator_finalized |
page_generator |
invoked at the end of PagesGenerator.generate_context |
page_generator_write_page |
page_generator, content |
invoked before writing each page, the page is passed as content |
page_writer_finalized |
page_generator, writer |
invoked after all pages have been written, but before the page generator
is closed. |
static_generator_context |
static_generator, metadata |
|
static_generator_preread |
static_generator |
invoked before a static file is read in StaticGenerator.generate_context;
use if code needs to do something before every static file is added to the
staticfiles list. |
static_generator_init |
static_generator |
invoked in the StaticGenerator.__init__ |
static_generator_finalized |
static_generator |
invoked at the end of StaticGenerator.generate_context |
content_object_init |
content_object |
invoked at the end of Content.__init__ |
content_written |
path, context |
invoked each time a content file is written. |
feed_generated |
context, feed |
invoked each time a feed gets generated. Can be used to modify a feed
object before it gets written. |
feed_written |
path, context, feed |
invoked each time a feed file is written. |
Warning
Avoid content_object_init
signal if you intend to read summary
or
content
properties of the content object. That combination can result in
unresolved links when Linking to internal content (see
pelican-plugins bug #314). Use _summary
and _content
properties
instead, or, alternatively, run your plugin at a later stage (e.g.
all_generators_finalized
).
Note
After Pelican 3.2, signal names were standardized. Older plugins may need
to be updated to use the new names:
Old name |
New name |
article_generate_context |
article_generator_context |
article_generate_finalized |
article_generator_finalized |
article_generate_preread |
article_generator_preread |
pages_generate_context |
page_generator_context |
pages_generate_preread |
page_generator_preread |
pages_generator_finalized |
page_generator_finalized |
pages_generator_init |
page_generator_init |
static_generate_context |
static_generator_context |
static_generate_preread |
static_generator_preread |
Recipes
We eventually realised some of the recipes to create plugins would be best
shared in the documentation somewhere, so here they are!
How to create a new reader
One thing you might want is to add support for your very own input format.
While it might make sense to add this feature in Pelican core, we wisely chose
to avoid this situation and instead have the different readers defined via
plugins.
The rationale behind this choice is mainly that plugins are really easy to
write and don’t slow down Pelican itself when they’re not active.
No more talking — here is an example:
from pelican import signals
from pelican.readers import BaseReader
# Create a new reader class, inheriting from the pelican.reader.BaseReader
class NewReader(BaseReader):
enabled = True # Yeah, you probably want that :-)
# The list of file extensions you want this reader to match with.
# If multiple readers were to use the same extension, the latest will
# win (so the one you're defining here, most probably).
file_extensions = ['yeah']
# You need to have a read method, which takes a filename and returns
# some content and the associated metadata.
def read(self, filename):
metadata = {'title': 'Oh yeah',
'category': 'Foo',
'date': '2012-12-01'}
parsed = {}
for key, value in metadata.items():
parsed[key] = self.process_metadata(key, value)
return "Some content", parsed
def add_reader(readers):
readers.reader_classes['yeah'] = NewReader
# This is how pelican works.
def register():
signals.readers_init.connect(add_reader)
Adding a new generator
Adding a new generator is also really easy. You might want to have a look at
Pelican internals for more information on how to create your own generator.
def get_generators(pelican_object):
# define a new generator here if you need to
return MyGenerator
def register():
signals.get_generators.connect(get_generators)
Adding a new writer
Adding a writer will allow you to output additional file formats to disk, or
change how the existing formats are written to disk. Note that only one writer
will be active at a time, so be sure to either subclass the built-in Writer, or
completely re-implement it.
Here is a basic example of how to set up your own writer:
from pelican.writers import Writer
from pelican import signals
class MyWriter(Writer):
# define new writer functionality
pass
def add_writer(pelican_object):
# use pelican_instance to setup stuff if needed
return MyWriter
def register():
signals.get_writer.connect(add_writer)
Using Plugins to Inject Content
You can programmatically inject articles or pages using plugins. This can be
useful if you plan to fetch articles from an API, for example.
Following is a simple example of how one can build a plugin that injects a
custom article, using the article_generator_pretaxonomy
signal:
import datetime
from pelican import signals
from pelican.contents import Article
from pelican.readers import BaseReader
def addArticle(articleGenerator):
settings = articleGenerator.settings
# Author, category, and tags are objects, not strings, so they need to
# be handled using BaseReader's process_metadata() function.
baseReader = BaseReader(settings)
content = "I am the body of an injected article!"
newArticle = Article(content, {
"title": "Injected Article!",
"date": datetime.datetime.now(),
"category": baseReader.process_metadata("category", "fromAPI"),
"tags": baseReader.process_metadata("tags", "tagA, tagB")
})
articleGenerator.articles.insert(0, newArticle)
def register():
signals.article_generator_pretaxonomy.connect(addArticle)
Frequently Asked Questions (FAQ)
Here are some frequently asked questions about Pelican.
What’s the best way to communicate a problem, question, or suggestion?
Please read our feedback guidelines.
How can I help?
There are several ways to help out. First, you can communicate any Pelican
suggestions or problems you might have via Pelican Discussions. Please first check the
existing list of discussions and issues (both open and closed) in order to
avoid submitting topics that have already been covered before.
If you want to contribute, please fork the Git repository, create a new feature branch, make
your changes, and issue a pull request. Someone will review your changes as
soon as possible. Please refer to the How to Contribute
section for more details.
You can also contribute by creating themes and improving the documentation.
Is the Pelican settings file mandatory?
Configuration files are optional and are just an easy way to configure Pelican.
For basic operations, it’s possible to specify options while invoking Pelican
via the command line. See pelican --help
for more information.
Changes to the settings file take no effect
When experimenting with different settings (especially the metadata ones)
caching may interfere and the changes may not be visible. In such cases, ensure
that caching is disabled via LOAD_CONTENT_CACHE = False
or use the
--ignore-cache
command-line switch.
I’m creating my own theme. How do I use Pygments for syntax highlighting?
Pygments adds some classes to the generated content. These classes are used by
themes to style code syntax highlighting via CSS. Specifically, you can
customize the appearance of your syntax highlighting via the .highlight pre
class in your theme’s CSS file. To see how various styles can be used to render
Django code, for example, use the style selector drop-down at top-right on the
Pygments project demo site.
You can use the following example commands to generate a starting CSS file from
a Pygments built-in style (in this case, “monokai”) and then copy the generated
CSS file to your new theme:
pygmentize -S monokai -f html -a .highlight > pygment.css
cp pygment.css path/to/theme/static/css/
Don’t forget to import your pygment.css
file from your main CSS file.
How do I create my own theme?
Please refer to Themes.
I want to use Markdown, but I got an error.
If you try to generate Markdown content without first installing the Markdown
library, you may see a message that says No valid files found in content
.
Markdown is not a hard dependency for Pelican, so if you have content in
Markdown format, you will need to explicitly install the Markdown library. You
can do so by typing the following command, prepending sudo
if permissions
require it:
python -m pip install markdown
How do I assign custom templates on a per-page basis?
It’s as simple as adding an extra line of metadata to any page or article that
you want to have its own template. For example, this is how it would be handled
for content in reST format:
For content in Markdown format:
Then just make sure your theme contains the relevant template file (e.g.
template_name.html
).
How can I override the generated URL of a specific page or article?
Include url
and save_as
metadata in any pages or articles that you want
to override the generated URL. Here is an example page in reST format:
Override url/save_as page
#########################
:url: override/url/
:save_as: override/url/index.html
With this metadata, the page will be written to override/url/index.html
and Pelican will use the URL override/url/
to link to this page.
How can I use a static page as my home page?
The override feature mentioned above can be used to specify a static page as
your home page. The following Markdown example could be stored in
content/pages/home.md
:
Title: Welcome to My Site
URL:
save_as: index.html
Thank you for visiting. Welcome!
If the original blog index is still wanted, it can then be saved in a
different location by setting INDEX_SAVE_AS = 'blog_index.html'
for
the 'index'
direct template.
What if I want to disable feed generation?
To disable feed generation, all feed settings should be set to None
. All
but three feed settings already default to None
, so if you want to disable
all feed generation, you only need to specify the following settings:
FEED_ALL_ATOM = None
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None
The word None
should not be surrounded by quotes. Please note that None
and ''
are not the same thing.
I’m getting a warning about feeds generated without SITEURL being set properly
RSS and Atom feeds require all URL links to be absolute. In order to properly
generate links in Pelican you will need to set SITEURL
to the full path of
your site.
Feeds are still generated when this warning is displayed, but links within may
be malformed and thus the feed may not validate.
Can I force Atom feeds to show only summaries instead of article content?
Instead of having to open a separate browser window to read articles, the
overwhelming majority of folks who use feed readers prefer to read content
within the feed reader itself. Mainly for that reason, Pelican does not support
restricting Atom feeds to only contain summaries. Unlike Atom feeds, the RSS
feed specification does not include a separate content
field, so by default
Pelican publishes RSS feeds that only contain summaries (but can optionally be
set to instead publish full content RSS feeds). So the default feed generation
behavior provides users with a choice: subscribe to Atom feeds for full content
or to RSS feeds for just the summaries.
Is Pelican only suitable for blogs?
No. Pelican can be easily configured to create and maintain any type of static
site. This may require a little customization of your theme and Pelican
configuration. For example, if you are building a launch site for your product
and do not need tags on your site, you could remove the relevant HTML code from
your theme. You can also disable generation of tag-related pages via:
TAGS_SAVE_AS = ''
TAG_SAVE_AS = ''
Why does Pelican always write all HTML files even with content caching enabled?
In order to reliably determine whether the HTML output is different before
writing it, a large part of the generation environment including the template
contexts, imported plugins, etc. would have to be saved and compared, at least
in the form of a hash (which would require special handling of unhashable
types), because of all the possible combinations of plugins, pagination, etc.
which may change in many different ways. This would require a lot more
processing time and memory and storage space. Simply writing the files each
time is a lot faster and a lot more reliable.
However, this means that the modification time of the files changes every time,
so a rsync
based upload will transfer them even if their content hasn’t
changed. A simple solution is to make rsync
use the --checksum
option,
which will make it compare the file checksums in a much faster way than Pelican
would.
How to process only a subset of all articles?
It is often useful to process only e.g. 10 articles for debugging purposes.
This can be achieved by explicitly specifying only the filenames of those
articles in ARTICLE_PATHS
. A list of such filenames could be found using a
command similar to cd content; find -name '*.md' | head -n 10
.
My tag cloud is missing/broken since I upgraded Pelican
In an ongoing effort to streamline Pelican, tag cloud generation has been
moved out of Pelican core and into a separate plugin. See the Plugins
documentation for further information about the Pelican plugin system.
Since I upgraded Pelican my pages are no longer rendered
Pages were available to themes as lowercase pages
and uppercase PAGES
.
To bring this inline with the Templates and Variables section, PAGES
has
been removed. This is quickly resolved by updating your theme to iterate over
pages
instead of PAGES
. Just replace:
with something like:
How can I stop Pelican from trying to parse my static files as content?
Pelican’s article and page generators run before it’s static generator. That
means if you use a setup similar to the default configuration, where a static
source directory is defined inside a *_PATHS
setting, all files that have a
valid content file ending (.html
, .rst
, .md
, …) will be treated
as articles or pages before they get treated as static files.
To circumvent this issue either use the appropriate *_EXCLUDES
setting or
disable the offending reader via READERS
if you don’t need it.
Why is [arbitrary Markdown syntax] not supported?
Pelican does not directly handle Markdown processing and instead delegates that
task to the Python-Markdown project, the core of which purposefully follows
the original Markdown syntax rules and not the myriad Markdown “flavors” that
have subsequently propagated. That said, Python-Markdown is quite modular, and
the syntax you are looking for may be provided by one of the many available
Markdown Extensions. Alternatively, some folks have created Pelican plugins
that support Markdown variants, so that may be your best choice if there is a
particular variant you want to use when writing your content.
Contributing and feedback guidelines
There are many ways to contribute to Pelican. You can improve the
documentation, add missing features, and fix bugs (or just report them). You
can also help out by reviewing and commenting on
existing issues.
Don’t hesitate to fork Pelican and submit an issue or pull request on GitHub.
When doing so, please consider the following guidelines.
How to get help
Before you ask for help, please make sure you do the following:
Read the documentation thoroughly. If in a hurry, at least use the search
field that is provided at top-left on the documentation pages. Make sure
you read the docs for the Pelican version you are using.
Use a search engine (e.g., DuckDuckGo, Google) to search for a solution to
your problem. Someone may have already found a solution, perhaps in the
form of a ‘plugins or a specific combination of settings.
Try reproducing the issue in a clean environment, ensuring you are using:
latest Pelican release (or an up-to-date Git clone of Pelican master)
latest releases of libraries used by Pelican
no plugins or only those related to the issue
NOTE: The most common sources of problems are anomalies in (1) themes, (2)
plugins, (3) settings files, and (4) make
/invoke
automation wrappers.
If you can’t reproduce your problem when using the following steps to generate
your site, then the problem is almost certainly with one of the above-listed
elements (and not Pelican itself):
cd ~/projects/your-site
git clone https://github.com/getpelican/pelican ~/projects/pelican
pelican content -s ~/projects/pelican/samples/pelican.conf.py -t ~/projects/pelican/pelican/themes/notmyidea
If you can generate your site without problems using the steps above, then your
problem is unlikely to be caused by Pelican itself, and therefore please
consider reaching out to the maintainers of the plugins/theme you are using
instead of raising the topic with the Pelican core community.
If despite the above efforts you still cannot resolve your problem, be sure to
include in your inquiry the following information, preferably in the form of
links to content uploaded to a paste service, GitHub repository, or other
publicly-accessible location:
Describe what version of Pelican you are running (output of pelican --version
or the HEAD commit hash if you cloned the repo) and how exactly you installed
it (the full command you used, e.g. python -m pip install pelican
).
If you are looking for a way to get some end result, prepare a detailed
description of what the end result should look like (preferably in the form of
an image or a mock-up page) and explain in detail what you have done so far to
achieve it.
If you are trying to solve some issue, prepare a detailed description of how
to reproduce the problem. If the issue cannot be easily reproduced, it cannot
be debugged by developers or volunteers. Describe only the minimum steps
necessary to reproduce it (no extra plugins, etc.).
Upload your settings file or any other custom code that would enable people to
reproduce the problem or to see what you have already tried to achieve the
desired end result.
Upload detailed and complete output logs and backtraces (remember to add
the --debug
flag: pelican --debug content [...]
)
Once the above preparation is ready, you can post your query as a new thread in
Pelican Discussions. Remember to include all the information you prepared.
Contributing code
Before you submit a contribution, please ask whether it is desired so that you
don’t spend a lot of time working on something that would be rejected for a
known reason. Consider also whether your new feature might be better suited as
a ‘plugins — you can ask for help to make that determination.
Also, if you intend to submit a pull request to address something for which there
is no existing issue, there is no need to create a new issue and then immediately
submit a pull request that closes it. You can submit the pull request by itself.
Using Git and GitHub
Create a new branch specific to your change (as opposed to making
your commits in the master branch).
Don’t put multiple unrelated fixes/features in the same branch / pull request.
For example, if you’re working on a new feature and find a bugfix that
doesn’t require your new feature, make a new distinct branch and pull
request for the bugfix. Similarly, any proposed changes to code style
formatting should be in a completely separate pull request.
Add a RELEASE.md
file in the root of the project that contains the
release type (major, minor, patch) and a summary of the changes that will be
used as the release changelog entry. For example:
Release type: minor
Reload browser window upon changes to content, settings, or theme
Check for unnecessary whitespace via git diff --check
before committing.
First line of your commit message should start with present-tense verb, be 50
characters or less, and include the relevant issue number(s) if applicable.
Example: Ensure proper PLUGIN_PATH behavior. Refs #428.
If the commit
completely fixes an existing bug report, please use Fixes #585
or Fix
#585
syntax (so the relevant issue is automatically closed upon PR merge).
After the first line of the commit message, add a blank line and then a more
detailed explanation (when relevant).
Squash your commits to eliminate merge commits and ensure a clean and
readable commit history.
After you have issued a pull request, the continuous integration (CI) system
will run the test suite on all supported Python versions and check for code style
compliance. If any of these checks fail, you should fix them. (If tests fail
on the CI system but seem to pass locally, ensure that local test runs aren’t
skipping any tests.)
Contribution quality standards
Check out our Git Tips page or ask for help if you
need assistance or have any questions about these guidelines.
Setting up the development environment
While there are many ways to set up one’s development environment, the following
instructions will utilize Pip and PDM. These tools facilitate managing
virtual environments for separate Python projects that are isolated from one
another, so you can use different packages (and package versions) for each.
Please note that Python >=3.8.1 is required for Pelican development.
(Optional) If you prefer to install PDM once for use with multiple projects,
you can install it via:
curl -sSL https://pdm.fming.dev/install-pdm.py | python3 -
Point your web browser to the Pelican repository and tap the Fork button
at top-right. Then clone the source for your fork and add the upstream project
as a Git remote:
mkdir ~/projects
git clone https://github.com/YOUR_USERNAME/pelican.git ~/projects/pelican
cd ~/projects/pelican
git remote add upstream https://github.com/getpelican/pelican.git
While PDM can dynamically create and manage virtual environments, we’re going
to manually create and activate a virtual environment:
mkdir ~/virtualenvs && cd ~/virtualenvs
python3 -m venv pelican
source ~/virtualenvs/pelican/*/activate
Install the needed dependencies and set up the project:
python -m pip install invoke
invoke setup
Your local environment should now be ready to go!
Development
Once Pelican has been set up for local development, create a topic branch for
your bug fix or feature:
git checkout -b name-of-your-bugfix-or-feature
Now you can make changes to Pelican, its documentation, and/or other aspects of
the project.
Running the test suite
Each time you make changes to Pelican, there are two things to do regarding
tests: check that the existing tests pass, and add tests for any new features
or bug fixes. The tests are located in pelican/tests
, and you can run them
via:
(For more on Invoke, see invoke -l
to list tasks, or
https://pyinvoke.org for documentation.)
In addition to running the test suite, it is important to also ensure that any
lines you changed conform to code style guidelines. You can check that via:
If code style violations are found in lines you changed, correct those lines
and re-run the above lint command until they have all been fixed. You do not
need to address style violations, if any, for code lines you did not touch.
After making your changes and running the tests, you may see a test failure
mentioning that “some generated files differ from the expected functional tests
output.” If you have made changes that affect the HTML output generated by
Pelican, and the changes to that output are expected and deemed correct given
the nature of your changes, then you should update the output used by the
functional tests. To do so, make sure you have both en_EN.utf8
and
fr_FR.utf8
locales installed, and then run the following command:
invoke update-functional-tests
You may also find that some tests are skipped because some dependency (e.g.,
Pandoc) is not installed. This does not automatically mean that these tests
have passed; you should at least verify that any skipped tests are not affected
by your changes.
You should run the test suite under each of the supported versions of Python.
This is best done by creating a separate Python environment for each version.
Tox is a useful tool to automate running tests inside virtualenv
environments.
Building the docs
If you make changes to the documentation, you should build and inspect your
changes before committing them:
Open http://localhost:8000 in your browser to review the documentation. While
the above task is running, any changes you make and save to the documentation
should automatically appear in the browser, as it live-reloads when it detects
changes to the documentation source files.
Plugin development
To create a new Pelican plugin, please refer to the plugin template
repository for detailed instructions.
If you want to contribute to an existing Pelican plugin, follow the steps
above to set up Pelican for local development, and then create a directory to
store cloned plugin repositories:
mkdir -p ~/projects/pelican-plugins
Assuming you wanted to contribute to the Simple Footnotes plugin, you would
first browse to the Simple Footnotes repository on GitHub and tap the Fork
button at top-right. Then clone the source for your fork and add the upstream
project as a Git remote:
git clone https://github.com/YOUR_USERNAME/simple-footnotes.git ~/projects/pelican-plugins/simple-footnotes
cd ~/projects/pelican-plugins/simple-footnotes
git remote add upstream https://github.com/pelican-plugins/simple-footnotes.git
Install the needed dependencies and set up the project:
Create a topic branch for your plugin bug fix or feature:
git checkout -b name-of-your-bugfix-or-feature
After writing new tests for your plugin changes, run the plugin test suite and
check for code style compliance via:
If style violations are found, many of them can be addressed automatically via:
If style violations are found even after running the above auto-formatters,
you will need to make additional manual changes until invoke lint
no longer
reports any code style violations.
Submitting your changes
Assuming linting validation and tests pass, add a RELEASE.md
file in the root
of the project that contains the release type (major, minor, patch) and a
summary of the changes that will be used as the release changelog entry.
For example:
Release type: patch
Fix browser reloading upon changes to content, settings, or theme
Commit your changes and push your topic branch:
git add .
git commit -m "Your detailed description of your changes"
git push origin name-of-your-bugfix-or-feature
Finally, browse to your repository fork on GitHub and submit a pull request.
Logging tips
Try to use logging with appropriate levels.
For logging messages that are not repeated, use the usual Python way:
# at top of file
import logging
logger = logging.getLogger(__name__)
# when needed
logger.warning("A warning with %s formatting", arg_to_be_formatted)
Do not format log messages yourself. Use %s
formatting in messages and pass
arguments to logger. This is important, because the Pelican logger will
preprocess some arguments, such as exceptions.
Outputting traceback in the logs
If you’re logging inside an except
block, you may want to provide the
traceback information as well. You can do that by setting exc_info
keyword
argument to True
during logging. However, doing so by default can be
undesired because tracebacks are long and can be confusing to regular users.
Try to limit them to --debug
mode like the following:
try:
some_action()
except Exception as e:
logger.error('Exception occurred: %s', e,
exc_info=settings.get('DEBUG', False))
Some history about Pelican
Warning
This page comes from a report the original author (Alexis Métaireau) wrote
right after writing Pelican, in December 2010. The information may not be
up-to-date.
Pelican is a simple static blog generator. It parses markup files (Markdown or
reStructuredText for now) and generates an HTML folder with all the files in
it. I’ve chosen to use Python to implement Pelican because it seemed to be
simple and to fit to my needs. I did not wanted to define a class for each
thing, but still wanted to keep my things loosely coupled. It turns out that it
was exactly what I wanted. From time to time, thanks to the feedback of some
users, it took me a very few time to provide fixes on it. So far, I’ve
re-factored the Pelican code by two
times; each time took less than 30 minutes.
Use case
I was previously using WordPress, a solution you can host on a web server to
manage your blog. Most of the time, I prefer using markup languages such as
Markdown or reStructuredText to type my articles. To do so, I use vim. I think
it is important to let the people choose the tool they want to write the
articles. In my opinion, a blog manager should just allow you to take any kind
of input and transform it to a weblog. That’s what Pelican does. You can write
your articles using the tool you want, and the markup language you want, and
then generate a static HTML weblog.
To be flexible enough, Pelican has template support, so you can easily write
your own themes if you want to.
Design process
Pelican came from a need I have. I started by creating a single file
application, and I have make it grow to support what it does by now. To start,
I wrote a piece of documentation about what I wanted to do. Then, I created the
content I wanted to parse (the reStructuredText files) and started
experimenting with the code. Pelican was 200 lines long and contained almost
ten functions and one class when it was first usable.
I have been facing different problems all over the time and wanted to add
features to Pelican while using it. The first change I have done was to add the
support of a settings file. It is possible to pass the options to the command
line, but can be tedious if there is a lot of them. In the same way, I have
added the support of different things over time: Atom feeds, multiple themes,
multiple markup support, etc. At some point, it appears that the “only one
file” mantra was not good enough for Pelican, so I decided to rework a bit all
that, and split this in multiple different files.
I’ve separated the logic in different classes and concepts:
writers are responsible of all the writing process of the files.
They are responsible of writing .html files, RSS feeds and so on. Since those
operations are commonly used, the object is created once, and then passed to
the generators.
readers are used to read from various formats (Markdown and
reStructuredText for now, but the system is extensible). Given a file, they
return metadata (author, tags, category, etc) and content (HTML formatted).
generators generate the different outputs. For instance, Pelican
comes with an ArticlesGenerator and PagesGenerator, into others. Given a
configuration, they can do whatever you want them to do. Most of the time
it’s generating files from inputs (user inputs and files).
I also deal with contents objects. They can be Articles
, Pages
,
Quotes
, or whatever you want. They are defined in the contents.py
module and represent some content to be used by the program.
In more detail
Here is an overview of the classes involved in Pelican.
The interface does not really exist, and I have added it only to clarify the
whole picture. I do use duck typing and not interfaces.
Internally, the following process is followed:
First of all, the command line is parsed, and some content from the user is
used to initialize the different generator objects.
A context
is created. It contains the settings from the command line and
a settings file if provided.
The generate_context
method of each generator is called, updating
the context.
The writer is created and given to the generate_output
method of each
generator.
I make two calls because it is important that when the output is generated by
the generators, the context will not change. In other words, the first method
generate_context
should modify the context, whereas the second
generate_output
method should not.
Then, it is up to the generators to do what the want, in the
generate_context
and generate_content
method. Taking the
ArticlesGenerator
class will help to understand some others concepts. Here
is what happens when calling the generate_context
method:
Read the folder “path”, looking for restructured text files, load each of
them, and construct a content object (Article
) with it. To do so, use
Reader
objects.
Update the context
with all those articles.
Then, the generate_content
method uses the context
and the writer
to generate the wanted output.
Release history
4.9.0 - 2023-11-12
Upgrade code to new minimum supported Python version: 3.8
Settings support for pathlib.Path
(#2758)
Various improvements to Simple theme (#2976 & #3234)
Use Furo as Sphinx documentation theme (#3023)
Default to 100 articles maximum in feeds (#3127)
Add period_archives common context
variable (#3148)
Use watchfiles
as the file-watching backend (#3151)
Add GitHub Actions workflow for GitHub Pages (#3189)
Allow dataclasses in settings (#3204)
Switch build tool to PDM instead of Setuptools/Poetry (#3220)
Provide a plugin_enabled
Jinja test for themes (#3235)
Preserve connection order in Blinker (#3238)
Remove social icons from default notmyidea
theme (#3240)
Remove unreliable WRITE_SELECTED
feature (#3243)
Importer: Report broken embedded video links when importing from Tumblr (#3177)
Importer: Remove newline addition when iterating Photo post types (#3178)
Importer: Force timestamp conversion in Tumblr importer to be UTC with offset (#3221)
Importer: Use tempfile for intermediate HTML file for Pandoc (#3221)
Switch linters to Ruff (#3223)
4.8.0 - 2022-07-11
Use JSON values for extra settings in Invoke tasks template (#2994)
Add content tag for links, which can help with things like Twitter social cards (#3001)
Improve word count behavior when generating summary (#3002)
4.7.2 - 2022-02-09
Fix incorrect parsing of parameters specified via -e / –extra-settings option flags (#2938)
Add categories.html
template to default theme (#2973)
Document how to use plugins to inject content (#2922)
4.7.1 - 2021-10-12
Extend rich logging to server component (#2927)
Fix an issue where metadata flagged to be discarded was being cached (#2926)
Adjust suffix in server to allow redirection when needed (#2931)
Add MIME types for web fonts (#2929)
Distribute sample data used to run tests (#2935)
Add Python 3.10 to test matrix
4.7.0 - 2021-10-01
Improve default theme rendering on mobile and other small screen devices (#2914)
Add support for hidden articles (#2866)
Improve word count behavior when generating summary CJK & other locales (#2864)
Add progress spinner during generation (#2869)
and richer logging (#2897), both via Rich
Invoke tasks serve
and livereload
now auto-open a web browser pointing to the locally-served web site (#2764)
Support some date format codes used by ISO dates (#2902)
Document how to add a new writer (#2901)
4.6.0 - 2021-03-23
Add new URL pattern to PAGINATION_PATTERNS
for the last page in the list (#1401)
Speed up livereload
Invoke task via caching (#2847)
Ignore None
return value from get_generators
signal (#2850)
Relax dependency minimum versions and remove upper bounds
4.5.4 - 2021-01-04
Replace plugin definitions in settings with string representations after registering, so they can be cached correctly (#2828).
4.5.3 - 2020-12-01
Fix a mistake made in PR #2821
4.5.2 - 2020-11-22
Improve logging of generators and writer loaders
4.5.1 - 2020-11-02
Refactor intra-site link discovery in order to match more permissively (#2646)
Fix plugins running twice in auto-reload mode (#2817)
Add notice to use from pelican import signals
instead of import pelican.signals
(#2805)
4.5.0 - 2020-08-20
Add namespace plugin support; list plugins via pelican-plugins
command
Override settings via -e
/ --extra-settings
CLI option flags
Add settings for custom Jinja globals and tests
Customize article summary ellipsis via SUMMARY_END_SUFFIX
setting
Customize Typogrify dash handling via new TYPOGRIFY_DASHES
setting
Support Unicode when generating slugs
Support Asciidoc .adoc
file generation in Pelican importer
Improve user experience when pelican --listen
web server is quit
Improve Invoke tasks template
Include tests in source distributions
Switch CI from Travis to GitHub Actions
Remove support for Python 2.7
4.2.0 - 2019-10-17
Support inline SVGs; don’t treat titles in SVGs as HTML titles
Add category to feeds (in addition to tags)
Improve content metadata field docs
Add docs for including other Markdown/reST files in content
4.1.3 - 2019-10-09
Fix quick-start docs regarding pelican --listen
Set default listen address to 127.0.0.1
Add extra/optional Markdown dependency to setup.py
Use correct SSH port syntax for rsync in tasks.py
Place all deprecated settings handling together
Add related project URLs for display on PyPI
Skip some tests on Windows that can’t pass due to filesystem differences
4.1.2 - 2019-09-23
Fix pelican.settings.load_source to avoid caching issues - PR #2621
4.1.1 - 2019-08-23
Add AutoPub to auto-publish releases on PR merge
Add CSS classes for reStructuredText figures
Pass argv
to Pelican main
entrypoint
Set default content status to a blank string rather than None
4.1.0 - 2019-07-14
Live browser reload upon changed files (provided via Invoke task)
Add pyproject.toml
, managed by Poetry
Support for invoking python -m pelican
Add relative source path attribute to content
Allow directories in EXTRA_PATH_METADATA
Add all_articles
variable to period pages (for recent posts functionality)
Improve debug mode output
Remove blank or duplicate summaries from Atom feed
Fix bugs in pagination, pelican-import, pelican-quickstart, and feed importer
4.0.1 (2018-11-30)
Refactor pelican.server
logging
Fix bug in which all static files were processed as “draft”
Bug fixes for Invoke/Makefile automation, Importer, and other miscellanea
If upgrading from 3.7.x or earlier, please note that slug-related settings in
4.0+ use {slug}
and/or {lang}
rather than %s
. If %s
-style
settings are encountered, Pelican will emit a warning and fall back to the
default setting. Some user-submitted themes might try to format setting values
but fail upon site build with a TypeError
. In such cases, the theme needs
to be updated. For example, instead of TAG_FEED_ATOM|format(tag.slug)
, use
TAG_FEED_ATOM.format(slug=tag.slug)
4.0.0 (2018-11-13)
Replace develop_server.sh
script with pelican --listen
Improved copy/link behavior for large static files (e.g., videos)
New {static}
syntax to link to static content; content linked to by
{static}
and {attach}
is automatically copied over even if not in
STATIC_PATHS
Pages can now have draft
status
Show current settings via new --print-settings
flag
All settings for slugs now use {slug}
and/or {lang}
rather than
%s
. If %s
-style settings are encountered, Pelican will emit a warning
and fallback to the default setting.
New signals: feed_generated
and page_generated_write_page
Replace Fabric with Invoke and fabfile.py
template with tasks.py
Replace PAGINATED_DIRECT_TEMPLATES
by PAGINATED_TEMPLATES
, extending
control over pagination to all templates and making page size variable
Replace SLUG_SUBSTITUTIONS
(and friends) by SLUG_REGEX_SUBSTITUTIONS
for more finegrained control
'{base_name}'
value in PAGINATION_PATTERNS
setting no longer strips
'bar'
from 'foo/bar.html'
(unless 'bar' == 'index'
).
ARTICLE_ORDER_BY
and PAGE_ORDER_BY
now also affect 1) category, tag
and author pages 2) feeds 3) draft and hidden articles and pages
New ARTICLE_TRANSLATION_ID
and PAGE_TRANSLATION_ID
settings to
specify metadata attributes used to identify/disable translations
Make the HTML reader parse multiple occurrences of metadata tags as a list
New Blogger XML backup importer
Wordpress importer now updates file links to point to local copies if the
files were downloaded with --wp-attach
.
Importer no longer inserts extra newlines, to prevent breaking of HTML
attributes.
Pelican server now prioritises foo.html
and foo/index.html
over
foo/
when resolving foo
.
3.7.0 (2016-12-12)
Atom feeds output <content>
in addition to <summary>
Atom feeds use <published>
for the original publication date and
<updated>
for modifications
Simplify Atom feed ID generation and support URL fragments
Produce category feeds with category-specific titles
RSS feeds now default to summary instead of full content;
set RSS_FEED_SUMMARY_ONLY = False
to revert to previous behavior
Replace MD_EXTENSIONS
with MARKDOWN
setting
Replace JINJA_EXTENSIONS
with more-robust JINJA_ENVIRONMENT
setting
Improve summary truncation logic to handle special characters and tags that
span multiple lines, using HTML parser instead of regular expressions
Include summary when looking for intra-site link substitutions
Link to authors and index via {author}name
and {index}
syntax
Override widget names via LINKS_WIDGET_NAME
and SOCIAL_WIDGET_NAME
Add INDEX_SAVE_AS
option to override default index.html
value
Remove PAGES
context variable for themes in favor of pages
SLUG_SUBSTITUTIONS
now accepts 3-tuple elements, allowing URL slugs to
contain non-alphanumeric characters
Tag and category slugs can be controlled with greater precision using the
TAG_SUBSTITUTIONS
and CATEGORY_SUBSTITUTIONS
settings
Author slugs can be controlled with greater precision using the
AUTHOR_SUBSTITUTIONS
setting
DEFAULT_DATE
can be defined as a string
Use mtime
instead of ctime
when DEFAULT_DATE = 'fs'
Add --fatal=errors|warnings
option for use with continuous integration
When using generator-level caching, ensure previously-cached files are
processed instead of just new files.
Add Python and Pelican version information to debug output
Improve compatibility with Python 3.5
Comply with and enforce PEP8 guidelines
Replace tables in settings documentation with data::
directives
3.6.2 (2015-08-01)
Fix installation errors related to Unicode in tests
Don’t show pagination in notmyidea
theme if there’s only one page
Make hidden pages available in context
Improve URLWrapper comparison
3.6.0 (2015-06-15)
Disable caching by default in order to prevent potential confusion
Improve caching behavior, replacing pickle
with cpickle
Allow Markdown or reST content in metadata fields other than summary
Support semicolon-separated author/tag lists
Improve flexibility of article sorting
Add --relative-urls
argument
Support devserver listening on addresses other than localhost
Unify HTTP server handlers to pelican.server
throughout
Handle intra-site links to draft posts
Move tag_cloud
from core to plugin
Load default theme’s external resources via HTTPS
Import drafts from WordPress XML
Improve support for Windows users
Enhance logging and test suite
Clean up and refactor codebase
New signals: all_generators_finalized
and page_writer_finalized
3.5.0 (2014-11-04)
Introduce ARTICLE_ORDER_BY
and PAGE_ORDER_BY
settings to control the
order of articles and pages.
Include time zone information in dates rendered in templates.
Expose the reader name in the metadata for articles and pages.
Add the ability to store static files along with content in the same
directory as articles and pages using {attach}
in the path.
Prevent Pelican from raising an exception when there are duplicate pieces of
metadata in a Markdown file.
Introduce the TYPOGRIFY_IGNORE_TAGS
setting to add HTML tags to be
ignored by Typogrify.
Add the ability to use -
in date formats to strip leading zeros. For
example, %-d/%-m/%y
will now result in the date 9/8/12
.
Ensure feed generation is correctly disabled during quickstart configuration.
Fix PAGE_EXCLUDES
and ARTICLE_EXCLUDES
from incorrectly matching
sub-directories.
Introduce STATIC_EXCLUDE
setting to add static file excludes.
Fix an issue when using PAGINATION_PATTERNS
while RELATIVE_URLS
is enabled.
Fix feed generation causing links to use the wrong language for month
names when using other locales.
Fix an issue where the authors list in the simple template wasn’t correctly
formatted.
Fix an issue when parsing non-string URLs from settings.
Improve consistency of debug and warning messages.
3.4.0 (2014-07-01)
Speed up content generation via new caching mechanism
Add selective post generation (instead of always building entire site)
Many documentation improvements, including switching to prettier RtD theme
Add support for multiple content and plugin paths
Add :modified:
metadata field to complement :date:
.
Used to specify the last date and time an article was updated independently
from the date and time it was published.
Add support for multiple authors via new :authors:
metadata field
Watch for changes in static directories when in auto-regeneration mode
Add filters to limit log output when desired
Add language support to drafts
Add SLUGIFY_SOURCE
setting to control how post slugs are generated
Fix many issues relating to locale and encoding
Apply Typogrify filter to post summary
Preserve file metadata (e.g. time stamps) when copying static files to output
Move AsciiDoc support from Pelican core into separate plugin
Produce inline links instead of reference-style links when importing content
Improve handling of IGNORE_FILES
setting behavior
Properly escape symbol characters in tag names (e.g., C++
)
Minor tweaks for Python 3.4 compatibility
Add several new signals
3.3.0 (2013-09-24)
Drop Python 3.2 support in favor of Python 3.3
Add Fabfile
so Fabric can be used for workflow automation instead of Make
OUTPUT_RETENTION
setting can be used to preserve metadata (e.g., VCS
data such as .hg
and .git
) from being removed from output directory
Tumblr import
Improve logic and consistency when cleaning output folder
Improve documentation versioning and release automation
Improve pagination flexibility
Rename signals for better consistency (some plugins may need to be updated)
Move metadata extraction from generators to readers; metadata extraction no
longer article-specific
Deprecate FILES_TO_COPY
in favor of STATIC_PATHS
and
EXTRA_PATH_METADATA
Summaries in Markdown posts no longer include footnotes
Remove unnecessary whitespace in output via lstrip_blocks
Jinja parameter
Move PDF generation from core to plugin
Replace MARKUP
setting with READERS
Add warning if img tag is missing alt
attribute
Add support for {}
in relative links syntax, besides ||
Add support for {tag}
and {category}
relative links
Add a content_written
signal
3.2 (2013-04-24)
Support for Python 3!
Override page save-to location from meta-data (enables using a static page as
the site’s home page, for example)
Time period archives (per-year, per-month, and per-day archives of posts)
Posterous blog import
Improve WordPress blog import
Migrate plugins to separate repository
Improve HTML parser
Provide ability to show or hide categories from menu using
DISPLAY_CATEGORIES_ON_MENU
option
Auto-regeneration can be told to ignore files via IGNORE_FILES
setting
Improve post-generation feedback to user
For multilingual posts, use meta-data to designate which is the original
and which is the translation
Add .mdown
to list of supported Markdown file extensions
Document-relative URL generation (RELATIVE_URLS
) is now off by default
3.1 (2012-12-04)
Importer now stores slugs within files by default. This can be disabled with
the --disable-slugs
option.
Improve handling of links to intra-site resources
Ensure WordPress import adds paragraphs for all types of line endings
in post content
Decode HTML entities within WordPress post titles on import
Improve appearance of LinkedIn icon in default theme
Add GitHub and Google+ social icons support in default theme
Optimize social icons
Add FEED_ALL_ATOM
and FEED_ALL_RSS
to generate feeds containing all
posts regardless of their language
Split TRANSLATION_FEED
into TRANSLATION_FEED_ATOM
and
TRANSLATION_FEED_RSS
Different feeds can now be enabled/disabled individually
Allow for blank author: if AUTHOR
setting is not set, author won’t
default to ${USER}
anymore, and a post won’t contain any author
information if the post author is empty
Move LESS and Webassets support from Pelican core to plugin
The DEFAULT_DATE
setting now defaults to None
, which means that
articles won’t be generated unless date metadata is specified
Add FILENAME_METADATA
setting to support metadata extraction from
filename
Add gzip_cache
plugin to compress common text files into a .gz
file within the same directory as the original file, preventing the server
(e.g. Nginx) from having to compress files during an HTTP call
Add support for AsciiDoc-formatted content
Add USE_FOLDER_AS_CATEGORY
setting so that feature can be toggled on/off
Support arbitrary Jinja template files
Restore basic functional tests
New signals: generator_init
, get_generators
, and
article_generate_preread
3.0 (2012-08-08)
Refactored the way URLs are handled
Improved the English documentation
Fixed packaging using setuptools
entrypoints
Added typogrify
support
Added a way to disable feed generation
Added support for DIRECT_TEMPLATES
Allow multiple extensions for content files
Added LESS support
Improved the import script
Added functional tests
Rsync support in the generated Makefile
Improved feed support (easily pluggable with Feedburner for instance)
Added support for abbr
in reST
Fixed a bunch of bugs :-)
2.8 (2012-02-28)
Dotclear importer
Allow the usage of Markdown extensions
Themes are now easily extensible
Don’t output pagination information if there is only one page
Add a page per author, with all their articles
Improved the test suite
Made the themes easier to extend
Removed Skribit support
Added a pelican-quickstart
script
Fixed timezone-related issues
Added some scripts for Windows support
Date can be specified in seconds
Never fail when generating posts (skip and continue)
Allow the use of future dates
Support having different timezones per language
Enhanced the documentation
2.7 (2011-06-11)
Use logging
rather than echoing to stdout
Support custom Jinja filters
Compatibility with Python 2.5
Added a theme manager
Packaged for Debian
Added draft support
2.6 (2011-03-08)
Changes in the output directory structure
Makes templates easier to work with / create
Added RSS support (was Atom-only)
Added tag support for the feeds
Enhance the documentation
Added another theme (brownstone)
Added translations
Added a way to use cleaner URLs with a rewrite url module (or equivalent)
Added a tag cloud
Added an autoreloading feature: the blog is automatically regenerated each
time a modification is detected
Translate the documentation into French
Import a blog from an RSS feed
Pagination support
Added Skribit support
2.4 (2010-11-06)
Minor themes changes
Add Disqus support (so we have comments)
Another code refactoring
Added config settings about pages
Blog entries can also be generated in PDF