Show "Read more" link if the $Content has more charaters than the set limit

Silverstripe Version: 4.*

Question:

Is there an option to get number of characters of content and summary in the template?
I’m showing “Read more” links in the blog post summary. And this works nicely.
But I wish to show “Read more” only if there is something more to read.

<% if $Summary %>
  <p class="l-card_excerpt">$Summary.LimitCharacters(350)</p>
<% else %>
  <p class="l-card_excerpt">$Content.LimitCharacters(350)</p>
<% end_if %>
// I want to show this link only if there is something more to read
// i.e. $Content has more than 350 chars
<a href="$link" class="read_more">Read more ></a>

Is there an option to get number of characters? Something in the lines of $Content.Length,…

This seems to work, but I don’t think this is the correct approach :slight_smile:

<% if $Summary.LimitCharacters(350) > $Summary.LimitCharacters(351) || $Content.LimitCharacters(350) > $Content.LimitCharacters(351) %>
      <a href="$link" class="read_more">Read more ></a>
<% end_if %>

How can that work? $*.LimitCharacters(350) cannot be greater than $*.LimitCharacters(351), or can it?

First of all I would fold that <% if %> branch into the controller, e.g.:

public function Stuff()
{
    return $this->Summary ? $this->Summary : $this->Content;
}

Then your template could become:

<p class="l-card_excerpt">$Stuff.LimitCharacters(350)</p>
<% if $Stuff.LimitCharacters(350) != $Stuff %>
  <a href="$link" class="read_more">Read more ></a>
<% end_if %>

, or can it?
At first I wrote the non working right way. And then without really thinking changed the less than to greater than and it started working. For some reason it works only if it is “wrong”.

I’m “printing” the read more in the <% loop $AllBlogPosts %> which I get with return BlogPost::get()->filter()...
Perhaps I should create a custom DataList and handle it there. I was hoping there was an option for this that I missed in the manual docs.

As mentioned, I think you’re better off moving a lot of this logic out of the template and into your PHP files. I’d suggest the template isn’t the best place for it.

In terms of your comparison, LimitCharacters returns a string, so a ‘greater than’ or ‘less than’ comparison is never going to make a lot of sense.

I think I’d just create a method which deals with the number of characters in your content (don’t forget to strip out the HTML tags) and then use that in the template as the condition for showing the read more link.

eg:

public function getShowReadMore()
{
  return (strlen(strip_tags($this->Content)) > 350) || (strlen(strip_tags($this->Summary) > 350);
}

And in your template:

<% if $ShowReadMore %>
  <a href="$link" class="read_more">Read more ></a>
<% end_if %>

Disclaimer: All completely untested and probably won’t work without a little tweaking!

I wrote that while I was searching for an option I could use - similar to $*.LimitCharacters(350).
I tried using custom functions, but the problem is, that they don’t seem to work inside the loop. I wanted to ask if it was somehow possible to make smth like this work without writing a custom DataList:

<% loop $AllBlogPosts %>
  <article class="l-card">
    <a href="$link" class="l-card_title">$Title</a>    
    <% loop $Categories %>  
       <a href=""><span>$Title</span></a>
     <% end_loop %>
    
    <p class="l-card_excerpt">$Stuff.LimitCharacters(350)</p>
      <% if $Stuff.LimitCharacters(350) != $Stuff %>
        <a href="$link" class="read_more">Read more ></a>
      <% end_if %>
  </article>
<% end_loop %>

For another approach I was thinking I would add the "$Stuf" into the BlogPost::get(); DataList or write the complete custom DataList.

Inside the loop, you’re in the scope of a BlogPost.

If you create an extension class, containing the functions, you can apply it to the BlogPost class, and it should all magically work.

Ah yes. I think this will be the way to go. Thnx