Agaric Collective: Doing links on Drupal 8

Planet Drupal - Fri, 2017/04/14 - 9:19pm

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(''));

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:


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': ) }}"> {{ '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()]);

Drupal core announcements: Drupal core security release window on Wednesday, April 19, 2017

Planet Drupal - Fri, 2017/04/14 - 5:29pm
Start:  2017-04-19 12:00 - 23:00 UTC Organizers:  xjm catch cilefen David_Rothstein stefan.r Event type:  Online meeting (eg. IRC meeting)

The monthly security release window for Drupal 8 and 7 core will take place on Wednesday, April 19.

This does not mean that a Drupal core security release will necessarily take place on that date for any of the Drupal 8 or 7 branches, only that you should watch for one (and be ready to update your Drupal sites in the event that the Drupal security team decides to make a release).

There will be no bug fix or stable feature release on this date. The next window for a Drupal core patch (bug fix) release for all branches is Wednesday, May 03. The next scheduled minor (feature) release for Drupal 8 will be on Wednesday, October 5.

For more information on Drupal core release windows, see the documentation on release timing and security releases, and the discussion that led to this policy being implemented.


I Fix Drupal: Synchronising production Drupal database to a dev environment

Planet Drupal - Fri, 2017/04/14 - 4:13pm
Drush has a great feature that allows you to limit the data that will be exported when you dump a database. Using this feature you can pull the schema for the entire database while specifying tables who's data you wish to ignore. This can substantially reduce the time it takes to complete an sync operation, especially the time spent importing the DB on the target. The key to this piece of magic lies inside drushrc.php, where you can predefine those lists of tables that do not require data to be dumped using this option. $options['structure-tables']['common'] = array('cache', 'cache_*', '...

Dropsolid: Online payments in Drupal

Planet Drupal - Fri, 2017/04/14 - 9:36am
Online payments in Drupal Thierry Fri, 04/14/2017 - 09:36

In this day and age, it’s very hard to imagine a world without online payments. They permeate every possible sector and purpose, ranging from banking apps to online ticket ordering and charity donations.

Drupal has kept pace with this evolution and is offering enterprise-quality solutions to tackle most online payment needs, most notably Drupal Commerce with secure payment integrations. Drupal Commerce allows developers to implement different gateways to PayPal, Stripe, iDeal, Mollie and Ingenico (previously known as Ogone).

In this blog post, I will explain the possibilities of the Drupal Payment module and describe an example of how to apply it together with Mollie, a rising star in the realm of payment service providers.


Drupal Payment module

Are you looking to make people pay for their membership when they register for an account? Then you will have to integrate an easily manageable payment system into your application.

In situations like these and more, Drupal’s Payment module can act as a bridge to a secure payment integration. You can implement different payment gateways that communicate directly with the Payment module. This means that all incoming payments from various payment service providers are stored in a centralised location.

The Payment module integrates well with Drupal Commerce and Ubercart, but you can even integrate the module into any kind of entity with both the Payment form field and the Payment reference field.

Do you think this might suit your need as an out-of-the-box solution for a simple integration with Drupal Webforms or a basic donation form with Drupal Payment integration? They are available for download on

Payment Service Providers

If you would like to receive online payments through you website, you'll have to implement an actual payment service provider. The most commonly used payment providers in the Benelux are Ingenico, Paypal and Mollie.


Mollie has become very popular very quickly, because it charges a transaction-based fee instead of a monthly subscription. This means that you will not be charged if there are no transactions, which is perfect for projects that do not (yet) generate a lot of transactions.

To allow for easy integration, Mollie provides developers with a very good API. Drupal (and other) developers can access the available RESTful service or a PHP API library, which makes it possible to implement logic - for example to refund a customer through the API.
If your Drupal project does not require automatic refunding of customers, you can use the mollie_payment module, which uses Mollie’s PHP API library.

Example: enabling a payment method

To enable payments with Mollie, you have to define a payment method using the so-called MolliePaymentMethodController. The controller is defined in the Mollie Payment module and uses Mollie's PHP API library to process the requests.

You can add the Payment method through the module install file:

