Doing links on Drupal 8

Submitted by on

There are plenty of ways to create links when using Drupal 8 and I will share some of those ways in this post.

The easiest way to create internal links is using Link::createFromRoute

And it is used like this:

 
use Drupal\Core\Link;
  $link = Link::createFromRoute('This is a link', 'entity.node.canonical', ['node' => 1]);

Using the Url object gives you more flexibility to create links, for instance, we can do the same as Link::createFromRoute method using the Url object like this:

 
  use Drupal\Core\Link;
  use Drupal\Core\Url;
  $link = Link::fromTextAndUrl('This is a link', Url::fromRoute('entity.node.canonical', ['node' => 1]));

And actually Link::fromTextAndUrl is what Drupal recommends instead of using the deprecated l() method. Passing the Url object to the link object gives you great flexibility to create links, here are some examples:

Internal links which have no routes:

 
$link = Link::fromTextAndUrl('This is a link', Url::fromUri('base:robots.txt'));

External links:

 
$link = Link::fromTextAndUrl('This is a link', Url::fromUri('http://www.google.com'));

links with only the fragment (without url) :

 
$link = Link::fromTextAndUrl('This is a link', Url::fromUri('internal:#fragment'));

Using the data provided by a user:

 
$link = Link::fromTextAndUrl('This is a link', Url::fromUserInput('/node/1');

The param passed to fromUserInput must start with /,#,? or it will throw an exception.

Linking entities.

 
$link = Link::fromTextAndUrl('This is a link', Url::fromUri('entity:node/1'));

Entities are a special case, and there are more ways to link them:

 
$node = Node::load(1);
$link = $node->toLink();
$link->setText('This is a link');

And even using the route:

 
$link = Link::fromTextAndUrl('This is a link', Url::fromRoute('entity.node.canonical', ['node' => 1]));

Drupal usually expects a render array if you are going to print the link, so the Link object has a method for that:

 
$link->toRenderable();

which will return an array.

Final tips:

Searching a route using Drupal Console

The easiest way to find the route of a specific path is using Drupal Console, with the following command.

 
$ drupal router:debug | grep -i "\/node"

That will return something like:

 
entity.node.canonical                                 /node/{node}
 entity.node.delete_form                               /node/{node}/delete
 entity.node.edit_form                                 /node/{node}/edit
 entity.node.preview                                   /node/preview/{node_preview}/{view_mode_id}
 entity.node.revision                                  /node/{node}/revisions/{node_revision}/view
 entity.node.version_history                           /node/{node}/revisions
 node.add                                              /node/add/{node_type}
 node.add_page                                         /node/add
 node.multiple_delete_confirm                          /admin/content/node/delete
 node.revision_delete_confirm                          /node/{node}/revisions/{node_revision}/delete
 node.revision_revert_confirm                          /node/{node}/revisions/{node_revision}/revert
 node.revision_revert_translation_confirm              /node/{node}/revisions/{node_revision}/revert/{langcode}
 search.help_node_search                               /search/node/help
 search.view_node_search                               /search/node
 view.frontpage.page_1                                 /node

Listing all the possible routes with that word, we can choose one and do:

 
drupal router:debug entity.node.canonical

And that will display more information about a specific route:

 
 Route             entity.node.canonical
 Path              /node/{node}
 Defaults
  _controller      \Drupal\node\Controller\NodeViewController::view
  _title_callback  \Drupal\node\Controller\NodeViewController::title
 Requirements
  node             \d+
  _entity_access   node.view
  _method          GET|POST
 Options
  compiler_class   \Drupal\Core\Routing\RouteCompiler
  parameters       node:
                     type: 'entity:node'
                     converter: paramconverter.entity

  _route_filters   method_filter
                   content_type_header_matcher

  _route_enhancers route_enhancer.param_conversion

  _access_checks   access_check.entity

So in this way we can search the route without the needing to search in all the *.routing.yml files and in this example the route is entity.node.canonical and the param expected is node.

Print links directly within a twig template

It is also possible to print links directly on the twig template with the following syntax:

<a href="{{url('entity.node.canonical', {'node': node.id( ) }}"> {{ 'This is a link'|t }} </a>

Add links inside a t() method.

If you want to add a link inside the t() method you need to pass the link as a string, something like this:

 
use Drupal\Core\Link;
$link = Link::fromTextAndUrl('This is a link', Url::fromRoute('entity.node.canonical', ['node' => 1]));
$this->t('You can click this %link' ['%link' => $link->toString()]);

Comments

Submitted by Pedro Rocha on Thu, 04/20/2017 - 11:00

Your post is really useful, but D8 requiring us to have such a post is an example of how complex it is to do such a simple thing as a link.

Submitted by Dave Hansen-Lange on Fri, 05/05/2017 - 15:18

I disagree, with D7 we had to remember l(), url(), theme_link(), '#theme' => 'link', and more. With D8 you just have to remember Drupal\Core\Link and Drupal\Core\URL. You can get to all the rest via autocomplete in your IDE.

Add new comment