No permalink in Eleventy - permalinks

I'm migrating from Jekyll to Eleventy, where previously my blog post links had the permalink in this style: /:title/
What I want: https://example.com/my-blog-post/ for posts/my-blog-post.md
What I get: https://example.com/posts/my-blog-post/ for posts/my-blog-post.md
How can I configure this in Eleventy? The official page on 11ty docs says it takes the name of the folder, which is posts in this case.
I want this /:title/ for all my markdown files. I can't manually set the permalink in all my files. Is there a way to do so for the entire posts collection?
I'm using this repo as the base theme.

So after searching a lot (not the docs), I finally found the solution in this article.
In the last part of that section, use this:
// posts.json (or whatever your collection name is)
{
// ...
"permalink": "/{{ title | slug }}/"
// ...
}
Excerpt:
Using directory data to manage defaults
By default, Eleventy will maintain the structure of your content files when generating your site. In our case, that means /_basic-syntax/lists.md is generated as /_basic-syntax/lists/index.html. Like Jekyll, we can change where files are saved using the permalink property. For example, if we want the URL for this page to be /basic-syntax/lists.html we can add the
following:
---
title: Lists
syntax-id: lists
api: "no"
permalink: /basic-syntax/lists.html
---
Again, this is probably not something we want to manage on a file-by-file basis but again, Eleventy has features that can help: directory data and permalink variables.
For example, to achieve the above for all content stored in the _basic-syntax folder, we can create a JSON file that shares the name of that folder and sits inside it, i.e. _basic-syntax/_basic-syntax.json and set our default values. For permalinks, we can use Liquid templating to construct our desired path:
{
"layout": "syntax",
"tag": "basic-syntax",
"permalink": "basic-syntax/{{ title | slug }}.html"
}

You can set up permalinks per page or per collection. Assume you create a posts folder, then add a posts.11tydata.json file with content to set up basic values for a collection.
{
"eleventyExcludeFromCollections": false,
"layout": "post",
"permalink": "post/{{ title }}/",
"tags": [
"posts"
]
}

Related

Need REST access to WooCommerce information available in XML dump of website

We have a WordPress eXtended RSS file generated by WordPress as an export of your site. It list all kind of things that I cannot find using REST queries. Most notable is an item which says, in part,
<item>
<title><![CDATA[MKT Products [NEW]]]></title>
<wp:post_id>14146</wp:post_id>
<wp:post_type><![CDATA[dtwpb_product_tpl]]></wp:post_type>
<wp:postmeta>
after which come a host of useful keys and values which describe the fields in the tpl.
When I do a REST call to the WooCommerce endpoint, I can get a list of products. In the meta_data for these product there is an entry describing the template that has been assigned to the product, e.g.
}, {
"id": 161714,
"key": "dtwpb_single_product_page",
"value": "14146"
}, {
My problem is that while I can work out how to get the definitive list of all the dtwpb_single_product_page values being used for the products, I can't figure out to take the 14146 and use it to get the post that defines its name and attributes.
Does such an endpoint exist and if so, where? One might think that /wp/v2/templates would be the go, but it just gives me an empty array.

How to properly map my markdown content to dynamic URLs in Next.js?

I'd like to have the following URL structure:
URL
Role
/
markdown contents of /index.md
/about
markdown contents of /about.md
/cookies
markdown contents of /cookies.md
/privacy-policy
markdown contents of /privacy-policy.md
/category1
category1 index page
/category1/post1
markdown contents of /category1/post1.md
/category1/post2
markdown contents of /category1/post2.md
/category2
category2 index page
/category2/post1
markdown contents of /category2/post1.md
/category2/post2
markdown contents of /category2/post2.md
I'd like to avoid having to create separate .js files for my content in the root directory (so no /about.js, /cookies.js, etc), but if I try something like this...
pages/
index.js
[root_article_id].js
[category]/
index.js
[category_article_id].js
... then Next.js complains because it cannot decide when I request the URL /about whether if it should use [category]/index.js or [root_article_id].js, even though I feel the latter should be called first, and if it doesn't want to deal with the request (i.e. if there's no about.md in the root of my markdown directory), then it should fall back to [category]/index.js, which still could pass the request through to the 404 handler if [category].js spits it out.
What's the correct way of structuring Next.js files for this? Do I really need to have separate .js files for my markdown files in the root content directory?
What's the correct way of structuring Next.js files for this? Do I really need to have separate .js files for my markdown files in the root content directory?
This is the easiest way since you have to somehow tell nextjs what pages you want to be articles. However, if want to avoid doing it, you can do it with rewrites.
If you know all articles (or categories), this is what you need in your next.config.js:
module.exports = {
rewrites() {
return [
{
source: "/about",
destination: "/article/about",
},
{
source: "/cookies",
destination: "/article/cookies",
},
{
source: "/privacy-policy",
destination: "/article/privacy-policy",
},
];
},
};
And then make article/[root_article_id] page. Note that rewrite does not mean redirect. The page will be available in /about but nextjs will handle it like the request was to /article/about. This means that these pages will also be available from article/about, but this can probably be prevented if for some reason necessary.
Whether you should do rewrites for articles or categories depends on which one is dynamic. If neither one is really dynamic in a sense that you know all the possible values, you should pick the one with less possible values.
If both of categories and articles are dynamic, you need to do the rewrites with middleware (beta). In your middleware you get the req and you somehow need to decide if the requested url is an article or a category page. How this is done obviously depends on where and how you store your data.