/** * Add payment method (Mollie) */ function MYMODULE_update_7001(){ $mollie = new PaymentMethod(array( 'controller' => payment_method_controller_load('MolliePaymentMethodController'), 'controller_data' => array('mollie_id' => 'test_AA11bb22CC33dd44EE55ff66GG77hh'), 'name' => 'pay_with_mollie', 'title_generic' => 'Pay with Mollie', 'title_specific' => 'Pay with Mollie', )); entity_save('payment_method', $mollie); }


Forms embedding a payment form

Start by defining a simple form, extendable with multiple form elements available in Drupal’s Form API.

/** * Callback function to build a basic payment form. * * @param array $form * The form build array. * @param array $form_state * The form state information. */ function MYMODULE_form($form, $form_state) { $form = array(); // Add form actions. $form['actions'] = array( '#type' => 'actions', ); $form['actions']['save'] = array( '#type' => 'submit', '#value' => t('Pay with Mollie'), ); return $form; }


This form is then capable to embed a payment form, provided by the Payment module. In order to do this, you should first define a Payment object. This will provide all the payment methods that have to be integrated in the payment form. You can pass context and context data for reference and later use, the currency you are making a payment in and the callback that has to be executed after a payment has been done.

// Define a payment object. $payment = new Payment(); $payment->context = 'donation'; $payment->context_data = array( 'time' => time(), 'type' => 'donation', ); $payment->currency_code = 'EUR'; $payment->description = 'Basic payment form'; $payment->finish_callback = 'MYMODULE_finish_callback';


A single payment object can contain multiple items. Useful if you would like to implement this in a commerce environment. In this example, a single line item will define the total amount that has to be paid. Don't forget to define the price without taxes, because the Payment module will handle all tax calculations.

// Define a payment line item. $line_item = new PaymentLineItem(); $line_item->amount = 100.00 / 1.21; $line_item->name = t('EUR 100'); $line_item->tax_rate = 0.21; $line_item->quantity = 1; // Add the payment line item to the payment object. $payment->setLineItem($line_item);


By assigning the payment object to the form, you can use the transferred information in a later stage - for instance during validation.

// Add the payment object to the form. $form_state['payment'] = $payment;

You can use multiple payment methods with the payment module. In this example, Mollie is forced as the only payment option available. It is of course also possible to add multiple methods in the payment options and to allow people to pick their payment method of choice.


// Get available payment methods and limit this form to Mollie payment. $payment_methods = $payment->availablePaymentMethods(); $payment_options = array(); foreach ($payment_methods as $payment_method) { if ($payment_method->enabled && $payment_method->name == 'pay_with_mollie') { $payment_options[] = $payment_method->pmid; } }

To include the payment form into your custom form, you have to call the payment_form_embedded function. The function will use the payment object and the available payment options to build the required form elements and form actions. Then assign the payment elements and submit action to your custom form in order to enable the payment.

// Get the payment embed elements. $payment_embed_form = payment_form_embedded($form_state, $payment, $payment_options); // Add the embedded payment form element. $form['payment'] = $payment_embed_form['elements']; // Define the form submit callback. $form['#submit'] = $payment_embed_form['submit'];

When defining the payment object, you actually define a finished callback. This callback will be triggered after a successful payment from the Mollie payment service provider. To be certain, you could check if there is a payment success status within the payment object and run any additional callbacks if needed.

/** * Handle successful payment from Mollie. * * @param \Payment $payment * The returned payment object containing all relevant information. */ function MYMODULE_finish_callback(Payment $payment) { $payment_complete = FALSE; // Check if the payment status contains a successful state. foreach ($payment->statuses as $status) { if ($status->status == 'payment_status_success') { $payment_complete = FALSE; break; } } if ($payment_complete) { drupal_set_message('Your payment has been received.', 'success'); // @TODO: Implement custom callbacks. } }



As you noticed, it's not that hard to implement a payment workflow in your own form! 

One final tip: use form validation to check if all requirements are met before people are redirected to the payment service provider.

I hope this blog post has helped you to make payments in Drupal easier. Feel free to leave a comment below if you have any questions or if you would like to share some thoughts on different possible approaches.

Add new comment Header image Tags Drupal 8 Tech Teaser image Publish to Drupal planet On

Aten Design Group: See you at DrupalCon Baltimore, hon!

Planet Drupal - Thu, 2017/04/13 - 7:56pm

It’s that time of year again when the Drupal community of developers, designers, strategists, project managers and more come together for the biggest Drupal event in the world: DrupalCon North America. This year, from April 24-28, we'll be in Baltimore and here’s where you can find us:

The Aten Booth

Be sure to stop by booth 216 in the exhibit hall, we’d love to chat about the successes and challenges you face in your web projects. We’ll also have our sought-after sketchbooks to add to your collection.

Monday, April 24 Nonprofit Summit

We are thrilled to support the newly added Nonprofit Summit at DrupalCon this year. Chris, Aten’s Director of Digital Strategy, and Joel, Aten’s Director of Engineering, work closely together and are sharing tips to create intuitive and compelling experiences for organizations to successfully connect with their users.

Tuesday, April 25

Mastering Drupal 8’s Libraries API
Matt Jager
2:45 p.m. - 3:15 p.m.
Room: 307 - Acquia

Wednesday, April 26

Powering an Interactive SVG and JavaScript Game Engine with Drupal
Peter Weber
2:45 p.m. - 3:15 p.m.
Room: 307 - Acquia

A Type System for Tomorrow
Gabe Sullice
3:45 p.m. - 4:45 p.m.
Room: 318 - New Target

Thursday, April 27

Testing for the Brave and True
Gabe Sullice
10:45 a.m. - 11:45 a.m. Room: 315 - Symfony


Mediacurrent: Inclusive Development: Using Style Guides to Improve Website Accessibility

Planet Drupal - Thu, 2017/04/13 - 5:58pm
What exactly is the role of a Front-end developer?

What exactly does it mean to be a 'front-end developer'? From company to company? From website to website? Really, from day to day? Does your colleague actually do the same job as you? For example, some days I’m working in InDesign or Photoshop all day, the next I’m writing jQuery or building theme components. The very next day I am writing a blog post, prepping for a presentation, or doing research on the latest trends.


Mediacurrent: Inclusive Development: Using Style Guides to Improve Website Accessiblity

Planet Drupal - Thu, 2017/04/13 - 5:58pm
What exactly is the role of a Front-end developer?

What exactly does it mean to be a 'front-end developer'? From company to company? From website to website? Really, from day to day? Does your colleague actually do the same job as you? For example, some days I’m working in InDesign or Photoshop all day, the next I’m writing jQuery or building theme components. The very next day I am writing a blog post, prepping for a presentation, or doing research on the latest trends.


Tag1 Consulting: Drupal Load Testing with

Planet Drupal - Thu, 2017/04/13 - 5:48pm
Apache JMeter and I have a long and complicated relationship. It is definitely a trusted and valuable tool, but I am also quite confident that certain parts of it will make an appearance in my particular circle of hell. Due to this somewhat uncomfortable partnership, I am always interested in new tools for applying load to an infrastructure and monitoring the results. is not exactly a new tool, but I have only recently begun to use it for testing. What Is Locust? Locust is a load-testing framework which allows you to write your load plan in regular Python. This is a welcome experiencRead more nnewton Thu, 04/13/2017 - 08:48

Mediacurrent: DrupalCon Baltimore - Mediacurrent&#039;s GamePlan

Planet Drupal - Thu, 2017/04/13 - 3:54pm

DrupalCon Baltimore here we come! We are Gold sponsors once again this year and there are a ton of ways to connect with our team. Here are some of the highlights:


Acquia Developer Center Blog: 12 Questions that Project Managers Should Ask Before a Drupal Project Kickoff

Planet Drupal - Thu, 2017/04/13 - 3:38pm

You are a Project Manager, sitting at your desk, maybe sipping a fresh-brewed coffee. Suddenly you receive a heads-up that a new Drupal Project is headed your way. Sprint 0 will be starting in the next two days.

You can assume that the SOW (Statement of Work) is signed, or almost signed, and a few SWAGs (Sophisticated Wild Ass Guesses) have already been ventured.

Tags: acquia drupal planet

Amazee Labs: Render a menu tree from custom code in Drupal 8

Planet Drupal - Thu, 2017/04/13 - 12:54pm
Render a menu tree from custom code in Drupal 8

Having menus rendered on a site in Drupal 8 is pretty simple. Most of the time this can be accomplished with site building, in a few clicks. And if you need some more advanced features on top of what the Drupal 8 core has, you can also have a look at modules like Menu Block, or have a look at this (a bit outdated) contributed modules for menus page.

However, you may have some special requirements, for example, to display some small portion of a menu inside the template of a node. There is no simple 'site building' solution for that. You most probably need to code a bit.

Vasi Chindris Thu, 04/13/2017 - 12:54

Let's say you have these requirements: a node which can be part of the main menu, and which could also have menu items bellow it, should display the first level of those menu items somewhere inside its template (so just as you would display a regular field).

The image above shows a very simple visual representation of what we'd like to achieve.

Now let's break this down into smaller and independent pieces. You can also skip to the entire code. Basically, you have to:

  • Load and render a menu (or parts of a menu).
  • Have a custom field available on the Manage display page for a content type, so that you can place it on the node page.

Let's actually start with the second part, as it is simpler.

Custom (extra) fields

There is the hook_entity_extra_fields_info hook which can be used to expose custom or extra fields on the entities. We'll use this hook to provide a custom field on a node.

The visible flag represents the default visibility setting of the field. Usually, you want this to be false, so you decide when the element is displayed and not when it is NOT displayed.

Now clear the cache and go to Structure >> Content types >> YourContentType, click on the Manage display tab and you should see your new field available there.

The next thing is to implement the hook_ENTITY_TYPE_view and particularly, in this case, hook_node_view. Here it is:

Save it, clear the cache, make sure that the field is visible in the display setting for that content type and visit a node of that type. You should see the custom text displayed.

So, we're done with the second part. Let's go and actually load the menu for this node and display the first level of menu items.

Render the menu

For this, we'll have to load a menu using a menu tree service and a set of parameters which define the root to start with, how many levels to load, and so on, then to apply a set of manipulators on the loaded tree that would check the access, do the sorting, etc, and finally to build the menu tree.

The root menu item

One of the tricky things is to get the correct root menu item. We know that the node can be part of a menu. It would be great if we could load a menu link based on the route name and some route parameters. For that, you can use the service.

Menu tree parameters

When loading a menu, we have to provide some parameters. For example, what the root of the menu you want to load (if you want to load a subtree, which is our case) is, or how many levels to load. These parameters are specified using a \Drupal\Core\Menu\MenuTreeParameters object.

More details about the MenuTreeParameters can be found here.

Load the menu

To load the menu, we will use the menu.link_tree service.

Menu tree manipulators

After we have the menu loaded, it is time to actually apply some manipulators on its menu items. These manipulators will deal with access checking, sorting according to the weights, or whatever other things you want to do with the menu tree. The code looks like that:

So, in this case, we want to check for the access and sort the items. There's a default tree manipulator service in Core which is Drupal\Core\Menu\DefaultMenuLinkTreeManipulators. That already provides a few basic manipulators you can apply to a menu tree, which is enough in our case. But of course, you can add any other callable to that array and use the implementation from Core as a guideline.

Build the menu

Finally, we have to build the menu. This is as simple as:

This would replace the

$build['my_custom_menu'] = [   '#markup' => 'Some custom menu', ]

that you used as a placeholder in the custom_node_view() hook.

And that's it. The first level of navigation, having the current node as root, will be displayed inside the template of your node.

Here is the entire code:

Categories: Blog: AGILEDROP: Agiledrop going to the WebCamp

Planet Drupal - Thu, 2017/04/13 - 9:19am
We must admit that in the past we were not so informative about where we will be and on which (Drupal) event we will go. We promise we'll do better from now on. This means that if you would like to talk to us in person, you'll know where to find us (you can also find us in our office of course). We'll start with a Web Camp we will attend next. A WebCamp will be held in Ljubljana on Saturday 22nd April 2017 in the Faculty of Computer and Information Science, Ljubljana. This is a place very familiar to our development director Bostjan Kovac because he got his bachelor’s degree there. An event… READ MORE

Valuebound: How to build a simple form using AJAX in Drupal 8

Planet Drupal - Thu, 2017/04/13 - 9:15am

Ajax is a script on the client side communicating asynchronously with the server without a complete page refresh.The best description I came across about Ajax as “the method of exchanging data with a server, and updating parts of a web page – without reloading the entire page.”

In our project, while creating a new account if we give the existing username, on submitting the page it will throw an error. But, instead of reloading the page, we can just update certain parts of DOM. This can be achieved using AJAX. So, here is the example how to implement this ajax in drupal 8 forms.

In order to build a simple form using AJAX in Drupal 8 , we created a form with Username field. Using ajax we are going to validate that field. To achieve this, create a…


erdfisch: Drupal Camp Northern Lights (Part 3)

Planet Drupal - Wed, 2017/04/12 - 6:03pm
Drupal Camp Northern Lights (Part 3) 12.04.2017 Michael Lenahan Body: 

This has, for reasons we are not quite sure of, ended up being a three-part blog post.

Part 1 is here and part 2 is here.

So, where we left off was at the tomato farm, where it felt like being in a future farm in outer space.

But the tomato farm is not only that. It is a pony (sorry, "Icelandic horse") farm as well!

On our way back to Reykjavik that evening, we were told "we have to hurry because a big storm is on its way".

When we woke up the next day, Reykjavik had experienced the biggest snow fall in 80 years, and all roads were closed.

There are some beautiful pictures of this here:…

None of this extraordinary weather deterred the incredible team who organized this event.

The Drupal camp at Drupal Camp Northern Lights

The amount of effort that went in to making sure we had a great time was truly amazing, and this was carried over into the sessions as well.

Sprint room

Oftentimes, I don't go into the sprint room at Drupal camps, you can have the feeling that you are interrupting something very important that you don't understand.

This time I thought "no, I'm among friends now" so I ventured in to the sprint room, and sheepishly explained that I'm new and looking for something to work on.

Enzo was there, and he helped me get started on a Drupal Console issue.

Here's how you get started:

And here is the issue I fixed a few weeks after coming back. I feel so proud!

Thanks, Enzo!

Drupal Twig - Mauricio Dinarte

This session was full of insider tips on how to get the most out twig, with lots of entertaining examples out of Drupal core.

You can see the slides here: - real version control of content - Rouven Volk

Rouven explained an interesting way of managing content using a git repository. We're used to having code in git, but there are times when the content needs to be equally trackable.

Rouven's approach is to use Drupal's content revisioning system together with git-wrapper to write all content revisions as commits into a git repository.

That means you can track changes to your content like this:

If you want to get involved with this, join us and work on it at

The Continuing Saga of Layouts in Drupal 8 - Tim Plunkett

Despite being a "certified" front-end developer I'm not really a front-end developer at all.

For this reason I'm very supportive of efforts to make Drupal front-end work less insane.

I was surprised and happy to discover that Tim's talk on Layouts was easy to understand, I even asked a question related to the way panels can be used without a UI.

I think all of this must have had something to do with the magic of Iceland, and this particular Drupal camp, where the entire atmosphere was so friendly that you felt you could chat with anyone about anything.

The Flexibility of Drupal 8 - Michael Miles (mikemiles86)

Mike Miles is a very entertaining and fun speaker to listen to. His talk showed 8 different ways to do a simple change in Drupal.

Slides and link to the code are here:

Or just go and watch the video already

Wrapping up

All that's left to say is thank you, thank you, thank you.

To the organizers and and all the others who I haven't named here.

As you said, Baddy: this was the coolest Drupal camp ever and an experience I think all of us will always remember.

Schlagworte/Tags:  planet drupal-planet Ihr Name Kommentar/Comment Kommentar hinzufügen/Add comment Leave this field blank

erdfisch: Drupal Camp Northern Lights (Part 2)

Planet Drupal - Wed, 2017/04/12 - 5:35pm
Drupal Camp Northern Lights (Part 2) 12.04.2017 Michael Lenahan Body: 

Thanks for sticking around. There will be more than just photos of us goofing around in Iceland, I promise.

For stuff about the actual Drupal Camp, please jump to the end of part three.

So, when we left you in part one, we were exploring the beautiful Golden Circle in Iceland.

We did, indeed, feel like true explorers.

We saw this awesome waterfall, the same one that was made famous by Kim Kardashian in her "Iceland Waterfall" tweet.

And then we went for dinner at this incredible place that grows tomatoes year-round using geothermal energy

More in part three which also features an Icelandic horse.

Schlagworte/Tags:  planet drupal-planet Ihr Name Kommentar/Comment Save Leave this field blank

OpenLucius: 16 Cool Drupal modules For site builders | April 2017

Planet Drupal - Wed, 2017/04/12 - 5:25pm

It took a while before I could write a new edition, I was just busy with the production of customer social intranet projects :) Here again with a brand new version, what struck me in module updates in the past month:

1. D8 Editor Advanced link

Acquia Developer Center Blog: ES6 for Drupal Developers: ES6 Modules, Classes, and Promises

Planet Drupal - Wed, 2017/04/12 - 5:10pm

Some of the most important new features in ES6 originate from existing solutions for problems shared by a large swath of JavaScript applications. This is particularly true of ES6 modules, a new system of class-based inheritance, and promises. Prototypal inheritance can be difficult for those new to JavaScript. And at some point, modules and promises have both been present in various JavaScript libraries, but until now, they were impossible to implement natively.

Tags: acquia drupal planet

erdfisch: Drupal Camp Northern Lights (Part 1)

Planet Drupal - Wed, 2017/04/12 - 4:32pm
Drupal Camp Northern Lights (Part 1) 12.04.2017 Michael Lenahan Body: 

tl;dr: Drupal Camp Northern Lights was even better than the actual Northern Lights.

This was the best Drupal event I have ever attended. So, even though it is two months late, it deserves a blog post.

95 very, very lucky people attended.

Instead of a camp t-shirt, the organizers gave us some memories we will always live with.

We had dinner at the Icelandic broadcasting corporation's offices. This was the view from the roof of RÚV.

Apologies to any real Drupal Vikings out there for this photo.

Here we are at the intercontinental divide between North America and Europe. North America is to the left and is, as you can see, by far the more impressive of the two tectonic plates.

We felt like true explorers.

More of this in part two.

Or you can skip to part three where the stuff about the Drupal camp actually is.

Schlagworte/Tags:  planet drupal-planet Ihr Name Kommentar/Comment Save Leave this field blank

Another Drop in the Drupal Sea: On being the change I want to see in the community

Planet Drupal - Wed, 2017/04/12 - 3:39pm

Yes, this is another one of "those posts."

No, this is not another one of "those posts."

read more


Evolving Web: Migrate translated content from Drupal 6 to Drupal 8

Planet Drupal - Wed, 2017/04/12 - 3:15pm

Now that Drupal 6 has reached end-of-life, many sites are moving to Drupal 8. If you had multilingual content in Drupal 6, this upgrade used to be very difficult—but since Drupal 8.2 there is support for migrating all your translations! In this article, we will discuss how to migrate translated content from Drupal 6 to Drupal 8.

This article would not have been possible without the help of my colleague Dave. Gracias Dave!

The problem

We have a Drupal 6 database containing story nodes about animal hybrids. Some nodes have translations in English, Spanish and French; some are untranslated; and others are language-neutral (non-translatable). Our goal is to migrate the D6 nodes into a D8 website, preserving the translations.

Before we start The module

To write the migrations, we create a module - in our case, migrate_example_i18n. There's nothing special about the module declaration, except for the dependencies:

  • migrate_plus and migrate_tools provide various features for defining and executing migrations.
  • migrate_source_csv: Will be used for demonstrating migration of translated content from non-Drupal sources in an upcoming article.
  • migrate_drupal: This module provides tools for migrating data from older versions of Drupal. It comes with Drupal 8.x core. Since this migration uses a Drupal 6 site as a source for its data, we need the migrate_drupal module.
How do translations work?

    Before jumping into writing these migrations, it is important to mention that Drupal 6 and Drupal 8 translations work very differently. Here's the difference in a nutshell:

    • Drupal 6: When we translate a node, a new node is created with a different ID. This translated node has a property named tnid, which stores the ID of the original node, linking the two nodes together. For language-neutral or untranslated content, the tnid is set to 0.
    • Drupal 8: When we translate a node, no new node is created! The translation is saved in the fields of the original node, but with a different language code.

    To map between the D6 and D8 translation models, we'll use two migrations:

    • The example_hybrid_base migration will migrate the original content of each node, untranslated.
    • The example_hybrid_i18n migration will migrate in all the translations, and connect each one to the original node from example_hybrid_base..

    We group the two migrations using the example_hybrid migration group to keep things clean and organized. Then we can execute both migrations with drush migrate-import --group=example_hybrid --update.

    Step 1: Base migration

    Let's start with the example_hybrid_base, to migrate all the base data (non-translations) in this migration. Described below are some noteworthy parameters:

    Source source: plugin: d6_node node_type: story key: drupal_6 constants: node_article: article body_format: full_html
    • plugin: Since we want to import data from a Drupal installation, we need to set the source plugin to d6_node. The d6_node source plugin is introduced by the migrate_drupal, module and it helps us read nodes from a Drupal 6 database without having to write queries manually.
    • node_type: This tells the source plugin that we are interested in just one particular Drupal 6 node type, namely story.
    • key: Our Drupal 6 data doesn't come from our main Drupal 8 database—instead it comes from a secondary database connection. We choose a key to identify each such connection, and we need to tell the source which such key to use. The keys themselves are defined in the $databases variable in our settings.php or settings.local.php. See the example settings.local.php file to see how it's done.
    • constants: We define some hard-coded values under this parameter.
    • translations: Notice there is no translations parameter here. The default value (false) tells the source plugin that we're only interested in migrating non-translations, i.e. content in the base language and language-neutral content.
    Destination destination: plugin: 'entity:node'
    • plugin: Since we want to create node entities in Drupal 8, we specify this as entity:node. That's it.
    • translations: Again we do not define the translations parameter while migrating base data. Omitting the parameter tells the destination plugin that we are interested in creating fresh nodes for each record, not translations of existing nodes.
    Process process: type: constants/node_article langcode: plugin: default_value source: language default_value: und 'body/value': body 'body/format': constants/body_format title: title field_one_liner: field_one_liner sticky: sticky status: status promote: promote

    This is where we map the old node properties to the new node properties. Most of the properties have been assigned as is, without alteration, however, some noteworthy properties have been discussed below:

    • type: We specify that we want to create article nodes.
    • langcode: The langcode parameter was formerly language in Drupal 6, so we rename it here. Also, if a Drupal 6 node is language-neutral, it will have no value at all here. In that case,  we default to und.
    • body: We can assign this property directly to the body property. However, the Drupal 6 data is treated as plain text in Drupal 8 in that case. So migrating with body: body, the imported nodes in Drupal 8 would show visible HTML markup on your site. To resolve this, we explicitly assign the old body to body/value and specify that the text is in HTML by assigning full_html to body/format. That tells Drupal to treat the body as Full HTML.
    • nidThere is no nid parameter here, because we don't care what nid each new node has in Drupal 8. Drupal can just assign a new nid to each node in the normal way.

    This takes care of the base data. If you run this migration with drush migrate-import example_hybrid_i18n --update, all Drupal 6 nodes which are in base language or are language-neutral will be migrated into Drupal 8.

    Step 2: Translation migration

    We are halfway through now! All that's missing is migrating translations of the nodes we migrated above. To do this, we create another migration with the ID example_hybrid_i18n:

    source: plugin: d6_node node_type: story translations: true # ... destination: plugin: 'entity:node' translations: true process: nid: plugin: migration source: tnid migration: example_hybrid_base langcode: language # ... migration_dependencies: required: - example_hybrid_base

    The migration definition remains mostly the same but has the following important differences as compared the base migration:

    • source:
      • translations: We set this to true to make the source plugin read only translations.
    • destination:
      • translations: We set this to true to make the destination plugin create translations for existing nodes instead of creating fresh new nodes for each source record.
    • process:
      • nid: In this case, we do care what the Drupal 8 nid is for each node. It has to match the nid for the untranslated version of this content, so that Drupal can add a translation to the correct node. This section uses the migration process plugin to figure out the right nid. It tells Drupal to check the previously-executed example_hybrid_base migration for a D6 node that has the same tnid as this D6 node. It will then then reuse the resulting nid here.
      • langcode: We define the language in which the translation should be created.
    • migration_dependencies: Since we cannot add translations to nodes that do not yet exist, we tell Drupal that this migration depends on the base migration example_hybrid_base. That way, the base migration will run before this migration.

    That's it! We can run our translation migration with drush migrate-import example_hybrid_i18n --update and the translations will be imported into Drupal 8. Alternatively, we can use the migration group we defined to run both these migrations at once - the base migration will automatically be executed first and then the i18n migration. Here's how the output should look:

    $ drush migrate-import --group=example_hybrid --update Processed 8 items (8 created, 0 updated, 0 failed, 0 ignored) - done with 'example_hybrid_base' Processed 9 items (9 created, 0 updated, 0 failed, 0 ignored) - done with 'example_hybrid_i18n'

    You can check if everything went alright by clicking the Translate option for any translated node in Drupal 8. If everything went correctly, you should see that the node exists in the original language and has one or more translations.

    Next steps + more awesome articles by Evolving Web