<p>This is based on Matt's answer to your <a href="https://craftcms.stackexchange.com/q/881/125">previous question</a>. Likewise this should better be used within <code>cache</code> tags!</p>

<p>This is untested, but it hopefully works out for you.</p>

<p>.</p>

<p><em>Edit:</em></p>

<p>This is still untested but it <a href="https://craftcms.stackexchange.com/q/1514/125">came to my ears</a>, that it could make problems to assign variables as array keys. That's why I changed the code to use objects instead. If anyone <em>uses</em> this code, I'd be happy to hear if it does actually work!</p>

<pre class="lang-twig prettyprint-override"><code>{# Get all tags #}
{% set allTags = craft.tags.find() %}

{# Define object outside the for loop #}
{% set weightedTags = [] %}

{# Iterate over all tags #}
{% for tag in allTags %}

    {# Get total number of tag occurrences in entries belonging to 'blog' section #}
    {% set count = craft.entries.section('blog').relatedTo(tag).total() %}

    {# Save tag id and count to our weightedTags object #}
    {% set weightedTags = weightedTags|merge([{ tagId: tag.id, tagCount: count }]) %}

{% endfor %}

{# Sort, reverse-sort and pick top 10 elements of the array #}
{% set weightedTags = weightedTags|sort|reverse|slice(0, 10) %}

{# To print the top 10 list iterate over our weightedTags array #}
{% for tagObject in weightedTags %}

    {# Get tag object for each tagId #}
    {% set tagEntry = craft.tags.id(tagObject.tagId).first() %}

    {# Return the list item #}
    &lt;a href="/entries/{{ tagEntry.slug }}" data-count="{{ tagObject.tagCount }}"&gt;{{ tagEntry.name }}&lt;/a&gt;

{% endfor %}
</code></pre>

CC BY-SA 4.0
2018-05-15T06:55:01.127Z
This seems to work if you set tagCount as first param in your weightedTags.
Jan_dh
CC BY-SA 3.0
2014-07-14T23:14:34.503Z
2016-05-19T10:57:22.957Z
2017-04-13T12:51:00.160Z
carlcs
<p>Have had success using this plugin: <a href="https://github.com/philbirnie/CraftPopularTags" rel="nofollow noreferrer">https://github.com/philbirnie/CraftPopularTags</a></p>

CC BY-SA 3.0
2017-06-17T03:41:14.947Z
2017-06-17T03:41:14.947Z
PhilR
<p>I couldn't quite get Carls answer to work (the "weightedTags"-array wasn't properly sorted), so I went and wrote a quick variable and service for achieving what I was after.</p>

<p>First off, the super-simple variable:</p>

<pre><code>public function getPopularTags($limit = NULL, $tagGroup = 'tags') {
    return craft()-&gt;PLUGIN_SERVICENAME-&gt;getPopularTags($limit, $tagGroup);
}
</code></pre>

<p>Simply replace "PLUGIN_SERVICENAME" with whatever your plugin and service is called, per example "myPlugin_tagFinder"</p>

<p>And the service is almost as simple:</p>

<pre><code>namespace Craft;
class PLUGIN_SERVICENAMEService extends BaseApplicationComponent
{
  public function getPopularTags($limit, $tagGroup = 'tags')
  {
    $sql = craft()-&gt;db-&gt;createCommand();
    $sql-&gt;select('tags.*, i18n.slug');
    $sql-&gt;from(['taggroups tagGroups', 'tags tags', 'relations relations', 'elements elements', 'elements_i18n i18n']);
    $sql-&gt;where(['AND',
                 "tagGroups.handle = '$tagGroup'",
                 'tags.groupId = tagGroups.id',
                 'relations.targetId = tags.id',
                 'elements.id = relations.sourceId',
                 "elements.enabled = '1'",
                 'i18n.elementId = tags.id']);
    $sql-&gt;group('relations.targetId');
    $sql-&gt;order('COUNT(elements.id) DESC');
    if (!is_null($limit) &amp;&amp; is_numeric($limit)) {
      $sql-&gt;limit($limit);
    }

    return TagModel::populateModels($sql-&gt;queryAll());
  }
}
</code></pre>

<p>Again, replace "PLUGIN_SERVICENAME" with whatever your plugin and service is called, per example "MyPlugin_tagFinderService"</p>

<p>Once that is done (caveat: And your plugin is, naturally, installed/activated) you can get the tags you require from your template simply by calling:</p>

<pre><code>{%set tags = craft.myPlugin.getPopularTags() %}
</code></pre>

<p>From there on you'll loop through them just as if you fetched them through the <code>craft.tags.find()</code>-methodology.</p>

CC BY-SA 3.0
2017-05-29T13:56:29.030Z
Caveats: The method above flat out ignores which field the relation is built through, and also does not bother to look at locales. If you need to customize it to take either into account, feel free to do so or even to poke me for assistance.
Fuglsetrampen
CC BY-SA 3.0
2017-05-29T14:27:23.203Z
This is a much better answer!
carlcs
CC BY-SA 3.0
2017-05-29T13:51:13.847Z
2017-06-16T07:45:10.207Z
2017-06-16T07:45:10.207Z
Fuglsetrampen
<p>I was working the last days on this query for craft 3.</p>
<p>I want to share it with u.</p>
<p>With this query u get the most used tags connected to other elements (wich are not revisions or drafts).</p>
<p>U also get the actual count of usages for every tag.</p>
<p>Hope it helps the next one.</p>
<pre><code>   $query = (new Query())
        -&gt;select([
            '{{relations}}.targetId as id',
            'COUNT({{relations.targetId}}) as count',
            '{{content}}.title as title'
        ])
        -&gt;from('relations')
        -&gt;leftJoin('tags', '{{relations}}.targetId={{tags}}.id')
        -&gt;leftJoin('content', '{{content}}.elementId={{tags}}.id')
        -&gt;leftJoin('elements', '{{elements}}.id={{tags}}.id')
        -&gt;leftJoin('elements source', '{{source}}.id={{relations}}.sourceId')
        -&gt;where([
            '{{elements}}.enabled' =&gt; 1,
            '{{source}}.enabled' =&gt; 1,
            '{{source}}.revisionId' =&gt; NULL,
            '{{source}}.draftId' =&gt; NULL,
        ])
        -&gt;groupBy('id, title')
        -&gt;orderBy( 'count DESC, title ASC')
    ;

    $query-&gt;limit($limit);

    if (is_numeric($limit) &amp;&amp; !is_null($limit)) {
        $query-&gt;limit($limit);
    }

    $results = $query-&gt;all();

    foreach ($results as $key =&gt; $value) {
        $id = $value['id'];
        $results[$key] = Tag::find()-&gt;id($id)-&gt;one();
    }

    return $results;
</code></pre>

CC BY-SA 4.0
2020-08-23T10:18:57.857Z
2020-08-23T10:18:57.857Z
Slowwie
<p>Also needed this one, but the example from carlcs resulted in a timeout in my browser due to the large dataset (20.000 entries, 10.000 tags). I got it fixed by using a custom query, which returned the top 10 list in 3-4 seconds;</p>
<pre><code>{% set query = craft.query()
        .select([
                'relations.targetId as id',
                'COUNT(relations.targetId) as count',
                'content.title as title'
        ])
        .from('relations')
        .leftJoin('tags', 'relations.targetId=tags.id')
        .leftJoin('content', 'content.elementId=tags.id')
        .leftJoin('elements', 'elements.id=tags.id')
        .leftJoin('elements source', 'source.id=relations.sourceId')
        .where({
                'elements.enabled': 1,
                'source.enabled': 1,
                'source.revisionId': null,
                'source.draftId': null
        })
        .groupBy('id, title')
        .orderBy('count DESC, title ASC')
        .limit(10) %}

{% set results = query.all() %}

{% for result in results %}
    {% set id = result['id'] %}
    {% set title = result['title'] %}
    {% set count = result['count'] %}
{% endfor %}

</code></pre>

CC BY-SA 4.0
2024-03-02T10:02:50.477Z
2024-03-02T10:02:50.477Z
Arjan
<p>I would like to have a Top 10 Tags list in descending order. I'm able to list and limit 10 tags used, but the order parameters are limited to name, group, and date essentially.</p>

CC BY-SA 3.0
2014-07-14T22:33:28.117Z
just as an FYI, I did set a count but trying order(count desc) doesn't do a thing. :P Because I don't think that's "allowed"?
lealea
CC BY-SA 3.0
2014-07-14T23:02:25.370Z
`count` isn't a property of [craft.tags](http://buildwithcraft.com/docs/templating/craft.tags). I'm [working on it](http://craftcms.stackexchange.com/questions/1091/how-can-i-best-extend-tagmodel-to-add-a-count-property) though, after [your last question about tag clouds](http://craftcms.stackexchange.com/questions/881/how-can-i-create-a-visually-weighted-tag-cloud)!
Matt Stein
CC BY-SA 3.0
2014-07-14T23:29:42.880Z
If you aren't in a hurry lea, you better wait for @matt's plugin. You can do lots of things with twig, but it's a template language and such thing like my code below are actually considered bad practice!
carlcs
<tags><ordering>
Order tags by count - e.g. Top 10 Tags Used
# Order tags by count - e.g. Top 10 Tags Used

(Asked by: username_0 on 2014-07-14)

I would like to have a Top 10 Tags list in descending order. I'm able to list and limit 10 tags used, but the order parameters are limited to name, group, and date essentially.

**Tags:** tags, ordering

> **Comments:**
> **username_0**: just as an FYI, I did set a count but trying order(count desc) doesn't do a thing. :P Because I don't think that's "allowed"?  
> **username_1**: `count` isn't a property of [craft.tags](http://buildwithcraft.com/docs/templating/craft.tags). I'm [working on it](http://craftcms.stackexchange.com/questions/1091/how-can-i-best-extend-tagmodel-to-add-a-count-property) though, after [your last question about tag clouds](http://craftcms.stackexchange.com/questions/881/how-can-i-create-a-visually-weighted-tag-cloud)!  
> **username_2**: If you aren't in a hurry lea, you better wait for @matt's plugin. You can do lots of things with twig, but it's a template language and such thing like my code below are actually considered bad practice!  

---

## 5 answers

### Answer by username_2 on 2014-07-14. Score: 7

This is based on Matt's answer to your previous question. Likewise this should better be used within cache tags!
This is untested, but it hopefully works out for you.
.
Edit:
This is still untested but it came to my ears, that it could make problems to assign variables as array keys. That's why I changed the code to use objects instead. If anyone uses this code, I'd be happy to hear if it does actually work!
{# Get all tags #}
{% set allTags = craft.tags.find() %}

{# Define object outside the for loop #}
{% set weightedTags = [] %}

{# Iterate over all tags #}
{% for tag in allTags %}

    {# Get total number of tag occurrences in entries belonging to 'blog' section #}
    {% set count = craft.entries.section('blog').relatedTo(tag).total() %}

    {# Save tag id and count to our weightedTags object #}
    {% set weightedTags = weightedTags|merge([{ tagId: tag.id, tagCount: count }]) %}

{% endfor %}

{# Sort, reverse-sort and pick top 10 elements of the array #}
{% set weightedTags = weightedTags|sort|reverse|slice(0, 10) %}

{# To print the top 10 list iterate over our weightedTags array #}
{% for tagObject in weightedTags %}

    {# Get tag object for each tagId #}
    {% set tagEntry = craft.tags.id(tagObject.tagId).first() %}

    {# Return the list item #}
    {{ tagEntry.name }}

{% endfor %}

> **Comments:**
> **username_3**: This seems to work if you set tagCount as first param in your weightedTags.  

---

### Answer by username_4 on 2017-06-17. Score: 2

Have had success using this plugin: <https://github.com/philbirnie/CraftPopularTags>


---

### Answer by username_5 on 2017-05-29. Score: 2

I couldn't quite get Carls answer to work (the "weightedTags"-array wasn't properly sorted), so I went and wrote a quick variable and service for achieving what I was after.
First off, the super-simple variable:
public function getPopularTags($limit = NULL, $tagGroup = 'tags') {
    return craft()->PLUGIN_SERVICENAME->getPopularTags($limit, $tagGroup);
}

Simply replace "PLUGIN_SERVICENAME" with whatever your plugin and service is called, per example "myPlugin_tagFinder"
And the service is almost as simple:
namespace Craft;
class PLUGIN_SERVICENAMEService extends BaseApplicationComponent
{
  public function getPopularTags($limit, $tagGroup = 'tags')
  {
    $sql = craft()->db->createCommand();
    $sql->select('tags.*, i18n.slug');
    $sql->from(['taggroups tagGroups', 'tags tags', 'relations relations', 'elements elements', 'elements_i18n i18n']);
    $sql->where(['AND',
                 "tagGroups.handle = '$tagGroup'",
                 'tags.groupId = tagGroups.id',
                 'relations.targetId = tags.id',
                 'elements.id = relations.sourceId',
                 "elements.enabled = '1'",
                 'i18n.elementId = tags.id']);
    $sql->group('relations.targetId');
    $sql->order('COUNT(elements.id) DESC');
    if (!is_null($limit) && is_numeric($limit)) {
      $sql->limit($limit);
    }

    return TagModel::populateModels($sql->queryAll());
  }
}

Again, replace "PLUGIN_SERVICENAME" with whatever your plugin and service is called, per example "MyPlugin_tagFinderService"
Once that is done (caveat: And your plugin is, naturally, installed/activated) you can get the tags you require from your template simply by calling:
{%set tags = craft.myPlugin.getPopularTags() %}

From there on you'll loop through them just as if you fetched them through the craft.tags.find()-methodology.

> **Comments:**
> **username_5**: Caveats: The method above flat out ignores which field the relation is built through, and also does not bother to look at locales. If you need to customize it to take either into account, feel free to do so or even to poke me for assistance.  
> **username_2**: This is a much better answer!  

---

### Answer by username_6 on 2020-08-23. Score: 1

I was working the last days on this query for craft 3.
I want to share it with u.
With this query u get the most used tags connected to other elements (wich are not revisions or drafts).
U also get the actual count of usages for every tag.
Hope it helps the next one.
   $query = (new Query())
        ->select([
            '{{relations}}.targetId as id',
            'COUNT({{relations.targetId}}) as count',
            '{{content}}.title as title'
        ])
        ->from('relations')
        ->leftJoin('tags', '{{relations}}.targetId={{tags}}.id')
        ->leftJoin('content', '{{content}}.elementId={{tags}}.id')
        ->leftJoin('elements', '{{elements}}.id={{tags}}.id')
        ->leftJoin('elements source', '{{source}}.id={{relations}}.sourceId')
        ->where([
            '{{elements}}.enabled' => 1,
            '{{source}}.enabled' => 1,
            '{{source}}.revisionId' => NULL,
            '{{source}}.draftId' => NULL,
        ])
        ->groupBy('id, title')
        ->orderBy( 'count DESC, title ASC')
    ;

    $query->limit($limit);

    if (is_numeric($limit) && !is_null($limit)) {
        $query->limit($limit);
    }

    $results = $query->all();

    foreach ($results as $key => $value) {
        $id = $value['id'];
        $results[$key] = Tag::find()->id($id)->one();
    }

    return $results;


---

### Answer by username_7 on 2024-03-02. Score: 1

Also needed this one, but the example from username_2 resulted in a timeout in my browser due to the large dataset (20.000 entries, 10.000 tags). I got it fixed by using a custom query, which returned the top 10 list in 3-4 seconds;
{% set query = craft.query()
        .select([
                'relations.targetId as id',
                'COUNT(relations.targetId) as count',
                'content.title as title'
        ])
        .from('relations')
        .leftJoin('tags', 'relations.targetId=tags.id')
        .leftJoin('content', 'content.elementId=tags.id')
        .leftJoin('elements', 'elements.id=tags.id')
        .leftJoin('elements source', 'source.id=relations.sourceId')
        .where({
                'elements.enabled': 1,
                'source.enabled': 1,
                'source.revisionId': null,
                'source.draftId': null
        })
        .groupBy('id, title')
        .orderBy('count DESC, title ASC')
        .limit(10) %}

{% set results = query.all() %}

{% for result in results %}
    {% set id = result['id'] %}
    {% set title = result['title'] %}
    {% set count = result['count'] %}
{% endfor %}


---