How do I generate Eleventy and display tags from a localized version of a collection file?

I'm new to Eleventy and working on a personal project - most of it is working fine, but I need help with generating and filtering tags based on posts stored in separate folders (as part of internationalizing/localizing my site).
I have two folders: en and ff. Inside each folder, I have a folder called posts - this contains a handful of posts.
I'm trying to work out a way to create a set of tags from just the en/posts folder or the fr/posts folder - each would be in a separate collection, not as one global collection.
I currently have this to generate an array of tags across all pages:
eleventyConfig.addFilter("filterTagList", filterTagList);
// Create an array of all tags
eleventyConfig.addCollection("tagList", function (collection) {
let tagSet = new Set();
collection.getAll().forEach(item => {
(item.data.tags || []).forEach(tag => tagSet.add(tag));
});
return filterTagList([...tagSet]);
});
(filterTagList is a separate filter that excludes certain redundant tags)
I can create a collection based on posts within the en/posts folder called posts_en, using this:
eleventyConfig.addCollection("posts_en", function (collection) {
return collection.getFilteredByGlob("./en/posts/*.md");
});
...which works fine to display English posts. I've also been able to create a collection that picks up posts in the en/posts folder, if I add posts_en as a tag to the post:
eleventyConfig.addCollection("tagGroup", function (collection) {
console.log(">>>> TAGGROUP:", collection.getFilteredByTags("posts_en"));
return collection.getFilteredByTags("posts_en");
});
(I've checked the console.log statement in this code extract - it renders all of the posts I tag with posts_en, but I'm not sure if this will keep the other tags as well? The collection needs to only contain English posts with their appropriate tags, but no French content (and vice-versa, for the FR content).
My problem is that I've been unable to adapt the original tagList method only to contain posts in the en folder (or the fr folder).
I've tried changing tagList to tagList_en, and adapting collection.getAll() to only reference the posts_en collection - this compiled, but gave zero results on my Tags page. I've scoured across SO and various posts on the Web, but so far, no joy - can anyone help advise, please? I'm happy to duplicate the solution from English to a French equivalent - as long as I can get something working for English content!
If your posts_en collection works as expected, then it should be possible to adapt the tagList collection to only show tags from English posts by replacing collection.getAll() with collection.getFilteredByGlob("./en/posts/*.md").
// Create an array of all tags
eleventyConfig.addCollection("tagList", function (collection) {
let tagSet = new Set();
collection.getFilteredByGlob("./en/posts/*.md").forEach(item => {
(item.data.tags || []).forEach(tag => tagSet.add(tag));
});
return filterTagList([...tagSet]);
});
This will set collections.tagList to an array of strings (the tags from English posts).

Create document set in Sharepoint with Graph API in a subfolder

I already implemented the creation of a document set at library root level. For this I used the following link: Is it possible to create a project documentset using graph API?
I follow the following steps :
1- Retrieve the document library's Drive Id:
GET https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}?$expand=drive
2- Create the folder:
POST https://graph.microsoft.com/v1.0/drives/${library.drive.id}/root/children
The body of the request is the following
{
"name": ${folderName},
"folder": {},
}
3- Get the folder's SharePoint item id:
GET https://graph.microsoft.com/v1.0/sites/${siteId}/drives/${library.drive.id}/items/${folder.id}?expand=sharepointids
4- Update the item in the Document Library so that it updates to the desired Document Set:
PATCH https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listId}/items/${sharepointIds.listItemId}
I do send the following body to the patch request:
{
"contentType": {
"id": "content-type-id-of-the-document-set"
},
"fields": {}
}
I'm looking now how to create a document set in a specific folder in Sharepoint.
For example, i want to create the following folder structure.
The documents folder is at the library root and I want to create a document set named billing.
documents
|_ billing
|_ 2021
|_11
|_01
|_ document1.pdf
|_ document2.pdf
|_ document3.pdf
|_02
...
|_03
...
|_04
|_10
...
thanks
I'm doing something similar but I'm a little behind you, haven't yet created the Document Set (almost there!), but may I respectfully challenge your approach?
I'm not sure it's a good idea to mix Folders and Document Sets, mainly because a Folder breaks the metadata flow, you could achieve the same results just using Document Sets.
I am assuming that your 'day' in the data structure above is your Document Set (containing document1.pdf, etc.) You might want to consider creating a 'Billing' Document Set and either specifically add a Date field to the Document Set metadata or, perhaps better still, just use the standard Created On metadata and then create Views suitably filtered/grouped/sorted on that date.
This way you can also create filtered views for 'Client' or 'Invoice' or 'Financial Year' or whatever.
As soon as your documents exist in a folder, you can no longer filter/sort/group etc., the document library based on metadata.
FURTHER INFORMATION
I am personally structuring my Sales document library thus:
Name: Opportunity; Content Type: Document Set; Metadata: Client Name, Client Address, Client Contact
Name: Proposal; Content Type: Document; Metadata: Proposal ID, Version
Name: Quote; Content Type: Document; Metadata: Quote ID, Version
Etc...
This way the basic SharePoint view is a list of Opportunities (Document Sets), inside which are Proposals, Quotes etc., but I can also filter the view to just show Proposals (i.e. filter by Content Type), or search for a specific Proposal ID, or group by Client Name, then sort chronologically, or by Proposal ID etc.
I'm just saying that you get a lot more flexibility if you avoid using Folders entirely.
p.s. I've been researching for days now how to create Document Sets with graph, it never occurred to me that it might be a two-step process i.e. create the folder, then patch its content type. Many thanks for your post!!
Just re-read your post and my assumption that the 'day' would be your document set was incorrect. In this case, there would be no benefit having a Document Set containing Folders because the moment a Folder exists in the Document Set, metadata flow stops, and the only reason (well, the main reason*) to use Document Sets in preference to Folders is that metadata flow.
*Document Sets also allow you to automatically create a set of documents based on defined templates.

