Forum Discussion

DougS's avatar
DougS
Khoros Oracle
14 years ago

Latest 3 blog articles (Freemarker)

Taken from http://lithosphere.lithium.com/t5/Everything-Studio/Cross-promote-blogs-and-discussion-boards/m-p/19658#M80 with big thanks to Kaela!

 

Description

Displays the Subject and Teaser (if there is a teaser) of the latest 3 blog articles in the community.

 

Requirements

Lithium version 9.18 or higher, Lithium Studio

 

How to add this to a Lithium community

 

1. Navigate to Lithium Studio
2. The first thing we want to do is add text keys that we will use in the component we create:

2a. Go to the Text Editor tab.
2b. Click the Search button.
2c. Enter the following custom text keys for the "posted by" label (include {0} to represent a variable our component will pass in to fill in the screen name of the user who posted the blog article) and for the "read more" link text, then click the save button:

 

 

custom.component.latest_three_blog_articles.posted_by = Posted By {0}
custom.component.latest_three_blog_articles.read_more = Read More

 

 

3. The next thing we will want to do is create our custom component:

3a. Go to the Components tab.
3b. Create a new component – name it whatever you like. I called it latest-three-blog-articles.
3c. Add the following markup to the component and click the save button:

 

 

<#assign messages = rest("/topics/style/blog/recent?page_size=3").messages />
<div class="custom-recent-articles-container">
  <#list messages.message as message>
    <#assign posted_by_userid = message.author.login?string />
    <#if posted_by_userid == "Anonymous">
      <#assign posted_by_userid = "" />
    </#if>
    <#assign posted_by_label = text.format("custom.component.latest_three_blog_articles.posted_by", posted_by_userid) />
    <div class="custom-recent-article-wrapper">
      <div class="custom-article-header">		
        <div class="custom-article-subject">
	      <a href="${message.@view_href}">${message.subject}</a>
	    </div>
        <div class="custom-article-posted-by">
          <span class="author">${posted_by_label}</span>
        </div>
      </div>
      <div class="custom-article-teaser">
        <#if message.teaser?length gt 0>
          ${message.teaser}
          <span class="custom-read-more"><a href="${message.@view_href}">${text.format("custom.component.latest_three_blog_articles.read_more")}</a></span>
        </#if>		
      </div>
    </div>
  </#list>
</div>

 

4. Next we want to decide where on the community we want to place the new component we have created. In this example we'll place it only on the community page, in the "main-content" section of the page:

4a. Go to the Page tab – the "Community Page" should be selected in the "Page Type" drop-down, but select it if it is not.
4b. In the Components bar on the left, expand "Custom Components" and hover over the component you added, then click the "Add" link to add the component onto the page – the component will appear in the "common-header" section of the page. Hover over your components you just added until you see the 4-directional arrow icon appear then drag and drop the component somewhere on the "main-content" section of the page.
4c. Click the save button at the bottom of the Page tab to save your page changes.

5. Next let's look at our changes so far:

5a. Navigate to the community page. You should see the component on the main section of the page. It doesn't look styled very well, so we should add some css selectors to style it. Also, we've decided we would like more than just the screen name to display – we'd also like to see the rank of the user and have the user's screen name hyperlink to their profile page. We could write custom logic for this, or we could use a core component named common.widget.user-name that already does this for us. First let's add in the core component, then we'll add some css styling. Let's also add a title for this component, but only have it show if there is at least 1 blog article.
5b. Go to the Components tab and click on the component you created.
5c. Change the markup to something more like this:

 

 

<#assign messages = rest("/topics/style/blog/recent?page_size=3").messages />
<div class="custom-recent-articles-container">
  <#if messages.message?size gt 0>
    <div class="custom-recent-articles-heading-bar">
      <span class="custom-recent-articles-heading-bar-title">${text.format("custom.component.latest_three_blog_articles.title")}</span>
    </div>
  </#if>
  <#list messages.message as message>
    <#assign posted_by_userid = message.author.login?string />
    <#assign posted_by_label = text.format("custom.component.latest_three_blog_articles.posted_by") />
    <div class="custom-recent-article-wrapper">
      <div class="custom-article-header">		
        <div class="custom-article-subject">
	      <a href="${message.@view_href}">${message.subject}</a>
	    </div>
        <div class="custom-article-posted-by">
          <span class="author">${posted_by_label} <#if ((posted_by_userid != "") && (posted_by_userid != "Anonymous"))><@component id="common.widget.user-name" user="conv:${message.author.login}" /></#if></span>
        </div>
      </div>
      <div class="custom-article-teaser">
        <#if message.teaser?length gt 0>
          ${message.teaser}
          <span class="custom-read-more"><a href="${message.@view_href}">${text.format("custom.component.latest_three_blog_articles.read_more")}</a></span>
        </#if>		
      </div>
    </div>
  </#list>
</div>

 

5d. We'll also want to go back to the Text Editor tab, add the component title text key, and change the text key value we added for the "posted by label" so it doesn't take a parameter any longer, something like this:

 

 

custom.component.latest_three_blog_articles.title = Latest Blog Entries
custom.component.latest_three_blog_articles.posted_by = Posted By:

 

6. Finally, let's add some css to our community skin to style the component:

6a. Go to the Community Style tab
6b. Click on an existing custom skin if you already have one, or click the "new skin" button to create a new skin.
6c. Click on the CSS sub-nav and add the following CSS:

 

 

 

