46

I have a Link field named field_my_link (machine name).

Within a Twig template I can get the link's URL value with this:

{{ node.field_my_link.uri }}

If inside the Link's URL there is an external URL, e.g. http://example.com it works good.

But, if inside the Link's URL there is stored an internal URL, e.g. "/node/11", I get a value like this:

"internal:/node/11"

with the "internal:" prefix.

How can I get the valid URL?

For example, if the link's URL is "http://example.com" I want "http://example.com" (this already works), if the link's URL is "/node/11" I want the relative URL "/node/11", if the link's URL is "<front>" I want the URL "/", etc.


EDIT

I can get the value I want within a PHP preprocess function, using this:

$url = $variables['node']->get('field_my_link')->first()->getUrl();

How can I access the same value within the Twig template?

I know I can do this within the preprocess function:

$variables['my_url'] = $url;

Then access the url within Twig using {{ my_url }}, but I would avoid to write a preprocess function each time I have a link field.

13 Answers 13

56

Your PHP from your latest edit would translate into twig like this:

{{ node.field_my_link.0.url }}

This works like this, 0 returns the first item of the field item list, url gets the url object and because twig will cast this object as a string this will call the magic method toString() and will output the url as a string value.

You only need to use url, because twig looks automatically for the method getxyz() if there is no property with that name xyz.

9
  • Thank you. Now I make a test with this function. Do you know if can I use this function also on links' URIs? What happen if node.field_my_link.uri is an external url like http://www.example.com? – Andrea Apr 26 '16 at 12:25
  • 1
    I tried with file_url(node.field_my_link.uri), and if node.field_my_link.uri is "http://www.example.com" it works (it leaves the url unchanged), but if node.field_my_link.uri is "internal:/" the function returns "/internal%3A/" (instead of "/").. – Andrea Apr 26 '16 at 12:32
  • I just saw your edit.. Sadly it doesn't works, the code node.field_my_link.entity.uri.value returns a null value.. Any other ideas? – Andrea Apr 30 '16 at 7:32
  • 1
    Yeah, it works. The syntax is a bit scary, but it does its job. – Andrea Apr 30 '16 at 11:53
  • 1
    This shouldn't be marked as "solution" as the file_url() function works just with files and not with link fields. The thread starter asked for the raw url output of a "link field". – mogio Dec 6 '16 at 13:30
25

You can access the render array element directly, in your case:

{{ node.field_my_link[0]['#url'] }}
3
  • This one worked for my. – esQmo_ Oct 23 '18 at 21:05
  • It appears this is now the correct answer. – maskedjellybean Mar 31 '20 at 21:40
  • This one worked for me. – Alex Jan 27 at 15:29
19

You have to cover both cases: external and internal URLs.

First let's check if the URL is external and simply print its *.uri.

Else if it's internal we have to wire its route name and parameters through Drupal's path($name, $parameters, $options) function.

