diff --git a/docs/settings.rst b/docs/settings.rst index c1b3e305..761b51d8 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -178,6 +178,27 @@ Example usage: This would save your articles in something like ``/posts/2011/Aug/07/sample-post/index.html``, and the URL to this would be ``/posts/2011/Aug/07/sample-post/``. +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'`` +* MONTH_ARCHIVE_SAVE_AS = ``'posts/{date:%Y}/{date:%b}/index.html'`` + +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'. + +.. 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. + ==================================================== ===================================================== Setting name (default value) What does it do? ==================================================== ===================================================== @@ -204,6 +225,12 @@ Setting name (default value) What does it do? `_SAVE_AS` The location to save content generated from direct templates. Where is the upper case template name. +`YEAR_ARCHIVE_SAVE_AS` (False) The location to save per-year archives of your + posts. +`MONTH_ARCHIVE_SAVE_AS` (False) The location to save per-month archives of your + posts. +`DAY_ARCHIVE_SAVE_AS` (False) The location to save per-day archives of your + posts. ==================================================== ===================================================== .. note:: diff --git a/docs/themes.rst b/docs/themes.rst index aba1ed4b..1e003967 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -17,16 +17,17 @@ To make your own theme, you must follow the following structure:: │   ├── css │   └── images └── templates - ├── archives.html // to display archives - ├── article.html // processed for each article - ├── author.html // processed for each author - ├── authors.html // must list all the authors - ├── categories.html // must list all the categories - ├── category.html // processed for each category - ├── index.html // the index. List all the articles - ├── page.html // processed for each page - ├── tag.html // processed for each tag - └── tags.html // must list all the tags. Can be a tag cloud. + ├── archives.html // to display archives + ├── period_archives.html // to display time-period archives + ├── article.html // processed for each article + ├── author.html // processed for each author + ├── authors.html // must list all the authors + ├── categories.html // must list all the categories + ├── category.html // processed for each category + ├── index.html // the index. List all the articles + ├── page.html // processed for each page + ├── tag.html // processed for each tag + └── tags.html // must list all the tags. Can be a tag cloud. * `static` contains all the static assets, which will be copied to the output `theme` folder. I've put the CSS and image folders here, but they are diff --git a/pelican/generators.py b/pelican/generators.py index c56366b3..d4b2e231 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -11,7 +11,7 @@ import shutil from codecs import open from collections import defaultdict from functools import partial -from itertools import chain +from itertools import chain, groupby from operator import attrgetter, itemgetter from jinja2 import ( @@ -257,6 +257,46 @@ class ArticlesGenerator(Generator): write(article.save_as, self.get_template(article.template), self.context, article=article, category=article.category) + def generate_period_archives(self, write): + """Generate per-year, per-month, and per-day archives.""" + try: + template = self.get_template('period_archives') + except Exception: + template = self.get_template('archives') + + def _generate_period_archives(dates, key, save_as_fmt): + """Generate period archives from `dates`, grouped by + `key` and written to `save_as`. + """ + # `dates` is already sorted by date + for _period, group in groupby(dates, key=key): + archive = list(group) + # arbitrarily grab the first date so that the usual + # format string syntax can be used for specifying the + # period archive dates + date = archive[0].date + save_as = save_as_fmt.format(date=date) + write(save_as, template, self.context, + dates=archive, blog=True) + + period_save_as = { + 'year' : self.settings.get('YEAR_ARCHIVE_SAVE_AS'), + 'month': self.settings.get('MONTH_ARCHIVE_SAVE_AS'), + 'day' : self.settings.get('DAY_ARCHIVE_SAVE_AS') + } + + period_date_key = { + 'year' : attrgetter('date.year'), + 'month': attrgetter('date.year', 'date.month'), + 'day' : attrgetter('date.year', 'date.month', 'date.day') + } + + for period in 'year', 'month', 'day': + save_as = period_save_as[period] + if save_as: + key = period_date_key[period] + _generate_period_archives(self.dates, key, save_as) + def generate_direct_templates(self, write): """Generate direct templates pages""" PAGINATED_TEMPLATES = self.settings.get('PAGINATED_DIRECT_TEMPLATES') @@ -320,6 +360,7 @@ class ArticlesGenerator(Generator): # to minimize the number of relative path stuff modification # in writer, articles pass first self.generate_articles(write) + self.generate_period_archives(write) self.generate_direct_templates(write) # and subfolders after that diff --git a/pelican/settings.py b/pelican/settings.py index 46901ffb..d8981a0f 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -60,6 +60,9 @@ _DEFAULT_CONFIG = {'PATH': '.', 'TAG_SAVE_AS': 'tag/{slug}.html', 'AUTHOR_URL': 'author/{slug}.html', 'AUTHOR_SAVE_AS': 'author/{slug}.html', + 'YEAR_ARCHIVE_SAVE_AS': False, + 'MONTH_ARCHIVE_SAVE_AS': False, + 'DAY_ARCHIVE_SAVE_AS': False, 'RELATIVE_URLS': True, 'DEFAULT_LANG': 'en', 'TAG_CLOUD_STEPS': 4,