For community shared business, development, and training tools, Agaric throws a little sponsorship at modulecraft.
Benjamin Melançon of Agaric helped with a patch for the Drupal 7 version of Insert module.
What the word agaric means and why Agaric took it for our cooperative's name.
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.
I've always had a passion for good design and healthy coding, even back in the days of owning a web site cart in downtown Natick. Back then, my business partner and I made all natural HTML roll-up web sites and, as an incentive for customers to wait in line, we baked Drupal into different flavored designs.
Full participation in Agaric's Drupal 8 migrations quickstart (half-day training) and Drupal 8 content migrations (full-day training) courses requires a working, local installation of Drupal 8.
The morning can be done online with a Pantheon.io free development site or SimplyTest.me (only web browser and working internet connection required).
The afternoon portion of the training requires a local dev environment— if you aren't able to get this set up ahead of time, we can help you during a break. The two approaches we have tested:
All of these approaches work on GNU/Linux, MacOS, and Windows.
Although no prior Migrate module knowledge is required, it is expected that you have a basic understanding of nodes, content types, and fields. You can learn about these and other Drupal concepts by watching this session recording.
A working Drupal 8 installation is required. It is possible to follow some examples using a hosted Drupal service like pantheon.io To get the most out of the training a local installation is needed. Installing Drupal locally using composer is recommended.
Drush needs to be installed in order to run migrations from the command line. Xdebug and PHPStorm are used for the debugging example (techniques apply for other debuggers and IDEs).
It is recommended to use DrupalVM and configure it to use the drupal composer template.
Follow the quickstart guide to install DrupalVM with the xdebug extra package.
Install the following contrib modules:
Assistance can be provided before the training starts, but it is better to come with your local environment already set up.
Agaric builds websites and online platforms that give people more control over their technology, including working with Drupal for more than thirteen years. They bring their expertise in backend development and Drupal migrations to projects for clients in different sectors including government, education, businesses, and not-for-profits/NGOs. Agaric is committed to giving back to the community. Over the last few years, they have presented 40+ sessions and full day trainings in 16+ DrupalCamps and DrupalCons in the Americas and Europe.
Benjamin Melançon (mlncn on drupal.org) has been working with Drupal since 2005. He led the 36 author project that produced the Definitive Guide to Drupal 7 and contributed dozens of modules to Drupal 5, 6, 7, and 8. For client projects, Benjamin uses this deep understanding of Drupal internals along with more general frontend, backend, and infrastructure knowledge to make sure requirements and expectations are met. He is a frequent speaker at Drupal and other technology events in North America.
Mauricio Dinarte is passionate about teaching. He is creating educational material in English, Spanish, and French to help break the language barrier when learning Drupal and other technologies. Check out his educational project at https://understanddrupal.com.
With the In Other Words module, it is now possible to keep your structured content and display it naturally. The logic of how a list should display in various scenarios is boiled down to an intuitive user interface for site builders, with no coding required. Try it for yourself! Get the module at drupal.org/project/inotherwords.
Increasingly, the entities and individuals who participate in such initiatives are geographically dispersed with limited opportunities for in-person or contemporaneous collaboration. They need spaces where they can work asynchronously—online communities that enable teams to share ideas and best practices, receive feedback from experts, and exchange resources. And each space or community needs to be their own. The required feature set is robust, but common—the perfect fit for a Drupal distribution. The NICHQ Collaboratory (“CoLab”) provided such spaces, but they were powered by a Drupal 7 distribution which made site-specific customization and ongoing maintenance fraught and unmanageable. Moreover, the list of improvements slated for implementation was increasing, and there was growing consensus that the information architecture for resources and other information needed rethinking.
Anecdotally, we knew the sites could use an upgrade, but there were also features users appreciated. In our upgrade, we did not want to disrupt any beloved processes in our quest for improving the experience.
We started with a survey to find the common pain points and the loved features to leave intact. We learned that overall people still loved the visual design, felt the quality of content was high, and moderation was strong. Most respondents were overwhelmed with the amount of content, despite its quality, and didn't find the notification system helpful.
The next step was to dig deeper to learn why exactly content was hard to find and the best way to solve this. The survey asked if the respondent would be interested in a follow-up interview so we had a good list to draw from.
We knew from our prior audience work that there were two primary user groups: Project Managers and Participants. We decided to start by interviewing one project manager, a new participant and a veteran participant. After this first round of interviews we would then decide if more research was needed.
There were some surprising findings. One is that each community had groups within it, for more specific topics. However, none of the interviewees used these groups. In fact, they got in the way of collaboration. For them, collaboration meant transcending groups and working with anyone within the team. We also learned that categorization had run a bit wild. Different users were tagging resources in different ways and there were terms that served the same purpose, creating redundancy and inconsistent tagging. This was both a process challenge and a technical one. NICHQ would get on the same page about how to categorize content and we would lock down the ability to add new categories, only to project managers.
We do not build websites page by page, but rather in components that get reused across a site. Atomic design is a way to conceive of components made up of smaller components, made up of even smaller components.
To ease development and design, we built our wireframes using the same concept. In Sketch these are called symbols.
It is tempting to punt all design questions until after wireframes are approved. However, sometimes it is too difficult for us to envision the functionality of something without more design polish added to it.
So, instead of pure, clean transitions we moved from wireframes to design knowing that some questions were still unresolved.
Luckily, our "atomic wireframes" were easy for our designer Todd Linkner to update.
As mentioned above, NICHQ's need for multiple sites using similar feature sets was the perfect fit for a Drupal distribution. However, we needed a workflow that could allow some sites to diverge from the original codebase but still bring in future improvements.
We had already started in on this endeavor with Drutopia, an initiative to improve the way Drupal manages configuration and distributions.
With the NICHQ CoLab as our practical use case, we worked with the Drupal shop Chocolate Lily to build and improve upon a suite of modules to manage and share different states of configuration across distributions.
For more, read this excellent series of posts by Nedjo Rogers.
Agaric adapts our approach to fit each project. Some building blocks to our approach are so fundamental that we use them on nearly every Drupal project we work on. These are those fundamental aspects to our approach.
Design can be a nebulous, subjective process. We give that process structure and purpose by focusing on the results. The design system we create speaks to your audience and meets your goals. We share our designs early, with real content, and in as interactive of a way as possible with your key stakeholders.
Knowing that design is never truly done, we like to get the design "80% of the way there", and then apply it to the actual site. That way we can improve and refine along the way using the actual site, not static files open to misinterpretation.
By launch time your site will have a design that is:
Drupal is a free software project built by thousands of designers and developers. As a result, your site benefits from security coverage and high quality code that follows best practices and ongoing maintenance and improvement.
As leaders in the Drupal community, we contribute to Drupal Core and maintain dozens of public modules (called "contributed modules" in the Drupalsphere) used by thousands of sites. For nonprofits in particular we are helping to build a Drupal 8 distribution putting together and providing ready-to-go configuration for key modules, many of which we also contribute to.
We draw from shared solutions whenever possible, tapping into and contributing back to this digital commons, because it saves time by not reinventing the wheel, and ensures your site continues to be maintainable and benefits from ongoing improvements from the community.
It is critical that your site be accessible to as many people as possible, including those using screen readers. To that end, all of our work is built to support compliance with W3C Web Content Accessibility Guidelines (WCAG) 2.0. The WCAG Guidelines, however, are not comprehensive and so we go beyond those guidelines to ensure high accessibility. Lastly, much of what makes a site accessible happens on the content entry and management side. We will provide resources for your content team so that after the site launches, you can rest assured that what you are creating is reaching as many people as possible.
Our developers will also follow SEO best-practice development and utilize Drupal’s range of SEO-related features that allow administrators to edit page titles, implement human-readable and editable URLs, enter meta tag information, and more. For further SEO-related services, we can also recommend SEO consultants.
I recently switched from Mac OS to Elementary, a Linux distribution focused on ease of use and privacy. As both a user experience designer and free software supporter, I am taking screenshots and annotating them all the time. After trying out several different tools, the one I enjoy by far is Ksnip.
Install ksnip with your preferred package manager. In my case I installed it via apt
sudo apt-get install ksnip
Ksnip comes with quite a few configuration options, including:
You can also integrate it with your Imgur account.
My favorite part of Ksnip is that it has all the annotation tools I need (plus one I hadn't thought of!).
You can annotate with:
You can also blur areas to remove sensitive information.
And my new favorite tool, numbered dots for steps on an interface.
KSnip Features List - https://github.com/DamirPorobic/ksnip#features
I'm enjoying Ksnip so much that I reached out to the creator, Damir Porobic, to learn more about the project.
I asked what inspired him to create Ksnip and here's what he said,
"I switched from Windows to Linux a few years ago and missed the Windows Snipping Tool that I was used to on Windows. All other screenshot tools at that time were either huge (a lot of buttons and complex features) or lacked key features like annotations so I decided to build a simple Snipping Tool Clone but with time it got more and more feature so here we are."
This is exactly what I found as I was evaluating screenshot tools. It's great that he took the time to build a solution himself and freely share it for others to benefit from.
As for the future of Ksnip, Damir would like to add Global Shortcuts (at least for Windows), tabs for new screenshots, and allow the application to run in the background. There is also a growing list of feature requests on GitHub.
The biggest need is with development. Damir and his wife are expecting a baby soon so he won't have as much time to devote to the project. He is available to review and accept pull requests though.
Also, the project could benefit from additional installation options via Snap, Flatpak and installers for MacOS and a Setup for Windows.
Lastly, use the project, rate it and review it on AlternativeTo.net and other tech comparison platforms and if you can spare a few bucks, donations are always appreciated.
We are a worker-owned cooperative specializing in building tools and websites that respect your freedom. We also provide training and consultation to meet your goals. Everything we do is part of our purpose to help all people gain the most power possible over their own lives.
In the previous article we provided a reference of available configuration options for migrate source plugins. In today’s article we are doing something similar for destination plugins. We will present a reference of available configuration options for migrate destination plugins provided by Drupal core and some contributed modules. Knowing which options are available might require some Drupal development knowledge. By providing this reference it should make the process of writing migrations easier.
For each migrate destination plugin we will present: the module that provides it, the class that defines it, the class that the plugin extends, and any inherited options from the class hierarchy. For each plugin configuration option we will list its name, type, a description, and a note if it is optional.
Module: Migrate (Drupal Core)
Class: Drupal\migrate\Plugin\migrate\destination\DestinationBase
Extends: Drupal\Core\Plugin\PluginBase
This abstract class is extended by many migrate destination plugins. This means that the provided configuration keys apply to any destination plugin extending it.
List of configuration keys:
Module: Migrate (Drupal Core) Plugin ID: entity:$entity_type See below.
Class: Drupal\migrate\Plugin\migrate\destination\Entity
Extends: Drupal\migrate\Plugin\migrate\destination\DestinationBase
Inherited configuration options: destination_module.
Related article: Drupal migrations reference: List of properties per content entity
This abstract class is extended by migrate destination plugins that want to import entities. It uses the MigrateEntity derivative to handle both content and configuration entities. The derivative sets the plugin ID to entity:$entity_type where $entity_type is the machine name of the entity. For example, entity:node and entity:node_type.
By default, content entities are handled by the EntityContentBase class while configuration entities use EntityConfigBase. Some entities like user (content) and node type (configuration) use specific classes for the import operation. The DefaultPluginManager::getDefinitions method triggers the search for classes that will override the default for a particular plugin ID. The override ultimately happens in the DerivativeDiscoveryDecorator::getDerivatives method.
In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys, which will be available to its derivatives:
Module: Migrate (Drupal Core) Plugin ID: entity:$entity_type See below.
Class: Drupal\migrate\Plugin\migrate\destination\EntityContentBase
Extends: Drupal\migrate\Plugin\migrate\destination\Entity
Inherited configuration options: destination_module and default_bundle.
This class is used to handle import operations for all content entities, unless a specific class exists for the plugin ID being used. For example, nodes are handled by this class, but users leverage the EntityUser class. The MigrateEntity derivative sets the plugin ID to entity:$entity_type where $entity_type is the machine name of the content entity. For example, entity:node, entity:user, entity:taxonomy_term, entity:file, entity:media, entity:comment, entity:block_content, and entity:contact_message.
In addition to the keys provided in the parent class chain, this class provides the following configuration keys:
Module: User (Drupal Core) Plugin ID: entity:user See below.
Class: Drupal\user\Plugin\migrate\destination\EntityUser
Extends: Drupal\migrate\Plugin\migrate\destination\EntityContentBase
Inherited configuration options: destination_module, default_bundle, translations, overwrite_properties, and validate.
This class provides a destination plugin for migrating user entities. It performs extra checks like preventing that the password for user 1 is overridden by the migration.
In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:
Module: Migrate (Drupal Core) Plugin ID: entity_revision:$entity_type See below.
Class: Drupal\migrate\Plugin\migrate\destination\EntityRevision
Extends: Drupal\migrate\Plugin\migrate\destination\EntityContentBase
Inherited configuration options: destination_module, default_bundle, translations, overwrite_properties, and validate.
This class provides an entity revision destination plugin. Only revisionable entities, those that define a revision entity key, can use this destination plugin. It uses the MigrateEntityRevision derivative which sets the plugin ID to entity_revision:$entity_type where $entity_type is the machine name of the entity. For example, entity_revision:node whose revision key is vid and entity_revision:block_content whose revision key is revision_id.
Entity revisions can only be migrated after the entity to which they belong has been migrated. For example, revisions of a given node (entity_revision:node destination migration) can be migrated only after the current version of that node (entity:node destination migration) has been imported.
Module: Entity Reference Revisions module Plugin ID: entity_reference_revisions:$entity_type See below.
Class: Drupal\entity_reference_revisions\Plugin\migrate\destination\EntityReferenceRevisions
Extends: Drupal\migrate\Plugin\migrate\destination\EntityRevision
Inherited configuration options: destination_module, default_bundle, translations, overwrite_properties, and validate.
Related article: Introduction to paragraphs migrations in Drupal
This class provides an entity revision revision destination plugin. It uses the MigrateEntityReferenceRevisions derivative which sets the plugin ID to entity_reference_revisions:$entity_type where $entity_type is the machine name of the entity. For example, entity_reference_revisions:node and entity_reference_revisions:paragraph. For example, entity_reference_revisions:node whose revision key is vid and entity_reference_revisions:paragraph whose revision key is revision_id.
This is the destination plugin used for migrating Paragraphs. Entity reference fields are no longer supported to reference Paragraphs. Instead, entity entity reference revisions must be used. Therefore, this class is used for paragraphs migrations with the entity_reference_revisions:paragraph plugin ID. See this article for an example on how to migrate paragraphs.
In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:
Module: Migrate (Drupal Core) Plugin ID: entity:$entity_id See below.
Class: Drupal\migrate\Plugin\migrate\destination\EntityConfigBase
Extends: Drupal\migrate\Plugin\migrate\destination\Entity
Inherited configuration options: destination_module and default_bundle.
This class is used to handle import operations for all configuration entities, unless a specific class exists for the plugin ID being used. For example, taxonomy vocabularies are handled by this class, but node types leverage the EntityNodeType class. The MigrateEntity derivative sets the plugin ID to entity:$entity_type where $entity_type is the machine name of the content entity. For example, entity:node_type, entity:user_role, entity:taxonomy_vocabulary, entity:block, entity:comment_type, entity:block_content_type, entity:contact_form, entity:date_format.
In addition to the keys provided in the parent class chain, this abstract class provides the following configuration keys:
Module: Node (Drupal Core) Plugin ID: entity:node_type
Class: Drupal\node\Plugin\migrate\destination\EntityNodeType
Extends: Drupal\migrate\Plugin\migrate\destination\EntityConfigBase
Inherited configuration options: destination_module, default_bundle, and translations.
This class is used to import node types. It does not take extra configuration options. The plugin overrides the import method to attach the body field to the imported content type. This depends on the presence of certain destination properties in the imported row. That is, the following properties needs to be mapped in the process section of the migration:
Module: Migrate (Drupal Core) Plugin ID: config
Class: Drupal\migrate\Plugin\migrate\destination\Config
Extends: Drupal\migrate\Plugin\migrate\destination\DestinationBase
Inherited configuration options: destination_module.
This class persists data to the configuration management system. In addition to the keys provided in the parent class chain, this class provides the following configuration keys:
Additionally, the plugin expects certain destination properties in the imported row. That is, the following properties needs to be mapped in the process section of the migration:
Module: Migrate Plus Plugin ID: table
Class: Drupal\migrate_plus\Plugin\migrate\destination\Table
Extends: Drupal\migrate\Plugin\migrate\destination\DestinationBase
Inherited configuration options: destination_module.
This class allows you to write directly to a table not registered with Drupal Schema API. See this test for an example on how to use this plugin.
In addition to the keys provided in the parent class chain, this class provides the following configuration keys:
In Drupal core itself there are around 50 migrate destination plugins. And many more are made available by contributed modules. It would be impractical to document them all here. To get a list by yourself, load the plugin.manager.migrate.destination service and call its getDefinitions() method. This will return all migrate destination plugins provided by the modules that are currently enabled on the site. This Drush command would get the list:
# List of migrate destination plugin definitions. $ drush php:eval "print_r(\Drupal::service('plugin.manager.migrate.destination')->getDefinitions());" # List of migrate destination plugin ids. $ drush php:eval "print_r(array_keys(\Drupal::service('plugin.manager.migrate.destination')->getDefinitions()));"
To find out which configuration options are available for any destination plugin consider the following:
What did you learn in today’s article? Did you know that migrate destination plugins can inherit configuration keys from their class hierarchy? Were you aware that there are so many destination plugins? Other than the ones listed here, which destination plugins have you used? Please share your answers in the comments. Also, we would be grateful if you shared this article with your friends and colleagues.
E-mail us at ask@agaric.coop, call us at +1 508 283 3557, or use this form below, and one of us worker-owners at Agaric will get back to you.
I'm back! Because I knew this blog post wasn't quite long enough already...certainly not because it occurred to me that I left off another alternative I've used in a pinch.
If you want to run a command using a different version of php, rather than rely on the shebang, you can always just call the desired script as an argument to php itself. When you run, e.g. drush status
, your shell sees the #!
on the first line, and uses that as the default interpreter for the script. In essence, your command is translated into /usr/bin/env php drush status
.
Rather than accept this default, you can specify the specific version on your command line, such as php8.1 drush status
. In this case the #!
is just ignored. Unfortunately, this method can only get you so far - particularly with drush. Drush often figures out what your command requires and in turn will spawn other php scripts to do the dirty work. These spawned scripts are unaware of the interpreter that drush itself was started with.