Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I choose a category page to be the home page for a Pelican site?

I would like the visitors to my site to land on a category page, not on the default index.html. I want them to see the articles in the News categories before anything else.

Maybe is there a way to tell Pelican to output category/news to index.html? I know this would be possible with normal handwritten pages using the save_as field, but how can I do it with an automatic page generated by Pelican?

like image 550
CamilB Avatar asked Mar 26 '19 17:03

CamilB


1 Answers

Your homepage, the index.html file, is just another template from the DIRECT_TEMPLATES list. It'll depend on your theme exactly how it is generated, but you can always override specific templates locally, or you can create a new template for your homepage to replace it (and optionally redirect the original index.html generated page to a different location).

Either way, you can then generate a section that shows the articles from a single category. All template pages are given the same basic variables, which includes the articles list, as well as a categories list with (Category, list_of_articles) tuples.

The easiest way to get all articles for a single, specific category is to filter the articles list directly with the Jinja2 selectattr filter. selectattr('category', '==', categoryname) is matched both against the category name or the slug (whatever you set categoryname to is converted to a slug for you). So if your category is named News, then both 'News' or 'news' works:

<h2>News:</h2>
<ol id="posts-list" class="hfeed">
{% for article in articles | selectattr('category', '==', 'news') %}
    <li><article class="hentry">
        <header>
            <h1><a href="{{ SITEURL }}/{{ article.url }}" rel="bookmark"
                   title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h1>
        </header>

        <div class="entry-content">
        {% include 'article_infos.html' %}
        {{ article.summary }}
        <a class="readmore" href="{{ SITEURL }}/{{ article.url }}">read more</a>
        {% include 'comments.html' %}
        </div><!-- /.entry-content -->
    </article></li>
{% endfor %}
</ol>

The above reuses the simple theme article markup. You may want to limit the number of news articles; in that case use the batch(size) filter together with first:

<h2>News:</h2>

<ol id="posts-list" class="hfeed">
{% for article in articles | selectattr('category', '==', 'news') | batch(5) | first %}
    <!-- render article, etc. -->

The above takes the first 5 articles with News as the category.

Since the basic theme reuses the index.html template for all of the individual archive pages too (for each category, author or tag page), I'd not override the index direct template here. Instead, I'd create a new homepage template (in the pages directory) and write that to index.html and. You need to add the template in the TEMPLATE_PAGES dictionary, where your template pages should live in a separate directory that is configured not to be treated as articles or pages.

Create a new directory for template pages in your content directory; you'll need to make sure Pelican doesn't try to treat files there as articles, so add it to the ARTICLE_EXCLUDES list. So if all your Pelican your content lives in content/, and you have a file homepage.html in the directory output/templates/, you'd use:

ARTICLE_EXCLUDES = ['templates']
TEMPLATE_PAGES = {
    'templates/homepage.html': 'index.html',
}

This will overwrite the default index.html generated for articles, there is no need to remove anything from DIRECT_TEMPLATES but you could do so to avoid generating a file you never keep.

The homepage.html template can make full use of any existing templates in the theme, so you can just extend base.html that most themes will have defined:

{% extends "base.html" %}
{% block content %}
<section id="content">

<h2>Recent news:</h2>
<ol>
{% for article in articles | selectattr('category', 'equalto', 'news') | batch(5) | first %}

    <!-- markup for each news item -->

{% endfor %}
</ol>

</section><!-- /#content -->
{% endblock content %}

Instead of overwriting the default index, you can also set INDEX_SAVE_AS to direct the original index.html file elsewhere:

ARTICLE_EXCLUDES = ['templates']
TEMPLATE_PAGES = {
    'pages/homepage.html': 'index.html',
}
# move the original article index elsewhere:
INDEX_SAVE_AS = 'all_articles.html'

If you use a theme that doesn't reuse the index.html template for more pages or you want to try to make the template work for in those contexts anyway, then you can override the template used for index instead. To override the default index.html from your theme, create a local directory (overrides perhaps) to put your local version into, then add that directory to the THEME_TEMPLATES_OVERRIDES list in your configuration:

THEME_TEMPLATES_OVERRIDES = ['overrides']

Now when Pelican tries to load the index.html template to render the index direct template, it'll look for overrides/index.html first. So in overrides/ add your own index.html:

{% extends "base.html" %}
{% block content %}
<section id="content">

<!-- put your desired content here -->

</section><!-- /#content -->
{% endblock content %}

A word on pagination: all templates, except for the special per-archive-type pages (categories, authors, tags, periods), are paginated on the full articles list, this isn't something that is further configurable. This means you can't paginate a homepage on a single category of articles.

This means that if you override the index.html template and removed the full article listing, then you may want to remove index from the PAGINATED_TEMPLATES dictionary so it isn't re-generated multiple times to match your article list.

like image 190
Martijn Pieters Avatar answered Sep 21 '22 12:09

Martijn Pieters