54

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.

14 Answers 14

62

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, 2016 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, 2016 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, 2016 at 7:32
  • 1
    Yeah, it works. The syntax is a bit scary, but it does its job.
    – Andrea
    Apr 30, 2016 at 11:53
  • 2
    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, 2016 at 13:30
27

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, 2018 at 21:05
  • It appears this is now the correct answer. Mar 31, 2020 at 21:40
  • This one worked for me.
    – Alex
    Jan 27, 2021 at 15:29
22

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 %}
3
  • 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, 2018 at 8:56
  • 3
    I believe you could just call node.field_link.0.url.toString as toString would handle the internal/external logic for you. Dec 3, 2021 at 17:06
  • 1
    external is now protected property, hence not accessible, use isExternal() function.
    – Sharique
    Jan 25 at 6:08
14

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. Jun 6, 2017 at 2:35
12

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() }}
5
  • 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, 2019 at 22:52
  • 1
    It worked for me to, this is the solution! Mar 30, 2020 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, 2020 at 15:43
  • For me this one works for internal & external links
    – Hodgekins
    Jun 15, 2021 at 13:07
  • Thank you. So what are Twig and Drupal doing internally when we say {{ paragraph.field_link.url that is not that? /headdesk (To be clear, Israel's code works, and it is Drupal failing to do that by default that is flabbergastering me.)
    – mlncn
    Mar 25 at 1:55
11

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, 2020 at 11:19
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

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, 2021 at 9:34
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

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

I'm using mix of the next solutions for wrap content in a link within paragraph entity and to add target attribute:

{% set link = paragraph.field_link.get(0) %}
{% set url = link.getUrl().toString() %}

{# prevent having urls built from special types "<button>", "<nolink>", but allow "<front>" #}
{% if url %}
  <a href="{{ url }}" target="{{ link.url.external ? '_blank' : '_self' }}">
{% endif %}
    content here...
{% if url %}
  </a>
{% endif %}
0

Following on from a previous answer - Twig tweak is my goto for future proofing some of the cryptic syntax used in the past.

{{ node.field_link_to_purchase | file_url }} - this work for me on the latest version at the time of writing.

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.