{% if node.field_link.0.url.external %}
  <a href="{{ node.field_link.uri }}">
    {{ node.field_link.title }}
  </a>
{% else %}
  <a href="{{ path(node.field_link.0.url.routeName, node.field_link.0.url.routeParameters) }}">
    {{ node.field_link.title }}
  </a>
{% endif %}
1
  • 2
    Thank you, this is exactly what I needed: get the url from a link field as a string: {% set url = path(node.field_link.0.url.routeName, node.field_link.0.url.routeParameters) %} Then I can create a custom link:` <a href="{{ url }}" class="mycustomclass">custom link text</a> No preprocess needed and no need to go via content.field_link, so no need to do anything in the 'Manage display' for the link field just to get the url. – Flyke Mar 1 '18 at 8:56
10

I had to do this on a Link Field in a Block. This worked well:

{{ content.field_my_link[0]['#url']|render }}
1
  • 4
    It is also fine to use {{ content.field_my_link[0]['#url'] }} without render, as in twig template, render array are automatically rendered when printed. – eric.chenchao Jun 6 '17 at 2:35
9

I know it's an old post but with the last version of Drupal 8 (8.6) you can directly display the url for both version (external and internal):

node.field_link.0.url

And if you need to know if the link is external or not (for my case it was for the target), you can use that:

node.field_link.0.url.external

Example:

<a href="{{ node.field_link.0.url }}" title="Title" target="{{ node.field_link.0.url.external ? '_blank' : '_self' }}"
1
  • 1
    I like your usage of target = _self for internal and external _blank. It improves the UX. – Tyeth Apr 27 '20 at 11:19
6

you can also use something like the following, it all depends of the type of object you are extracting and the field name, In my case it was a paragraph with a field named field_link and the following worked:

{{ paragraph.field_link.get(0).getUrl().toString() }}
3
  • You are the man today my friend! Look at this craziness! I added a page_link field on one of my taxonomies. So i have to do this: {% set page_url = content.field_category.0['#options'].entity.field_page_link.get(0).getURL().toString() %} Now it outputs the url instead of the node ID, thank you! – Robbiegod Dec 13 '19 at 22:52
  • It worked for me to, this is the solution! – Yann Chabot Mar 30 '20 at 15:35
  • 1
    You saved me again today! This time a paragraph field and getting the full internal link url. {% set full_link_url = content.field_content_block.0['#paragraph'].field_external_link.get(0).getUrl().toString() %} - BTW, this worked in a node template. – Robbiegod Apr 9 '20 at 15:43
4

In paragraph, to get the link url and link name -

<a href="{{ content.FIELD_LINK_NAME[0]['#url']|render }}">
   {{ content.FIELD_LINK_NAME[0]['#title']|render }}
</a>
1

I know it's horrible, but if nothing else works:

{{ link|replace({'internal:':''}) }}

My situation: accessing a Link field via an overridden views template: views-view-fields.html.twig

I had to get the variable from:

row._entity.field_machine_name.value.0.uri

(I gave up trying to use the fields variable, you can seemingly get a .content property out of that, but not much else)

….field_machine_name.value is just a flat array, which only has a uri key, NOT url, and the filters mentioned in other answers (toString(), render etc.) simply don't seem to work here.

0
1

Here's another way to do this. This example exclude the use of the Title field.

{% set link_url = content.field_link.0['#url'] %}
{% set link = link_url ? link_url : content.field_link.0['#title'] %}

{% if link %}
  {{ link.toString() }}
{% endif %}

Possible results

# Input ---------------- Output -----------
# This is a node (23)    /relative/url
# <front>                /
# https://drupal.org     https://drupal.org
1

I needed to add some classes to my link. field_url is a link field. I didn't have content in the Twig context.

{{ node.field_url[0] }} gives me a \Drupal\Core\Url object.

{% set link = node.field_url[0] | view %} This is a filter from the Twig Tweak module. It returns a render array.

I can now output my link like this:

<a href="{{ link['#url'] | render }}" class="featured-link featured-link--small">{{ link['#title'] | render }}</a>

Twig tweak is amazing. Here is a link to the cheat sheet where you can see all the functionality.

0

Actually there is much simpler solution using https://www.drupal.org/project/twig_field_value module

<a href="{{ content.FIELD_LINK_NAME|field_value|first['#url']|render }}">
  {{ content.FIELD_LINK_NAME|field_value|first['#title'] }}
</a>

This will work for both internal and external links.

1
  • Better if you use this: {{ content.field_my_link|field_raw('uri') }} – Roger Apr 14 at 9:34
0

Supplementary answer

The answer above can be applied to a Drupal Paragraph:

{{ node.field_link.0.url }}

...if you replace the entity type name node with paragraph as so:

{{ paragraph.field_link.0.url }}

Where in your site, you would have created a Paragraph with a field called link - which would have machine name field_link.

I found that the above {{ paragraph.field_link.0.url }} renders to the URL when used link this:

<a href="{{ paragraph.field_link.0.url }}">{{ paragraph.field_link.0.title }}</a> 

This works for both internal and external URLs. I tested:

  • #our-team - a URL fragment for use with an <a anchor
  • https://bbc.co.uk

I have defined in the paragraph instance I added in a entity reference node - the usual process for adding paragraphs, of course.

For my purpose, I wanted to create a Call-to-action (CTA) button, using a paragraph, here is all my code below to do that, which illustrates how I've used the twig link and title.

I enclose the whole paragraph markup with the with <a href="{{ paragraph.field_link.0.url }... .../>

And put the link text, the title inside: {{ paragraph.field_link.0.title }}

file:

web/themes/custom/my_theme/templates/paragraphs/paragraph--call-to-action.html.twig

code:

{%
  set classes = [
    'paragraph',
    'paragraph--type--' ~ paragraph.bundle|clean_class,
    view_mode ? 'paragraph--view-mode--' ~ view_mode|clean_class,
    not paragraph.isPublished() ? 'paragraph--unpublished'
  ]
%}
{% block paragraph %}

  <div class="mysite-cta-outer">
  <a href="{{ paragraph.field_link.0.url }}">
    <span{{ attributes.addClass(classes).addClass('mysite-cta-fixed') }}>
      {% block content %}
        {{ paragraph.field_link.0.title }}
      {% endblock %}
    </span>
  </a>
  </div>

{% endblock paragraph %}

file:

web/themes/custom/my_theme/css/styles/_cta.css

code:

.mysite-cta-outer {
  padding-top: 1.0em;
  padding-left: 1.5em;
}

.field--name-field-main-call-to-action-area {
  margin-bottom: 5em;
}


.mysite-cta-fixed {
  border-radius: 0.5em;
  border: 0.2em solid;
  padding-top: 0.8em;
  padding-bottom: 0.8em;
  width: 15em;
  color: white;
  display: inline-block;
  text-align: center;
}

span.mysite-cta-fixed a
{
  text-decoration: none;
  color: white;
}


span.mysite-cta a
{
    text-decoration: none;
    color: white;
}

.mysite-cta {
  border-radius: 0.5em;
  border: 0.2em solid;
  padding-top: 0.8em;
  padding-bottom: 0.8em;
  padding-left: 2em;
  padding-right: 2em;
  color: white;
  display: inline-block;
}

Also, a comment about, url vs uri as this has been talked about in other answers. For me, as you can see from my code, url is what I use, in the <a href="{{ paragraph.field_link.0.url }}">...

vardumper util (from Drupal module twig_vardumper ) shows the following for url and url:

{{ vardumper( paragraph.field_link.0.url ) }}

  • output :-

output of vardumper( paragraph.field_link.0.url )

^ that initially put me off using url because it was a Url class and not text which I assumed had to be output but it is the right one for outputting the URL. So what seems to happen is that twig renders this Url object as text automatically.

And here's uri output

{{ vardumper( paragraph.field_link.0.uri ) }}

output:-

^ "internal:#our-story"

Which I didn't use for aforementioned explanation.

This took me a few hours for troubleshooting so I'm grateful for the other answers here, though a bit despairing that there are multiple ways to do it, which potentially causes confusion, also somewhat demoralising to spend a lot of time on something so small. The 'dot' notation here is still something mysterious to me as to how to use it fully, and it shouldn't be. I hope to encounter a definitive guide to get results quickly with this. These answers here do help in the meantime!

0

Another solution would be installing Twig Field Value module and then do the following:

{{ content.field_my_link|field_raw('uri') }}

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.