Building Tag Lists by Category

I’m re-starting work on a plug-in to gather a list of all the tags used for each of the categories defined in my blog. The taxonomylist plug-in creates arrays of all the categories and all the tags, but not which goes with which.

rhukster suggested I start with the related pages plug-in, which I am.

Testing my understanding:

  • For each page load Grav runs through it’s lifecycle
  • I would want to attach my plug-in to the onPageInitialized event, as does the related pages plug-in
  • My plug-in would define its own variable in its declaration, perhaps protected $categories_tags = [];
  • I could check the cache to see if my variable needed to be updated with:
$cache_id = md5('categories_tags'.$page->path().$cache->getKey());
$this->categories_tags = $cache->fetch($cache_id);
  • If I needed to update, I could walk the $pages = $this->grav['pages']; variable and build my array
  • I send my variable over to Twig with $this->grav['twig']->twig_vars['categorie s_tags'] = $this->categories_tags;
  • And then my template can do what it wants with that array

Am I on the right track?

Sounds ok so far to me :slight_smile: Let me know when you have some initial code and i’ll take a look at that, just easier for my brain to grok actual code.

I think the best it’s add a twig function with params for filter by tag/category/etc. For now im busy with other projects, but if is userfully for some ppl i can pause other projects and develop this :slight_smile:

Here’s a snippet of the code I’m working on for this.

$cache_id = md5('categorymenu'.$page->path().$cache->getKey());
$this->categories_tags = $cache->fetch($cache_id);

if ($this->categories_tags === false) {
	// reset array
	$this->categories_tags = [];
	$debugger->addMessage("CategoryMenu Plugin cache miss. Rebuilding...");

	// Sort the resulting list
	asort($this->categories_tags, SORT_NUMERIC);
	$this->categories_tags = array_reverse($this->categories_tags);
	$this->categories_tags = ['testfiller'];
	$cache->save($cache_id, $this->categories_tags);
} else {
	$debugger->addMessage("CategoryMenu Plugin cache hit.");

It does not seem to be caching the testing array of category_tags because each time through the loop $this->categories_tags = $cache->fetch($cache_id); returns false.

So I’ve messed something up, or misunderstand something else. But what?

asort do not need because if you have a empty array what you need to sorting? :stuck_out_tongue:
another, the filler, i think the categories_tags have page object, not have sense save in cache only the tagname, try remove this and add pages with category tag and try again :slight_smile:

OK, finally a little code to show:

public function onPageInitialized()
		/** @var Cache $cache */
		$cache = $this->grav['cache'];
		/** @var Pages $pages */
		$pages = $this->grav['pages'];
		/** @var Page $page */
		$page = $this->grav['page'];
		/** @var Debugger $debugger */
		$debugger = $this->grav['debugger'];

		$this->enable(['onTwigSiteVariables' => ['onTwigSiteVariables', 0]]);
		$cache_id = md5('categorymenu' . $page->path() . $cache->getKey());
		$this->categories_tags = $cache->fetch($cache_id);

		if ($this->categories_tags === false) {
			// the array was not in the cache, so reset and rebuild it. 
			$this->categories_tags = array();
			$debugger->addMessage("CategoryMenu Plugin cache miss. Rebuilding...");

			// get all the pages in the blog
			$blogPages = $page->find('/blog')->children();

			if (!empty($blogPages)) {
				foreach ($blogPages as $blogPage) {
					$thisTaxonomy = $blogPage->taxonomy();

					if (!empty($thisTaxonomy['category'])) {
						foreach ($thisTaxonomy['category'] as $key => $value) {
							if (!array_key_exists($value, $this->categories_tags)) {
								$this->categories_tags[$value] = array();
							if (!empty($thisTaxonomy['tag'])) {
								foreach ($thisTaxonomy['tag'] as $key2 => $value2) {
									if (!in_array($value2, $this->categories_tags[$value])) {
										$this->categories_tags[$value][] = $value2;

			// Sort the tag lists for each category
			if (!empty($this->categories_tags)) {
				foreach ($this->categories_tags as $key => $value) {
					$theCategories[] = $key;

			if (!empty($theCategories)) {
				foreach ($theCategories as $key => $value) {

			$cache->save($cache_id, $this->categories_tags);
		} else {
			$debugger->addMessage("CategoryMenu Plugin cache hit.");

This seems to be doing what I want, except that $this->categories_tags is seemingly never cached. I never get a cache hit after reloading a page several times.

What didn’t get coded right?

It looks ok at first glance to me Bob. Did you ensure that you are getting to the $cache->save() call?

Hi Bob,

I follow your conversation a while, but I had no time to answer… However I copied your code and tested it. It works fine. On the first request of page the message “CategoryMenu Plugin cache miss. Rebuilding…” comes up and after reloading “CategoryMenu Plugin cache hit.” . Since your code is working, you have a problem with your cache. Have you enabled the cache i.e. set

  enabled: true

in your user/config/system.yaml? Maybe you have to play around with the driver or method, too. After that it is probably a good idea to clear the cache (using GPM or manually delete all contents in the cache folder).

By the way, here is an example output of your code:

array:1 [
  "blog" => array:8 [
    0 => "architecture"
    3 => "birds"
    5 => "city"
    4 => "journal"
    6 => "night"
    2 => "ocean"
    1 => "photography"
    7 => "travel"

Dang! I’ll bet that’s it. I routinely disable the cache on my development machine. Some days I am not so smart. :frowning:

Your welcome :smiley: