## III. Using NBBC

[ Previous: F. Adding Callback Tags | Next: H. Supporting Local Images ]

### G. Supporting Wiki-Links

NBBC has a feature that allows your users to easily link to content on a specific web site of your choice. This feature is called wiki-links, because it uses a syntax very similar to that of many wikis (like Wikipedia), and because it often links to content on a wiki. In this section, we're going to look at how to set up wiki-links on your site in three different ways: First, we're going to look at the simple case of pointing them to a wiki you've installed; then we're going to look at how to point them at unique custom content, such as a webcomic or a content-management system (CMS) like Drupal; and finally, we'll look at how to set them up so that they can point to several different kinds of content at the same time.

#### Linking to a Wiki

Let's say that you want to make it very easy for your users to link to content on Wikipedia. For example, you'd like this to happen:

Code:

    [[Ronald Reagan]] was the 40th [[President of the United States]],
    following [[Jimmy Carter]] and [[Gerald Ford]], and preceding
    [[George H. W. Bush]] and [[Bill Clinton]].

Output:
Ronald Reagan was the 40th President of the United States, following Jimmy Carter and Gerald Ford, and preceding George H. W. Bush and Bill Clinton.

Normally, doing this would require a lot of `[url]` tags. But if your users commonly link to Wikipedia, why not make it easier for them? That's where wiki-links come in: It's a lot easier to type `[[Ronald Reagan]]` than it is to type `[url=http://en.wikipedia.org/wiki/Ronald_Reagan]Ronald Reagan[/url]` no matter how fast a typist you are.

NBBC has built-in support for detecting special tags that are surrounded by `[[`double brackets]]: Any time it sees such a thing, it invisibly converts the tag from `[[abc]]` to `[wiki="abc" title="abc"]`, thus saving your users the time of having to type out such a tag themselves.

