Page 1 of 2

Auto-linking Reddit References

Posted: Sun Dec 09, 2018 3:47 pm
by romans1423
I've been out of the phpBB game for a long time, and I'm having trouble wrapping my mind around how extensions are built/structured. This feels like it should be a simple thing to accomplish but I'm just not getting it...

Anyway, I want to automatically link Reddit references in posts on my board. There are two kinds:

r/subredditname -- these always take the form of r/ followed by a string containing letters, numbers, and underscores (underscore can't be the first character). When detected, these should be automatically turned into a link of the form:

Code: Select all

<a href="https://www.reddit.com/r/subredditname" target="_new">r/subredditname</a>
u/username -- these always take the form of u/ followed by a string containing letters, numbers, underscores, and dashes. When detected, these should be automatically turned into a link of the form:

Code: Select all

<a href="https://www.reddit.com/user/username" target="_new">r/username</a>
Any help would be appreciated!

Re: [REQUEST] Auto-linking Reddit References

Posted: Sun Dec 09, 2018 6:24 pm
by mrgoldy
And why not simply create a BBCode for those instances?
So it will be something like [reddit]r/subreddit[/reddit. Which then automatically turned into a link with its HTML replacement?
Or does this per sé have to be automatic parsing when a post text contains r/subreddit?

Re: Auto-linking Reddit References

Posted: Sun Dec 09, 2018 7:32 pm
by romans1423
I have a BBCode already set up ([r]) for this, but we're wanting it to be automated, which is the behavior on not only Reddit but also Facebook Messenger when simply typing a subreddit name. Automatic linking is far more intuitive, I think.

Re: Auto-linking Reddit References

Posted: Sun Dec 09, 2018 8:08 pm
by mrgoldy
Okay, well if you want to get into the 'extension' side of things, this documentation will help you out:
- https://area51.phpbb.com/docs/dev/3.2.x ... index.html

And the phpBB Skeleton Extension will give you a head start on some of the files:
- https://area51.phpbb.com/docs/dev/3.2.x ... nsion.html

You will mostly need the new s9e text formatter and alter the parsing and/or rendering to your needs.
- https://area51.phpbb.com/docs/dev/3.2.x ... ode-engine

Re: Auto-linking Reddit References

Posted: Tue Dec 11, 2018 6:19 am
by romans1423
OK, I've gotten this far... I have a working extension installed, I've figured out how to modify the text of posts a bit, but now I can't figure out how to actually piece together the code I have. When in use, it simply blanks out every post -- whoops. I mimicked the phpBB code that makes email addresses clickable as closely as I could understand it. The functions I copied/trimmed down were make_clickable() and make_clickable_callback().

Code: Select all

class main_listener implements EventSubscriberInterface
{
	static public function getSubscribedEvents()
	{
		return array(
			'core.modify_text_for_display_after'	=> 'autolink_reddit_references',
		);
	}

	public function make_reddit_reference_clickable_callback($matches)
	{
		// make sure no HTML entities were matched
		$chars = array('<', '>', '"');
		$split = false;

		$url = $matches[2];

		foreach ($chars as $char)
		{
			$next_split = strpos($url, $char);
			if ($next_split !== false)
			{
				$split = ($split !== false) ? min($split, $next_split) : $next_split;
			}
		}

		if ($split !== false)
		{
			// an HTML entity was found, so the URL has to end before it
			$append			= substr($url, $split) . $relative_url;
			$url			= substr($url, 0, $split);
		}

		// if the last character of the url is a punctuation mark, exclude it from the url
		$last_char = $url[strlen($url) - 1];

		switch ($last_char)
		{
			case '.':
			case '?':
			case '!':
			case ':':
			case ',':
				$append = $last_char;
				$url = substr($url, 0, -1);
			break;

			// set last_char to empty here, so the variable can be used later to
			// check whether a character was removed
			default:
				$last_char = '';
			break;
		}

		$text	= $url;
		$url	= 'https://www.reddit.com/' . $url;

		$url	= htmlspecialchars($url);
		$text	= htmlspecialchars($text);
		$append	= htmlspecialchars($append);

		$html	= "<a href=\"$url\">$text</a>$append";

		return $html;
	}

	public function make_reddit_reference_clickable($text)
	{
		static $reddit_regex;

		$reddit_regex = '(r|u)\/(([a-z0-9]{1}[a-z0-9\-\_]{0,62}[a-z0-9]{1}))+';

		if (preg_match('/(^|[\n\t (>])(' . $reddit_regex . ')/iu', $text, $matches))
		{
			$text = preg_replace_callback('/(^|[\n\t (>])(' . $reddit_regex . ')/iu', array($this, 'make_reddit_reference_clickable_callback'), $text);
		}

		return $text;
	}

	/**
	 * A sample PHP event
	 * Modifies the names of the forums on index
	 *
	 * @param \phpbb\event\data	$event	Event object
	 */
	public function autolink_reddit_references($event)
	{
		$event['text'] = $this->make_reddit_reference_clickable($text);
	}
}

Re: Auto-linking Reddit References

Posted: Tue Dec 11, 2018 9:31 am
by JoshyPHP
If you do it at parsing time, it will allow you to leverage the Preg plugin and reduce the code for your extension to this:

Code: Select all

class main_listener implements EventSubscriberInterface
{
	public static function getSubscribedEvents()
	{
		return ['core.text_formatter_s9e_configure_after' => 'onConfigure'];
	}
	public function onConfigure($event)
	{
		$configurator = $event['configurator'];
		
		$configurator->Preg->replace(
			'#\\br/(?<name>\\w+)#',
			'<a href="https://www.reddit.com/r/$1" target="_new">$0</a>',
			'REDDITSUB'
		);
		$configurator->Preg->replace(
			'#\\bu/(?<username>\\w+)#',
			'<a href="https://www.reddit.com/user/$1" target="_new">$0</a>',
			'REDDITUSER'
		);
	}
}

Re: Auto-linking Reddit References

Posted: Tue Dec 11, 2018 5:47 pm
by ViolaF
Thanks, Josh...

Re: Auto-linking Reddit References

Posted: Tue Dec 11, 2018 10:07 pm
by romans1423
JoshyPHP wrote:
Tue Dec 11, 2018 9:31 am
If you do it at parsing time, it will allow you to leverage the Preg plugin and reduce the code for your extension to this
I used the code as given, and it doesn't change anything in my posts. References like r/murderedywords aren't linked. Is there a reference for what is valid in the regex patterns there? I don't recognize a lot of that, such as "#." Why do we need to match a # character?

I even used their own example along side your two blocks of replacement code, and nothing happens with it either. And yes, the extension I'm editing is active -- if I use invalid code, it obviously breaks my site. LOL

Re: Auto-linking Reddit References

Posted: Tue Dec 11, 2018 11:37 pm
by AbaddonOrmuz
The # character is just a regex delimiter, see:

https://secure.php.net/manual/en/regexp ... miters.php

Re: Auto-linking Reddit References

Posted: Tue Dec 11, 2018 11:37 pm
by mrgoldy
I suggest using a site like regexr to get familiar with RegEx expressions.
The # signs are the delimiters, meaning they mark the beginning and the end of the expression to check for.

I think how ever a few too many characters are escaped in the example provided by Joshy, not tested it myself on a board though.
Could you try the following examples:

Code: Select all

	public function onConfigure($event)
	{
		$configurator = $event['configurator'];
		
		$configurator->Preg->replace(
			'#\br\/(?<name>\w+)#',
			'<a href="https://www.reddit.com/r/$1" target="_new">$0</a>',
			'REDDITSUB'
		);
		$configurator->Preg->replace(
			'#\bu\/(?<username>\w+)#',
			'<a href="https://www.reddit.com/user/$1" target="_new">$0</a>',
			'REDDITUSER'
		);
	}
Explanation:
# are the delimiters, as explained above.
\b means look for the end of any word, a "end of word character". Such as spaces, commas, dots, new lines, etc..
r look for the letter r (case sensitive!)
\/ look for the / symbol, I believe that needs escaping, hence the prepended \.
() is a capturing group, group 1, refered to in the next line for the replacement, see the $1
- The entire regex line is capture group 0, anything between () will then start counting up.
?<username> is the name of this particular capturing group
\w looks for a word, a word can consist of letter, digits and underscores (exactly what you are looking for)
+ is a quantifier, meaning it needs atleast 1 word or more to match.

Hope this helps.

Re: Auto-linking Reddit References

Posted: Tue Dec 11, 2018 11:48 pm
by JoshyPHP
romans1423 wrote:
Tue Dec 11, 2018 10:07 pm
nothing happens with it either
Doing things at parsing time means it happens at posting time, so it only applies to new posts and posts being edited.

The regexp is correctly escaped. Meta-characters should be escaped in PHP so they're unambiguous and forward-compatible with syntax changes.

Re: Auto-linking Reddit References

Posted: Wed Dec 12, 2018 3:46 am
by romans1423
Regexr is one of my favorite coding sites -- I used it to piece together the Regex that was in use in my original code above.

I'm still not getting any success with any code posted so far, and it doesn't matter if I view an old post, new post, edited post, or anything. I've tested each scenario. :cry:

Re: Auto-linking Reddit References

Posted: Wed Dec 12, 2018 4:52 am
by romans1423
I'm having absolutely zero luck with the s9e configurator thing.

I even tried this super simple example, but even it does nothing when posting an entry with "test" in it:

Code: Select all

$configurator->Preg->replace(
			'/(test)/',
			'pass',
			'PASSFAIL'
		);
This is the full text of my main_listener.php file which was created by the phpBB Extension Skeleton tool. I haven't modified anything else that the tool created because this was the first thing I wanted to get to work. None of the configurator customizations work, either on post views, new posts, or post edits. :\

Code: Select all

<?php
/**
 *
 * Local Customizations. An extension for the phpBB Forum Software package.
 *
 * @copyright (c) 2018, Rick Beckman
 * @license GNU General Public License, version 2 (GPL-2.0)
 *
 */

namespace secnow\secnowsoc\event;

/**
 * @ignore
 */
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * SecularNow.xyz Customizations Event listener.
 */
class main_listener implements EventSubscriberInterface
{
	public static function getSubscribedEvents()
	{
		return ['core.text_formatter_s9e_configure_after' => 'onConfigure'];
	}
	public function onConfigure($event)
	{
		$configurator = $event['configurator'];

		# Reddit subreddits
		$configurator->Preg->replace(
			'#\br\/(?<name>\w+)#',
			'<a href="https://www.reddit.com/r/{name}" target="_new">{name}</a>',
			'REDDITSUB'
		);
		# Reddit usernames
		$configurator->Preg->replace(
			'#\bu\/(?<username>\w+)#',
			'<a href="https://www.reddit.com/user/{username}" target="_new">{username}</a>',
			'REDDITUSER'
		);
		# Twitter usernames, from the S9E Configurator documentation
		$configurator->Preg->replace(
			'/@(?<username>\\w+)/',
			'<a href="https://twitter.com/{@username}">@{username}</a>',
			'TWITTERUSER'
		);
		# Super simple test
		$configurator->Preg->replace(
			'/(test)/',
			'pass',
			'PASSFAIL'
		);
	}
}

Re: Auto-linking Reddit References

Posted: Wed Dec 12, 2018 6:19 am
by AbaddonOrmuz
You need to clear the cache after making changes.

Try the following, I tested it:

Code: Select all

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class listener implements EventSubscriberInterface
{
	static public function getSubscribedEvents()
	{
		return [
			'core.text_formatter_s9e_configure_after' => 'reddit_autolink'
		];
	}

	public function reddit_autolink($event)
	{
		$configurator = $event['configurator'];

		$configurator->Preg->replace(
			'#\\br/([^_]\\w+)\\b#',
			'<a href="https://www.reddit.com/r/$1" class="postlink" rel="nofollow noreferrer noopener">$0</a>',
			'SUBREDDIT'
		);

		$configurator->Preg->replace(
			'#\\bu/([^_]\\w+)\\b#',
			'<a href="https://www.reddit.com/user/$1" class="postlink" rel="nofollow noreferrer noopener">$0</a>',
			'REDDITUSER'
		);
	}
}
It checks that the username and subreddit does not start with _

Re: Auto-linking Reddit References

Posted: Wed Dec 12, 2018 7:25 am
by romans1423
Oh.

My.

God.

THANK YOU.

Something so simple. Ugh. I knew phpBB cached template things, but I never even considered that configurator rules would be cached as well.