""" collate_content.py ================== (c) 2014 - Edward Stronge Connects to the content generator finalized signal to combine articles and pages sharing a category into lists that will be available in the template context. Thanks to #pelican member @kura for suggestions on creating this plugin. """ from collections import defaultdict import functools import re from pelican import signals def group_content(generator, content_type): """ Assembles articles and pages into lists based on each article or page's content. These lists are available through the global context passed to the template engine. When multiple categories are present, splits category names based on commas and trims whitespace surrounding a category's name. Thus, commas may not appear within a category but they can be used to delimit categories and may be surrounded by arbitrary amounts of whitespace. For each category, substitutes '_' for all whitespace and '-' characters, then creates a list named `SUBSTITUTED_CATEGORY_NAME`_articles or `SUBSTITUTED_CATEGORY_NAME`_pages for Articles or Pages, respectively. Note that the *original* category name must appear in the `CATEGORIES_TO_COLLATE` when using this plugin with category filtering enabled. """ category_filter = generator.settings.get('CATEGORIES_TO_COLLATE', None) filtering_active = type(category_filter) in (list, tuple, set) collations = generator.context.get('collations', defaultdict(list)) for content in generator.context[content_type]: category_list = [c.strip() for c in content.category.name.split(',')] for category in category_list: if filtering_active and category not in category_filter: continue category = substitute_category_name(category) collations['%s_%s' % (category, content_type)].append(content) generator.context['collations'] = collations def substitute_category_name(category_name): """ Replaces whitespace and '-' characters in `category_name` to allow category_name to be made into a valid Python identifier. Doesn't check all possible ways a string might be invalid; the user of the collate_content module is advised to use categories with Python-friendly names. """ return re.sub(r'\s', '_', category_name).replace('-', '_').lower() ARTICLE_GROUPER = functools.partial(group_content, content_type='articles') PAGE_GROUPER = functools.partial(group_content, content_type='pages') def register(): """Register the new plugin""" signals.article_generator_finalized.connect(ARTICLE_GROUPER) signals.page_generator_finalized.connect(PAGE_GROUPER)