How can I best extend TagModel to add a `count` property?
Before worrying about how templating should work, let’s just get one thing out of the way: Computing this data every time it’s requested is horribly inefficient, and could easily take a site down. You’ll absolutely need to find a way to store the tag counts in a more permanent location, and calculate it when entries are saved rather than when the template requests it. (Even if you wrap the template in a {% cache %} tag, you’re still forcing a couple people to experience slow page load times for no good reason.)

You have multiple options on how to store the data, but giving it its own table is probably the most obvious/reliable. I’d call it something like tagcounts, and give it tagId and count columns. tagId should be a FK to the tags table, set to cascade delete.

Then you’d want to listen to the entries.onSaveEntry event. When it fires, loop through all the entry’s Tags fields, and each of their selected tags. For each one, get the total count of rows in the relations table where the targetId column is set to the tag’s ID. Use DbCommand::insertOrUpdate() to save the value in your table.

craft()-&gt;db-&gt;createCommand()-&gt;insertOrUpdate('tagcounts', array(
    'tagId' =&gt; $tag-&gt;id
), array(
    'count' =&gt; $count
));


You’ll also need to loop through all existing tags and populate this table when the plugin is first installed.

With the tag count data in place, next up is templating. Unfortunately I don’t have a good answer for you there. It’s a complicated problem.

I think what I would do is, create a Variable class which accepts an ElementCriteriaModel, passes that off to craft()-&gt;elements-&gt;buildElementsQuery() which will take most of the parameters into account, then make some additional modifications to the query – join in the tagcounts table and set the ORDER BY.

Next up you would basically have to copy a ton of code from ElementsService::findElements(), which is totally lame. I’m going to see what I can do to make it much easier on you going forward. Ideally at this point you would be able to just do something like:

return craft()-&gt;elements-&gt;findElementsUsingQuery($query);