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

Shortcode equivalent for Jekyll’s {% link %} tag? #544

Closed
beep opened this issue May 27, 2019 · 8 comments
Closed

Shortcode equivalent for Jekyll’s {% link %} tag? #544

beep opened this issue May 27, 2019 · 8 comments

Comments

@beep
Copy link

beep commented May 27, 2019

I’m tinkering with a move from Jekyll to Eleventy, and am getting a little tripped up trying to create a shortcode equivalent for Jekyll’s {% link %} tag, which turns this:

{% link _posts/2017-08-31-ampersand.md %}

into something like:

/wrote/ampersand/

I’ve registered a basic shortcode to just pass the path through to the rendered markup, but as near as I can tell, Eleventy’s complaining about the lack of quotes around the path in my shortcode:

$ npx eleventy
Problem writing Eleventy templates: (more in DEBUG output)
> Having trouble rendering liquid (and markdown) template ./_posts/2018-09-18-revamp.md (TemplateContentRenderError)
> invalid syntax at line 1 col 1:

  _posts/2017-08-31-ampersand.md
  ^, line:7 (RenderError)

If I wrap the path in quotes (e.g., {% link "_posts/2017-08-31-ampersand.md" %}), then the error moves onto the next {% link %} in my post.

Am I reading that correctly? If so, is there a decent way to work around this?

(Also, if there’s a better forum for intro-level questions like this, please let me know and I’ll redirect. Thank you!)

@zachleat
Copy link
Member

You can do this but it’s not straightforward, unfortunately.

By default shortcode arguments are treated as code and not raw literal values (like strings). This allows us to use variables as arguments to shortcodes. However, you can work around this limitation by creating your own custom tag. Here’s how you would do this for (I’m assuming you’re using) Liquid:

eleventyConfig.addLiquidTag("link", function(liquidEngine) {
  return {
    parse: function(tagToken, remainTokens) {
      this.path = tagToken.args;
    },
    render: function(scope, hash) {
      let outputPath = doSomethingWithInputPath(this.path);
      return Promise.resolve(outputPath);
    }
  };
});

…where you’d have to implement doSomethingWithInputPath in the above.

Perhaps in the future we could make this an option you could configure on a per-shortcode basis. Not sure!

@zachleat
Copy link
Member

Docs for LiquidJS custom tags: https://www.11ty.io/docs/custom-tags/#liquidjs-example

@zachleat
Copy link
Member

@benbrignell might also be interested in this sample code (per his related issue in #496) but his use case was quite a bit more complicated (multi-argument parsing)

@zachleat
Copy link
Member

Filed #545 which you may want to upvote!

@zachleat
Copy link
Member

Alright I went overboard because I wanted this for my blog and just made it (for Liquid)

eleventyConfig.addLiquidTag("link", function(liquidEngine) {
	return {
		parse: function(tagToken, remainTokens) {
			this.path = tagToken.args;
		},
		render: function(scope, hash) {
			let isQuoted = this.path.charAt(0) === "'" || this.path.charAt(0) === '"';
			let path = isQuoted ? liquidEngine.evalValue(this.path, scope) : this.path;

			// This is cheating a little bit because it‘s using the `collections.all` object
			// Anything not in the `all` collection won’t resolve
			let results = scope.contexts[0].collections.all.filter(function(tmpl) {
				return tmpl.inputPath === path;
			});
			if( results.length ) {
				return Promise.resolve(results[0].url);
			}
			return Promise.reject(`Template ${path} not found in \`link\` shortcode.`);
		}
	};
});

Sample Usage:

<a href="{% link "./index.liquid" %}">Test</a>
<a href="{% link ./index.liquid %}">Test</a>

Outputs:

<a href="/">Test</a>
<a href="/">Test</a>

zachleat added a commit that referenced this issue May 29, 2019
@beep
Copy link
Author

beep commented May 29, 2019 via email

@beep
Copy link
Author

beep commented Jun 7, 2019

Finally got a chance to try this out, and it worked a treat. I did have to prepend a ./ to path, since Jekyll allows (assumes?) a root-relative path ({% link _posts/blah.md %}, rather than {% link ./_posts/blah.md %}), but otherwise I think I’m set.

Thanks so much, Zach! I really appreciate it.

@edgarasben
Copy link

Is it possible to add a custom folder path while parsing?

I am trying to convert markdown links like that [My favorite link](my-favorite-link.md) to <a href="/posts/my-favorite-link">My favorite link</a>. So I need the parser to add a custom /posts/ string, depending on which folder my markdown files are coming from in the output. Is there a system variable for that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants