Skip to main content

Blog

Functionality designed to your life is the Agaric Design signature. Utilizing open source, free software from around the world, Agaric Design websites are impeccably crafted with a modern, sophisticated and understated spirit.

Our guiding philosophy is to bring open source and usability that works effortlessly in your day to day life.

I know we will become a favorite in your contacts list. And thank you! I consider that the ultimate compliment.

Dan Hakimzadeh

Wow, that was fun. The very first event for the Boston/Cambridge Worker Ownership Meetup group on October 10th, 2014, was a great success. We met at The Industry Lab, Agaric's new co-working headquarters and event location. We had a great discussion that was led by our friend Gonzalo Chomon of EvoVelo, a cooperative located in Spain.

Gonzalo Chomon shared a wealth of knowledge about the inner workings of cooperatives that engaged everyone from the start. About a dozen attendees talked about the different ways cooperative companies are structured, laws governing different types of companies in Spain and the US and about the different internal processes used to add or remove members from the group.

Attendees were very engaged in the discussion from the start. One member asked about the company structure, how does it work, are there contracts, bylaws? A cooperative company can be structured in any way the partners agree upon. Usually the company is formed as an LLC between the partners with equal shares, but that is not an absolute. An organization the size of Mondragon has an entirely different structure, it is a federation of cooperatives.

The pizza from The Just Crust rocked and was totally consumed by the end of the evening. Many thanks, to our friend Kay Van Valkenburg who brought some lush fruits and scrumptious chocolate chip and dark chocolate dipped cookies—oooooh. Thanks to everyone that came to the first Boston/Cambridge Worker Ownership Meetup at the Industry Lab in Cambridge, despite the brilliant New England weather.

We have already planned our next meetup for November 17th at the Industry Lab.

We will talk with Carolyn Edsell-Vetter, from A Yard & A Half Landscaping Cooperative, based right in Waltham, MA, about transitioning to a coop from another ownership/governance structure. Meet some local people that are currently working in successful worker cooperatives in any industry, doing what they love to do. Let's discuss how they started and how they continue to thrive in this economy. What are the benefits and what are the hurdles to overcome when forming a cooperative relationship with your partners?

Join us! Visit the Boston/Cambridge Worker Ownership Meetup, we have started to list some great coop resources and links, and if you are in the Boston area, let us know.

If you are interested in a private training tailored to your needs, give us an idea of what you are looking for and we will follow up with you soon thereafter.

What are you all about?

Seven fresh dough balls and a rolling pin.

Drupal migrations

Understanding the ETL process

 

 

Find It Overview

I. Features

  1. Intuitive, Structured Authoring Experience for Service Providers
  2. Easy but Powerful Search for Residents
  3. Informative Opportunity Pages

II. Communities Using Find It

 

I. Features

1. Intuitive, Structured Authoring Experience for Service Providers

The value of a directory are the listings within it. It is truly a community effort to assemble enough accurate and up-to-date resources in a single place for it to be useful. For Cambridge, the service providers that work at government agencies and nonprofits are the lifeblood of the directory. Without them, there would be no Find It Cambridge.

For these service providers (many already pressed for time), Find It is a system that is easy enough to take the time to enter information into, and which conveniently structures the data so that it can easily be searched and filtered on by community-members looking for opportunities.

Through user research, we mapped the information architecture to the mental models that service providers hold for their events and programs.

Input Fields Grouped by Key Questions

Most service providers thought of their events in terms of what the event is about, how to contact the organizers, who it is for, when it is happening, where it is happening, how much it costs, and if there is any sort of registration required. So we organized fields into working tabs to match: About, Contact, For whom, When, Where, Cost, and Signup.

Autosave and Soft Required Fields

Even with fields grouped by tabs, the form can take some time to complete. That is why we introduced autosave and soft save features. When working on a form, the site automatically saves the current draft every few seconds. Service providers can also save a draft to return to later. Fields that are required for publishing, are optional for a draft.

Draft States to Save Work for Later

Service providers have many responsibilities to juggle. It is important that they can start creating an event or program, save it and return to it later before publishing it.

Drupal has powerful workflow states, which we have put to use to help service providers clearly know the status of their content.

A service provider can either save their content as a draft or publish it immediately. If saved as a draft, a banner appears on the page clearly indicating that the event or program is not yet published.

Screencast of save as a draft workflow.
Authors can save their work as a draft, bypassing required fields until they are ready to publish.

Authors can also create a draft alongside a published version. This allows new versions to be worked on, while maintaining the current page for site visitors.

Screencast of workflow for having a draft while a previous version of a page stays publishe
Authors can have a published version of a page and also have a working draft that eventually becomes the new version.

Help Text and Character Counts for Guidance

There are particular ways to write and format content on events and programs to make the most of Find It's features. We provide help text along the way to clue providers in on the best ways to write their content. We also include a character count so providers know if they are staying within the recommended limits for certain text fields.

Bulk Select for Quick Data Entry

Certain fields have many options. In some cases the majority of them apply. For example, many educational events are for all ages up to 18. In that scenario, having a "Select All" option speeds up the data entry process. The Selectize JavaScript library adds elegant toggle and check all options to multi-value fields. We created the CheckboxesJS Drupal project so that other Drupal sites can easily incorporate these features on fields of their choosing.

Conditional Fields to Show Only What is Relevant

Some fields on Event and Programs only need to show under certain conditions. For example, if an event does not require registration, then there is no need to worry service providers with a registration link field. Using conditional logic keeps forms simple and streamlined.

Multiple Dates

There was a lot of discussion on whether to support repeating rules or instead allow multiple dates. We decided on multiple dates, as experience has shown that even repeating events oftentimes have exceptions (and because the events we import from Cambridge Public Libraries are a list of arbitrary dates rather than a recurring rule, and somehow no one in computer science has created a library to produce a best-effort recurring rule from a list of dates).

Multiple date fields.
Multiple date fields allow for flexibility on events and programs that happen more than once.

2. Easy but Powerful Search for Residents

Find It search is powered by Apache Solr, a popular open-source enterprise search platform. We use its numerous features to make the search results as relevant as possible for site visitors.  It is an ongoing process of tweaks; here are some of the things we have done so far.

Weighted Fields for Relevance

On content with lots of data like the events and programs of Find It, certain fields carry more importance than others. The title of an event, for example, is one of the most important. The transportation notes, on the other hand, carries less significance in search queries. When someone types the keyword "music lesson", an event with music lesson in the title or summary shows up before a program for English lessons.

Synonym Matching

When someone searches "childcare" but a program uses "child care", the search engine should know these are equivalent. The same is true for "STEM" and "science education."

Find It supports synonyms. The site manager can define synonyms so that when site visitors search for a certain term, results with matching synonyms show up as well.

Key Information in Search Results

We used the results of our user research to show the critical information people need to pin point the right opportunities: title, neighborhood, and a short summary.

Filters for Sophisticated Queries

Filters help users narrow a search query down to specific criteria. In our testing, we found that age and neighborhood were most important, especially for low-income caregivers. For those of us that rely on public transportation, events and programs need to be nearby. We placed these filters accordingly towards the top of the page.

Naming conventions in Cambridge are unique, which is true for other cities too. Residents might not know the official name of their neighborhood or live at the border between two. We have included a labeled, clickable map to help users choose the right neighborhood. We built this so that other Find It platforms can upload their own SVG map to show their neighborhood.

3. Informative Opportunity Pages

Find It comes out of the box with four different types of opportunities: Events, Places, Organizations and Programs.

Organization

The organization serves as the foundation for opportunities posted on a Find It page. Every event and program posted to Find It, belongs to an organization. This helps an organization's page serve as a mini-website. When an event or program is published, it automatically shows up on its organization page.

Organizations can also have "child" organizations, which is helpful for larger groups that might have distinct sub-committees or departments that have sub-departments.

Related programs field.
An organization can have a parent - child relationship.

Event

An event is an opportunity with a clear start and end date. When an event is published it shows up on the Homepage, Events page, Search page and on the organization's page.

Visitors can sort opportunities by start date to find upcoming events.

Find It event page.
An event's multiple dates is converted into human friendly language.

Program

A program is similar to an event. In fact, most fields are shared between the two. A program though, implies more longevity and commitment than an event. Rather than requiring a specific date or dates, a program can simply be "ongoing." There is the option to include specific dates though.

Find It program page.

Place

In the first version of Find It Cambridge, a new opportunity surfaced that did not quite fit into the event, program, or organization categories. Parks, neighborhood pools, and other destinations were a good fit for Find It's library of opportunities. They have open hours, but many of the event fields were irrelevant. The same went for Programs. In fact, sometimes these places have events or programs happening at them.

These are community-minded destinations people can go to. In other words, places.

Find It place page.

 

II. Communities using Find It

Find It Cambridge

Curated by members of the Cambridge Kid's Council, Find It Cambridge was designed to help busy parents stay informed about the plethora of educational opportunities available for their children.

Navigator Immigrant Integration Program (coming soon!)

Curated by Immigrant Family Services Institute, the Immigrant Navigator was designed to provide information on educational events and social services for new Haitian Immigrants in order to ease their transition into life in the United States.

 

 

The Global Training Days is an initiative coordinated by the Drupal Association to introduce new people to the wonderful world of Drupal. The initiative is about providing free or low-cost training to facilitate people gaining familiarity with Drupal in just a day. Depending on the format, attendees can leave the workshop with a website already built. In this blog post, I will explain how to organize one and share experiences and lessons learned after organizing them in Nicaragua since 2014. It is my hope to inspire you to be part of the initiative and organize a workshop in your local community.

Mauricio leading a training.

The basics

To get started, find out the next dates when the workshops would be given worldwide. They happen two days in a row (on Friday and Saturday) approximately every 3 months. Dates are set in the last quarter of the previous year and can be checked at https://www.drupal.org/global-training-days.

For the workshop itself there are two options to choose from in terms of time and curriculum. The first is a What is Drupal? half-day workshop where attendees learn the basics of Drupal. If you go this route it is recommended to spend most of the time explaining the different Drupal concepts, and how they relate to each other in order to build a site. Hands-on instructions where each attendee builds a site can be left out due to time constraints, but it is fine to have a demo where you show how to assemble a website using Drupal.

The second option is an Intro to Drupal full-day workshop where attendees learn the basic concepts and have the opportunity to build a simple yet functional Drupal site. For this type of workshop, you can spend the first half explaining concepts and the second half building the site. Remember the introductory nature of the workshop. Do not try to cover advanced site building concepts. Stick to Drupal core and build your site using using nodes, blocks, views, and core modules like Contact. In either version of the workshop, do not go over how to build themes or modules. If you try to cover too many topics, you might not develop them all appropriately. If you really want to cover these topics, it is better to organize a follow up workshop where they could be explained with more time.

Once you decide the date and type of workshop you want to present, sign up at this page. After doing so you will get an email from the Drupal Association. You will also be added to the list of organizers.

Plan ahead

The dates for the workshops are announced way ahead of time. Be an early bird and do not leave things to the last minute. Ask yourself these questions and plan accordingly:

  • Am I participating the two days (Friday and Saturday) or only one day?
  • Am I presenting a half-day or a full-day workshop?
  • Am I providing computers to attendees or they are required to bring a laptop?
  • Am I providing lunch for attendees or they are required to bring/buy their own food?
  • How many people can attend based on the facility’s capacity?
  • How many people can attend based on the number of speakers?
  • Does each speaker know which section of the workshop they are going to present?
  • If the workshop includes building a Drupal site, which tools will I use?
  • Where should I advertise the workshop?
  • What is the contingency plan in case the Internet service does not work?

Before the training

It may seem obvious, but make sure you have a place with the proper conditions to give a workshop. You will need:

  • a projector
  • a whiteboard or chalkboard, or flipchart and markers
  • a decent Internet connection
  • good room lighting
  • comfortable room temperature
  • zero sound pollution

The last item is very important as you do not want to yell to be heard. It happened to us once that the room next to the workshop laboratory was occupied by a group of loud children. This not only distracted the attendees, but also forced me to raise my voice to be heard. After speaking loudly for a couple of hours my voice had disappeared.

Even without noise pollution, giving back-to-back trainings two days in a row poses quite a challenge to keeping your voice audible. Make sure you have multiple speakers and take turns presenting. Use a microphone if available. It helps to preserve your voice, and helps participants who might not hear very well.

Once you have the venue figured out, be realistic about how many people you can effectively manage. Organizing a workshop takes lots of effort. It is fine to try to teach as many people as possible, but quality is preferred over quantity. In our experience, teaching small groups is more effective because you can dedicate more time to answer all questions each attendee might have and provide a personalized learning experience.

Make sure you get a confirmation of the venue at least 3 weeks before the training so you have time to promote the workshop. In Nicaragua, we always make the announcement in our official Drupal group and on the community’s Twitter and Facebook accounts. But experience has shown us that only a minority of the attendees find out about the event through these channels. In our case, about 90% of attendees discovered the event after seeing an invitation posted to a non-Drupal specific Facebook group of Nicaraguan developers. The 10% remaining is a combination of word of mouth (past participants recommending the workshop to others), people I meet in various tech meetups, and the channels mentioned before.

When deciding where to advertise the workshop, find the right pond and remember to fish where the fish are. If you have some spare dollars, feel free to invest in paid social media advertisement. No matter where you decide to promote the workshop, include the following information in the announcement:

  • Date and times.
  • Name of venue and address.
  • A photo of the building where the workshop will take place! We have experienced people being unable to find the venue. So, play it safe, be verbose with directions, and add a photo of the venue.
  • Whether or not it is required to bring a laptop.
  • Whether or not lunch will be provided.
  • If registration is required, the url where people can register.
  • A note that no previous knowledge is required and that anyone (not only tech people) can join! :-D

Prepare the tools you will use in the training. In Nicaragua, we prefer to use Patrick Drotleff‘s amazing service https://simplytest.me This allows us to focus on building the Drupal site, instead of configuring the myriad of local environments that attendees may have. In our experience, configuring local environments on each attendee’s computer takes too much time. For example, most of the participants that come to our workshops use Windows. Trying to set up a LAMP environment could be surprisingly complicated in this operating system. Even out of the box solutions like XAMPP might not be able to start the web server due to port conflicts. Skype is a recurrent culprit. Starting a MySQL server might also fail. If that happens, skip it altogether and install using SQLite. More often than not, we go the fastest route and use disposable Drupal installations. Keep in mind that you are teaching Drupal site building, not server configuration.

"Anything that can go wrong, will go wrong." Murphy’s law will manifest more often than you would like. Be prepared and have a contingency plan for as much as you can. During one of our workshops, our favorite tool https://simplytest.me was down, but we were prepared with packages for local installation. In another instance, the venue was changing Internet provider and we had no Internet at all. Again, local installations came to the rescue. In such cases, save time by asking people to work in pairs or small groups so you do not have to configure a lot of computers. Bring a copy of your slide deck in a thumb drive so you can present offline in case it is needed. In Nicaragua, not only the tech is community vibrant. Volcanoes are too! With a handful of active volcanoes that produce tremors very often, we need to make sure to have clear instructions on how to leave the facility if necessary. Do your homework and be ready in case anything goes wrong.

On the day of the training

Take with you a laptop, a VGA/DVI/HDMI cable and adapter, and a back up projector if available. Have a copy of your slide deck for offline presenting and all the tools you might need in case the Internet decides to visit Saturn. Arrive early at the venue, set up your computer and projector for the presentation, and write the wi-fi password on the board. If you are providing computers, make sure any tool you intend to use is installed and working.

Take lots of photos (with participants' permission) and share them on social media. Be sure to record the training for posterity. This is not to show off, but to inspire others to organize workshops in their local communities. Make sure to use the official #DrupalGTD hashtag when sharing content. And please respect those who might not want to appear online! In our trainings, after finishing presenting theory and before starting to build sites we ask the attendees for a group photo which we later share on Facebook and Twitter.

We drupalers are fond of freebies. We enjoy stickers, T-shirts, trial online subscriptions, or anything that comes in an event as swag, right? Let’s share this passion with attendees. In our trainings, we use to have a table with lots of stickers for people to take from. In one occasion we also gave away T-shirts. And we have gotten in contact with online education providers to give attendees free trial access to their content. Chris Shattuck from Build a Module has been so kind in offering free access to his amazing library of content for 8 days to every attendee of our workshops. He also gave us some 1-month free memberships to raffle off. And the friendly folks from Knp University provided free access to Drupal-related material to attendees of the November 2015 edition of the workshop. When organizing a workshop make sure to have some treats for your attendees and partner with education providers so they can keep learning when the day is over. Also, show attendees how to stay connected with the broader community by helping them create a drupal.org profile and teaching them how to get involved.

A final comment for this section has to do with attendance. Do not feel bad if the number of people who show up is not the same that the number of people who registered. In fact, almost every time those numbers will not match. Sometimes you will have many attendees and in other occasions only a few. Do not let this disappoint you. Remember what motivated you in the first place to organize the event. Share your knowledge with others, no matter the number of attendees. Personally, I would present any workshop or session as long as at least one person shows up. Everyone’s time is valuable and each attendee sets aside time to listen to you. That is an honor I take with great responsibility, and you should too.

After the training

After you have enjoyed the Global Training Days experience, give thanks to everyone who made the workshop possible. This includes the attendees, co-presenters, venue providers, sponsors, and educational partners. In Nicaragua we post pictures and thank-you notes on Twitter and Facebook. And in those thank-you messages we also include the next dates of the workshop for those who missed it this time.

Of utmost importance is to perform an evaluation of the workshop. Meditate on things that went well, but also on things that went wrong and can be improved. At the end of our workshops we ask for feedback from the attendees. We also take time to improve the slide deck based on the concepts that attendees had difficulty understanding. This often translates to changing the copy, images, and examples used to explain the different concepts.

After all the hard work, give yourself a pat on the back, and share your story with others. You can write a blog post like this or simply post pictures of the workshop online. The Drupal Association is also interested in feedback from you and the attendees, so do not hesitate in providing it.

My wish list

The Drupal Association provides a lot of support and material to promote these events. Unfortunately, this content is only available in English at the moment. I would love to see this content translated to every language spoken by a member of our community. In Spanish for example, there is a great community that could help with the task of translating the content. The same can be said for communities which speak other languages. Eduardo Garcia is running for Director at Large within the Drupal Association and he has interesting ideas about making our community more inclusive for non-English speaking members.

Another wish of mine is collaboration in curriculum building. When the Nicaraguan community started to participate in the Global Trainings Days initiative back in 2014, we found little content that could be used in the workshop. The Drupal Association offers a curriculum in case you need it, but it is in English and our audience speaks Spanish. Because of this, we basically had to start creating a curriculum from scratch. The curriculum we use in Nicaragua is far from perfect, but the content has improved a lot over time. This has taken a lot of time and effort, yet there is no need to repeat the process again. Because of this, we have made our content available under a Creative Commons Attribution - Non Commercial - Share Alike license for anyone to use and adapt to their needs. So far we have available both a slide deck and a video recording of the theory part of one of the workshops. Unfortunately, some videos do not have audio, but we are planning on making another recording in a future edition. Also, I have started working on a written version of the workshop. This document is in a very early stage, but I will continue adding to it as time permits. It would be great if other communities would use this documentation and provide feedback to improve it. Collaborating in building a curriculum in different languages would be amazing. If you like this idea, start working on the curriculum in a new language and promote it to get feedback from others.

Measuring success

There are various parameters that you could use to measure the success of your workshops. For example, the number of attendees and the number of people who keep engaged with the local community thereafter. In Nicaragua, we have organized 10 workshops since 2014 and over 120 people have attended. Some keep engaged, while others do not. But numbers can be cold, so we measure success in non-quantitative ways. For example, seeing people smile when they understand the basic concepts of Drupal, or viewing their excitement after being able to build a website during the training.

Sometimes, we are able to make a more significant impact on the life of attendees. For instance, we are aware of people who could land a Drupal job after attending the workshop and continuing to learn on their own. The fact that we are making an impact on their lives is our best reward. Here are two testimonials of people who got a job after attending our workshops.

Ada Hernández - Translation and code contributor:

Hello everyone. My name is Ada Hernández Acosta and I am from León, Nicaragua. Attending a Drupal workshop presented by Lucas Hedding and Mauricio Dinarte set a milestone in my professional and personal life. At the workshop I learned the basic of Drupal: nodes, taxonomies, views, modules, themes, and more. I also learned the benefits of using Drupal including its security and no cost for usage. Moreover, a worldwide community is actively working on creating new modules, themes, and security updates. After attending the workshop I developed a strong interest in Drupal and decided let Drupal take part in my life. Today I work at MTech, LLC building websites on Drupal. Now I am also a member of this great community and I am able to make contributions to modules I use on the sites I work on. Thank you very much.

Edys Meza - Code contributor:

It was my first experience in something of this nature. I had just finished college and I wanted to learn new technologies. The Global Training Days workshop was a great opportunity for this. After attending the workshop I got an overview of Drupal that helped me a lot in the future. I learned basic concepts (nodes, taxonomies, users, blocks, etc.) each with real life examples; this was intuitive and easy to understand. That day I became part of the great Drupal community. Attending the workshop changed my life. After it I kept learning in the free classes presented by MTech, LLC where I currently work and continue learning everyday. I think these workshops are what make the Drupal community grow and help improve the lives of attendees.

Final comments

Be flexible. Nothing related to the Global Training Day is set in stone. For example, if for any reason you cannot give the training on the day suggested by the Drupal Association, pick another day. It can be in the same week or the week before or after. A good reason to do this is to let yourself rest and have enough time to recover your voice between multiple workshops in the same edition of the initiative.

Community first, companies later. Although the Drupal Association primarily has invited companies to give workshops to promote themselves, growing the Drupal community and sharing your knowledge should be the focus. In Nicaragua, we started to give the training as a local community initiative. It was Drupal Nicaragua, not a company who started giving the workshop in 2014. Later, both Agaric and MTech sponsored the events and education providers partnered with us. Of course, we are very grateful to them for their ongoing support!

Keep calm and enjoy the experience. Undoubtedly there will be mistakes, particularly the first few times you organize the workshop. In Nicaragua, we have given 10 workshops so far and none has been perfect. What is important is that you learn from the mistakes and improve for the next edition. Sometimes we face many difficulties, but we are able to work through them. At the end of the workshop, you will be rewarded by the smiles of people who have learned to build a simple yet functional website in a matter of hours. :-D

This is how the Nicaraguan Drupal community organizes Global Training Days. It is my hope that after reading through you feel inspired to give a training in your local community. When you are ready to take the challenge, pour your heart into it. Upload some photos of the workshop once it is finished, and share your experience, so that the entire Drupal community can benefit from it. If you have already participated in the Global Training Days, please share your story in the comments below. Have fun!

Special thanks to Alina Mackenzie and Lizz Trudeau for their thorough reviews and suggestions to this blog post. Also to Lucas Hedding who has helped move the Nicaraguan Drupal community forward by creating documentation and organizing events. His contributions to the local community are invaluable. And thanks to the amazing BADCamp organizers for providing me financial support to attend the camp the last two years. I have learned a lot during these events and the acquired knowledge has greatly improved the curriculum used at the Global Training Days workshop. The effort that you pour into the camp and keeping it free is inspiring and greatly appreciated. Keep up the good work! :-)

In the 31 days of Drupal migrations series, we explained different aspects of the syntax used by the Migrate API. In today’s article, we are going to dive deeper to understand how the API interprets our migration definition files. We will explain how to configure process plugins and set subfields and deltas for multi-value field migrations. We will also talk about process plugin chains, source constants, pseudofields, and the process pipeline. After reading this article, you will better comprehend existing migration definition files and improve your own. Let’s get started.

Understanding the syntax of Drupal migrations.

Field mappings: process plugin configuration

The Migrate API provides syntactic sugar to make migration definition files more readable. The field mappings under the process section are a good example of this. To demonstrate the syntax consider a multi-value Link field to store links to online profiles. The field machine name is field_online_profiles and it is configured to accept the URL and the link text. For brevity, only the `process` section will be shown, but it is assumed that the source includes the following columns: `source_drupal_profile`, `source_gitlab_profile`, and `source_github_profile`.


process:
  field_online_profiles: source_drupal_profile

In this case, we are directly assigning the value from source_drupal_profile in the source to the field_online_profiles in the destination entity. For now, we are ignoring the fact that the field accepts multiple values. We are setting the link text either, just the URL. Even in this example, the Migrate API is making some assumptions for us. Every field mapping requires at least one process plugin to be configured. If none is set, the get plugin is assumed. It copies a value from the source to the destination without making any changes. The previous snippet is equivalent to the next one:


process:
  field_online_profiles:
    plugin: get
    source: source_drupal_profile

The process plugin configuration options should be placed as direct children of the field that is being mapped. In the previous snippet, plugin and source are indented one level to the right under field_online_profiles. There are many process plugins provided by Drupal core and contributed modules. Their configuration can be generalized as follows:


process:
  destination_field:
    plugin: plugin_name
    config_1: value_1
    config_2: value_2
    config_3: value_3

Check out the article on using process plugins for data transformation for a working example.

Field mappings: setting sub-fields

Let's expand the example by setting the a value for the Link text in addition to the URL. To accomplish this, we will migrate data into subfields. Fields can store complex data and in many cases they have multiple components. For example, a rich text field has a subfield to store the text value and another for the text format. Address fields have 13 subfields available. Our example uses Link fields which have three subfields:

  • uri: The URI of the link.
  • title: The link text.
  • options: Serialized array of options for the link.

For now, only the uri and title subfields will be set. This also demonstrates that, depending on the field, it is not necessary to provide values for all the subfields. One more thing we will implement is to include the name of the online profile in the Link text. For example: “Drupal.org profile”.


process:
  field_online_profiles/uri: source_drupal_profile
  field_online_profiles/title:
    plugin: default_value
    default_value: 'Drupal.org profile'

If you want to set a value for a subfield, you use the field_name/subfield syntax. Then, each subfield can define its own mapping. Note that when setting the uri we are taking advantage of the get plugin considered the default to simplify the value assignment. In the case of title, the default_value process plugin is used to set a fixed value to comply with our example requirement.

When setting subfields, it is very important to understand what format is expected. You need to make sure the process plugins return data in the expected format or the migration will fail. In particular, you need to know if they return a scalar value or an array. In the case of scalar values, you need to verify if numbers or strings are expected. In the previous example, the uri subfield of the Link field expects a string containing the URL. On the other hand, File fields have a target_id subfield that expects an integer representing the File ID that is being referenced. Some process plugins might return an array or let you set subfields directly as part of the plugin configuration. For an example of the latter, have a look at the article on migrating images using the image_import plugin. image_import lets you set the alt, title, width, and height subfields for images directly in the plugin configuration. The following snippets shows a generalization for setting subfields:


process:
  destination_field/subfield_1:
    plugin: plugin_name
    config_1: value_1
    config_2: value_2
  destination_field/subfield_2:
    plugin: plugin_name
    config_1: value_1
    config_2: value_2

If a field can have multiple subfields, how can I know which ones are available? For easy reference, our next blog post will include a list of subfields for different types of fields. To find out by yourself, check out this article that covers available subfields. In summary, you need to locate the class that provides the FieldType plugin and inspect its schema method. The latter defines the database columns used by the field to store its data. Because of object oriented practices, sometimes you need to look at the parent class to know all the subfields that are available. When migrating into subfields, you are actually migrating into those particular database columns. Any restriction set by the database schema needs to be respected. Link fields are provided by the LinkItem class whose schema method defines the three subfields we listed before.

If a field can have multiple subfields, how does the Migrate API know which one to set when no one is manually specified? Every Drupal field has at least one subfield. If they have more, the field type itself specifies which one is the default. For easy reference, our next blog post will indicate the default subfield for different types of fields. To find out by yourself, check out this article that covers default subfields. In summary, you need to locate the class that provides the FieldType plugin and inspect its mainPropertyName method. Its return value will be the default subfield used by the Migrate API. Because of object oriented practices, sometimes you need to look at the parent class to find the method that defines the default subfield. Link fields are provided by the LinkItem class whose mainPropertyName returns uri. That is why in the first example there was no need to specify a subfield to set the value for the link URL.

Field mappings: setting deltas for multi-value fields

Once more, let’s expand the example by setting the populating multiple values for the same field. To accomplish this, we will specify field deltas. A delta is a numeric index starting at 0 and incrementing by 1 for each subsequent element in the multi-value field. Remember that our example assumes that the source has the following columns: source_drupal_profile, source_gitlab_profile, and source_github_profile. One way to migrate all of them into the multi-value link field is:


process:
  field_online_profiles/0/uri: source_drupal_profile
  field_online_profiles/0/title:
    plugin: default_value
    default_value: 'Drupal.org profile'
  field_online_profiles/1/uri: source_gitlab_profile
  field_online_profiles/1/title:
    plugin: default_value
    default_value: 'GitLab profile'
  field_online_profiles/2/uri: source_github_profile
  field_online_profiles/2/title:
    plugin: default_value
    default_value: 'GitHub profile'

If you want to set a value for a subfield, you use the field_name/delta/subfield syntax. Then, every combination of delta and subfield can define its own mapping. Both delta and subfield are optional. If no delta is specified, 0 is assumed which corresponds to the first element of a (multi-value) field. If no subfield is specified, the default subfield is assumed as explained before. In the previous example, if there is no need to set the link text the configuration would become:


process:
  field_online_profiles/0: source_drupal_profile
  field_online_profiles/1: source_gitlab_profile
  field_online_profiles/2: source_github_profile

In this example, we wanted to highlight syntax variations that can be used with the Migrate API. Nevertheless, this way of migrating multi-value fields is not very flexible. You are required to know in advance how many deltas you want to migrate. Depending on your particular configurations, you can write complex process pipelines that take into account an unknown number of deltas. Sometimes, writing a custom migration process plugin is easier and/or the only option to accomplish a task. Even if you can write a migration with existing process plugins, that might not be the best solution. When writing migrations, strive for them to be easy to read, understand, and maintain. For reference, the generic configuration for mapping fields with deltas and subfields is:


process:
  destination_field/0/subfield_1:
    plugin: plugin_name
    config_1: value_1
    config_2: value_2
  destination_field/0/subfield_2:
    plugin: plugin_name
    config_1: value_1
    config_2: value_2
  destination_field/1/subfield_1:
    plugin: plugin_name
    config_1: value_1
    config_2: value_2
  destination_field/1/subfield_2:
    plugin: plugin_name
    config_1: value_1
    config_2: value_2

Process plugin chains

So far, for every field_name/delta/subfield combination we only have used one process plugin. The Migrate API does not impose any restrictions to the number of transformations that the source data can undergo before being assigned to a destination property or field. You can have as many as needed. Chaining of process plugins works similarly to Unix pipelines in that the output of one process plugin becomes the input of the next one in the chain. When the last plugin in the chain completes its transformation, the return value is assigned. We have covered this topic in greater detail in the article on using process plugins for data transformation. For now, let’s consider an example chain of two process plugins:


process:
  title:
    - plugin: concat
      source:
        - source_first_name
        - source_last_name
      delimiter: ' '
    - plugin: callback
      callable: strtoupper

In this example, we are using the concat plugin to glue together the source_first_name and source_last_name. A space is placed in between as specified by the delimiter configuration. The result of this is later passed to the callback plugin which executes the strtoupper PHP function on the concatenated value effectively making the string uppercase. Because there are no more process plugins in the chain, the string transformed to uppercase is assigned to the title destination property. If source_first_name is ‘Mauricio’ and source_last_name is ‘Dinarte’, then title would be set to ‘MAURICIO DINARTE’. Refer to the article mentioned before for other things to consider when manipulating strings. The configuration of process plugin chains can be generalized as follows:


process:
  destination_field:
    - plugin: plugin_name
      source: source_column_name
      config_1: value_1
      config_2: value_2
    - plugin: plugin_name
      config_1: value_1
      config_2: value_2
    - plugin: plugin_name
      config_1: value_1
      config_2: value_2

It is very important to note that only the first process plugin in the chain should set a source configuration. Remember that the output of the previous process plugin is the input for the next one. Setting the source configuration in subsequent process plugins is unnecessary and can actually make the chain produce unexpected results or fail altogether.

Source constants, pseudofields, and the process pipeline

We have covered source constants, pseudo-fields, and the process pipeline in the article on using data placeholders in the migration process. This time, we are only going to give an overview to explain their syntax. Constants are arbitrary values that can be used later in the process pipeline. They are set as direct children of  the source section. Let’s consider this example:


source:
  constant:
    DRUPAL_LINK_TITLE: 'Drupal.org profile'
    GITLAB_LINK_TITLE: 'GitLab profile'
    GITHUB_LINK_TITLE: 'GitHub profile'
process:
  field_online_profiles/0/uri: source_drupal_profile
  field_online_profiles/0/title: constant/DRUPAL_LINK_TITLE
  field_online_profiles/1/uri: source_gitlab_profile
  field_online_profiles/1/title: constant/GITLAB_LINK_TITLE
  field_online_profiles/2/uri: source_github_profile
  field_online_profiles/2/title: constant/GITHUB_LINK_TITLE

To define source constants, you write a constants key and set its value to an array of name-value pairs. When you need to refer to them in the process section, you use constant/NAME and they behave like any other column present in the source. Although not required, it is customary to name constants in uppercase. This makes it easier to distinguish them from regular source columns. Notice how their use makes assigning the link titles simpler. Instead of using the default_value plugin, we read the value directly from the source constants.

Pseudofields also store arbitrary values for use later, but they are defined in the process section. Their names can be arbitrary as long as they do not conflict with a property name or field name in the destination. The value can be set to a verbatim copy from the source (a column or a constant) or they can use process plugins for data transformations. For the next example, consider that there is no need for the link text to be different among online profiles. Additionally, there is another Link field that can only store one value. This new field is used to store the URL to the primary profile. The example can be rewritten as follows:


source:
  constant:
    LINK_TITLE: 'Online profile'
process:
  pseudo_link_text:
    - plugin: get
      source: constant/LINK_TITLE
    - plugin: callback
      callable: strtoupper
  field_online_profiles/0/uri: source_drupal_profile
  field_online_profiles/0/title: '@pseudo_link_text'
  field_online_profiles/1/uri: source_gitlab_profile
  field_online_profiles/1/title: '@pseudo_link_text'
  field_online_profiles/2/uri: source_github_profile
  field_online_profiles/2/title: '@pseudo_link_text'
  field_primary_profile: '@field_online_profiles/0'

