Statiq.Web icon indicating copy to clipboard operation
Statiq.Web copied to clipboard

Related Posts?

Open codeease1 opened this issue 4 years ago • 3 comments

Hello all!

I am a newbie here. I am learning Wyam to try to convert my old blog site to a static content site. I have done most of things but just left several features. The one important feature is "Related Posts" or call "Read Also". I have tried to do myself (based on the existing tag links that Wyam can generates) but I don't know how to do for a single post, and I could not search a solution from the internet also.

We might know lots of CMS/blog site visitors come from the Google Searching and they quickly view an article to get the info that they are interested in and then probably quickly leave to continue the Google Searching. They don't like to use the website own search box (even if the site has one), but if each of our blog articles has put "Related Posts / Read Also" links (inline the post or bottom of the post), the visitor will see them, and it is very possible the visitor will click the links to continue to read our blog posts. This is very helpful to increase a website's visiting rate.

So would you share an example how to implement the "Related Post" feature? Can I know how to implement the related post links in either a blog website or a site just integrates Wyam? like this one .

Thanks!

codeease1 avatar Aug 25 '19 16:08 codeease1

I also had this question. I have done this e.g in here .

Implementation :

Pipelines["BlogPosts"].Append(
Meta("similarPosts", (doc, ctx) => {//get similar posts based on tags
        if(doc.Get<string[]>(BlogKeys.Tags) ==null)
         return null;
         //search all docs
        var docsWithSameTags = ctx.Documents.Where(c=> c.String("filename")!=doc.String("filename") //for other documents
              && c.Get<string[]>(BlogKeys.Tags) != null)//where tags are presented
              .Select(x=>(x,x.Get<string[]>(BlogKeys.Tags).Intersect(doc.Get<string[]>(BlogKeys.Tags)).Count() ))//get tuple: (document, numOfSameTags)
              .Where(x=>x.Item2>0)//remove docs with 0 same tags
              .OrderByDescending(x=>x.Item2).Take(5)//take five with topmost num of similar tags
              .Select(x=>x.Item1);// get documents from tuples
         return docsWithSameTags;
        
}));

And similarPosts meta is used here and here.

tesar-tech avatar Aug 26 '19 06:08 tesar-tech

Nice approach @tesar-tech. I'd also love to do something based on natural language processing in one or more of the themes for Statiq. In the meantime, this is probably the best approach until Statiq ships since Wyam will no longer be getting feature updates.

daveaglick avatar Aug 26 '19 12:08 daveaglick

Thank you @tesar-tech! I did not realize you have other configs in the pipeline so when I firstly just copied the code above it did not work, later I found the code needs other steps. So for the convenience of other new guys, let me copy the full config code that works for the related posts:

Pipelines["BlogPosts"].Append(
  Meta(Keys.RelativeFilePath, (doc, ctx) =>//change relative file path
  {   
    DateTime published = doc.Get<DateTime>(BlogKeys.Published);
    
    string fileName = doc.Bool("FrontMatterPublished")
      ? doc.FilePath(Keys.SourceFileName).ChangeExtension("html").FullPath
      : doc.FilePath(Keys.SourceFileName).ChangeExtension("html").FullPath.Substring(11);//when date is specified in fileName
    return $"{doc.Get<String>("RelativeFileDir")}/{fileName}";
    }));

Pipelines["BlogPosts"].Append(
   Meta ("fileName", (doc,ctx) => { 
     return doc.Get<String>("RelativeFilePath").Split('/').Last();}
    )
);

Pipelines["BlogPosts"].Append(
Meta("similarPosts", (doc, ctx) => {//get similar posts based on tags
        if(doc.Get<string[]>(BlogKeys.Tags) ==null)
         return null;
         //search all docs
        var docsWithSameTags = ctx.Documents.Where(c=> c.String("filename")!=doc.String("filename") //for other documents
              && c.Get<string[]>(BlogKeys.Tags) != null)//where tags are presented
              .Select(x=>(x,x.Get<string[]>(BlogKeys.Tags).Intersect(doc.Get<string[]>(BlogKeys.Tags)).Count() ))//get tuple: (document, numOfSameTags)
              .Where(x=>x.Item2>0)//remove docs with 0 same tags
              .OrderByDescending(x=>x.Item2).Take(5)//take five with topmost num of similar tags
              .Select(x=>x.Item1);// get documents from tuples
         return docsWithSameTags;        
}));

Then I put the code below into _PostFooter.schtml file (I changed tesar-tech's code a little bit for my blog site):

@{
   var similarPosts = Model.Get<List<IDocument>>("similarPosts");
}
@if(similarPosts !=null && similarPosts.Count()>0)
{
<p>
    <div class="clearfix">
        <h3>Related Posts:</h3>
        <ul>
            @foreach(var fil in similarPosts)
       {
            <li>               
                <a class="text-capitalize text-primary" href="@Context.GetLink(fil)">
                    @fil.WithoutSettings.String(BlogKeys.Title)
                </a>
            </li>
            }
        </ul>
    </div>
</p>
}

Now you can see the single post has related post links here.

BTW: I found tesar-tech's config code did not work for all existing posts, the "similar posts" returned empty, I have not known the reason.

codeease1 avatar Aug 28 '19 02:08 codeease1