26

Say I am extending The blockBase class to create a custom block, and I am implementing the blockBuild method to create some markup for my block. Something like this:

 class YourModuleBlock extends BlockBase {

   /**
     * Implements \Drupal\block\BlockBase::blockBuild().
     */
     public function build() {
      return array(
        '#markup' => 'This is a block!',
      );
     }
   }

If I wanted to provide a link in this markup, in D7 I would have used the l function, but this is no longer available (see here). So, I need to make available the new D8 method for generating links. I could just use an <a> tag, but this was never best practice in D7.

So, what is the right method to use for creating links and how do I make it available to my function?

53

\Drupal::l is deprecated. Maybe this case will be useful for somebody

  use Drupal\Core\Url;
  use Drupal\Core\Link;
  $url = Url::fromRoute('entity.node.edit_form', array('node' => NID));
  $project_link = Link::fromTextAndUrl(t('Open Project'), $url);
  $project_link = $project_link->toRenderable();
  // If you need some attributes.
  $project_link['#attributes'] = array('class' => array('button', 'button-action', 'button--primary', 'button--small'));
  print render($project_link);
  • 2
    This toRenderable() trick is very useful, thanks! – Nic Aug 30 '16 at 13:03
  • Still works on Drupal 8.4 core – podarok May 23 '18 at 9:31
24

One, this is not 100% complete, see this issue . With that said, let me quote some code from the change notice:

Drupal 7:

// Internal path.
$internal_link = l(t('Book admin'), 'admin/structure/book');

// External Uri.
$external_link = l(t('External link'), 'http://www.example.com/', array('external' => TRUE));

Drupal 8:

// Internal path (defined by a route in Drupal 8).
use Drupal\Core\Url;
$url = Url::fromRoute('book.admin');
$internal_link = \Drupal::l(t('Book admin'), $url);

// External Uri.
use Drupal\Core\Url;
$url = Url::fromUri('http://www.example.com/');
$external_link = \Drupal::l(t('External link'), $url);

Edit: route names are in the moduledirectory/modulename.routing.yml files and (by default) in the {router} table.

  • 2
    I found the $router_name in the {router} table. – 24ma13wg Jan 22 '15 at 10:30
  • 1
    How can i create link for front page. In drupal 7, it can be l('home', '<front>'). but what about in drupal 8? – Guru Jan 12 '16 at 10:31
  • fromRoute('<front>') – user49 Jan 12 '16 at 16:22
  • 7
    \Drupal::l is deprecated. Use \Drupal\Core\Link::fromTextAndUrl($text, $url) instead – Eyal Apr 6 '16 at 11:06
  • Drupal::l deprecation notice api.drupal.org/api/drupal/core!lib!Drupal.php/function/… – leymannx Oct 28 '16 at 12:00
19

Another option is to create a link in a render array

$url = Url::fromRoute('entity.node.edit_form', array('node' => NID));
$link = [
  '#type' => 'link',
  '#url' => $url,
  '#title' => t('This link was rendered')
];

Drupal supplies us with some helper methods to create urls and links to entities.

$url = Node::load(NID)->toUrl('edit-form');

And

$link = Node::load(NID)->toLink(t('link text'), 'edit-form');
$link_render_array = $link->toRenderable();
15

The ability to set attributes seems lost or convoluted in the previous examples because the functionality is just not obvious. There are two ways to create links depending on if it has a route or not and each behaves a little bit different so here are the examples.

  1. With a route. This makes the most sense, you can just supply it in the options.

    Link::createFromRoute('My link', 
      'entity.node.canonical',
      ['node' => 123],
      ['attributes' => ['class' => 'special']]));
    
  2. With an external url. This one is a little weird. There isn't an option argument so it might seem impossible but its actually OK. The reason is that inexplicably links never have options only the URL they describe. This means you pass in the class to the URL when you create it and it will just work.

    Link::fromTextAndUrl('My link', 
      Url::FromUrl('https://example.com/about',
        ['attributes' => ['class' => 'special']]));
    

    A corollary to all this is that you can also do this.

    $link = Link::fromTextAndUrl('Example',  Url::fromUri('https://example.com/about'));
    $link->getUrl()->setOption('attributes', ['class' => 'superspecial']);
    
13

Here are some examples of creating links in Drupal 8. Note that $this->t('some text') is available within blocks that extend BlockBase. If you copy these to another class that doesn't have it or use these in a .module file, you may need to change this to t() 1.

Basic Link to a node:

$node = Node::load($nid);
$build['node_link'] = $node->toLink()->toRenderable();

