facebook / docusaurus

Easy to maintain open source documentation websites.
https://docusaurus.io
MIT License
56.85k stars 8.56k forks source link

proposed feature: hook to control blog URL generation #8612

Closed johnnyreilly closed 6 months ago

johnnyreilly commented 1 year ago

Have you read the Contributing Guidelines on issues?

Description

The URL for blog posts in Docusaurus is determined by the parseBlogFileName function:

https://github.com/facebook/docusaurus/blob/847a401669ebc54b7333e8389f3d83b8997e246e/packages/docusaurus-plugin-content-blog/src/blogUtils.ts#L147-L162

Either the URL is controlled by a slug frontmatter parameter, or is derived from filename parsing.

I'd like to propose a hook which, if supplied, could be used as the default strategy for determining a blogs URL. slug, if present would have higher priority. But it would allow consumers to come up with different approaches for naming.

Has this been requested on Canny?

No

Motivation

I wrote recently about how I'd ruined my SEO on my Docusaurus based blog. I'm working with Growtika on improving it. One thing that I've learned (this is not my area of expertise) is that blogs with numbers in the URL are generally ranked lower than ones without.

Consequently, I'm planning to migrate my blog to use slug for each blog post and effectively have the same URL as before, but without the 2023/02/01/ type prefix.

Slug allows me to do this manually, and I shall. I shall script my way to glory. But what if I didn't have to do it for every post? What if there was a way to control it?

API design

The idea is some kind of URL generator function that could supply as an optional parameter in the blog configuration: https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog#configuration

Imaging something like:

defaultSlugGenerator: ({ frontMatter, blogSourceRelative }) => {
    // user supplies naming strategy here and returns a string
}

And then this code:

https://github.com/facebook/docusaurus/blob/847a401669ebc54b7333e8389f3d83b8997e246e/packages/docusaurus-plugin-content-blog/src/blogUtils.ts#L283

Becomes:

const slug = frontMatter.slug ?? (
    options.defaultSlugGenerator
        ? options.defaultSlugGenerator({ blogSourceRelative, frontmatter }) 
        : parsedBlogFileName.slug
);

Now the consumer can control the default generated blog URL with using slog each time.

Have you tried building it?

I haven't, but I've planned it out. Seems pretty straightforward.

Self-service

shubhankar-mern commented 1 year ago

@johnnyreilly basically for now the slug is some date and text..u want it to be a user generated input..right?

Josh-Cena commented 1 year ago

This should be doable with createFrontMatter, proposed in https://github.com/facebook/docusaurus/issues/5568

johnnyreilly commented 1 year ago

Yup that could work. Is anyone planning on implementing that, or is it an idea which may not land?

johnnyreilly commented 1 year ago

@shubhankar-mern - yeah totally. Driven by data of the blog post

slorber commented 1 year ago

I'd prefer if we used createFrontMatter for this use-case.

Yup that could work. Is anyone planning on implementing that, or is it an idea which may not land?

This is definitively something we want to add for a while as it's low-level and unlocks a lot of flexibility for various use-cases.

Unfortunately until we ship v3 with MDX 2 + React 18 I have to focus on these and unusual project maintenance 😅


Side note: I would also recommend to not create your own blog slug generation logic but instead being explicit for all your posts. Using some userland algo, you are more likely to update it and change permalinks, and ruin your SEO again 😅 Maybe the friction we have to not do this is a feature and not a bug. Maybe instead you should automate the addition of a slug: xxx frontmatter as a one-time throwable script rather than trying to plug a mutable algorithm?

johnnyreilly commented 1 year ago

Side note: I would also recommend to not create your own blog slug generation logic but instead being explicit for all your posts. Using some userland algo, you are more likely to update it and change permalinks, and ruin your SEO again sweat_smile Maybe the friction we have to not do this is a feature and not a bug. Maybe instead you should automate the addition of a slug: xxx frontmatter as a one-time throwable script rather than trying to plug a mutable algorithm?

Hey @slorber - so this exactly what I did; you can see it in action here:

https://github.com/johnnyreilly/blog.johnnyreilly.com/pull/423

You'll note that part of this is generating 301 redirects which should mean my SEO is maintained. I'm working with Growtika and one of their pieces of advice to improve my SEO was removing numbers and / from my URLs.

Docusaurus blog URLs implicitly have yyyy/mm/dd/ as a prefix to URLs if slug is not provided. This means the default Docusaurus blog URL has less SEO potential than it might. My suggestion here was a very generic solution to the problem which would allow me to avoid specifying slug in each post. My needs would be equally served by an excludeDateFromBlogUrl feature also ;-)

slorber commented 6 months ago

The "parseFrontMatter" config callback has been released in Docusaurus v3.1: https://docusaurus.io/blog/releases/3.1#parsefrontmatter-hook

It receives the file path and file content as param, so technically you can create your own slug front matter based on the file path, using your own conventions.

function computeCustomSlug(filePath) {
  // return your front matter slug here
}

export default {
  markdown: {
    parseFrontMatter: async (params) => {
      // Reuse the default parser
      const result = await params.defaultParseFrontMatter(params);

      result.frontMatter.slug = computeCustomSlug(params.filePath);

      return result;
    },
  },
};

This is a bit lower-level than a first-class blog URL generation feature, but it is more flexible and works for all plugins (including third-party ones supporting custom URL front matter).

I assume this feature is good enough to close this issue