1 | const getTag = require("get-tag");
|
2 |
|
3 | module.exports = (eleventyConfig, pluginNamespace) => {
|
4 | eleventyConfig.namespace(pluginNamespace, () => {
|
5 | eleventyConfig.addShortcode("metagen", (data) => {
|
6 |
|
7 | function comments(data, key, commentGroup) {
|
8 | return data.comments ? `${(data[key] ? `<!-- ${data[key]} -->` : `<!-- ${commentGroup} -->`)}` : "";
|
9 | }
|
10 |
|
11 | function getDnsTags(data, rel) {
|
12 | if (typeof data == "string") {
|
13 | return getTag("link", null, {rel: rel, href: data});
|
14 | } else if (typeof data == "object" && typeof data.crawlers === "object" && data.constructor === Object) {
|
15 | let tags = "";
|
16 | data.forEach(link => tags += getTag("link", null, {rel: rel, href: link}));
|
17 | return tags;
|
18 | }
|
19 | }
|
20 |
|
21 | function handleDnsResolution(data) {
|
22 | let tags = "";
|
23 | if (data.preconnect) tags += getDnsTags(data.preconnect, "preconnect");
|
24 | if (data.dns_prefetch) tags += getDnsTags(data.dns_prefetch, "dns-prefetch");
|
25 | return tags;
|
26 | }
|
27 |
|
28 | function handleCustomCrawlers(data) {
|
29 | if (data.crawlers && typeof data.crawlers === "object" && data.constructor === Object) {
|
30 | let tags = "";
|
31 | for (const key in data.crawlers) tags += getTag("meta", null, {name: key, content: data.crawlers[key] });
|
32 | return tags;
|
33 | }
|
34 | }
|
35 |
|
36 | function getStaticAssets(tagInfoList, asset) {
|
37 | return tagInfoList
|
38 | .filter(tagInfo => tagInfo[1])
|
39 | .map(tagInfo => {
|
40 | if (tagInfo[0] === `inline-${asset}`) {
|
41 | return asset == "css" ? `\t${getTag("style", tagInfo[1])}` : `\t${getTag("script", tagInfo[1])}`;
|
42 | } else {
|
43 | return tagInfo[1].map(tagData => {
|
44 | if (typeof tagData === "object") {
|
45 | return `<script src="${tagData[0]}" ${tagData[1]}></script>`;
|
46 | }
|
47 | return asset == "css" ? getTag("link", null, {rel: "stylesheet", href: tagData }) : `<script src="${tagData}"></script>`;
|
48 | }).join("\n\t");
|
49 | }
|
50 | });
|
51 | }
|
52 |
|
53 | if (data) {
|
54 | let canonical, css, js, customTags = "";
|
55 | const metadata = [
|
56 | ["charset", getTag("meta", null, {charset: data.charset || "utf-8"})],
|
57 | ["http-equiv", getTag("meta", null, { "http-equiv": "X-UA-Compatible", content: "IE=edge" })],
|
58 | ["viewport", "width=device-width, initial-scale=1"],
|
59 | ["dns", handleDnsResolution(data)],
|
60 | ["mainTitle", getTag("title", data.title)],
|
61 | ["author", data.name],
|
62 | ["title", data.title],
|
63 | ["description", data.desc],
|
64 | ["robots", data.robots],
|
65 | ["crawlers", handleCustomCrawlers(data)],
|
66 | ["generator", data.generator]
|
67 | ].filter(tagInfo => tagInfo && tagInfo[1]).map(tagInfo => {
|
68 | if (["charset", "dns", "crawlers", "http-equiv", "mainTitle"].includes(tagInfo[0])) return tagInfo[1];
|
69 | return getTag("meta", null, { name: tagInfo[0], content: tagInfo[1] });
|
70 | });
|
71 |
|
72 | const openGraph = [
|
73 | ["comments", comments(data, "og-comment", "Open Graph")],
|
74 | ["og:type", data.type || "website"],
|
75 | ["og:url", data.url],
|
76 | ["og:site_name", data.site_name],
|
77 | ["og:video", data.og_video],
|
78 | ["og:audio", data.og_audio],
|
79 | ["og:determiner", data.og_determiner],
|
80 | ["og:locale:alternate", data.og_alternate_locales],
|
81 | ["og:locale", data.locale || "en_US"],
|
82 | ["og:title", data.og_title || data.title],
|
83 | ["og:description", data.og_desc || data.desc],
|
84 | ["og:image", data.img],
|
85 | ["og:image:alt", data.img_alt],
|
86 | ["og:image:width", data.img_width],
|
87 | ["og:image:height", data.img_height],
|
88 | ["og:image:type", data.og_img_type],
|
89 | ["og:image:secure_url", data.og_img_url]
|
90 | ].filter(tagInfo => tagInfo[1]).map(tagInfo => {
|
91 | if (tagInfo[0] == "og:locale:alternate") {
|
92 | return tagInfo[1].map(locale => {
|
93 | return getTag("meta", null, {property: tagInfo[0], content: locale });
|
94 | }).join("\n\t");
|
95 | }
|
96 | return tagInfo[0] === "comments" ? tagInfo[1] : getTag("meta", null, { property: tagInfo[0], content: tagInfo[1] });
|
97 | });
|
98 |
|
99 | const twitterCard = [
|
100 | ["comments", comments(data, "twitter-comment", "Twitter")],
|
101 | ["twitter:card", data.twitter_card_type || 'summary'],
|
102 | ["twitter:site", `@${data.twitter_handle}`],
|
103 | data.twitter_card_type === "summary_large_image" ? ["twitter:creator", `@${data.creator_handle || data.twitter_handle}`] : "",
|
104 | ["twitter:url", data.url],
|
105 | ["twitter:title", data.twitter_title || data.title],
|
106 | ["twitter:description", data.twitter_desc || data.desc],
|
107 | ["twitter:image", data.img],
|
108 | ["twitter:image:alt", data.img_alt]
|
109 | ].filter(tagInfo => tagInfo[1]).map(tagInfo => {
|
110 | return tagInfo[0] === "comments" ? tagInfo[1] : getTag("meta", null, { [data.attr_name || "name"]: tagInfo[0], content: tagInfo[1] });
|
111 | });
|
112 |
|
113 | if (data.url) canonical = getTag("link", null, {rel: "canonical", href: data.url });
|
114 | if (data.css || data.inline_css) css = getStaticAssets([["css", data.css], ["inline-css", data.inline_css]], "css").join("\n");
|
115 | if (data.js || data.inline_js) js = getStaticAssets([["js", data.js], ["inline-js", data.inline_js]], "js").join("\n");
|
116 |
|
117 | if (data.custom) {
|
118 | customTags = data.custom.map(item => {
|
119 | if (item.length < 3) return;
|
120 | if (item.length === 3) return getTag(item[0], item[1], item[2]);
|
121 | return getTag(item[0], item[1], item[2], item[3]);
|
122 | }).join("\n\t");
|
123 | }
|
124 |
|
125 | return [...metadata, ...openGraph, ...twitterCard, canonical, customTags, css, js].filter(Boolean).join("\n\t");
|
126 | } else {
|
127 | console.error("No data was added into the meta generator")
|
128 | return "";
|
129 | }
|
130 | });
|
131 | });
|
132 | };
|