Monday Jan 05, 2009

Related entries

[Originally posted by Wayne Horkan]

Do you have lots of blog postings, possibly over a number of years? And do you suspect that despite embedding search and tag clouds into your blog that your readers are still not finding content related to that they enjoy? In fact do you have evidence of that very problem from your web analytics data but don't know what to do about it? Yes? So did I, so I created this roller weblogger code to generate a list of the most related blog entries based upon tag and category relationships.

To show you what I mean, here's examples for a couple of blog entries:

Messaging Sub-Systems in the UK Government

and

My banana yellow Yamaha V-Max

The way this works is that for any given individual blog post it attempts to match both category and tags to genuinely find the most related entries (first it cycles though entries related by the same category for tag matches, then though an aggregate of all categories for tag matches, and finally, just those related by category alone).

So this has to be my favourite roller weblogger functionality to date; simply because it offers up the most pertinent content to that which the reader is currently looking at, based upon tag affinity, without forcing them to search or link endlessly though tag clouds (which often contain large number of posts that have very little related contextual meaning).

Here's the code:


					
						
## Related Entries
## Cycles through 100 articles of the same category - look for entries with tag matches - order by no. of matches
## Cycles through  20 articles of any category (ignoring the previous category) - look for entries with tag matches - order by no. of matches
## If still not enough items in the menu adds the most recent entries from the same category

    #if ($model.permalink)

        ## number to display (in menu) 
        #set ($dispFlag = 10)
        
        ## Cycles through 100 articles of the same category
        #set ($cycleEntriesTotal = 100)
        
        ## Go through same category first - should get most hits 
        #set ($cycleEntries = $model.weblog.getRecentWeblogEntries($model.weblogEntry.category.name, $cycleEntriesTotal))

        ## Set up other variables
        #set ($theseTags = $entry.tags)
        #set ($sawEntries = [] )
        #set ($sawCount = [] )

        #foreach ($cycleEntry in $cycleEntries)

            #if (($entry.title != $cycleEntry.title) && ($model.weblogEntry.locale == $cycleEntry.locale))

                #set ($matchBun = 1)
                #set ($bunTags = $cycleEntry.tags)

                #foreach ($thisTag in $theseTags)
                    #foreach ($bunTag in $bunTags)
                        #if ($thisTag.name == $bunTag.name)
                            #set ($matchBun = $matchBun + 1)
                        #end
                    #end
                #end

                #if ($matchBun >= 2)

                    #set ($bunEntry = $cycleEntry)
                    #set ($entryCounter = 0)
                    #set ($bunFlag = 0)

                    #foreach ($sawNum in $sawCount)
                        #if (($matchBun > $sawNum) || (($bunFlag == 1) && ($matchBun == $sawNum)))
                            #if ($bunFlag == 0)
                                #set ($bunFlag = 1)
                            #end
                            #set ($bunEntry = $sawEntries.set($entryCounter, $bunEntry))
                            #set ($matchBun = $sawCount.set($entryCounter, $matchBun))
                        #end
                        #set ($entryCounter = $entryCounter + 1)
                    #end

                    #if ($entryCounter <= $dispFlag)
                        #if ($sawEntries.add($bunEntry))
                        #end
                        #if ($sawCount.add($matchBun))
                        #end
                    #end

                #end

            #end

        #end
       
        ## Cycles through  20 articles of any category (ignoring the previous category)
        #set ($cycleEntriesTotal = 20)
        
        ## Go through all categories next - should get fewer hits 
        #set ($cycleEntries = $model.weblog.getRecentWeblogEntries("", $cycleEntriesTotal))

        ## Reset other variables
        #set ($theseTags = $entry.tags)

        #foreach ($cycleEntry in $cycleEntries)

            #if (($entry.title != $cycleEntry.title) && ($entry.category.name != $cycleEntry.category.name) && ($model.weblogEntry.locale == $cycleEntry.locale))

                #set ($matchBun = 0)

                #set ($bunTags = $cycleEntry.tags)
                #foreach ($thisTag in $theseTags)
                    #foreach ($bunTag in $bunTags)
                        #if ($thisTag.name == $bunTag.name)
                            #set ($matchBun = $matchBun + 1)
                        #end
                    #end
                #end

                #if ($matchBun >= 1)

                    #set ($bunEntry = $cycleEntry)
                    #set ($entryCounter = 0)
                    #set ($bunFlag = 0)

                    #foreach ($sawNum in $sawCount)
                        #if (($matchBun > $sawNum) || (($bunFlag == 1) && ($matchBun == $sawNum)))
                            #if ($bunFlag == 0)
                              #set ($bunFlag = 1)
                            #end
                            #set ($bunEntry = $sawEntries.set($entryCounter, $bunEntry))
                            #set ($matchBun = $sawCount.set($entryCounter, $matchBun))
                        #end
                        #set ($entryCounter = $entryCounter + 1)
                    #end

                    #if ($entryCounter <= $dispFlag)
                        #if ($sawEntries.add($bunEntry))
                        #end
                        #if ($sawCount.add($matchBun))
                        #end
                    #end

                #end

            #end

        #end

        <ul class="rEntriesList">

        ## Set up count variables
        #set ($noneFlag = 0)
        #set ($entryCounter = 0)

        ## Output related entries
        #foreach ($sawEntry in $sawEntries)

            #if ($noneFlag < $dispFlag)        
                #set ($noneFlag = $noneFlag + 1)
                #set ($matchBun = $sawCount.get($entryCounter))
                <li class="recentposts"><a href="$url.entry($sawEntry.anchor)" title="relationships: $matchBun" name="$utils.encode($sawEntry.anchor)" id="$utils.encode($sawEntry.anchor)">» $sawEntry.title</a></li>
            #end

            #set ($entryCounter = $entryCounter + 1)

        #end

        ## If still not enough items in the menu adds the most recent entries from the same category
        #if ($noneFlag < $dispFlag)

            ## Cycle though the number to be displayed (plus one including the 'calling' entry itself) 
            #set ($cycleEntriesTotal = ($dispFlag + 1))

            ## Reset variables
            #set ($cycleEntries = $model.weblog.getRecentWeblogEntries($model.weblogEntry.category.name, $cycleEntriesTotal))
  
            ## Cycle though the number to be displayed (plus one including the 'calling' entry itself) 
            #foreach ($cycleEntry in $cycleEntries)
  
                #set ($addFlag = 0)
                
                #foreach ($sawEntry in $sawEntries)
                    #if ($sawEntry.title == $cycleEntry.title)
                        #set ($addFlag = 1)
                    #end
                #end        

                #if ($addFlag == 0)
                    #if ($noneFlag < $dispFlag)        
                        #if (($entry.title != $cycleEntry.title) && ($model.weblogEntry.locale == $cycleEntry.locale))
                            #set ($noneFlag = $noneFlag + 1)
                            <li class="recentposts"><a href="$url.entry($cycleEntry.anchor)" title="relationships: 1" name="$utils.encode($cycleEntry.anchor)" id="$utils.encode($cycleEntry.anchor)">» $cycleEntry.title</a></li>
                        #end
                    #end
                #end

            #end

        #end

        </ul>

    #end




											
						
					
					
										