#lia-body .lia-content .custom-recent-articles-container .custom-recent-articles-heading-bar { padding:0 10px 5px; margin:0 0 5px; }
#lia-body .lia-content .custom-recent-articles-container .custom-recent-articles-heading-bar-title { line-height:27px; font-size:27px; color:#${color_primary_01}; }
#lia-body .lia-content .custom-recent-articles-container .custom-recent-article-wrapper { padding:3px 0; border-bottom: 1px solid #E5E5E5; margin:0 10px 5px; }
#lia-body .lia-content .custom-recent-articles-container .custom-recent-article-wrapper .custom-article-subject { font-weight:bold; }

 

Example

 

Go to the Code Sample 3 Example Page to see this in action.

 

 

  • Thank you for this excellent documentation and code sample for displaying the latest three blog entries from the community in a custom component.

     

    I have taken this and added it to our community and it is working well, however I would like to make it display like the Lithosphere version, which includes a teaser image on the left, then the title and teaser in the middle and all the way to the right is the friendly date, the author name and a tiny thumbnail of the author.

     

    Here is a snapshot of the Lithosphere recent blog articles captured from the home page of the community today.  What I would like to know is where to the teaser images come from?  Are they coming from a special location, or are they simply included in the teaser of the blog by policy?

     

    Lithosphere recent blog articles

     

    I would also like to know where to get the tiny thumbnails for the author are found.  Are they standard or custom?

     

    Thanks again for the great post.

    • MoniqueL's avatar
      MoniqueL
      Lithium Alumni (Retired)

      "What I would like to know is where to the teaser images come from?"

       

      For that particular component, some free marker has been added to pull in an image if an image has been added to the blog teaser section when a blog author is drafting their article. If the author fails to add a custom image specific to that blog teaser/article, then it'll pull in the "generic" Li image"

       

      Also note that some css has been added to force the blog teaser images in this component to be the same square size as the li image, for a more uniform look. I would suggest tweaking the css or simply not relying on the css but rather try to have your creative team and/or blog authors crop & create images for blog teasers that are a consistent in size & ratio so you avoid image distortion that you sometimes see on the lithosphere

       

      <td class="image<#if thisRow == 3> last</#if>">			
      			<#assign teaser = message.teaser />
      			<#assign imageLink = "&nbsp;" />
      			<#assign imgPosB = teaser?index_of("<IMG src=") />			
      			<#if (imgPosB > 0) >
      				<#assign teaser2 = teaser?substring(imgPosB) />
      				<#assign imgPosE = teaser2?index_of("/>") />		
      				<#if (imgPosE >0) >
      					<#assign imageLink = teaser2?substring(0, imgPosE) + " height=110px width=110px /> " />
      					<#assign teaser = teaser?substring(0, imgPosB) + teaser2?substring(imgPosE+2) />
      				</#if>
      			</#if>			
      				<div style="width: 110px; height: 110px; background-image: url('/html/assets/blogfeedimgsquare-blue.png'); border-radius: 2px;"> ${imageLink} </div>
      			</td>

       

       

       

      "I would also like to know where to get the tiny thumbnails for the author are found.  Are they standard or custom?"

       

      They're standard in the sense that the particular freemaker code here is reference the message size version of the avatar but relying on specifically written css for this component to shrink the image down.

       

      <td class="created<#if thisRow == 3> last</#if>">
                      <div id="date"><#if (useFriendlyDate) >${message.post_time.@view_friendly_date}<#else>${message.post_time.@view_date?date("MM-dd-yyyy")}</#if></div>
                      <#assign avatar = rest(message.author.@href + "/profiles/avatar/size/message").image>
                      <div id="authors"><a href="${message.author.@view_href}">${message.author.login}</a> <a href="${message.author.@view_href}"><img src="${avatar.url}" title="${message.author.login}" /></a></div>
                  </td

       

       

      • ebroyles's avatar
        ebroyles
        Maven

        Thank you very much, MoniqueL, for answering my questions directly and providing the exact code to do what I wanted.  I have implemented that in my custom component and it works just as claimed.

         

        Before you responded, I had come up with my own solution which is slightly different, and I will share with the community in case it may be of value to anyone.  Not knowing how to include an image in the teaser but be able to yank it out and display it elsewhere (which is effectively what MoniqueL's solution does), I made use of the REST API and the fact that a message has an images collection.

         

        Here is the relevant portion of the code.

        <td class="image">
                    <#assign images_for_message = rest("${message.@href}/images").images />
                        <div style="width: 110px; height: 110px; margin: 0px 10px 10px 0px; background-image: url('/html/assets/community-blog-teaser-background-110.jpg'); border-radius: 2px;">
                      <#if images_for_message?size gt 0>
                      <#list images_for_message.image as image>
                        <img src="${image.thumbnail.url}" alt="${image.title}" title="${image.title}" border="0" align="left" width="110px" height="110px"/>
                        <#break>
                      </#list>
                      </#if>
                      </div>
                    </td>

        This calls the REST API to get a list of the images for the message and then loops through them (if any exist) and displays the thumbnail version of the first one it finds, ignoring all the others. It carries the same caveat that MoniqueL's code carries with respect to the sizing of images, though it specifically sizes the image right here in the code rather than relying on separate CSS styles.

         

        MoniqueL's code has the advantage of enabling the author to decide which image to include in the teaser and also choose an appropriate size, and for that reason I prefer it over my original solution.