Search code examples
phphtmlstringsubstringtrim

Facebook-like "show more" button for a string with URLs


I'm trying to have a feature that acts like Facebook's show more behaviour. I want it to trim the string if:

  • its length is more than 200 characters.
  • there are more than 5 /n occurrences.

It sounds simple and I already have an initial function (that does it only by length, I haven't implemented the /n occurrences yet):

function contentShowMore($string, $max_length) {
    if(mb_strlen($string, 'utf-8') <= $max_length) {
        return $string; // return the original string if haven't passed $max_length
    } else {
        $teaser = mb_substr($string, 0, $max_length); // trim to max length
        $dots = '<span class="show-more-dots"> ...</span>'; // add dots
        $show_more_content = mb_substr($string, $max_length); // get the hidden content
        $show_more_wrapper = '<span class="show-more-content">'.$show_more_content.'</span>'; // wrap it

        return $teaser.$dots.$show_more_wrapper; // connect all together for usage on HTML.
    }
}

The problem is that the string might include URLs, so it breaks them. I need to find a way to make a functional show-more button that checks length, newlines and won't cut URLs.

Thank you!

Example:

input: contentShowMore("hello there http://google.com/ good day!", 20).

output:

hello there http://g
<span class="show-more-dots"> ...</span>
<span class="show-more-content">oogle.com/ good day!</span>

the output i want:

hello there http://google.com/
<span class="show-more-dots"> ...</span>
<span class="show-more-content"> good day!</span>

Solution

  • found a solution!

    function contentShowMore($string, $max_length, $max_newlines) {
    
        $trim_str = trim($string);
    
        if(mb_strlen($trim_str, 'utf-8') <= $max_length && substr_count($trim_str, "\n") < $max_newlines) { // return the original if short, or less than X newlines
            return $trim_str;
        } else {
            $teaser = mb_substr($trim_str, 0, $max_length); // text to show
            $show_more_content = mb_substr($trim_str, $max_length);
    
            // the read more might have cut a string (or worse - an URL) in the middle of it.
            // so we will take all the rest of the string before the next whitespace and will add it back to the teaser.
            $content_parts = explode(' ', $show_more_content, 2); // [0] - before first space, [1] - after first space
            $teaser .= $content_parts[0];
    
            if(isset($content_parts[1])) { // if there are still leftover strings, its on show more! :)
                $show_more_content = $content_parts[1];
            }
    
            // NOW WERE CHEKING MAX NEWLINES.
            $teaser_parts = explode("\n", $teaser); // break to array.
            $teaser = implode("\n", array_slice($teaser_parts, 0, $max_newlines)); // take the first $max_newlines lines and use them as teaser.
            $show_more_content = implode("\n", array_slice($teaser_parts, $max_newlines)) . ' ' . $show_more_content; // connect the rest to the hidden content.
    
            if(mb_strlen($show_more_content, "UTF-8") === 0) {
                return $trim_str; // nothing to hide - return original.
            } else {
                $show_more_wrapper = '<span class="show-more-content">'.$show_more_content.'</span>';
    
                $dots = '<span class="show-more-dots"> ...</span>'; // dots will be visible between the teaser and the hidden.
                $button = ' <span class="show-more">Show more</span>';
    
                return $teaser.$dots.$button.$show_more_wrapper; // connect ingredients
            }
    
        }
    }