Max character length of Discourse Replies below WP Posts


(Erik Molenaar) #1

Hi Discourse team,

Sometimes replies below WP Posts are very long. This is great content when reading directly in Discourse, but sometimes too much to handle to show below a WP Post. It can almost look kinda spammy.

A real live example is at: Multiple Spanning Tree (MST) | NetworkLessons.com. I always show 5 replies and the 4th reply is almost 16,000 pixels in height. Great when reading it in Discourse, but not so much below a post.

I would like to suggest to limit the length of the reply and show a link to continue reading the reply on Discourse.

Suggested settings in Wordpress plugin:

Thanks for listening and looking forward to your reply.


(Erik Molenaar) #2

I managed to write a function which uses the filter wpdc_comment_body to limit the length to 1000 characters, keeps complete words and closes the HTML tags.

However, I’d like to place a link to the reply at the text “…Continue reading in our forum”.

Anyone can help me out to complete this code? Thanks :slight_smile:

*-----------------------------------------------------------------------------------*/
/* Shortening content of Discourse replies below Wordpress posts
/*-----------------------------------------------------------------------------------*/

add_filter( 'wpdc_comment_body', 'wpdc_custom_comment_body' );
function wpdc_custom_comment_body( $content ) {

	// Truncate the next
	$new_content = truncate(
		$content, 1000,
		array(
			'html' => true,
			'ending' => '<strong>... Continue reading in our forum {discourse_url}</strong>')
	);
	
	return '<p>' . $new_content . '</p>';

}

/**
* Truncates text.
*
* Cuts a string to the length of $length and replaces the last characters
* with the ending if the text is longer than length.
*
* ### Options:
*
* - `ending` Will be used as Ending and appended to the trimmed string
* - `exact` If false, $text will not be cut mid-word
* - `html` If true, HTML tags would be handled correctly
*
* @param string  $text String to truncate.
* @param integer $length Length of returned string, including ellipsis.
* @param array $options An array of html attributes and options.
* @return string Trimmed string.
* @access public
* @link http://book.cakephp.org/view/1469/Text#truncate-1625
*/

function truncate($text, $length = 100, $options = array()) {
    $default = array(
        'ending' => '...', 'exact' => true, 'html' => false
    );
    $options = array_merge($default, $options);
    extract($options);

    if ($html) {
        if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
            return $text;
        }
        $totalLength = mb_strlen(strip_tags($ending));
        $openTags = array();
        $truncate = '';

        preg_match_all('/(<\/?([\w+]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER);
        foreach ($tags as $tag) {
            if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) {
                if (preg_match('/<[\w]+[^>]*>/s', $tag[0])) {
                    array_unshift($openTags, $tag[2]);
                } else if (preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag)) {
                    $pos = array_search($closeTag[1], $openTags);
                    if ($pos !== false) {
                        array_splice($openTags, $pos, 1);
                    }
                }
            }
            $truncate .= $tag[1];

            $contentLength = mb_strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3]));
            if ($contentLength + $totalLength > $length) {
                $left = $length - $totalLength;
                $entitiesLength = 0;
                if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE)) {
                    foreach ($entities[0] as $entity) {
                        if ($entity[1] + 1 - $entitiesLength <= $left) {
                            $left--;
                            $entitiesLength += mb_strlen($entity[0]);
                        } else {
                            break;
                        }
                    }
                }

                $truncate .= mb_substr($tag[3], 0 , $left + $entitiesLength);
                break;
            } else {
                $truncate .= $tag[3];
                $totalLength += $contentLength;
            }
            if ($totalLength >= $length) {
                break;
            }
        }
    } else {
        if (mb_strlen($text) <= $length) {
            return $text;
        } else {
            $truncate = mb_substr($text, 0, $length - mb_strlen($ending));
        }
    }
    if (!$exact) {
        $spacepos = mb_strrpos($truncate, ' ');
        if (isset($spacepos)) {
            if ($html) {
                $bits = mb_substr($truncate, $spacepos);
                preg_match_all('/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER);
                if (!empty($droppedTags)) {
                    foreach ($droppedTags as $closingTag) {
                        if (!in_array($closingTag[1], $openTags)) {
                            array_unshift($openTags, $closingTag[1]);
                        }
                    }
                }
            }
            $truncate = mb_substr($truncate, 0, $spacepos);
        }
    }
    
    if ($html) {
        foreach ($openTags as $tag) {
            $truncate .= '</'.$tag.'>';
        }
    }

	$truncate .= $ending;
    return $truncate;
}

(Erik Molenaar) #3

Please note the {discourse_url} in above code should be {comment_url}, but these are not parsed as these should be in HTML and not PHP.

Anyone more skilled in PHP out there who could take a look at my code? Thx :slight_smile: