Repository: getpelican/pelican

Issue:
"Hidden" pages
I would like to use the same engine to be able to render my error pages (404, 50x, ect) but I don't want them to show on the menu with the rest of them.

Maybe there should be a way to mark certain pages for exclusion from being added to the pages variable seen by templates? I will poke around to see if there is a more optimal way of handling this.



Discussion:
You can set the PAGE_EXCLUDES parameter in your settings file. do PAGE_EXCLUDES=('404.html', '505.html',)..
I see this is undocumented so it's not your fault for not seeing this

This feature does not cover what I need. This feature takes a directory (I did extensive testing to figure this out) and excludes it from being built completely.

I want my 404.md and 50x.md files to be build as pages but not added to the menu even when `DISPLAY_PAGES_ON_MENU` is set.

Oh, so you mean like, add a metadata field like
:hidden: true
I think something similar is there already, at least with drafts. 

Exactly! `status: draft` only works for articles though; placing them in the drafts folder and removing them from any lists.
If the hidden or draft status worked for pages it would be perfect.

I am going to see if I can hack the feature in myself if there is no complaints!

I was about to implement that but I'll go to sleep instead, hack away :)

Basically, see how the :status: draft is used. you'll want to add a similar mechanism in PageGenerator. in generators.py
Make sure that status would get a default value if not specified. It should be almost 1:1 as in articles.

Good luck!


Resolving patch:
diff --git a/pelican/generators.py b/pelican/generators.py
--- a/pelican/generators.py
+++ b/pelican/generators.py
@@ -357,10 +357,13 @@ class PagesGenerator(Generator):
 
     def __init__(self, *args, **kwargs):
         self.pages = []
+        self.hidden_pages = []
+        self.hidden_translations = []
         super(PagesGenerator, self).__init__(*args, **kwargs)
 
     def generate_context(self):
         all_pages = []
+        hidden_pages = []
         for f in self.get_files(
                 os.path.join(self.path, self.settings['PAGE_DIR']),
                 exclude=self.settings['PAGE_EXCLUDES']):
@@ -373,15 +376,25 @@ def generate_context(self):
                         filename=f)
             if not is_valid_content(page, f):
                 continue
-            all_pages.append(page)
+            if page.status == "published":
+                all_pages.append(page)
+            elif page.status == "hidden":
+                hidden_pages.append(page)
+            else:
+                logger.warning(u"Unknown status %s for file %s, skipping it." %
+                               (repr(unicode.encode(page.status, 'utf-8')),
+                                repr(f)))
+
 
         self.pages, self.translations = process_translations(all_pages)
+        self.hidden_pages, self.hidden_translations = process_translations(hidden_pages)
 
         self._update_context(('pages', ))
         self.context['PAGES'] = self.pages
 
     def generate_output(self, writer):
-        for page in chain(self.translations, self.pages):
+        for page in chain(self.translations, self.pages,
+                            self.hidden_translations, self.hidden_pages):
             writer.write_file(page.save_as, self.get_template('page'),
                     self.context, page=page,
                     relative_urls=self.settings.get('RELATIVE_URLS'))


Test patch:
diff --git a/tests/TestPages/bad_page.rst b/tests/TestPages/bad_page.rst
new file mode 100644
--- /dev/null
+++ b/tests/TestPages/bad_page.rst
@@ -0,0 +1,8 @@
+This is a test bad page
+#######################
+
+:status: invalid
+
+The quick brown fox jumped over the lazy dog's back.
+
+The status here is invalid, the page should not render.
diff --git a/tests/TestPages/hidden_page.rst b/tests/TestPages/hidden_page.rst
new file mode 100644
--- /dev/null
+++ b/tests/TestPages/hidden_page.rst
@@ -0,0 +1,8 @@
+This is a test hidden page
+##########################
+
+:status: hidden
+
+The quick brown fox jumped over the lazy dog's back.
+
+This page is hidden
diff --git a/tests/TestPages/hidden_page_markdown.md b/tests/TestPages/hidden_page_markdown.md
new file mode 100644
--- /dev/null
+++ b/tests/TestPages/hidden_page_markdown.md
@@ -0,0 +1,12 @@
+title: This is a markdown test hidden page
+status: hidden
+
+Test Markdown File Header
+=========================
+
+Used for pelican test
+---------------------
+
+The quick brown fox jumped over the lazy dog's back.
+
+This page is hidden
diff --git a/tests/TestPages/page.rst b/tests/TestPages/page.rst
new file mode 100644
--- /dev/null
+++ b/tests/TestPages/page.rst
@@ -0,0 +1,4 @@
+This is a test page
+###################
+
+The quick brown fox jumped over the lazy dog's back.
diff --git a/tests/TestPages/page_markdown.md b/tests/TestPages/page_markdown.md
new file mode 100644
--- /dev/null
+++ b/tests/TestPages/page_markdown.md
@@ -0,0 +1,9 @@
+title: This is a markdown test page
+
+Test Markdown File Header
+=========================
+
+Used for pelican test
+---------------------
+
+The quick brown fox jumped over the lazy dog's back.
diff --git a/tests/test_generators.py b/tests/test_generators.py
--- a/tests/test_generators.py
+++ b/tests/test_generators.py
@@ -4,7 +4,7 @@
 import os
 import re
 
-from pelican.generators import ArticlesGenerator, LessCSSGenerator
+from pelican.generators import ArticlesGenerator, LessCSSGenerator, PagesGenerator
 from pelican.settings import _DEFAULT_CONFIG
 from .support import unittest, temporary_folder, skipIfNoExecutable
 
@@ -94,6 +94,48 @@ def test_direct_templates_save_as_false(self):
         write.assert_called_count == 0
 
 
+class TestPageGenerator(unittest.TestCase):
+    """
+    Every time you want to test for a new field;
+    Make sure the test pages in "TestPages" have all the fields
+    Add it to distilled in distill_pages_for_test
+    Then update the assertItemsEqual in test_generate_context to match expected
+    """
+
+    def distill_pages_for_test(self, pages):
+        distilled = []
+        for page in pages:
+           distilled.append([
+                    page.title,
+                    page.status
+                ]
+           )
+        return distilled
+
+    def test_generate_context(self):
+        settings = _DEFAULT_CONFIG.copy()
+
+        settings['PAGE_DIR'] = 'TestPages'
+        generator = PagesGenerator(settings.copy(), settings, CUR_DIR,
+                                      _DEFAULT_CONFIG['THEME'], None,
+                                      _DEFAULT_CONFIG['MARKUP'])
+        generator.generate_context()
+        pages = self.distill_pages_for_test(generator.pages)
+        hidden_pages = self.distill_pages_for_test(generator.hidden_pages)
+
+        pages_expected = [
+            [u'This is a test page', 'published'],
+            [u'This is a markdown test page', 'published']
+        ]
+        hidden_pages_expected = [
+            [u'This is a test hidden page', 'hidden'],
+            [u'This is a markdown test hidden page', 'hidden']
+        ]
+
+        self.assertItemsEqual(pages_expected,pages)
+        self.assertItemsEqual(hidden_pages_expected,hidden_pages)
+
+
 class TestLessCSSGenerator(unittest.TestCase):
 
     LESS_CONTENT = """