Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic permalink data variable / string interpolation doesn't work in .11ty.js templates #2318

Closed
JohJonker opened this issue Apr 9, 2022 · 3 comments
Labels
education: template language Learning about a template language.

Comments

@JohJonker
Copy link

JohJonker commented Apr 9, 2022

Describe the bug
I'm trying to specify a custom permalink with string interpolation in an 11ty.js template. I tried the instructions from the Docs, but I note that "These will be parsed with the current template’s rendering engine" and therefore understand that the {{ ... }} is not working in my 11ty.js template. However, there doesn't seem to be a different way to bring in variables. I've tried:

permalink: '/categories/{{category.slug}}/index.html',
permalink: '/categories/${category.slug}/index.html',
permalink: '`/categories/${category.slug}/index.html`',
permalink: "'/categories/' + category.slug + '/index.html'",

In each case I can see the string is not being interpolated in the error output:

[11ty] > Output conflict: multiple input files are writing to `dist/ideas/${category.slug}/index.html`. Use distinct `permalink` values to resolve this conflict.

The workaround is to explicitly set templateEngineOverride: 'njk' in the frontmatter to allow the {{ ... }} syntax, but that causes some obvious downstream issues with the template.

Is this me missing something fundamental or is this a valid bug / feature request / documentation update request?

To Reproduce
Here is my code from sample file category.11ty.js:

exports.data = {
  pagination: {
    data: 'constants.CATEGORIES', // object array from /_config/constants.js
    size: 1,
    alias: 'category',
  },
  permalink: '/categories/${category.slug}/index.html',
};
exports.render = async function getPage({ category }) {
  return `<h1>${category.title}</h1>`;
};

Expected behavior
I would assume there has to be a way to do dynamic permalinks in 11ty.js templates.

Environment:

  • OS and Version: MacOS Montery 12.2.1 (M1)
  • Eleventy Version: 1.0.0

Additional context:
I looked at a bunch of related issues, and this one seems closest, but for Pug: #1899

@pdehaan
Copy link
Contributor

pdehaan commented Apr 9, 2022

@JohJonker I think you're close, but a couple small issues…

permalink: '/categories/${category.slug}/index.html',

This wouldn't work since:

  1. it isn't using backticks
  2. category wouldn't be defined here (it's more of a "reference" here, not a variable [yet]).
  3. we can't use /categories/{{ category.slug }}/index.html either since LiquidJS/Nunjucks don't preprocess .11ty.js files

Here's my small sample files:

// src/categories.11ty.js
exports.data = {
  pagination: {
    data: 'CATEGORIES',
    size: 1,
    alias: 'category',
  },
-  // permalink: '/categories/${ category.slug }/index.html',
+  eleventyComputed: {
+    permalink(data) {
+      return `/categories/${ data.category.slug }/`;
+    }
  }
};

exports.render = async function getPage({ category }) {
  return `<h1>${category.title}</h1>`;
};
// .eleventy.js
module.exports = function (eleventyConfig) {
  // I was too lazy to make a global data file, so I used `.addGlobalData()` (Eleventy v1.0.0+).
  // Note my inconsistently silly slugs.
  eleventyConfig.addGlobalData("CATEGORIES", [
    { slug: "one", title: "Page ONE" },
    { slug: "Two", title: "pAge tWO" },
    { slug: "ThReE", title: "paGe tHrEe" },
    { slug: "foUR", title: "pagE FOur" },
  ]);

  return {
    dir: {
      input: "src",
      output: "www"
    }
  };
};

Now, running npm run build will give me the following glorious output:

> 11ty-2318@1.0.0 build
> eleventy

[11ty] Writing www/categories/one/index.html from ./src/category.11ty.js
[11ty] Writing www/categories/Two/index.html from ./src/category.11ty.js
[11ty] Writing www/categories/ThReE/index.html from ./src/category.11ty.js
[11ty] Writing www/categories/foUR/index.html from ./src/category.11ty.js
[11ty] Wrote 4 files in 0.02 seconds (v1.0.0)

Note that it's using my exact slug values from the object, which gives me some undesirable URLs (again, it's a bad example, but possibly valid).

We can solve that by enforcing slugified URLs using the built-in slugify filter (again, Eleventy 1.0.0+; previous versions of Eleventy used a slug filter, but the new slugify handles more special characters and default behavior):

  eleventyComputed: {
    permalink(data) {
-      return `/categories/${ data.category.slug }/`;
+      return `/categories/${ this.slugify(data.category.slug) }/`;
    }
  }

And now if I rerun npm run build locally, I get the following (where my category slugs are lowercased and slugified):

> 11ty-2318@1.0.0 build
> eleventy

[11ty] Writing www/categories/one/index.html from ./src/category.11ty.js
[11ty] Writing www/categories/two/index.html from ./src/category.11ty.js
[11ty] Writing www/categories/three/index.html from ./src/category.11ty.js
[11ty] Writing www/categories/four/index.html from ./src/category.11ty.js
[11ty] Wrote 4 files in 0.03 seconds (v1.0.0)

Possibly not a big deal depending on your exact values for category.slug, but worth considering 🤷 .

@pdehaan pdehaan added education: template language Learning about a template language. and removed needs-triage labels Apr 9, 2022
@zachleat
Copy link
Member

Awesome investigation @pdehaan!

One thing I would also note here is that you needn’t use eleventyComputed with permalink, e.g.:

// src/categories.11ty.js
exports.data = {
  pagination: {
    data: 'CATEGORIES',
    size: 1,
    alias: 'category',
  },
-  permalink: '/categories/${ category.slug }/index.html',
+  permalink: function(data) {
+    return `/categories/${this.slugify(data.category.slug)}/index.html`;
+  }
  }
};

exports.render = async function getPage({ category }) {
  return `<h1>${category.title}</h1>`;
};

@zachleat
Copy link
Member

This is an automated message to let you know that a helpful response was posted to your issue and for the health of the repository issue tracker the issue will be closed. This is to help alleviate issues hanging open waiting for a response from the original poster.

If the response works to solve your problem—great! But if you’re still having problems, do not let the issue’s closing deter you if you have additional questions! Post another comment and we will reopen the issue. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
education: template language Learning about a template language.
Projects
None yet
Development

No branches or pull requests

3 participants