This creates a render array like this:

$link = [
  '#type' => 'link',
  '#url' => $url_object,
  '#title' => 'Title of Node',
];

You can create the render array without loading the node this way:

$url_object = Url::fromRoute('entity.node.canonical', ['node' => $nid]);
$link = [
  '#type' => 'link',
  '#url' => $url_object,
  '#title' => $this->t('Read More'),
];

Or using the core Link class:

$url = Url::fromRoute('entity.node.canonical', ['node' => $nid]);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

If you want to use markup in the text of your link, you can't just put a string in. You need to use a render array element:

$url = Url::fromRoute('entity.node.canonical', ['node' => $nid]);
$link_text =  [
  '#type' => 'html_tag',
  '#tag' => 'span',
  '#value' => $this->t('Load More'),
];
$link = Link::fromTextAndUrl($link_text, $url);

To create an absolute link, you add this option to the URL, not the link:

$url = Url::fromRoute('entity.node.canonical', ['node' => $nid], ['absolute' => TRUE]);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

To add a class to your link, you also need to add this to the URL, not the link:

$options = [
  'attributes' => [
    'class' => [
      'read-more-link',
    ],
  ],
];
$url = Url::fromRoute('entity.node.canonical', ['node' => $nid], $options);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

To add a query string to your link, you also need to this to the URL, not the link:

$options = [
  'query' => [
    'car' => 'BMW',
    'model' => 'mini-cooper',
  ],
  'attributes' => [
    'class' => [
      'read-more-link',
    ],
  ],
];
$url = Url::fromRoute('entity.node.canonical', ['node' => $nid], $options);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

To set the link to open in a new window with target = _blank:

$options = [
  'attributes' => [
    'target' => '_blank'
  ],
];
$url = Url::fromRoute('entity.media.edit_form', ['media' => $entity->id()], $options);
$link = Link::fromTextAndUrl(t('Edit'), $url);
$form['entity']['edit_link'] = $link->toRenderable();

Here's a link to a taxonomy term page:

$url = Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $tid]);
$link = Link::fromTextAndUrl($this->t('Read more'), $url);
$build['read_more'] = $link->toRenderable();

Here's a link to node edit page:

$url = Url::fromRoute('entity.node.edit_form', ['node' => $nid]);
$link = Link::fromTextAndUrl($this->t('Edit'), $url);
$build['read_more'] = $link->toRenderable();

To create an external link:

$url = Url::fromUri('http://www.example.com/');
$link = Link::fromTextAndUrl($this->t('Vist this example site'), $url);
$build['external_link'] = $link->toRenderable();

Link to homepage:

$url = Url::fromRoute('<front>');
$link = Link::fromTextAndUrl($this->t('Home'), $url);
$build['homepage_link'] = $link->toRenderable();

Note that on any of these url objects, you can get the url as a string by calling:

$url->toString();

For example:

$url_string = Url::fromRoute('<front>')->toString();
  • The link method is deprecated. – Eyal Mar 8 '17 at 20:11
  • I have revised my answer to use toLink() from the node object, i.e. $node->toLink()->toRenderable(); – oknate Jul 19 '17 at 16:17
  • This is a good run down. – Brady Oct 15 '17 at 0:03
2

A complete example with attributes and HTML markup in the link text:

  $url = Url::fromRoute(
   'your.route.name', 
   [], 
   ['attributes' => ['id' => 'add-link', 'class' => ['btn', 'btn-sm', 'btn-primary']]]
  );
  $link = Link::fromTextAndUrl(
    Markup::create('<span class=\'glyphicon glyphicon-plus\'></span> ' . t('Add new item')), 
    $url
  );
0

I was need to add link to the table as a #suffix, but was need to put it as a html, to Achieve this I did

\Drupal\Core\Link::fromTextAndUrl("Add New page", Url::fromRoute('mymodule.add_new_page'))->toString();

Where mymodule.add_new_page is route from my module yml file.

0

The answers here gave me some good pointers. All I wanted was to provide a link to the node in my logs...So here's what I ended up with

  use Drupal\Core\Url;
  use Drupal\Core\Link;
  /* ...
  .. */  
  $url = Url::fromRoute('entity.node.canonical', array('node' => $object->id()));
$strings = array(
  '!node' => Link::fromTextAndUrl($object->getTitle(), $url)->toString(),
  '%nid' => $nid,
);
\Drupal::logger('mymodule_actions')->notice('Updating !node (%nid)', $strings);
-3
\Drupal\Core\Link::createFromRoute(t('TEXT'), 'ROUTE')->toString()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.