(Like many wikis do, NBBC detects a vertical bar in the tag as a separator, so if you type `[[abc|def]]` you'll get `[wiki="abc" title="def"]` as your output. Within a wiki-link tag, NBBC allows all characters to be part of the name and title except for `[` and `]` and `|`.)

How, then, does NBBC process a `[wiki]` tag when it encounters one? The default behavior of the Standard BBCode Library is very simple: Convert the `[wiki]` tag into an `<a href="...">...</a>` element, with the main URL provided by the `SetWikiURL()` function, and a cleaned-up version of the `name` parameter appeneded to the end of the URL.

Let's look at a simple example: We'll process "`[[Ronald Reagan]]`" to be a link to his page at Wikipedia. First, before any BBCode parsing gets done, we need to tell the parser where our wiki is:

Code:

    $bbcode = new BBCode;
    $bbcode->SetWikiURL("http://en.wikipedia.org/wiki/");

Next, we call the `$bbcode->Parse()` function to convert our input BBCode to HTML. This is what happens when `Parse()` sees the wiki link:

1. The `[[Ronald Reagan]]` wiki-link is converted to a `[wiki="Ronald Reagan" title="Ronald Reagan"]` tag.
2. The parser looks for a rule for the new `[wiki]` tag. A rule is provided by the Standard BBCode Library, and unless you override it (with AddRule(), as in another example below), that rule will process the tag.
3. The standard wiki-link rule uses the Wikify() function to convert the `name` parameter from `Ronald Reagan` to `Ronald_Reagan`, which can be safely passed through a URL (and which is understood by most wikis as equivalent to the version with a space character in it).
4. The standard wiki-link rule then converts the rest of the BBCode tag to HTML like this:
   `[wiki="abc"&bsp;title="def"]`
   To this:
   `<a href="{wikiurl}{abc}">{def}</a>`
   So in the case where our wiki URL is `http://en.wikipedia.org/wiki/` and our "wikified" name is `Ronald_Reagan` and our title is `Ronald Reagan`, the output would be: `<a href="http://en.wikipedia.org/wiki/Ronald_Reagan">Ronald Reagan</a>`

So, then, to complete our first example, here is the code and its output, in full:

Code:

    $bbcode = new BBCode;
    $bbcode->SetWikiURL("http://en.wikipedia.org/wiki/");
    $input = "[[Ronald Reagan]]";
    $output = $bbcode->Parse($input);
    print $output;

Output:
Ronald Reagan

As we said before, users can use a vertical bar to separate names from titles, so this also works:

Code:

    $bbcode = new BBCode;
    $bbcode->SetWikiURL("http://en.wikipedia.org/wiki/");
    $input = "[[Ronald Reagan|Mister President Dude]]";
    $output = $bbcode->Parse($input);
    print $output;

Output:
Mister President Dude

#### Linking to Other Things

What if you don't have a wiki? What if you don't want to link to a wiki? The `[[...]]` tag can really be used for any purpose you want: It simply links to related content on a single site of your choice, be that wiki pages, news articles, webcomic pages, blog postings, or anything else you deem useful. Some possible examples follow.

Example 1. Let's say you want your users to be able to link to pages in your webcomic easily, and that your webcomic pages are organized by date. You might use the wiki-link tag like this:

Code:

    $bbcode = new BBCode;
    $bbcode->SetWikiURL("http://www.thewotch.com/?epDate=");

User input:

    This is the [[2002-11-21|first Wotch comic]]

Output:
This is the first Wotch comic

Example 2. Maybe you run a news site, and you'd like your users to be able to easily link to news postings.

Code:

    $bbcode = new BBCode;
    $bbcode->SetWikiURL("http://mercurynews.com/ci_");

User input:

    [[9921286|"Mamma Mia" is cheesy fun]]

Output:
"Mamma Mia" is cheesy fun

#### Advanced linking

It's entirely possible that the simple technique of "clean up the name and add it to the URL" isn't going to be good enough for some needs. So here, we look at ways you can perform more sophisticated wiki-linking by using your own `[wiki]`-tag processing function.

Let's say that you want to link to articles in Ars Technica, a technology news blog. Articles in Ars are generally linked by a date and by a name, not just a name. We'd like to be able to write this:

User input:

    [[As expected, EU widens antitrust probe of Intel]]

But we can't do that, because Ars articles include a date in their URL as well. So we need a more sophisticated parsing function that can convert just enough information into the kind of URL that the Ars website wants to see. First, we'll alter our requirements a little; the information given by the user needs to include a date:

User input:

    [[20080717:As expected, EU widens antitrust probe of Intel]]

Now we need to tell NBBC that we're going to use our own custom `[wiki]` tag callback function to process this kind of content:

Code:

    $bbcode = new BBCode;
    $bbcode->AddRule("wiki", Array(
        'mode' => BBCODE_MODE_CALLBACK,
        'method' => "DoArsTag",
        'class' => 'link',
        'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
        'end_tag' => BBCODE_PROHIBIT,
        'content' => BBCODE_PROHIBIT,
    ));

And finally, we need to add our special function that can convert names to the format Ars requires:

Code:

    function DoArsTag($bbcode, $action, $name, $default, $params, $content) {

        // Break the name into the part before the colon (the date) and
        // the part after (the actual name)
        $pieces = explode(":", $default);

        // Convert everything in the name that isn't alphanumeric to a hyphen.
        $date = trim($pieces[0]);
        $name = str_replace(" ", "-", trim(preg_replace("/[^a-z0-9]+/",
            " ", $pieces[1])));

        // Tell NBBC whether this name is legal.
        if ($action == BBCODE_CHECK)
            return strlen($name) > 0 && preg_match("/^[0-9]+$/", $date);

        // Decide on a suitable title.
        $title = trim(@$params['title']);
        if (strlen($title) <= 0) $title = trim($pieces[1]);

        // And format the result as HTML.
        return "<a href=\"http://arstechnica.com/news.ars/post/{$date}-"
            . "{$name}.html\">" . htmlspecialchars($title) . "</a>";
    }

This new function will yield this output:

User input:

    [[20080717:As expected, EU widens antitrust probe of Intel]]

Output:
As expected, EU widens antitrust probe of Intel

#### Linking to Multiple Things

What if just one `[[...]]` tag isn't enough? What if you want to be able to easily link to several different things all at once? For example, you might run a webcomic site, and want to be able to easily link to comics, story arcs, your own comic's wiki, and even Wikipedia! You can use the same `[[...]]` tag to handle all of these at once, with a little cleverness.

First, you need to establish some rules: What kind of content links to which site? Your comics have dates attached to them, so if a user specifies just a date, they probably want a link to a comic; your story arcs are numbered, so if a user specifies just a number, they probably want a link to a story arc; everything else can probably safely be a link into your wiki, but if the user adds "`WP:`" to the start of the tag, they probably want a link into Wikipedia. So you might want something like this:

User input:

    [[2002-11-21|The first Wotch comic]]
    [[3|"Enter the Wotch"]]
    About [[The Wotch]]
    [[WP:The Wotch]] at Wikipedia

Output:
The first Wotch comic
Enter the Wotch
About The Wotch
The Wotch at Wikipedia

Clearly, simple text-replacement can't handle all of these, but allowing "smart" linking like this is much easier than it looks. First, we'll need to tell NBBC that we're doing something unusual with the `[wiki]` tag, just like with the advanced-linking example above:

Code:

    $bbcode = new BBCode;
    $bbcode->AddRule("wiki", Array(
        'mode' => BBCODE_MODE_CALLBACK,
        'method' => "DoWotchLinkTag",
        'class' => 'link',
        'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
        'end_tag' => BBCODE_PROHIBIT,
        'content' => BBCODE_PROHIBIT,
    ));

Now, all we need is a function that can analyze the name and link to the appropriate web site, which is conceptually not that much different from the advanced linking example above: We first test to see what kind of name the user provided, and then create a link to the correct site based on that. Here's our resulting function:

Code:

    function DoWotchLinkTag($bbcode, $action, $name, $default, $params, $content) {

        // Tell NBBC this tag is legal no matter what it contains.
        if ($action == BBCODE_CHECK) return true;

        // Remove any surrounding whitespace on the name.
        $default = trim($default);

        if (preg_match("/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/", $default)) {
            // If we have a comic date, return a link to the comic on our site.
            $title = trim(@$params['title']);
            if (strlen($title) <= 0) $title = "Comic for $default";
            return "<a href=\"http://www.thewotch.com/?epDate=$default\">"
                . htmlspecialchars($title) . "</a>";
        }
        if (preg_match("/^[0-9]+$/", $default)) {
            // If we have a number, return a link to a story arc on our site.
            $title = trim(@$params['title']);
            if (strlen($title) <= 0) $title = "Arc #$default";
            return "<a href=\"http://www.thewotch.com/archives/?arc=$default\">"
                . htmlspecialchars($title) . "</a>";
        }
        else if (preg_match("/^WP\\:/", $default) {
            // If we have something that starts with "WP:", link to Wikipedia.
            $default = substr($default, 3);    // Remove the "WP:" from the name.
            $title = trim(@$params['title']);
            if (strlen($title) <= 0) $title = $default;
            $name = $bbcode->Wikify($default);
            return "<a href=\"http://en.wikipedia.org/wiki/$name\">"
                . htmlspecialchars($title) . "</a>";
        }
        else {
            // Otherwise, link to our "Wotchipedia".
            $title = trim(@$params['title']);
            if (strlen($title) <= 0) $title = $default;
            $name = $bbcode->Wikify($default);
            return "<a href=\"http://wiki.thewotch.com/$name\">"
                . htmlspecialchars($title) . "</a>";
        }
    }

[ Previous: F. Adding Callback Tags | Next: H. Supporting Local Images ]

Copyright © 2010, the Phantom Inker. All rights reserved.