install page hierarchy plugin
authorM. Taylor Saotome-Westlake <ultimatelyuntruethought@gmail.com>
Thu, 22 Feb 2018 00:14:59 +0000 (16:14 -0800)
committerM. Taylor Saotome-Westlake <ultimatelyuntruethought@gmail.com>
Thu, 22 Feb 2018 00:14:59 +0000 (16:14 -0800)
pelicanconf.py
plugins/page_hierarchy.py [new file with mode: 0644]

index c35c598..7952a3f 100644 (file)
@@ -64,7 +64,7 @@ PAGINATION_PATTERNS = (
 THEME = 'theme'
 
 PLUGIN_PATHS = ["plugins"]
-PLUGINS = ["tag_cloud", "simple_footnotes"]
+PLUGINS = ["tag_cloud", "simple_footnotes", "page_hierarchy"]
 
 TAG_CLOUD_STEPS = 6
 TAG_CLOUD_SORTING = "alphabetically"
diff --git a/plugins/page_hierarchy.py b/plugins/page_hierarchy.py
new file mode 100644 (file)
index 0000000..95f06ff
--- /dev/null
@@ -0,0 +1,87 @@
+from pelican import signals, contents
+import os.path
+from copy import copy
+from itertools import chain
+
+# akhayyat/pelican-page-hierarchy@ad7c987914
+
+'''
+This plugin creates a URL hierarchy for pages that matches the
+directory hierarchy of their sources.
+'''
+
+class UnexpectedException(Exception): pass
+
+def get_path(page, settings):
+    ''' Return the dirname relative to PAGE_PATHS prefix. '''
+    path = os.path.split(page.get_relative_source_path())[0] + '/'
+    path = path.replace( os.path.sep, '/' )
+    # Try to lstrip the longest prefix first
+    for prefix in sorted(settings['PAGE_PATHS'], key=len, reverse=True):
+        if not prefix.endswith('/'): prefix += '/'
+        if path.startswith(prefix):
+            return path[len(prefix):-1]
+    raise UnexpectedException('Page outside of PAGE_PATHS ?!?')
+
+def in_default_lang(page):
+    # page.in_default_lang property is undocumented (=unstable) interface
+    return page.lang == page.settings['DEFAULT_LANG']
+
+def override_metadata(content_object):
+    if type(content_object) is not contents.Page:
+        return
+    page = content_object
+    path = get_path(page, page.settings)
+
+    def _override_value(page, key):
+        metadata = copy(page.metadata)
+        # We override the slug to include the path up to the filename
+        metadata['slug'] = os.path.join(path, page.slug)
+        # We have to account for non-default language and format either,
+        # e.g., PAGE_SAVE_AS or PAGE_LANG_SAVE_AS
+        infix = '' if in_default_lang(page) else 'LANG_'
+        return page.settings['PAGE_' + infix + key.upper()].format(**metadata)
+
+    for key in ('save_as', 'url'):
+        if not hasattr(page, 'override_' + key):
+            setattr(page, 'override_' + key, _override_value(page, key))
+
+def set_relationships(generator):
+    def _all_pages():
+        return chain(generator.pages, generator.translations)
+
+    # initialize parents and children lists
+    for page in _all_pages():
+        page.parent = None
+        page.parents = []
+        page.children = []
+
+    # set immediate parents and children
+    for page in _all_pages():
+        # Parent of /a/b/ is /a/, parent of /a/b.html is /a/
+        parent_url = os.path.dirname(page.url[:-1])
+        if parent_url: parent_url += '/'
+        for page2 in _all_pages():
+            if page2.url == parent_url and page2 != page:
+                page.parent = page2
+                page2.children.append(page)
+        # If no parent found, try the parent of the default language page
+        if not page.parent and not in_default_lang(page):
+            for page2 in generator.pages:
+                if (page.slug == page2.slug and
+                    os.path.dirname(page.source_path) ==
+                    os.path.dirname(page2.source_path)):
+                    # Only set the parent but not the children, obviously
+                    page.parent = page2.parent
+
+    # set all parents (ancestors)
+    for page in _all_pages():
+        p = page
+        while p.parent:
+            page.parents.insert(0, p.parent)
+            p = p.parent
+
+
+def register():
+    signals.content_object_init.connect(override_metadata)
+    signals.page_generator_finalized.connect(set_relationships)