collate_content.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. """
  2. collate_content.py
  3. ==================
  4. (c) 2014 - Edward Stronge
  5. Connects to the content generator finalized signal to combine
  6. articles and pages sharing a category into lists that will be
  7. available in the template context.
  8. Thanks to #pelican member @kura for suggestions on creating this
  9. plugin.
  10. """
  11. from collections import defaultdict
  12. import functools
  13. import re
  14. from pelican import signals
  15. def group_content(generator, content_type):
  16. """
  17. Assembles articles and pages into lists based on each
  18. article or page's content. These lists are available
  19. through the global context passed to the template engine.
  20. When multiple categories are present, splits category names
  21. based on commas and trims whitespace surrounding a
  22. category's name. Thus, commas may not appear within a category
  23. but they can be used to delimit categories and may be surrounded by
  24. arbitrary amounts of whitespace.
  25. For each category, substitutes '_' for all whitespace and '-'
  26. characters, then creates a list named `SUBSTITUTED_CATEGORY_NAME`_articles
  27. or `SUBSTITUTED_CATEGORY_NAME`_pages for Articles or Pages,
  28. respectively.
  29. Note that the *original* category name must appear in the
  30. `CATEGORIES_TO_COLLATE` when using this plugin with category
  31. filtering enabled.
  32. """
  33. category_filter = generator.settings.get('CATEGORIES_TO_COLLATE', None)
  34. filtering_active = type(category_filter) in (list, tuple, set)
  35. collations = generator.context.get('collations', defaultdict(list))
  36. for content in generator.context[content_type]:
  37. category_list = [c.strip() for c in content.category.name.split(',')]
  38. for category in category_list:
  39. if filtering_active and category not in category_filter:
  40. continue
  41. category = substitute_category_name(category)
  42. collations['%s_%s' % (category, content_type)].append(content)
  43. generator.context['collations'] = collations
  44. def substitute_category_name(category_name):
  45. """
  46. Replaces whitespace and '-' characters in `category_name`
  47. to allow category_name to be made into a valid Python
  48. identifier.
  49. Doesn't check all possible ways a string might be invalid;
  50. the user of the collate_content module is advised to use
  51. categories with Python-friendly names.
  52. """
  53. return re.sub(r'\s', '_', category_name).replace('-', '_').lower()
  54. ARTICLE_GROUPER = functools.partial(group_content, content_type='articles')
  55. PAGE_GROUPER = functools.partial(group_content, content_type='pages')
  56. def register():
  57. """Register the new plugin"""
  58. signals.article_generator_finalized.connect(ARTICLE_GROUPER)
  59. signals.page_generator_finalized.connect(PAGE_GROUPER)