A psedofield named pseudo_link_text has been created. It has its own process pipeline to provide the link text that will be used for all online profiles. When you want to use the pseudo, you have to enclose it in quotes (') and prepend an at sign (@) to the name. The pseudo_ prefix in the name is not required. In this case it is used to make it easier to distinguish among pseudofields and regular property or field names.

The previous snippets is also a good example of how the migrate process pipeline works. When setting field_primary_profile, we are reusing a value stored in another field: the first delta of field_online_profiles. There are many things to note here:

  • The migrate process pipeline lets you reuse anything that has been defined previously in the file. It can be source constants, pseudo fields, or regular destination properties and fields. The only requirement is that whatever you want to use needs to be previously defined in the migration definition file.
  • Source columns are accessed directly by name. Source constants are accessed using the constant/NAME syntax.
  • Any element defined in the process section can be reused later in the process pipeline by enclosing its name in quotes (') and prepending an at sign (@). This applies to pseudofields and regular destination properties and fields.

When reusing an element in the process pipeline, its whole structure becomes available. In the previous example, we set field_primary_profile to '@field_online_profiles/0'. This means that all subfields in the first delta of the field_online_profiles field will be assigned to field_primary_profile. Effectively this means both the uri and title properties will be set. Be mindful that when you reuse a field, all its delta and subfields are copied along unless specifically restricted. For example, if you only want to reuse the uri of the first delta you would use '@field_online_profiles/0/uri'. In none of these scenarios, indicating that you want to reuse something guarantees that it will be stored in the new element assignment. For example, the field_primary_profile field only accepts one value. Even if we used '@field_online_profiles' to reuse all the deltas of the multi-value field, only the first one will be stored per the field's (cardinality) definition.

The Migrate API is pretty flexible and you can write very complex process pipelines. The examples we have presented today have been exaggerated to demonstrate many syntax variations. Again, when writing migrations, strive for process pipelines that are easy to read, understand, and maintain.

What did you learn in today's article? Did you know that it is possible to specify deltas and subfields in field mappings? Were you aware that process plugins can be chained for multiple data transformations? How have you used source constants and psuedofield before? Please share your answers in the comments. Also, we would be grateful if you shared this article with your friends and colleagues.

Today we will present an introduction to paragraphs migrations in Drupal. The example consists of migrating paragraphs of one type, then connecting the migrated paragraphs to nodes. A separate image migration is included to demonstrate how they are different. At the end, we will talk about behavior that deletes paragraphs when the host entity is deleted. Let’s get started.

Example mapping for paragraph reference field.

Getting the code

You can get the full code example at https://github.com/dinarcon/ud_migrations The module to enable is UD paragraphs migration introduction whose machine name is ud_migrations_paragraph_intro. It comes with three migrations: ud_migrations_paragraph_intro_paragraph, ud_migrations_paragraph_intro_image, and ud_migrations_paragraph_intro_node. One content type, one paragraph type, and four fields will be created when the module is installed.

Note: Configuration placed in a module’s config/install directory will be copied to Drupal’s active configuration. And if those files have a dependencies/enforced/module key, the configuration will be removed when the listed modules are uninstalled. That is how the content type, the paragraph type, and the fields are automatically created and deleted.

You can get the Paragraph module is using composer: composer require drupal/paragraphs. This will also download its dependency: the Entity Reference Revisions module. If your Drupal site is not composer-based, you can get the code for both modules manually.

Understanding the example set up

The example code creates one paragraph type named UD book paragraph (ud_book_paragraph). It has two “Text (plain)” fields: Title (field_ud_book_paragraph_title) and Author (field_ud_book_paragraph_author). A new UD Paragraphs (ud_paragraphs) content type is also created. This has two fields: Image (field_ud_image) and Favorite book (field_ud_favorite_book) containing references to images and book paragraphs imported in separate migrations. The words in parenthesis represent the machine names of the different elements.

The paragraph migration

Migrating into a paragraph type is very similar to migrating into a content type. You specify the source, process the fields making any required transformation, and set the destination entity and bundle. The following code snippet shows the source, process, and destination sections:

source:
  plugin: embedded_data
  data_rows:
    - book_id: 'B10'
      book_title: 'The definite guide to Drupal 7'
      book_author: 'Benjamin Melançon et al.'
    - book_id: 'B20'
      book_title: 'Understanding Drupal Views'
      book_author: 'Carlos Dinarte'
    - book_id: 'B30'
      book_title: 'Understanding Drupal Migrations'
      book_author: 'Mauricio Dinarte'
  ids:
    book_id:
      type: string
process:
  field_ud_book_paragraph_title: book_title
  field_ud_book_paragraph_author: book_author
destination:
  plugin: 'entity_reference_revisions:paragraph'
  default_bundle: ud_book_paragraph

The most important part of a paragraph migration is setting the destination plugin to entity_reference_revisions:paragraph. This plugin is actually provided by the Entity Reference Revisions module. It is very important to note that paragraphs entities are revisioned. This means that when you want to create a reference to them, you need to provide two IDs: target_id and target_revision_id. Regular entity reference fields like files, images, and taxonomy terms only require the target_id. This will be further explained with the node migration.

The other configuration that you can optionally set in the destination section is default_bundle. The value will be the machine name of the paragraph type you are migrating into. You can do this when all the paragraphs for a particular migration definition file will be of the same type. If that is not the case, you can leave out the default_bundle configuration and add a mapping for the type entity property in the process section.

You can execute the paragraph migration with this command: drush migrate:import
ud_migrations_paragraph_intro_paragraph
. After running the migration, there is not much you can do to verify that it worked. Contrary to other entities, there is no user interface, available out of the box, that lists all paragraphs in the system. One way to verify if the migration worked is to manually create a View that shows paragraphs. Another way is to query the database directly. You can inspect the tables that store the paragraph fields’ data. In this example, the tables would be:

  • paragraph__field_ud_book_paragraph_author for the current author.
  • paragraph__field_ud_book_paragraph_title for the current title.
  • paragraph_r__8c3a9563ac for all the author revisions.
  • paragraph_r__3fa7e9863a for all the title revisions.

Each of those tables contains information about the bundle (paragraph type), the entity id, the revision id, and the migrated field value. Table names are derived from the machine names of the fields. If they are too long, the field name will be hashed to produce a shorter table name. Having to query the database is not ideal. Unfortunately, the options available to check if a paragraph migration worked are limited at the moment.

The node migration

The node migration will serve as the host for both referenced entities: images and paragraphs. The image migration is very similar to the one explained in a previous article. This time, the focus will be the paragraph migration. Both of them are set as dependencies of the node migration, so they need to be executed in advance. The following snippet shows how the source, destinations, and dependencies are set:

source:
  plugin: embedded_data
  data_rows:
    - unique_id: 1
      name: 'Michele Metts'
      photo_file: 'P01'
      book_ref: 'B10'
    - unique_id: 2
      name: 'Benjamin Melançon'
      photo_file: 'P02'
      book_ref: 'B20'
    - unique_id: 3
      name: 'Stefan Freudenberg'
      photo_file: 'P03'
      book_ref: 'B30'
  ids:
    unique_id:
      type: integer
destination:
  plugin: 'entity:node'
  default_bundle: ud_paragraphs
migration_dependencies:
  required:
    - ud_migrations_paragraph_intro_image
    - ud_migrations_paragraph_intro_paragraph
  optional: []

Note that photo_file and book_ref both contain the unique identifier of records in the image and paragraph migrations, respectively. These can be used with the migration_lookup plugin to map the reference fields in the nodes to be migrated. ud_paragraphs is the machine name of the target content type.

The mapping of the image reference field follows the same pattern than the one explained in the article on migration dependencies. Using the migration_lookup plugin, you indicate which is the migration that should be searched for the images. You also specify which source column contains the unique identifiers that match those in the image migration. This operation will return a single value: the file ID (fid) of the image. This value can be assigned to the target_id subfield of field_ud_image to establish the relationship. The following code snippet shows how to do it:

field_ud_image/target_id:
  plugin: migration_lookup
  migration: ud_migrations_paragraph_intro_image
  source: photo_file

Paragraph field mappings

Before diving into the paragraph field mapping, let’s think about what needs to be done. Paragraphs are revisioned entities. To make a reference to them, you need two IDs: their entity id and their entity revision id. These two values need to be assigned to two subfields of the paragraph reference field: target_id and target_revision_id respectively. You have to come up with a process pipeline that complies with this requirement. There are many ways to do it, and the specifics will depend on your field configuration. In this example, the paragraph reference field allows an unlimited number of paragraphs to be associated, but only of one type: ud_book_paragraph. Another thing to note is that even though the field allows you to add as many paragraphs as you want, the example migrates exactly one paragraph.

With those considerations in mind, the mapping of the paragraph field will be a two step process. First, use the migration_lookup plugin to get a reference to the paragraph. Second, use the fetched values to set the paragraph reference subfields. The following code snippet shows how to do it:

pseudo_mbe_book_paragraph:
  plugin: migration_lookup
  migration: ud_migrations_paragraph_intro_paragraph
  source: book_ref
field_ud_favorite_book:
  plugin: sub_process
  source:
    - '@pseudo_mbe_book_paragraph'
  process:
    target_id: '0'
    target_revision_id: '1'

The first step is a normal migration_lookup procedure. The important difference is that instead of getting a single value, like with images, the paragraph lookup operation will return an array of two values. The format is like [3, 7] where the 3 represents the entity id and the 7 represents the entity revision id of the paragraph. Note that the array keys are not named. To access those values, you would use the index of the elements starting with zero (0). This will be important later. The returned array is stored in the pseudo_mbe_book_paragraph pseudofield.

The second step is to set the target_id and target_revision_id subfields. In this example, field_ud_favorite_book is the machine name paragraph reference field. Remember that it is configured to accept an arbitrary number of paragraphs, and each will require passing an array of two elements. This means you need to process an array of arrays. To do that, you use the sub_process plugin to iterate over an array of paragraph references. In this example, the structure to iterate over would be like this:

[
  [3, 7]
]

Let’s dissect how to do the mapping of the paragraph reference field. The source configuration of the sub_process plugin contains an array of paragraph references. In the example, that array has a single element: the '@pseudo_mbe_book_paragraph' pseudofield. The quotes (') and at sign (@) are required to reuse an element that appears before in the process pipeline. Then, in the process configuration, you set the subfields for the paragraph reference field. It is worth noting that at this point you are iterating over a list of paragraph references, even if that list contains only one element. If you had more than one paragraph to migrate, whatever you defined in process will apply to all of them.

The process configuration is an array of subfield mappings. The left side of the assignment is the name of the subfield you want to set. The right side of the assignment is an array index of the paragraph reference being processed. Remember that this array does not have named-keys, so you use their numerical index to refer to them. The example sets the target_id subfield to the element in the 0 index and the target_revision_id subfield to the element in the one 1 index. Using the example data, this would be target_id: 3 and target_revision_id: 7. The quotes around the numerical indexes are important. If not used, the migration will not find the indexes and the paragraphs will not be associated. The end result of this operation will be something like this:

'field_ud_favorite_book' => array (1) [
  array (2) [
    'target_id' => string (1) "3"
    'target_revision_id' => string (1) "7"
  ]
]

There are three ways to run the migrations: manually, executing dependencies, and using tags. The following code snippet shows the three options:

# 1) Manually.
$ drush migrate:import ud_migrations_paragraph_intro_image
$ drush migrate:import ud_migrations_paragraph_intro_paragraph
$ drush migrate:import ud_migrations_paragraph_intro_node

# 2) Executing depenpencies.
$ drush migrate:import ud_migrations_paragraph_intro_node --execute-dependencies

# 3) Using tags.
$ drush migrate:import --tag='UD Paragraphs Intro'

And that is one way to map paragraph reference fields. In the end, all you have to do is set the target_id and target_revision_id subfields. The process pipeline that gets you to that point can vary depending on how your paragraphs are configured. The following is a non-exhaustive list of things to consider when migrating paragraphs:

  • How many paragraphs types can be referenced?
  • How many paragraphs instances are being migrated? Is this a multivalue field?
  • Do paragraphs have translations?
  • Do paragraphs have revisions?

Do migrated paragraphs disappear upon node rollback?

Paragraphs migrations are affected by a particular behavior of revisioned entities. If the host entity is deleted, and the paragraphs do not have translations, the whole paragraph gets deleted. That means that deleting a node will make the referenced paragraphs’ data to be removed. How does this affect your migration workflow? If the migration of the host entity is rollback, then the paragraphs will be removed, the migrate API will not know about it. In this example, if you run a migrate status command after rolling back the node migration, you will see that the paragraph migration indicated that there are no pending elements to process. The file migration for the images will report the same, but in that case, the images will remain on the system.

In any migration project, it is common that you do rollback operations to test new field mappings or fix errors. Thus, chances are very high that you will stumble upon this behavior. Thanks to Damien McKenna for helping me understand this behavior and tracking it to the rollback() method of the EntityReferenceRevisions destination plugin. So, what do you do to recover the deleted paragraphs? You have to rollback both migrations: node and paragraph. And then, you have to import the two again. The following snippet shows how to do it:

# 1) Rollback both migrations.
$ drush migrate:rollback ud_migrations_paragraph_intro_node
$ drush migrate:rollback ud_migrations_paragraph_intro_paragraph

# 2) Import both migrations againg.

$ drush migrate:import ud_migrations_paragraph_intro_paragraph
$ drush migrate:import ud_migrations_paragraph_intro_node

What did you learn in today’s blog post? Have you migrated paragraphs before? If so, what challenges have you found? Did you know paragraph reference fields require two subfields to be set? Did you that deleting the host entity also deletes referenced paragraphs? Please share your answers in the comments. Also, I would be grateful if you shared this blog post with others.

Next: Migrating CSV files into Drupal

This blog post series, cross-posted at UnderstandDrupal.com as well as here on Agaric.coop, is made possible thanks to these generous sponsors: Drupalize.me by Osio Labs has online tutorials about migrations, among other topics, and Agaric provides migration trainings, among other services.  Contact Understand Drupal if your organization would like to support this documentation project, whether it is the migration series or other topics.

Agaric's newsletter will contain news updates and links to blog posts and articles on a variety of topics:

  • Agaric's Free Software Platforms and the communities using them
  • Free Software tools that we use and development projects that we support
  • Agaric's regular online community events
  • Strategies and ideas for democratizing technology
  • Strategies for protecting your data and privacy
  • The variety of services that we offer
  • News regarding cooperatives, organizations, and movements in our solidarity network

Sign Up

Agaric is grateful to the Drupal community for all the effort poured into the amazing collaborative project. As part of giving back to it, we go to conferences to share with others what we have learned. These are some events where Agaric will be presenting this month.

Eastern Conference for Workplace Democracy

This is a convergence of worker-owned cooperatives. Representatives come from all over the country to attend workshops and sessions on all things related to owning a cooperative. It will be help in New York City on weekend of June 9th -11th at the John Jay College of Criminal Justice.

Benjamin and Micky will be hosting a workshop/discussion with Danny Spitzberg on Drutopia. They will cover how it can help cooperatives and smaller businesses have a we presence above and beyond the costs they can afford by consolidating the hosting and feature development into a group effort.

Montreal Drupal Camp

This event will take place on June 15-18 at John Molson School of Business de l'Université Concordia. Benjamin will be speaking on how Software as a Service can lead to long-term success in a software project.

Twin Cities Drupal Camp in Minneapolis

At Twin Cities Agaric will be presenting one workshop and two sessions.

On Thursday, June 22, Benjamin and Mauricio will be presenting the Getting Started with Drupal workshop. It is aimed to people who are just starting with Drupal and want to have a birds eye view of how the system works. As part of the workshop attendees will have the chance to create a simple yet functional website to put in practice their new knowledge. The organizers have gone above and beyond to make this training FREE for everyone! You do not even need a camp ticket to participate. You just need to register.

On Saturday, June 24, Mauricio will be presenting on Drupal 8 Twig recipes. This will be an overview of the theme system in Drupal 8 and will include practical example of modifying the default markup to your needs. The same day, Benjamin will present his Software as a Service.

Design4Drupal

This is THE yearly Camp for Drupal doers in Boston and it happens June 22nd-23rd. Micky will be hosting a workshop/discussion on Drutopia, an initiative within the Drupal project based in social justice values and focused on building collectively owned online tools. Current focuses include two Drupal distributions aimed at grassroots groups also offered as software as a service, ensuring that the latest technology is accessible to low-resourced communities.
Agaric will have a busy month attending and speaking at conferences. Please come to say hi and have fun with us.

Easy Payment Processing with Stripe

Give uses the popular payment processor Stripe. It does all the heavy lifting of card validation and payment processing so that you can accept donations with confidence.

To get started, create a Stripe account at stripe.com:

Stripe account creation form.

Choose the "Integrate with Stripe's API" option:

Stripe's getting started screen, with API option.

Click the "Get your API keys" link on the dashboard.

Stripe's dashboard with link to creating API keys pointed out.

Copy the Publishable key and Secret key. You'll need these for configuring the Give module on your site.

Screenshot of Stripe's interface showing the API keys

On your Drupal site, enable the Give module. Then, navigate to Configuration > Web services > Give donation settings (/admin/config/services/give). Enter your API keys and if you'd like, enable problem logging under the Advanced Settings tab.

Give module's configuration page

You're now ready to start building donation forms in your site.

Simple, Flexible Donation Forms

Navigate to Structure > Donation Forms (/admin/structure/give) to see a list of forms. The module comes with a default donation form to get you started.

Give administrative page listing all donation forms.

For each form you can:

  • specify the recipients to be emailed when a donation is made
  • configure the subject and message for an automatic thank you email (common tokens available)
  • choose whether or not to ask for a mailing address
  • show an "other" message to collect donations by check or other method
  • set optional text above the credit card field
  • specify the page to redirect a visitor to after they donate
  • change the text of the "donate" button
  • choose recurring options to offer (available intervals are any number of days, weeks, months, or years)  

Give donation form creation page

Integrate with Paragraphs

Paragraphs is a popular module allowing content editors to build pages with a variety of components such as a featured image, text block, video, etc. in any desired order. Give adds a new paragraph type for "Donation form", giving you full control over your donation pages and allowing you to strategically embedding donation forms throughout a site.

To use a Donation Form paragraph, edit the content type you'd like a donation form available on by navigating to Structure > Content Types > Manage fields.

If you already have a paragraph field then edit the field and check the box for Donation form.

Field configuration page with paragraph options.

You will now see the Donation form paragraph as an option when creating a node of the content type you configured.

Paragraph selection field with Donation form option

After adding the Donation form paragraph, you will see an autocomplete field. Start typing the name of the desired donation form and select the form.

Paragraph donation form with autocomplete field.

People visiting your site can now see a form like this, in the context of the page you added it to, and entirely in control of your design and CSS if you choose:

Screenshot of a give donation form, with name, e-mail address, amount, recurring options as radio buttons, and a big Give button at the bottom.

People's contact information and intention to give is collected first, and then they are brought to a page, still fully on your site, with the payment options with which to complete the donation.

Donation Reporting

At Structure > Donation forms > List (/admin/structure/give/donations) you can see a list of donations. The list shows all donations, completed or otherwise. Donations are listed by date submitted and shows the donor's name, amount, the form used, donation method and recurring information.

List of donations on the site.

To see more details, click into the donation record. Here you will see additional contact information you collected such as their email address. For failed donations, Give displays the error recorded by Stripe to help with troubleshooting.

Report of a specific donation.

Conclusion

Giving to a cause we care about should be simple and hassle-free. By creating your donation forms from within your site you keep your branding and ensure a seamless experience for your supporters. The security of Stripe combined with the flexibility of Drupal means you can now build donation opportunities at exactly the moments in your site that visitors are looking for.

Give is free and open source software, available for anyone to use. If you find it useful, we encourage you to give (ha!) to the project to make it even better. If there's more that you'd like Give to do for your site, suggest a feature in the issue queue. We're always looking for ways to improve it.

Woman planting an EU flag with a security symbol in the middle into the ground.

With Europe threatening $25,000,000 fines and Facebook losing $80,000,000,000 of stock value, are you paying attention to data privacy yet? If millions and billions of dollars in news headlines never grabbed you, maybe you've noticed the dozens of e-mails from services you'd forgotten ever signing up for, declaring how much they respect your right to control your data. These e-mails are silly and possibly illegal, but they nonetheless welcome us to a better world of greater privacy rights and people's control of their own data that we web developers should embrace.

The huge potential fines (for large companies, the sky's the limit at four percent of global revenue) come from the European Union's General Data Protection Regulation, and they signal that the GDPR is more than a suggestion. If you're not a European-based company, the European Union does not intend to discriminate: You're still liable when citizens of member states use your services or are monitored by you.

Don't lose sleep for Facebook's wealthy stockholders. That sizeable dip in Facebook stock was not due to the impending GDPR enforcement, but came in the wake of the Cambridge Analytica scandal. Since then, the privacy-invading monopoly so many rich people are betting on regained its market cap and then some. (GDPR-related lawsuits are just starting.)

There's a lot of good resources for GDPR-proofing existing sites (see the bottom of this article); the work ranges from trivial for most sites to monumental tasks for web developers who, fortunately for me, aren't me (and who have finished their labor, I hope, as GDPR enforcement took effect today).

The fun and exciting part starts when we get to build new sites or new features on existing sites and from the beginning put privacy by design into practice (which also is in the law). And yes, I'm referring to complying with a continental government's regulations as fun and exciting.

Presentations and Workshops:

2020

  • Boston College online interview on AI and Free Software
  • WMBR - Online interview on Free Software solutions for communications
  • Platform Cooperative Ideathon
  • MayFirst Need to Know Series

2019

2018

2017

  • Open.coop 2017 - London University, London, UK
    • Panel: Empowering digital collaboration: Introducing the open app ecosystem
    • Workshop: Designing interoperable apps for the open app ecosystem
Manifestante con signo en el fondo que dice "Lucha contra el racismo. El sexismo. Toda opresión". Atribución: Johnny Silvercloud CC Share Igual

Portside

Amplificando diversas voces a la izquierda.