totocaster / metalsmith-tags

A metalsmith plugin to create dedicated pages for tags in posts or pages.
49 stars 43 forks source link

order tags by alphabetical order #49

Open oupala opened 7 years ago

oupala commented 7 years ago

I have a page that list all the used tags.

MegaJ commented 6 years ago

I'm new to using this plugin, so please excuse my misconceptions, if any.

I'm not sure this plugin's use case fits listing all tags on a page. I thought it was meant to allow you to paginate / group posts by tags. For all your listed concerns, there are no direct options in this plugin that you can set to solve your problem. I've thought of some alternative solutions, if you're interested:

Although there is a sortBy option available, this is for ordering the files with tags within an array for pagination, not the tags themselves. If you have a page already that lists all tags, you could, in your templating engine perform a sort to achieve an alphabetized list. Or if you have the list, javascript has a builtin .sort() for arrays.

Counting: this plugin can add a tags property to your metalsmith global metadata object (use the metadataKey option). The format for that object like this: { tag1: [Array], tag2: [Array], tag3: [Array] ...} } where each tag keys to an array of other file objects. You can calculate length from there to get a count.

You third concern, I would probably look at the tag index files, where you can access the pagination field. You can look at the array of files each index has under it, so you could come up with something to see if the counts for all index pages of that particular tag exceed your x=3.

I don't know if that was any help at all. You asked in September, and it's months later. What solution did you come up with?

oupala commented 6 years ago

I have a special handlebars template for displaying all tags:

<div class="container">
    <ul class="tags-list">
    {{#each tags}}
        <li><a href="/tags/{{urlSafe}}/">{{@key}}</a></li>
    {{/each}}
    </ul>
</div>

I might have to look at handlebars on how to order tags instead of simply listing them by {{#each tags}}.

And I have absolutely no idea on how to add a counter on tags to know how many time they are used.

As you can see, I also respond you months after your answer, and I still not have found any solution.

MegaJ commented 6 years ago

I've never written handlebars but I can link to some docs.

You can do what you want in Handlebars. This relevant doc tells you how to access properties of your array using the #with block, but I think a this.length in the loop will also give you the length of the array (aka, number of posts with a particular tag).

You will also need to create a helper for a way to use an #if block to only display tags if there is a post threshold met. A tutorial, or follow the doc

And you might need a lookup call to get the key (tag name), of your tags object inside the #with block, but you might be able to do it without. I suspect your template structure to look something like (untested):

<div class="container">
    <ul class="tags-list">
    {{#each tags}}
        {{#with this}}
          <!-- some if statement here to guard the <li> by checking for length -->
          <li><a href="/tags/{{urlSafe}}/">
            <!-- lookup call to get the key, which is the name of the tag --> 
            ({{ length }})</a></li>
        {{/with}}
    {{/each}}
    </ul>
</div>
oupala commented 4 years ago

I found a partial solution with a helper.

Here is the solution for ordering tags:

{{#each_with_sort tags}}
    <li><a href="/tags/{{urlSafe}}/" class="badge badge-secondary" aria-label="tag {{name}}">{{name}}</a></li>
{{/each_with_sort}}
Handlebars.registerHelper('each_with_sort', function(object, options) {
  console.log(object);
  var keys = Object.keys(object);
  var array = [];
  keys.forEach(key => {
    array.push({
      name: key,
      data: object[key][0], // get and store document data from object
      urlSafe: object[key].urlSafe
    });
  })
  array.sort((a,b) => (a.name.toLowerCase() > b.name.toLowerCase()) ? 1 : ((b.name.toLowerCase() > a.name.toLowerCase()) ? -1 : 0));
  var output = '';
  for (let i = 0; i < array.length; i++) {
    output += options.fn(array[i]);
  }
  return output;
});
oupala commented 4 years ago

Here is a full solution that is a solution for the following question (from the original issue):

The solution is a new helper that can be used in many ways. I add then 3 ways to call the helper:

{{#each_tags tags "occurencies" 3 1000 true}}
    <li><a href="/tags/{{urlSafe}}/" class="badge badge-secondary" aria-label="tag {{name}}">{{name}} ({{occurencies}})</a></li>
{{/each_tags}}
{{#each_tags tags "name" 2 1000 false}}
    <li><a href="/tags/{{urlSafe}}/" class="badge badge-secondary" aria-label="tag {{name}}">{{name}} ({{occurencies}})</a></li>
{{/each_tags}}
{{#each_tags tags "name" 1 1 false}}
    <li><a href="/tags/{{urlSafe}}/" class="badge badge-secondary" aria-label="tag {{name}}">{{name}}</a></li>
{{/each_tags}}
Handlebars.registerHelper('each_tags', function(object, sortField, minOccurency, maxOccurency, reverse, options) {
  var keys = Object.keys(object);
  var array = [];
  keys.forEach(key => {
    if ((object[key].length >= minOccurency) && (object[key].length <= maxOccurency)) {
      array.push({
        name: key,
        urlSafe: object[key].urlSafe,
        occurencies: object[key].length
      });
    }
  })
  array.sort((a,b) => {
    if (typeof a[sortField] === "string") {
      return ((a[sortField].toLowerCase() > b[sortField].toLowerCase()) ? 1 : ((b[sortField].toLowerCase() > a[sortField].toLowerCase()) ? -1 : 0));
    } else {
      return ((a[sortField] > b[sortField]) ? 1 : ((b[sortField] > a[sortField]) ? -1 : 0));
    }
  });
  if (reverse) {
    array = array.reverse();
  }
  var output = '';
  for (let i = 0; i < array.length; i++) {
    output += options.fn(array[i]);
  }
  return output;
});
oupala commented 4 years ago

I had to use a helper because the plugin does not evolve anymore.

But I think that the features offered by this helper should be included in the plugin itself.