After writing this article I got a mention by Dave Johnson, which inspired me to change the code based on his comments so it only grabs the last 100 entries of the same category and then the last 20 entries of the other categories to analyse. Obviously you can change this by editing #set ($cycleEntriesTotal = 100) to whatever you feel appropriate.

I've also removed all redundant variables, fixed a bug due to non-allocation of variables, and changed the sort code so that it keeps date and time based precedence (so entries with the same number of matches will remain in date and time sequence).

Rather than repost another article I've retconned the code example into this article; the code displayed is the newer, healthier code; the old code is still there, but hidden in a non-displayed "div" code block at the end (just after this text in fact).

## Related Entries #if ($model.permalink) #set ($theseTags = $entry.tags) #set ($sawEntries = [] ) #set ($tempEntryFlag = 0) #set ($cycleEntriesTotal = 1000) ## Go through same category first - should get most hits #set ($cycleEntries = $model.weblog.getRecentWeblogEntries($model.weblogEntry.category.name, $cycleEntriesTotal)) #set ($flagProc = 0) #set ($sawCount = [] ) #foreach ($cycleEntry in $cycleEntries) #set ($matchBun = 0) #if (($entry.title != $cycleEntry.title) &amp;&amp; ($model.weblogEntry.locale == $cycleEntry.locale)) #set ($bunTags = $cycleEntry.tags) #foreach ($thisTag in $theseTags) #foreach ($bunTag in $bunTags) #if ($thisTag.name == $bunTag.name) #set ($matchBun = $matchBun + 1) #end #end #end #end #if ($matchBun &gt;= 1) #set ($bunEntry = $cycleEntry) #set ($entryCounter = 0) ## Loop through tags - sorting #foreach ($sawNum in $sawCount) #if ($matchBun &gt; $sawNum) #set ($bunEntry = $sawEntries.set($entryCounter, $bunEntry)) #set ($matchBun = $sawCount.set($entryCounter, $matchBun)) #end #set ($entryCounter = $entryCounter + 1) #end #if ($sawEntries.add($bunEntry)) #end #if ($sawCount.add($matchBun)) #end #end #end #if ($noneFlag &lt; $dispFlag) #set ($theseTags = $entry.tags) #set ($tempEntryFlag = 0) #set ($cycleEntriesTotal = 1000) ## Go through all categories next - should get fewer hits #set ($cycleEntries = $model.weblog.getRecentWeblogEntries(&quot;&quot;, $cycleEntriesTotal)) #foreach ($cycleEntry in $cycleEntries) #set ($matchBun = 0) #if (($entry.title != $cycleEntry.title) &amp;&amp; ($model.weblogEntry.locale == $cycleEntry.locale)) #set ($bunTags = $cycleEntry.tags) #foreach ($thisTag in $theseTags) #foreach ($bunTag in $bunTags) #if ($thisTag.name == $bunTag.name) #set ($matchBun = $matchBun + 1) #end #end #end #end #if ($matchBun &gt;= 2) #set ($bunEntry = $cycleEntry) #set ($entryCounter = 0) ## Loop through tags - sorting #foreach ($sawNum in $sawCount) #if ($matchBun &gt; $sawNum) #set ($bunEntry = $sawEntries.set($entryCounter, $bunEntry)) #set ($matchBun = $sawCount.set($entryCounter, $matchBun)) #end #set ($entryCounter = $entryCounter + 1) #end #if ($sawEntries.add($bunEntry)) #end #if ($sawCount.add($matchBun)) #end #end #end #end &lt;ul class=&quot;rEntriesList&quot;&gt; #set ($noneFlag = 0) #set ($dispFlag = 10) #set ($entryCounter = 0) #foreach ($sawEntry in $sawEntries) #if ($noneFlag &lt; $dispFlag) #set ($noneFlag = $noneFlag + 1) #set ($matchBun = $sawCount.get($entryCounter)) &lt;li class=&quot;recentposts&quot;&gt;&lt;a href=&quot;$url.entry($sawEntry.anchor)&quot; title=&quot;relationships: $matchBun&quot; name=&quot;$utils.encode($sawEntry.anchor)&quot; id=&quot;$utils.encode($sawEntry.anchor)&quot;&gt;» $sawEntry.title&lt;/a&gt;&lt;/li&gt; #end #set ($entryCounter = $entryCounter + 1) #end #if ($noneFlag &lt; $dispFlag) #set ($cycleEntriesTotal = 50) #set ($cycleEntries = $model.weblog.getRecentWeblogEntries($model.weblogEntry.category.name, $cycleEntriesTotal)) #foreach ($cycleEntry in $cycleEntries) #set ($addFlag = 0) #foreach ($sawEntry in $sawEntries) #if ($sawEntry.title == $cycleEntry.title) #set ($addFlag = 1) #end #end #if ($addFlag == 0) #if ($noneFlag &lt; $dispFlag) #if (($entry.title != $cycleEntry.title) &amp;&amp; ($model.weblogEntry.locale == $cycleEntry.locale)) #set ($noneFlag = $noneFlag + 1) &lt;li class=&quot;recentposts&quot;&gt;&lt;a href=&quot;$url.entry($cycleEntry.anchor)&quot; title=&quot;relationships: 1&quot; name=&quot;$utils.encode($cycleEntry.anchor)&quot; id=&quot;$utils.encode($cycleEntry.anchor)&quot;&gt;» $cycleEntry.title&lt;/a&gt;&lt;/li&gt; #end #end #end #end #end &lt;/ul&gt; #end

