A new generator for Pelican that replaces the default Page and Article generators, allowing the definition of arbitrary content types, aka, entity types (e.g: projects, events) and associated indices/direct templates.
Similar to nodes in Drupal.
To install the library, you can use pip
$ pip install pelican-entities
Update
pelicanconf.py
:- Add
entities
toPLUGINS
. PLUGINS = ['entities', ...]
- Add
Disable default page and article generators:
PAGE_PATHS = [] ARTICLE_PATHS = [] DIRECT_TEMPLATES = [] PAGINATED_TEMPLATES = {}
Specify entity types to use in your site and their settings:
ENTITY_TYPES = { <type1_name>: { PATHS: [<type1_path1>, <type1_path2>, ...], EXCLUDES: [...], <type1_name>_URL: "...", <type1_name>_SAVE_AS: "...", ... }, <type2_name>: { ... } }
Update theme to use new variables.
Watch out for incompatible plugins (those that rely on the pages and article generator signals or on the existence of variables defined by them).
Settings defined at the ENTITY_TYPES level take precedence over global ones.
- Settings for each entity type are defined as the value of the corresponding
key in the
ENTITY_TYPES
dictionary. PAGE_PATHS
andARTICLE_PATHS
are replaced byPATHS
.PAGE_EXCLUDES
andARTICLE_EXCLUDES
are replaced byEXCLUDES
.PAGE_URL
,ARTICLE_URL
,PAGE_SAVE_AS
andARTICLE_SAVE_AS
replaced by generic<entity_name>_URL
and<entity_name>_SAVE_AS
.ARTICLE_ORDER_BY
andPAGE_ORDER_BY
are removed in favour ofSORTER
.
DEFAULT_TEMPLATE
: Template to use by default when generating pages for that entity type.MANDATORY_PROPERTIES
: List of properties that has to be defined for an entity to be considered valid (by default, just title).SORTER
: Function taking list of entities as argument and which is responsible for sorting it as desired. Default value is the result of a call toentities.attribute_list_sorter(["date"], reverse=True)
ARCHIVE_TEMPLATE
: Template used for archive pages.CATEGORY_TEMPLATE
: Template used for category pages.TAG_TEMPLATE
: Template used for tag pages.AUTHOR_TEMPLATE
: Template used for author pages.SUBGENERATOR_CLASS
: Optionally define a custom subgenerator class. This should either be a callable matching theentities.EntityGenerator.EntitySubGenerator
interface or an import path to such a callable which will be imported dynamically.
- Global:
url
: The url of the current page.entity_type
: Type of the entity associated with this page.entity_types
: Dict having all declared entity types as keys and their generators as values.<entity_type_name>
: For each declared entity type, an object is added to the context containing:entities
: All entities of that entity type.translations
: All translations of that entity type.tags
: All tags of that entity type.categories
: All categories of that entity type.authors
: All authors of that entity type.drafts
: All drafts of that entity type.drafts_translations
: All draft translations of that entity type.hidden_entities
: All hidden entities of that entity type.hidden_translations
: All hidden translations of that entity type.
- Entity page:
entity
: Contains the object describing an entity (replacesarticle
orpage
).
- Direct templates:
direct
: Variable always equal to True when rendering a direct template.
- Tag, category, author pages:
entities
: Replacesarticles
.all_entitites
: Replacesall_articles
.
- Draft pages:
entity
: Replacesarticle
.all_entities
: Replacesall_articles
.
- Paginated pages (direct templates or tag, category, author pages):
entities_paginator
: Replacesarticles_paginator
.entities_page
: Replacesarticles_page
.entities_previous_page
: Replacesarticles_previous_page
.entities_next_page
: Replacesarticles_next_page
.
- Entity page:
category
: Access throughentity.category
.
- Direct templates:
dates
: If you want to iterate in the opposite order do it explicitly.
This is the configuration I'm using on my site:
ENTITY_TYPES = {
"Page": {
"PATHS": [""],
"EXCLUDES": ["blog", "projects"],
"PAGE_URL": "{slug}",
"PAGE_SAVE_AS": "{slug}/index.html",
"PATH_METADATA": r"(?P<slug>[^/]+)/.*",
"DIRECT_TEMPLATES": ["search"],
"SEARCH_SAVE_AS": "search/index.html"
},
"Article": {
"PATHS": ["blog"],
"ARTICLE_URL": "blog/{category}/{slug}/",
"ARTICLE_SAVE_AS": "blog/{category}/{slug}/index.html",
"PATH_METADATA": r".*/(?P<category>[^/]+)/(?P<date>\d{4}/\d{2}/\d{2})/(?P<slug>[^/]+)/.*",
"DIRECT_TEMPLATES": ["blog"],
"PAGINATED_TEMPLATES": {"blog": None, "blog_category": None},
"BLOG_SAVE_AS": "blog/index.html",
"CATEGORY_TEMPLATE": "blog_category",
"CATEGORY_URL": "blog/{slug}/",
"CATEGORY_SAVE_AS": os.path.join("blog", "{slug}", "index.html"),
"FEED_ATOM": os.path.join("blog", "feeds", "atom.xml"),
"CATEGORY_FEED_ATOM": os.path.join("blog", "feeds", "{slug}.atom.xml")
},
"Project": {
"PATHS": ["projects"],
"SORTER": entities.attribute_list_sorter(["date", "project_start"], reverse=True),
"PROJECT_URL": "projects/{category}/{slug}/",
"PROJECT_SAVE_AS": "projects/{category}/{slug}/index.html",
"PATH_METADATA": r".*/(?P<category>[^/]+)/(?P<slug>[^/]+)/.*",
"DIRECT_TEMPLATES": ["projects"],
"PAGINATED_TEMPLATES": {"projects": None, "project_category": None},
"PROJECTS_SAVE_AS": "projects/index.html",
"CATEGORY_TEMPLATE": "project_category",
"CATEGORY_URL": 'projects/{slug}/',
"CATEGORY_SAVE_AS": os.path.join('projects', '{slug}', 'index.html'),
"FEED_ATOM": os.path.join("projects", "feeds", "atom.xml"),
"CATEGORY_FEED_ATOM": os.path.join("projects", "feeds", "{slug}.atom.xml")
}
}
For a working example check my site and my site's source code.
entity_generator_init
: Initialization of the parent generator. This generator is responsible for creating the generators for each entity type.entity_generator_finalized
: End of context generation by the parent generator.entity_writer_finalized
: End of output generation by the parent generator.entity_subgenerator_*
: Signals for the generator of a particular entity type. These are the same signals used by the article generator.