Solutions Cookbook

This page provides recipes and solutions for common tasks that arise when using Pico.


Navigation Tree

How to create a navigation tree for pages?

Pico Plugin
class PicoPageTreePlugin extends AbstractPicoPlugin
{
    protected $pageTree = array();

    public function onPagesLoaded(
        array &$pages,
        array &$currentPage = null,
        array &$previousPage = null,
        array &$nextPage = null
    ) {
        foreach ($pages as &$page) {
            $id = (substr($page['id'], -6) === '/index') ? substr($page['id'], 0, -6) : $page['id'];
            $parent = (($pos = strrpos($id, '/')) !== false) ? $parent = substr($id, 0, $pos) : '';

            $this->pageTree[$parent][$page['id']] = &$page;
        }
    }

    public function onPageRendering(Twig_Environment &$twig, array &$twigVariables, &$templateName)
    {
        $twigVariables['pageTree'] = $this->pageTree;
    }
}
    
Twig
{% macro rnav(tree, parent = "") %}
    {% import _self as macros %}
    {% if tree[parent] %}
        <ul>
            {% for page in tree[parent] %}
                <li>
                    <a href="{{ page.url }}">{{ page.title }}</a>

                    {% set sub = page.id|slice(-6) == "/index" ? page.id|slice(0, -6) : page.id %}
                    {{ macros.rnav(tree, sub) }}
                </li>
            {% endfor %}
        </ul>
    {% endif %}
{% endmacro %}

<nav id="nav">
    {% import _self as macros %}
    {{ macros.rnav(pageTree) }}
</nav>
    

One-level navigation

How to show only pages of the first level (i.e. page.md and sub/index.md, not sub/page.md) on the navigation?

Template snippet
<ul>
    {% for page in pages if page.title %}
        {% set pageDepth = page.id|split('/')|length %}
        {% if (pageDepth == 2) and (page.id ends with "/index") or (pageDepth == 1) %}
            <li>
                <a href="{{ page.url }}">{{ page.title }}</a>
            </li>
        {% endif %}
    {% endfor %}
</ul>

Pluralize filter

How can I easily pluralize a string?

Twig macro
{% macro pluralize(number, singular, plural) %}
    {{ number }} {% if number == 1 %}{{ singular }}{% else %}{{ plural }}{% endif %}
{% endmacro %}
    
Usage
{% import _self as util %}
{{ util.pluralize(pages|length, "page", "pages") }}
    

Recursive table of contents

How can I realize a arbitrary deep TOC?

Twig Macro
{% macro rnav(toc) %}
    {% import _self as macros %}
    <ul>
        {% for sectionKey, section in toc %}
            {% if section._title %}
                <li>
                    <a href="#{{ sectionKey }}">{{ section._title }}</a>
                    {{ macros.rnav(section) }}
                </li>
            {% elseif sectionKey != "_title" %}
                <li>
                    <a href="#{{ sectionKey }}">{{ section }}</a>
                </li>
            {% endif %}
        {% endfor %}
    </ul>
{% endmacro %}
    
Usage
{% import _self as macros %}
{% if meta.toc %}
    {{ macros.rnav(meta.toc) }}
{% endif %}
    

RSS Feed Generation

By using the following code in a separate feed.twig template (in your theme folder), you can automatically generate an RSS feed from your Pico pages.

Simply create a “feed.md” file in your content folder with the header “Template: feed”, and anyone who visits “/feed” on your site will recieve an RSS feed instead of a regular page.

Code
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  {% set RFC822 = "D, d M Y H:i:s O" %}
  <channel>
    <title>{{ site_title | e }}</title>
    <description>{{ pages.index.meta.description | e }}</description>
    <link>{{ base_url }}/</link>
    <atom:link href="{{ base_url ~ "/feed" }}" rel="self" type="application/rss+xml"/>
    <pubDate>{{ "now" | date(RFC822) }}</pubDate>
    <lastBuildDate>{{ "now" | date(RFC822) }}</lastBuildDate>
    <generator>Pico</generator>
    {% for page in pages if page.id not in ['index','feed'] and not end %}
      <item>
        <title>{{ page.title | e }}</title>
        <description>{{ page.id | content | e }}</description>
        <pubDate>{{ page.date | date(RFC822) }}</pubDate>
        <link>{{ page.url }}</link>
        <guid isPermaLink="true">{{ page.url }}</guid>
        {% for cat in page.meta.categories %}
          <category>{{ cat | e }}</category>
        {% endfor %}
      </item>
      {% if loop.index == 10 %}{% set end = true %}{% endif %}
    {% endfor %}
  </channel>
</rss>

Table of contents

How to generate TOCs very easy?

YAML header
---
toc:
    item-on-level-1:
        _title: Item on Level 1
        item-on-level-2a: Item on Level 2 (a)
        item-on-level-2b: Item on Level 2 (b)
    another-level-1-item: Another Item on Level 1
---
    
Template snippet
<ul>
    {% for sectionKey, section in meta.toc %}
        <li>
            {% if section._title %}
                <a href="#{{ sectionKey }}">{{ section._title }}</a>
                <ul>
                    {% for subSectionKey, subSection in section if subSectionKey != "_title" %}
                        <li><a href="#{{ subSectionKey }}">{{ subSection }}</a></li>
                    {% endfor %}
                </ul>
            {% else %}
                <a href="#{{ sectionKey }}">{{ section }}</a>
            {% endif %}
        </li>
    {% endfor %}
</ul>
    
GitHub Pages - This page was generated from 9164cea2f254e611a1de2311775f6d0ee370c838 at 2022-08-10 21:26:48 +0000

Pico was made by Gilbert Pellegrom and is maintained by The Pico Community. Released under the MIT license.