How do I list a simple list of category and tag references?

Ok then I probably understood your requirements…

A note on the concept of taxonomy: The taxonomies listed in /user/config/site.yaml are not related. Tags cannot be assigned to categories. The list generated below shows which categories and which tags are assigned to the same page. The list is therefor only 2-levels deep, instead of the 3-levels in your sample.

Here is some rough code. It may (will) contain imperfections… And feedback is welcome.

Steps to create the plugin:

  • To install Devtools (if not already installed) , open a command prompt (terminal) and run the following command:
    $ bin/gpm install devtools
    
  • At the same command prompt run the following command to create a basic plugin skeleton:
    $ bin/plugin devtools newplugin
    
    The ‘wizard’ will ask you a few questions: plugin name, description, your name, GitHub ID (may be empty) and your email.
  • If you named your plugin ‘taxonomytree’, there will be a file named:
    /user/plugins/taxonomytree/taxonomytree.php.
  • In that file replace everything starting from line 33 down to and including line 62 (leave the last curly bracket in place) with the code below.
    public function onPluginsInitialized()
    {
        // Don't proceed if we are in the admin plugin
        if ($this->isAdmin()) {
            return;
        }
    
        // Enable the main event we are interested in
        $this->enable([
            'onPagesInitialized' => ['onPagesInitialized', 0],
            'onTwigSiteVariables' => ['onTwigSiteVariables', 0],
            'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0],
        ]);
    }
    
    public function onPagesInitialized(Event $e)
    {
        $cache = Grav::instance()['cache'];
        $taxonomiesUsed = Grav::instance()['taxonomy']->taxonomy();
        $hash = hash('md5', serialize($taxonomiesUsed));
    
        // If no categories/tags have been added/removed from pages we can reuse cache
        if ($this->taxonomyTree = $cache->fetch($hash) ?: []) {
            return;
        } else {
            // Get all pages in the site
            $pages = $e['pages'];
    
            // Loop through all pages
            foreach ($pages->all() as $page) {
                $taxonomy = $page->taxonomy();
                if (array_key_exists('category', $taxonomy)) {
                    if (is_array($taxonomy['category'])) {
                        foreach($taxonomy['category'] as $category) {
                            if (!array_key_exists($category, $this->taxonomyTree)) {
                                $this->taxonomyTree[$category] = [];
                            }
                            $this->addTags($taxonomy, $category);
                        }
                    } else {
                        $category = $taxonomy['category'];
                        if (!array_key_exists($category, $this->taxonomyTree)) {
                            $this->taxonomyTree[$category] = [];
                        }
                        $this->addTags($taxonomy, $category);
                    }
                }
            }
            // Store tree in cache for reuse
            $cache->save($hash, $this->taxonomyTree);
        }
    }
    
    protected function addTags($taxonomy, $category)
    {
        // If field taxonomy has a subfield 'tag', continue
        if (array_key_exists('tag', $taxonomy)) {
            if (is_array($taxonomy['tag'])) {
                foreach($taxonomy['tag'] as $tag) {
                    if (!array_key_exists($tag, $this->taxonomyTree[$category])) {
                        $this->taxonomyTree[$category][$tag] = $tag;
                    }
                }
            } else if (!array_key_exists($tag, $this->taxonomyTree[$category])) {
                $this->taxonomyTree[$category][$tag] = $tag;
            }
        }
    }
    
    public function onTwigSiteVariables(Event $e)
    {
        $this->grav['twig']->twig_vars['taxonomytree'] = $this->taxonomyTree;
    }
    
    public function onTwigTemplatePaths()
    {
        $this->grav['twig']->twig_paths[] = __DIR__ . '/templates';
    }
    
  • At line 13 add:
    private $taxonomyTree = [];
    
  • At line 4 add:
    use Grav\Common\Grav;
    
  • For the translation of the header displayed above the list, replace the content of file /user/plugins/taxonomytree/language.yaml with:
    en:
      SIDEBAR:
        TAXONOMYTREE:
            HEADLINE: Taxonomy Tree
    
  • Create file /user/plugins/taxonomytree/templates/partials/taxonomytree.html.twig and add the following content: (Adapt to your likings)
    <ul>
        {% for category in taxonomytree|keys %}
            <li><a href="{{ page.url }}/category:{{ category }}">{{ category }}</a>
                <ul>
                {% for tag in taxonomytree[category]|keys %}
                    <li><a href="{{page.url}}/category:{{ category }}/tag:{{ tag }}">{{ tag }}</a></li>
                {% endfor %}
                </ul>
            </li>
        {% endfor %}
    </ul>
    
  • The plugin should now be working.

The taxonomy tree will now be created and passed on to Twig as a variable called ‘taxonomytree’.

I have no experience nor any understanding of Gantry so I cannot help you there…
I hope that you, as a designer, know way better than me where to display the taxonomy tree.

  • In one of the templates you could add the following code:
    Some themes have a partials/sidebar.html.twig which would be a good choice. Again,adapt to your likings and context.
    {% if config.plugins.taxonomytree.enabled %}
    <div class="sidebar-content">
        <h4>{{ 'SIDEBAR.TAXONOMYTREE.HEADLINE'|t }}</h4>
        {% include 'partials/taxonomytree.html.twig' %}
    </div>
    {% endif %}
    
  • CSS styling of the nested list should not present you any issues I guess.
2 Likes