Roller Archive Menu

[Originally posted by Wayne Horkan]

Whenever I read my friends blogs who host on Blogger I always admire the archive menu that comes as standard; it's pretty neat and really helps when you have a large number of blog posts over a number of years (something that bothers me because if a reader enjoys a blog post I want to make it as easy as possibly for them to find other, similar and related posts, but more on this later).

So I mocked up this simple, yet effective, version which produces a similar, self-generating, archive menu list.

Here's an example:

And here's the code (and don't forget to change the $startYear and $startMonth variables to the year and month you started your blog as well as using your blog handle instead of 'eclectic'):


## Blog Start Year
#set ($startYear  = 2007)

## Blog Start Month
#set ($startMonth = 4)

## Get the current Year and Month
#set ($countYear  = $now.getYear() + 1900)
#set ($countMonth = $now.getMonth() + 1)

## Text Adjust

#set ($zero = 0)

## Total number of years to cycle through
#set ($numberYear  = $countYear - $startYear)

<ul class="rEntriesList">

#foreach ($number in [0..$numberYear])

  #if ($countYear >= $startYear)

    ## Months in a year
    #foreach ($number in [1..12])

      #if  (($countMonth != 0) && ((($countYear > $startYear) || (($countYear == $startYear) && ($countMonth >= $startMonth)))))

        <li class="recentposts">

        #if ($countMonth     ==  1)
          #set ($nameMonth = "January")
        #elseif ($countMonth ==  2)
          #set ($nameMonth = "February")
        #elseif ($countMonth ==  3)
          #set ($nameMonth = "March")
        #elseif ($countMonth ==  4)
          #set ($nameMonth = "April")
        #elseif ($countMonth ==  5)
          #set ($nameMonth = "May")
        #elseif ($countMonth ==  6)
          #set ($nameMonth = "June")
        #elseif ($countMonth ==  7)
          #set ($nameMonth = "July")
        #elseif ($countMonth ==  8)
          #set ($nameMonth = "August")
        #elseif ($countMonth ==  9)
          #set ($nameMonth = "September")
        #elseif ($countMonth == 10)
          #set ($nameMonth = "October")
        #elseif ($countMonth == 11)
          #set ($nameMonth = "November")
        #elseif ($countMonth == 12)
          #set ($nameMonth = "December")
        #end

        #if ($countMonth > 9)
          <a href="/eclectic/?date=$countYear$countMonth">» $nameMonth, $countYear</a>
        #else
          <a href="/eclectic/?date=$countYear$zero$countMonth">» $nameMonth, $countYear</a>
        #end

        </li>

        #set ($countMonth = $countMonth - 1)

      #end
 
    #end

  #set ($countMonth = 12)

##</ul>

  #end

#set ($countYear = $countYear - 1)

#end

</ul>

About

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today