From d8bc5c4cf011e80bd5a7784a227c10eb223c98b5 Mon Sep 17 00:00:00 2001 From: Leonardo Giordani Date: Sun, 31 Mar 2024 19:10:28 +0100 Subject: [PATCH 1/2] Added series for pages --- README.md | 19 ++++++-- pelican/plugins/series/series.py | 80 ++++++++++++++++++++++---------- pyproject.toml | 2 +- 3 files changed, 71 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index acefeb4..33136c3 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,21 @@ Or, for Markdown-formatted content: Series: NAME_OF_THIS_SERIES -The plugin collects all articles belonging to the same series and provides series-related variables that you can use in your template. +The plugin collects all articles or pages belonging to the same series and provides series-related variables that you can use in your template. + +Articles and pages +------------------ + +This plugin works both with articles and pages. As Pelican uses the specific variable `article` for article templates and `page` for page templates it is complicated to give examples that work for both cases. In the following documentation all example will mention `article.` (e.g. `article.series`, `article.title`) but the code works in the same way with `page` (e.g. `page.series`, `page.title`). + +Article series and page series are created separately, so even if an article and a page have the same series they won't appear together. Indexing -------- -By default, articles in a series are ordered by date and then automatically numbered. +By default, articles in a series are ordered by date and then automatically numbered. Pages in a series are ordered by title and automatically numbered. -If you want to force a given order, specify `:series_index:` (reST) or `series_index:` (Markdown) in the article metadata, starting from 1. All articles with this enforced index are put at the beginning of the series and ordered according to the index itself. All the remaining articles come after them, ordered by date. +If you want to force a given order, specify `:series_index:` (reST) or `series_index:` (Markdown) in the article metadata, starting from 1. All articles with this enforced index are put at the beginning of the series and ordered according to the index itself. All the remaining articles come after them, ordered with the default ordering (date for articles and title for pages). The plugin provides the following variables to your templates: @@ -64,7 +71,9 @@ For example: Global Context -------------- -The plugin also adds the key `series` to the global context, which is a dictionary of all series names (as keys) and articles (as values). You can use that to list all the series of articles in your site, for example +**Warning**: in version 3 the global key `series` has been renamed to `article_series` to differentiate it from the new global key `page_series`. + +The plugin also adds the keys `article_series` and `page_series` to the global context. They are dictionaries of all series names (as keys) and items (as values). You can use that to list all the series in your site, for example ```html+jinja {% for series_name, series_articles in series.items() %} @@ -83,6 +92,8 @@ The plugin also adds the key `series` to the global context, which is a dictiona {% endfor %} ``` +As it is not possible to create pages from plugins you can leverage it to create a page for a specific series, even though you have to hard code the name of the series in the template. + Contributing ------------ diff --git a/pelican/plugins/series/series.py b/pelican/plugins/series/series.py index f5c2323..421c21b 100644 --- a/pelican/plugins/series/series.py +++ b/pelican/plugins/series/series.py @@ -15,6 +15,39 @@ from pelican import signals ordered_articles_all = {} +ordered_pages_all = {} + + +def generate_serie(series_name, series_items, sort_key): + forced_order_items = [i for i in series_items if i["index"] != 0] + forced_order_items.sort(key=itemgetter("index")) + + custom_order_items = [i for i in series_items if i["index"] == 0] + custom_order_items.sort(key=itemgetter(sort_key)) + + all_items = forced_order_items + custom_order_items + ordered_items = [i["content"] for i in all_items] + + for index, page in enumerate(ordered_items): + page.series = { + "name": series_name, + "index": index + 1, + "all": ordered_items, + "all_previous": ordered_items[0:index], + "all_next": ordered_items[index + 1 :], + } + + if index > 0: + page.series["previous"] = ordered_items[index - 1] + else: + page.series["previous"] = None + + try: + page.series["next"] = ordered_items[index + 1] + except IndexError: + page.series["next"] = None + + return ordered_items def aggregate_series(generator): @@ -35,44 +68,41 @@ def aggregate_series(generator): series[article.metadata["series"]].append(article_entry) - for series_name, series_articles in series.items(): - forced_order_articles = [i for i in series_articles if i["index"] != 0] - forced_order_articles.sort(key=itemgetter("index")) + for series_name, series_items in series.items(): + ordered_items = generate_serie(series_name, series_items, "date") + + generator.context["series"][series_name] = ordered_items + ordered_articles_all[series_name] = ordered_items - date_order_articles = [i for i in series_articles if i["index"] == 0] - date_order_articles.sort(key=itemgetter("date")) - all_articles = forced_order_articles + date_order_articles - ordered_articles = [i["content"] for i in all_articles] +def aggregate_series_pages(generator): + generator.context["series"] = {} + + series = defaultdict(list) - for index, article in enumerate(ordered_articles): - article.series = { - "name": series_name, - "index": index + 1, - "all": ordered_articles, - "all_previous": ordered_articles[0:index], - "all_next": ordered_articles[index + 1 :], + for page in generator.pages: + if "series" in page.metadata: + page_entry = { + "index": int(page.metadata.get("series_index", 0)), + "content": page, } - if index > 0: - article.series["previous"] = ordered_articles[index - 1] - else: - article.series["previous"] = None + series[page.metadata["series"]].append(page_entry) - try: - article.series["next"] = ordered_articles[index + 1] - except IndexError: - article.series["next"] = None + for series_name, series_items in series.items(): + ordered_items = generate_serie(series_name, series_items, "title") - generator.context["series"][series_name] = ordered_articles - ordered_articles_all[series_name] = ordered_articles + generator.context["series"][series_name] = ordered_items + ordered_pages_all[series_name] = ordered_items def onGeneratorsFinalized(generators): for generator in generators: - generator.context["series"] = ordered_articles_all + generator.context["article_series"] = ordered_articles_all + generator.context["page_series"] = ordered_pages_all def register(): signals.article_generator_finalized.connect(aggregate_series) + signals.page_generator_finalized.connect(aggregate_series_pages) signals.all_generators_finalized.connect(onGeneratorsFinalized) diff --git a/pyproject.toml b/pyproject.toml index 7f36079..157b622 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pelican-series" -version = "2.1.0" +version = "3.0.0" description = "Series is a Pelican plugin that joins multiple posts into a series" authors = ["Leonardo Giordani ", "Justin Mayer "] license = "AGPL-3.0" From a4b5e1bb91bbce2c33a2a183a751ce166065d9c3 Mon Sep 17 00:00:00 2001 From: Leonardo Giordani Date: Sun, 31 Mar 2024 19:20:58 +0100 Subject: [PATCH 2/2] Prepare release using autopub --- RELEASE.md | 7 +++++++ pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..4c8a0c6 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,7 @@ +Release type: major + +Add series metadata to pages. + +Change `series` global context variable to `article_series`. + +Improve documentation. diff --git a/pyproject.toml b/pyproject.toml index 157b622..7f36079 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pelican-series" -version = "3.0.0" +version = "2.1.0" description = "Series is a Pelican plugin that joins multiple posts into a series" authors = ["Leonardo Giordani ", "Justin Mayer "] license = "AGPL-3.0"