The following documentation requires some knowledge of PHP, how to create a Drupal module and the Drupal Core Plugin API.

For this example, we will try to create a plugin to allow users to create freelinking links words on locale.drupal.org based on the user's language. We will call the module freelinking_drupal_localize.

The goal is to return a direct link to localize.drupal.org's page for a translated string. This is fictitious example because we have to link by string id so no one would use this anyway.

  1. Scaffold the following new directories inside your module project structure: src/Plugin/freelinking.
  2. Create a new PHP Class file inside this directory with the file name DrupalLocalize.php, class name DrupalLocalize and the namespace \Drupal\freelinking_drupal_localize\Plugin\freelinking.

Freelinking Plugin Annotation

The Freelinking plugin annotation has properties described in the table below. Add the plugin annotation following this example:

/**
 * Freelinking localize.drupal.org lookup link plugin.
 *
 * @Freelinking(
 *   id = "freelinking_drupal_localize",
 *   title = @Translation("localize.drupal.org Link"),
 *   weight = 0,
 *   hidden = false,
 *   settings = { }
 */
class DrupalLocalize extends FreelinkingPluginBase {

Plugin annotation property table
Property Name Description Example
id The unique plugin ID to use. freelinking_drupal_localize
title A translatable title that will be displayed to users with administration privileges. @Translation("Localize.drupal.org Link")
weight An integer that is used to sort the plugins on the Text format page. 0
hidden A boolean value used to hide the plugin from the Text format page. This should not normally used and is an internal property. false
settings An associative array of default configuration. { }

Explanation of methods to implement

getIndicator()

This method expects us to the Regular Expression pattern used to match the “indicator” that users will need to use the plugin. It is nice to provide a short hand as well.

  public function getIndicator() {
    // Allows [[ldo:]] or [[localizedrupalorg]] or [[localizedo]] among other possibilities.
    return '/^l(ocalize)?d(rupal)?o(org)?$/';
  }

getTip()

This method expects us to return a translatable string to use as the link “tip”, which is displayed to users viewing the content when hovering over the anchor link.

The buildLink method is the main method of our plugin. It will return a render array to display as a link or a render array to display an error. The method argument $target is an associative array that describes the text. At this point, the Freelinking module has already determined that the text should be rendered using our plugin, and so no additional check is necessary.

The target array has the following keys
Key Description Example
text The text that the user has input or the dest string. This is prefilled for you. sets
indicator The indicator string used. ldo
dest The target string which could be a node id, node title, etc.. In this case the string id. 6
tooltip Unused. getTip should be used instead. N/A
language The object to use for the Url object. This would allow the anchor link to be translatable. See \Drupal\Core\Language\LanguageInterface
  public function buildLink(array $target) {
    return [
      '#type' => 'link',
      '#title' => $target['text] ? $target['text'] : $target['dest'],
      '#url' => Url::fromUri(
        'https://localize.drupal.org/translate/languages/es/translate',
        [
          'absolute' => TRUE,
          'language' => $target['language'],
          'query' => [
            'sid' => $target['dest'],
          ],
        ]
      ),
      '#attributes' => [
        'title' => $this->getTip(),
      ],
    ];
  }

Now when the plugin is activated on a Text Format users can type [[ldo:6|sets]] to create external anchor links similar to <a href="https://localize.drupal.org/translate/languages/es/translate?sid=6">sets</a>.

What else can we do to improve this?

  1. If our mythical external link provided an API to lookup string ids, we could inject the http_client service into our plugin and do a lookup. This is fairly expensive as each freelink using this indicator would do so on an uncached node.
  2. We could provide a settings form to allow choosing which languages can be looked up.

You should now be able to write your own freelinking plugins that expand and allow your users to create wiki-like markup to link to other sites or internal content.