Control index.xml for Atom/RSS to generate valid rss feed (without relative links)

Task: I want to add an RSS feed to my site. (Later I want to add a separate RSS feed for a specific category [for R Bloggers])
Setup:
I use the Hugo Academic template
via the R blogdown package
push my sources to github
https://github.com/Tazinho/AlmostRandom
from where it gets published via netlify
http://www.malte-grosser.com/
added an example blogpost here
http://www.malte-grosser.com/post/test-post/
Issue and validation:
According to this video
https://www.youtube.com/watch?v=gF0tohv99Ow
my blogs rss should be this
http://www.malte-grosser.com/index.xml
According to some validator side
http://www.feedvalidator.org/
My rss feed seems not to be valid and has several kinds of errors
http://www.feedvalidator.org/check.cgi?url=http%3A%2F%2Fwww.malte-grosser.com%2Findex.xml
eg: line 5, column 11: link must be a full and valid URL: / [help]
Steps to solve this so far:
I followed some SO posts, as far as I could. For example this related one
Control index.xml for Atom/RSS (hugo / blogdown generates feed with relative links)
I added rss.xml to /post/layouts/ and modified it according to
https://coolbutuseless.bitbucket.io/2018/02/07/blogdown-rss-feed-of-full-articles/
I struggled a bit with the part under
"# Reference your RSS Feed". I don't know wehre exactly what exactly has to go
I read several other posts and tried to find similar public repositories from rbind.io.
I deleted most of my trials, to have a clean setup for further trials
the only parts I kept are the following changes within config.toml
baseurl = "http://malte-grosser.com/"
rssLimit = 10
[outputs]
home = [ "HTML", "CSS", "RSS" ]
section = [ "HTML", "RSS" ]
taxonomy = [ "HTML", "RSS" ]
taxonomyTerm = [ "HTML", "RSS" ]
and the rss.xml under /post/layouts/
From my understanding (after reading once more Control index.xml for Atom/RSS (hugo / blogdown generates feed with relative links)) it seems to be ok to have these kind of errors.
Also for anyone with similar problems: It turns out that the blogs RSS should be under http://www.malte-grosser.com/post/index.xml and the categories RSS's should be under http://www.malte-grosser.com/categories/R-bloggers/index.xml

Resources