11

I kind of want a tag archive page where it doesn't just list all the tags and links to entries based on that tag, but where the sizes of the actual tag link vary based on frequency of use.

Any idea how?

2 Answers 2

15

Brandon commented on getting tag usage count (and how it can be expensive) in this Google+ post and again in this SE question where I was trying to think through a plugin.

So to completely steal from that, you could loop through your tags and get a count for each...

{% set tags = craft.tags.find() %}

{% for tag in tags %}
    {% set count = craft.entries.section('blog').relatedTo(tag).total() %}
    <a href="/entries/{{ tag.slug }}" data-count="{{ count }}">{{ tag.name }}</a>
{% endfor %}

Then manipulate the listing with JavaScript or find the max count and loop again to apply inline CSS percentages or font-sizes that are scaled accordingly. As Brandon noted in that post, be sure to wrap everything in {% cache %} tags since this will be an intense template to render.

Update:

Since this answer, Phil Birnie released a plugin for this he's linked to below, and I came up with my own that we trashed in a Straight Up Craft Hangout thanks to Marion's stellar idea of using a Preparse field to tally counts, which I've added here as an alternative answer.

12
  • Would it be less expensive if done via a plugin?
    – Natetronn
    Commented Jul 10, 2014 at 2:24
  • @Natetronn I guess it depends on the plugin itself, but probably. It'd be nice to get counts and limit to X most-used tags, for example. Off the top of my head, I'm not sure how I'd approach this.
    – Matt Stein
    Commented Jul 10, 2014 at 3:00
  • 3
    I may be able to pull a Low and answer with that plugin, but not in the immediate future.
    – Matt Stein
    Commented Jul 10, 2014 at 3:27
  • 2
    By all means, "pull a Low"! :)
    – Natetronn
    Commented Jul 10, 2014 at 16:59
  • 2
    Sorry for reposting - noticed I misspelled "popular" in the repo name and couldn't edit the comment - thanks @MattStein, I'll post to slack. github.com/philbirnie/CraftPopularTags Commented Oct 7, 2015 at 19:56
14

Marion Newlevant had a clever, efficient idea in this Straight Up Craft Hangout if you don't mind having a slight lag (like a day) for your tag counts to be up to date. That idea: store the counts you need in a Preparse field on each tag, and set up a cron job to re-save all tags periodically.

1. Set Up Preparse

Preparse is a free plugin from André Elvan that renders Twig code to a field when an entry is saved. Install it, add a Preparse field to your Tag elements (like tagCount) for example, and make the contents of said field {{ craft.entries.section('blog').relatedTo(tag).total }}, where blog is the section for which we're building the tag cloud. Be sure to set Column TypeNumber, since we're storing a count and we'll sort on it later in our template.

the settings for your Preparse field

When a Tag is saved, Craft will count the entries related to it and store the total in this new tagCount field. Now we just need to make sure tags are saved every now and then!

2. Set up a task for resaving elements.

Here we'll make a publicly-accessible PHP script that'll get an instance of Craft (which is easy) and tell it to resave our tags. In this case we'll save all tags, but you can limit the scope in the task settings if you need to.

In your /public folder, create a file called resave-tags.php and drop this in it:

<?php

namespace Craft;

$app = require("../craft/app/bootstrap.php");

$app->tasks->createTask('ResaveElements', 'Resaving tags!', array(
    'elementType' => 'Tag'
));

Note that you don't have to make this public, you can run it from a terminal, shell script, or any old way you'd normally interact with PHP.

Now you should be able to hit yourdomain.craft.dev/resave-tags.php and go confirm that Craft has updated your tagCount values. (You did already set up entries and tags, right?) Now we just need our reliable friend cron to trigger this for us periodically.

3. Tie cron to your task.

If you've never used cron, it's a very simple, powerful tool that lets you run commands at intervals, whether it's every second or every second Tuesday or every decade. The process for editing cron tasks depends on your hosting environment, but the vast majority give you some way to edit these tasks.

For this example, we'll hit our URL at midnight every day and ignore the output (because we're brave):

0 0 * * * /usr/bin/wget --spider \"http://foo.dev/resave-elements.php\" >/dev/null 2>&1

4. Write Your Template

Here we'll get our tags and order by tagCount starting with the greatest number. Using just a dash of math, we'll loop through entries and get a number we can use to size text—the biggest tags will be 4em and the smallest will be 1em, per minScale and maxScale:

{% set tags = craft.tags.order('tagCount desc').limit(999) %}

{% if tags | length %}
    {% set minScale = 1 %}
    {% set maxScale = 4 %}
    {% set biggestTagCount = (tags|first).tagCount %}
    {% set smallestTagCount = (tags|last).tagCount %}

    <ul class="cloud">
        {% for tag in tags %}
            {% set fontSize = ((tag.tagCount - smallestTagCount) / biggestTagCount) * (maxScale - minScale) + minScale  %}
            <li>
                <span style="font-size: {{ fontSize }}em;">
                    {{ tag.title }}
                </span>
            </li>
        {% endfor %}
    </ul>
{% endif %}

And that's one way to make a visually-weighted tag cloud.

2
  • Nice solution, thanks for the write up! There was an update to the Preparse plugin that allows to make it save to numeric db columns, do you don't need the type casting any longer! ;)
    – carlcs
    Commented Jun 12, 2016 at 3:25
  • I can't keep up around here, @carlcs! Thanks for mentioning it, I've just updated my answer.
    – Matt Stein
    Commented Jun 12, 2016 at 3:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.