Wyamio / Wyam

A modular static content and static site generator.
MIT License
141 stars 29 forks source link

Blog recipe posts in root URL #2

Closed jansotola closed 4 years ago

jansotola commented 4 years ago

We're migrating our blog to WYAM. For SEO reasons we'd like to keep our posts in root URL (not in /posts/ subfolder). For example /my-article-1 instead of /posts/my-article-1.

I know we can use redirects (using metadata RedirectFrom:), but it is not enough for us. We need the final (redirected) URL to stay in root.

When setting BlogKeys.PostsPath to /, an error "Rooted globbing patterns are not supported" occurs. When setting BlogKeys.PostsPath to empty string, an error "Access to the path 'c:\index.html' is denied." occurs (because WYAM is trying to overwrite index of homepage with index of archive page).

Is there any way how to do it properly?

daveaglick commented 4 years ago

It’s definitely possible, a couple different approaches come to mind. One way would be to override the output path at the end of the pipeline before the file gets written. Take a look at https://github.com/Wyamio/Wyam/issues/612#issuecomment-363944693 and the follow-up comments. I think that code is still valid but I’ve been so heads down in Statiq recently (the successor to Wyam) that I might be confusing parts of the two. Let me know if you run into any trouble adapting that code.

If that doesn’t work or seems to confusing/heavyweight let me know and I’ll brainstorm some alternatives. One of the things I love about how Wyam worked out is that it’s so flexible - the downside is that’s it’s not always immediately obvious the best way to customize something since there are so many possibilities :)

jansotola commented 4 years ago

Thanks! It has helped. The final code is here:

Pipelines["BlogPosts"].Append(
  Meta(Keys.RelativeFilePath, (doc, ctx) =>
  {
    // just copied from the original implementation
    string fileName = doc.Bool("FrontMatterPublished")
      ? doc.FilePath(Keys.SourceFileName).ChangeExtension("html").FullPath
      : doc.FilePath(Keys.SourceFileName).ChangeExtension("html").FullPath.Substring(11);
    // put posts to the blog root (don't add any path before the filename)
    return fileName;
  }));

Now I have the following environment:

So the main problem is solved. But it would be nice to change the archive URL to archive/ while keeping the posts source still in input/posts/. I can do it by setting URL rewriting rule on my production server, but doing it directly in WYAM would be better. Can you, please, advice, where to modify the pipeline to achieve this?

daveaglick commented 4 years ago

FYI - the original Wyam project is being moved to statiqdev to continue work there as Statiq Web (the successor to Wyam and the Wyam blog recipe). Since this issue relates specifically to Wyam, I've transfered it to a new replacement project for legacy Wyam issues.

jansotola commented 4 years ago

I've managed to do renaming of the "Archive" page web folder by rewriting BlogArchive pipeline. It may be a dirty and brute force solution but it works:


int archiveIndex = Pipelines.IndexOf("BlogArchive");
Pipelines.Remove("BlogArchive");
Pipelines.Insert(archiveIndex, "BlogArchive",
  // most of the lines have been copied from WYAM Blog.cs
  new Wyam.Web.Pipelines.ConditionalPipeline(
    ctx => ctx.Bool(BlogKeys.GenerateArchive),
    new Wyam.Web.Pipelines.Archive(
      "BlogArchive",
      new Wyam.Web.Pipelines.ArchiveSettings
      {
        Pipelines = new string[] { "BlogPosts" },
        TemplateFile = ctx => "_Archive.cshtml",
        Layout = "/_Layout.cshtml",
        PageSize = ctx => ctx.Get(BlogKeys.ArchivePageSize, int.MaxValue),
        Title = (doc, ctx) => "Archive",
        // the only redefined line
        RelativePath = (doc, ctx) => $"{ctx.DirectoryPath(BlogKeys.PostsPath, ".").FullPath.Replace(ctx.String(BlogKeys.PostsPath), "archive")}"
      })));
qqq
daveaglick commented 4 years ago

Great, glad you found a solution!