Tutorial: Working With BBCodes¶
Introduction¶
phpBB 3.2 introduced an all new BBCode engine powered by the s9e/TextFormatter library. This tutorial explains several ways extensions can tap into the new BBCode engine to manipulate and create more powerful BBCodes.
This tutorial explains:
Toggle BBCodes On / Off¶
BBCodes and other tags can be toggled before or after parsing using any of the following events:
Event |
Description |
---|---|
|
Triggers once, when the text Parser service is first created. |
|
Triggers every time text is parsed, before parsing begins. |
|
Triggers every time text is parsed, after parsing has completed. This can be used to restore values to their original state, for example. |
Most common operations are available through the Parser service using the phpbb\textformatter\parser_interface
API.
This includes the functions:
Function |
Description |
---|---|
|
Disable a BBCode |
|
Disable BBCodes in general |
|
Disable the censor |
|
Disable magic URLs |
|
Disable smilies |
|
Enable a specific BBCode |
|
Enable BBCodes in general |
|
Enable the censor |
|
Enable magic URLs |
|
Enable smilies |
For more advanced functions, the instance of s9e\TextFormatter\Parser
can be retrieved via get_parser()
to access its API.
The following sample code shows how BBCodes can be toggled and manipulated using a PHP event listener:
class listener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'core.text_formatter_s9e_parse_before' => 'toggle_bbcodes',
];
}
public function toggle_bbcodes($event)
{
// Get the parser service: \phpbb\textformatter\parser_interface
$service = $event['parser'];
// Disable the [color] BBCode through the parser service
$service->disable_bbcode('color');
// Set the [url] BBCode to only parse the first occurrence.
// Note this requires an instance of \s9e\TextFormatter\Parser
$service->get_parser()->setTagLimit('URL', 1);
}
}
Executing PHP Code With BBCodes¶
Extensions can configure BBCodes to execute PHP functions. This makes it possible to create BBCodes that do a lot more than just generically format text.
In the following simple example, we re-configure the QUOTE
tag (which handles the [quote]
BBCode) to run a PHP
method to read and change its attributes during parsing based on who is being quoted in the BBCode.
class listener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'core.text_formatter_s9e_configure_after' => 'configure_quotes'
];
}
public function configure_quotes($event)
{
// Add self::filter_quote() to filter the QUOTE tag that handles quotes
$event['configurator']->tags['QUOTE']->filterChain
->append([__CLASS__, 'filter_quote']);
}
static public function filter_quote(\s9e\TextFormatter\Parser\Tag $tag)
{
if (!$tag->hasAttribute('author'))
{
// If the author is empty, we attribute the quote to Mark Twain
$tag->setAttribute('author', 'Mark Twain');
}
elseif (stripos($tag->getAttribute('author'), 'Gary Oak') !== false)
{
// If the author is Gary Oak we invalidate the tag to disallow it
$tag->invalidate();
// Return FALSE for backward compatibility
return false;
}
// We return TRUE for backward compatibility, to indicate that the tag is allowed
return true;
}
}
Template Parameters¶
Some of phpBB’s template variables can be used in BBCodes to produce dynamic output. For example, to create a BBCode that will only show its content to registered users.
Default phpBB template parameters:
Variable |
Description |
---|---|
|
Whether the current user is a bot. |
|
Whether the current user is registered. |
|
Whether the current user is logged in. |
|
Whether the current user’s preferences are set to hide censored words. |
|
Whether the current user’s preferences are set to display Flash objects. |
|
Whether the current user’s preferences are set to display images. |
|
Whether the current user’s preferences are set to display smilies. |
|
ID of the current style. |
|
Path to the smilies directory. |
In the following example, we will use the Configurator to create a custom BBCode dynamically that only registered users can see the contents of:
[noguests]{TEXT}[/noguests]
class listener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'core.text_formatter_s9e_configure_after' => 'configure_noguests',
];
}
public function configure_noguests($event)
{
// Get the BBCode configurator
$configurator = $event['configurator'];
// Let's unset any existing BBCode that might already exist
unset($configurator->BBCodes['noguests']);
unset($configurator->tags['noguests']);
// Let's create the new BBCode
$configurator->BBCodes->addCustom(
'[noguests]{TEXT}[/noguests]',
'<xsl:choose>
<xsl:when test="$S_USER_LOGGED_IN and not($S_IS_BOT)">
<div>{TEXT}</div>
</xsl:when>
<xsl:otherwise>
<div>Only registered users can read this content</div>
</xsl:otherwise>
</xsl:choose>'
);
}
}
Note
Notice in the code above, a test is used to check the value of the template variable S_USER_LOGGED_IN
and the appropriate BBCode HTML output is generated.
Template parameters can also be set using any of the following events:
Event |
Description |
---|---|
|
Triggers once, when the renderer service is created. |
|
Triggers every time a text is rendered, before the HTML is produced. |
|
Triggers every time a text is rendered, after the HTML is produced. It can be used to restore values to their original state. |
In the following simple example, we set a template parameter to generate a random number in every text. The number changes every time a new text is rendered. Although this serves no practical application, it does illustrate how this can be used in conjunction with the events and techniques above to pragmatically create your own template parameters, in addition to the default one’s already available in phpBB.
class listener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'core.text_formatter_s9e_render_before' => 'set_random'
];
}
public function set_random($event)
{
$event['renderer']->get_renderer()->setParameter('RANDOM', mt_rand());
}
}
Registering Custom Variables¶
It is possible to register custom variables to be used during parsing. For instance, phpBB uses
max_font_size
to limit the values used in the [font]
tag dynamically. Callbacks used during parsing
must be static and serializable as the parser itself is cached in a serialized form. However, custom variables
are set at parsing time and are not limited to scalar types. For instance, they can be used to access the
current user object during parsing.
In the following example, we add an attribute filter to modify URLs used in [url]
BBCodes and links. In
addition to the attribute’s value (the URL) we request that the custom variable my.id
be passed as the
second parameter. It’s a good idea to namespace the variable names to avoid collisions with other extensions
or phpBB itself.
The core.text_formatter_s9e_parser_setup
event uses $event['parser']->set_var()
to set a value for
my.id
variable once per initialization. The core.text_formatter_s9e_parse_before
event could be used to
set the value before each parsing.
class listener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'core.text_formatter_s9e_configure_after' => 'configure_links',
'core.text_formatter_s9e_parser_setup' => 'set_random_id'
];
}
static public function add_link_id($url, $my_id)
{
return $url . '#' . $my_id;
}
public function configure_links($event)
{
// Add self::add_link_id() to filter the attribute value of [url] BBCodes and links
$event['configurator']->tags['url']->attributes['url']->filterChain
->append([__CLASS__, 'add_link_id'])
->resetParameters()
->addParameterByName('attrValue')
->addParameterByName('my.id');
}
public function set_random_id($event)
{
// We set my.id to a random number in this example
$event['parser']->set_var('my.id', mt_rand(111, 999));
}
}
Enable Text Formatter Plugins¶
The Text Formatter library has a collection of plugins that can be enabled through an extension, such as MediaEmbed, Pipe Tables, etc.
Plugins can be toggled via the configurator
var available through the core.text_formatter_s9e_configure_before
and core.text_formatter_s9e_configure_after
events which respectively trigger before and after the default
settings are configured.
class listener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
'core.text_formatter_s9e_configure_after' => 'configure'
];
}
public function configure($event)
{
$configurator = $event['configurator'];
// Disable the Autolink plugin
unset($configurator->Autolink);
// Enable the PipeTables plugin
$configurator->PipeTables;
// Do something if the MediaEmbed plugin is enabled
$is_enabled = isset($configurator->MediaEmbed);
if ($is_enabled)
{
// ...
}
// Get the names of all loaded plugins
$names = [];
foreach ($configurator->plugins as $plugin_name => $plugin_configurator)
{
$names[] = $plugin_name;
}
}
}