Feeds

Author

Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
Oct 17 2024
Oct 17

Series Overview & ToC | Previous Article | Next Article - coming soon!

We executed the last field-related migrations in the previous article, but we are not done with field configuration yet. Back in article 17, we used the Migrate Skip Fields module to prevent the automatic migration from importing image and YouTube fields. Today, we are going to use Drupal recipes to create media types and manually add media reference fields where needed.

Drupal recipes

The Recipes API,introduced in Drupal 10.3, allows installing modules and themes, importing configuration and content, and altering existing configuration. Recipes can also depend on other recipes, making them composable and highly flexible. Another benefit is the potential to replace installation profiles. This not only saves time but can bring consistency across different projects. In fact, Core's standard installation profile was replicated as a set of recipes. We are going to use a couple of those recipes to add media types to our Drupal 10 project.

Drupal recipes can validate that configuration elements are in a known state before the recipe is applied. Once a recipe is applied, the imported configuration is handled by the site itself. Any updates should follow standard configuration management practices.

Take a look at the core/recipes folder in Drupal 10’s docroot to better understand the anatomy of a recipe. Each one is contained in a folder with a required recipe.yml file. They can optionally contain config and content folders to import configuration and content respectively. We could certainly write a whole series on Drupal recipes, but for now we are going to focus on what is applicable to our example project.

Technical note: Recipes are a first-class Composer project type: drupal-recipe. They can be required as any other Composer package.

Applying a Drupal recipe

Drupal Core provides a built-in script for applying recipes. Starting with Drush 13, a recipe command is available. When executed from a Drupal 10 docroot, any of these commands can be used to apply a recipe:

php core/scripts/drupal recipe /path/to/recipe_folder
drush recipe /path/to/recipe_folder

We are going to use the Drush approach since applying recipes from the host into the Docker container requires some extra arguments. For reference, refer to this documentation to apply recipes when using DDEV.

First, we will apply a recipe to use images as media entities. From the Drupal 10 folder in your host machine, run the following command:

ddev drush recipe core/recipes/image_media_type

If things go as expected, you will see a message indicating that the Image media type applied successfully. This should create an image media type, add an image field to it, and configure the default and media_library view and form modes. Visit https://migration-drupal10.ddev.site/admin/structure/media/manage/image/fields to see how things were set up.

Manage Form Display page

These changes required adding new configuration to the site. Remember to export and commit the changes as with any other configuration change. If the recipe failed to apply, refer to the troubleshooting section below.

With one recipe applied, we will now do another that will allow YouTube videos to be embedded. From the Drupal 10 folder in your host machine, run the following command:

ddev drush recipe core/recipes/remote_video_media_type

When applied, the recipe will create a remote_video media type, add a plain text field to it, and configure the default and media_library view and form modes. The text field is used to store a link to the remote video URL. YouTube and Vimeo are supported out of the box. Visit https://migration-drupal10.ddev.site/admin/structure/media/manage/remote_video/fields to see how things were set up. As you would expect, the site configuration has been updated. Export the changes and commit them to the repository.

With media types already created, we are going to manually add media reference fields where appropriate. Per the site audit document referenced in article 3, these are the fields to add:

  1. In the Article content type, add a media reference field to images.
  2. In the Venue content type, add a media reference field to images.
  3. In the Session content type, add a media reference field to remote videos. Add this field to the Resources group.

This is a site building exercise readers should be able to do on their own. Refer to the code repository for the final configuration.

Troubleshooting recipe application

Recipes verify that included configuration does not exist or that existing configuration matches the recipe definition exactly. This check is also performed for dependent recipes.

In the case of existing configuration, the check is based on machine names. Any variation will prevent the recipe from applying. For example, the image_media_type recipe depends on the large image style. If we update its label from Large (480×480) to Large 480×480 px, the following error will be triggered when trying to apply the recipe:

In ConfigConfigurator.php line 47:


 The configuration 'image.style.large' exists already and does not match the recipe's configuration

Our label change might not be meaningful, but what if we had made changes to the image effects used in that image style? We certainly would not want to lose those customizations! As a general rule, recipes would not overwrite any configuration element if its current value differs from the recipe definition. Instead, a validation error is yielded. This might seem limiting. What is the point of using recipes then?

Remember that recipes are meant to be starting points. You can install a site from recipes. When there is no existing configuration, no conflicts can arise. That being said, applying recipes on existing sites is a valid and useful feature. In addition to those provided by Core, there are contributed recipes that you can use on your projects today.

Note: As of Drupal 10.4, recipes can opt out of strict comparisons with existing config. At the time of publishing, a strict comparison is still the default. Changing to making the configuration comparison lenient by default is being discussed in this issue.

Should we use recipes in migration projects?

It depends on your project requirements and the desired content model.

In our case, our Drupal 7 project did not use the Media module, but we still wanted to use media entities in Drupal 10. Recipes are available for creating media types modeled after the standard installation profile. No need to reinvent the wheel here!

Even so, put on your site builder hat as we take a deeper look at the implications of using these recipes.

Our example Drupal 7 project is arguably very simple. It is based on the standard installation profile and there are not many customizations. No custom image styles or text formats, nor changes to those provided out of the box. Only one custom role (Editor) and no WYSIWYG configuration. We could definitely use many Core recipes modeled after the standard installation profile, but should we?

For the sake of the example, consider image styles. Drupal Core provides a migration for image styles from Drupal 7. If we were to use it, the migration will overwrite any image style to match its Drupal 7 definition. In the case of Core image styles, Drupal 10 uses a WebP converter. That feature did not exist before. Since we are not customizing the Core image styles, and we do not have any custom one, for our example project it is better not to migrate image styles. That way, we take advantage of the optimizations that come with WebP in Drupal 10.

If you have custom image styles, use the upgrade_d7_image_styles migration from the ref_migrations folder. In this case, the image style migration needs to happen after applying the image_media_type recipe. Otherwise, updates to existing image styles will make the configuration validation fail and the recipe would not be applied. While this might seem like a chicken and egg problem, good planning goes a long way into determining the correct order to apply recipes, migrate configuration, and do manual configuration changes.

Technical note: Most source plugins for upgrading from Drupal 7 connect directly to the database to fetch data. Drupal 7 allowed some configuration to be defined in code, either by modules or features. When that configuration is in its default state, only the code representation exists. The database would not hold a reference to it. That is the case for the image styles in our example. Checking the status of the upgrade_d7_image_styles reveals there are no records to migrate, but we know that image styles do exist in Drupal 7. Those present only exist in code. For them to exist in the database, you would need to overwrite them. This also happens with views, field groups, and other configurations that can be represented in code. Take this into account if a migration reports no records to migrate or the total count is lower than expected.

To answer the question posed at the start of this section, it is ok to use recipes when they can be cleanly applied. If subsequent migrations might overwrite configuration elements created by the recipes, make sure the new configuration is truly what you want. If we export and commit configuration changes after every step, git should show us if anything was overridden. Keep in eye on functionality that did not exist in Drupal 7 and could be lost. That should not stop you from using the migration. If anything, manually apply the configuration that was overwritten by the migration.

Today, we've covered the basics of the Recipes API, how to apply recipes, and used them for creating media types. In our upcoming articles, we’ll walk through migrating user roles, permissions, and text and input formats to your new Drupal 10 site.

Image by Hans from Pixabay

Oct 03 2024
Oct 03

Series Overview & ToC | Previous Article | Next Article

In this article, we are completing field-related migrations by importing formatter settings. This step builds on our previous work with view modes and field groups, bringing us closer to a functional Drupal 10 site. As we go through the process we will also identify other configuration elements used by field formatters that don’t have an automatic migration.

Remember, if you have been following our series, you have already migrated view modes—a prerequisite for field formatters. The Migrate Skip Fields module will also be used to handle content model changes in the new site.

Before we begin

Familiarity with site building concepts related to fields is assumed. Refer to article 16 for a high level overview. Today's article also touches on view modes and date formats.

Field formatter migrations

A formatter determines how field data is rendered by Drupal. Each field type can be supported by one or more field formatters. For example, an entity reference field can print only the entity ID, its label as plain text or as a link, or the representation of the entity as specified by a view mode. Some field configuration might affect which formatters are available. For example, entity reference fields that point to taxonomy terms can use the RSS category formatter.

Technical note: The FormatterInterface interface includes a isApplicable method that determines if a formatter can be used for a field taking into account its configuration.

We use upgrade_d7_field_formatter_settings to migrate field formatter settings. Copy it from the reference folder into our custom module and rebuild caches for the migration to be detected.

cd drupal10
cp ref_migrations/migrate_plus.migration.upgrade_d7_field_formatter_settings.yml web/modules/custom/tag1_migration/tag1_migration_config/migrations/upgrade_d7_field_formatter_settings.yml
ddev drush cache:rebuild

Note that while copying the file, we also changed its name and placed it in a migrations folder inside our custom module. After copying the file, make the following changes:

  • Remove the following keys: uuid, langcode, status, dependencies, cck_plugin_method, and migration_group. Notice that for field migrations, we preserve the field_plugin_method key.
  • Add two migration tags: component_entity_display and tag1_configuration.
  • Add key: migrate under the source section.
  • Update the required migration_dependencies to include upgrade_d7_field, upgrade_d7_field_instance, upgrade_d7_view_modes, and the migrations that create configuration entities.

In addition to the updates above, remember that the Migrate Skip Fields module is installed on the site. Via hook_migration_plugins_alter, it modifies the field formatter migration to prevent some fields being imported. In particular, those excluded by the migrate_skip_fields_by_name setting as explained in article 17.

For field formatters, the module does not act on the migrate_skip_fields_by_type setting. The original migration already accounts for not importing formatter data for a field whose storage setting was not migrated. This happens in the field_type_exists pipeline of the process section.

We are going to make a small addition here. The last process plugin in this pipeline is skip_on_empty. We will add a message configuration to log when a field is skipped because its storage setting is missing. The logs are added to the migration tables and can be viewed from the command line or the migration messages admin interface.

After the modifications, the upgrade_d7_field_formatter_settings.yml file should look like this:

id: upgrade_d7_field_formatter_settings
class: Drupal\migrate_drupal\Plugin\migrate\FieldMigration
field_plugin_method: alterFieldFormatterMigration
migration_tags:
 - 'Drupal 7'
 - Configuration
 - component_entity_display
 - tag1_configuration
label: 'Field formatter configuration'
source:
 key: migrate
 plugin: d7_field_instance_per_view_mode
 constants:
   third_party_settings: {  }
process:
 # @modified
 field_type_exists:
   -
     plugin: migration_lookup
     migration: upgrade_d7_field
     source:
       - field_name
       - entity_type
   -
     plugin: extract
     index:
       - 0
   -
     plugin: skip_on_empty
     method: row
     message: "Field storage configuration does not exist."
 entity_type:
   -
     plugin: get
     source: entity_type
   -
     plugin: static_map
     map:
       field_collection_item: paragraph
       paragraphs_item: paragraph
     bypass: true
 bundle:
   -
     plugin: migration_lookup
     migration: upgrade_d7_field_instance
     source:
       - entity_type
       - bundle
       - field_name
   -
     plugin: extract
     index:
       - 1
 view_mode:
   -
     plugin: migration_lookup
     migration: upgrade_d7_view_modes
     source:
       - entity_type
       - view_mode
   -
     plugin: extract
     index:
       - 1
   -
     plugin: static_map
     bypass: true
     map:
       full: default
 field_name:
   -
     plugin: get
     source: field_name
 options/label:
   -
     plugin: get
     source: formatter/label
 options/weight:
   -
     plugin: get
     source: formatter/weight
 plugin_id:
   -
     plugin: process_field
     source: type
     method: getPluginId
 formatter_type:
   -
     plugin: process_field
     source: type
     method: getFieldFormatterType
 options/type:
   -
     plugin: static_map
     bypass: true
     source:
       - '@plugin_id'
       - '@formatter_type'
     map:
       taxonomy_term_reference:
         taxonomy_term_reference_link: entity_reference_label
         taxonomy_term_reference_plain: entity_reference_label
         taxonomy_term_reference_rss_category: entity_reference_label
         i18n_taxonomy_term_reference_link: entity_reference_label
         i18n_taxonomy_term_reference_plain: entity_reference_label
         entityreference_entity_view: entity_reference_entity_view
       email:
         email_formatter_default: email_mailto
         email_formatter_contact: basic_string
         email_formatter_plain: basic_string
         email_formatter_spamspan: basic_string
         email_default: email_mailto
         email_contact: basic_string
         email_plain: basic_string
         email_spamspan: basic_string
       field_url:
         url_default: link
         url_plain: link
       field_collection:
         field_collection_view: entity_reference_revisions_entity_view
       addressfield:
         addressfield_default: address_default
       telephone:
         text_plain: string
         telephone_link: telephone_link
       entityreference:
         entityreference_label: entity_reference_label
         entityreference_entity_id: entity_reference_entity_id
         entityreference_entity_view: entity_reference_entity_view
       file:
         default: file_default
         url_plain: file_url_plain
         path_plain: file_url_plain
         image_plain: image
         image_nodelink: image
         image_imagelink: image
       datetime:
         date_default: datetime_default
         format_interval: datetime_time_ago
         date_plain: datetime_plain
   -
     plugin: d7_field_type_defaults
   -
     plugin: skip_on_empty
     method: row
 hidden:
   -
     plugin: static_map
     source: '@options/type'
     map:
       hidden: true
     default_value: false
 options/settings:
   -
     plugin: default_value
     source: formatter/settings
     default_value: {  }
 options/third_party_settings:
   -
     plugin: get
     source: constants/third_party_settings
 options/settings/view_mode:
   field_collection:
     plugin: paragraphs_process_on_value
     source_value: type
     expected_value: field_collection
     process:
       plugin: get
       source: formatter/settings/view_mode
destination:
 plugin: component_entity_display
migration_dependencies:
 required:
   - upgrade_d7_field
   - upgrade_d7_field_collection_type
   - upgrade_d7_field_instance
   - upgrade_d7_node_type
   - upgrade_d7_taxonomy_vocabulary
   - upgrade_d7_view_modes
 optional: { }

Now, rebuild caches for our changes to be detected and execute the migration. Run migrate:status to make sure we can connect to Drupal 7. Then, run migrate:import to perform the import operations.

ddev drush cache:rebuild
ddev drush migrate:status upgrade_d7_field_formatter_settings
ddev drush migrate:import upgrade_d7_field_formatter_settings

No errors after running the migration. Great! Feel free to have a look at the logs using the drush migrate:messages command.

Similar to other field-related migrations, we should confirm that the result of migrating field formatter settings is correct. There are two places you should look at. Using the Event content type as an example, go to:

  1. The manage display page where you can make adjustments to the migrated field formatter configuration.
  2. The view page for a session node where you can see the current state of the field formatter configuration. At the moment, we have not migrated nodes nor other content entities. Feel free to create some content to see how it is rendered.

This is where having familiarity with site building concepts and past experience will help. Below is a screenshot of an Event node comparing how some of the fields attached to the content type are rendered.

Manage Display page

Notice that the Date field in Drupal 10 shows the time even though the field type is supposed to store a date value only. This is because the Default long date format used to render the field is configured to render a time component. In Drupal 7, the Date field is configured to use Long date format, which can also render a time component; however, it is hidden when the date field is configured to store a date value only. This highlights how formatters can behave differently between Drupal versions and the importance of carefully reviewing the migrated configuration.

For the example above, we could hide the time component for the Date field in multiple ways. One option is to create a new date format which does not print the time. Another option is the Custom date formatter for the date field and use a PHP datetime pattern that does not print the time like l, F j, Y. The first option is recommended if you plan to reuse the same date format in multiple places. The second option can be used if you are certain that there is no need to reuse the pattern.

For the purpose of this example, we are going to go with a third option: use a different date format. Because we are using the Olivero theme, we can use the Olivero Medium date format which will hide the time and the day of the week. An acceptable compromise for the example.

Technical note: Drupal 10 does not provide an automated upgrade path for custom date types and formats from Drupal 7. They are stored in the date_format_type and date_formats tables respectively. You can write a custom migration to read from those Drupal 7 tables and create DateFormat configuration entities in Drupal 10. Or you can recreate them manually on the new site. In either case, you will have to identify where the custom date formats were used in Drupal 7 and manually update the corresponding configuration in Drupal 10. At the time of this writing, this issue contains a patch for migrating custom date formats, but no date types.

Below is a screenshot of an Session node comparing how some of the fields attached to the content type are rendered.

Session Node

Notice that for the Topics field, the label is rendered in bold in Drupal 10, but not in Drupal 7. As for the terms themselves, in Drupal 10 they appear stacked on top of each other and, in Drupal 7, they are listed next to one another. For the Slides field, Drupal 10 shows the file size in parenthesis and not the file icon. In Drupal 7, you see an icon that varies per file type and there is no reference to the file size. These differences are a combination of changes to how formatters are implemented in different versions of Drupal and how themes decide to render some user interface elements.

For our example project, we are not going to take any action here. In real life projects, you are likely going to use a custom theme that will control how interface elements are rendered. Contributed modules like Fences can also manipulate the output of fields. As a rule of thumb, before adding any module to your project, evaluate if the functionality provided outweighs the extra configuration and maintenance required to use it.

Below is a screenshot of a Venue node rendered in Drupal 10.

Venue Node

The Venue content type has a Phone field that is rendered as plain text. This matches the configuration from Drupal 7, but that does not mean that we cannot make improvements as part of the migration. In this case, we can update the field to use the Telephone link formatter to render a link using the tel URL scheme. Users visiting the site with a mobile phone will be able to place the call by clicking on the link. Drupal is producing semantic HTML markup and it is up to the visitor's browser to determine what action to take when the link is clicked. Not obvious from the screenshot above, but the Address field shows the country in Drupal 10. The field formatter in Drupal 7 hides it when the field only allows a single country to be selected. No action to take as part of the example project.

While reviewing the field formatter migration, we identified that date formats are not migrated automatically. Migrations can be complex, and not every Drupal 7 setting has an automated upgrade path. Make sure to thoroughly review the migrated configuration and perform manual updates as needed. To wrap up the migration of fields, remember that storage, instance, widget, and formatter settings are closely interconnected.

Coming up in our step-by-step migration series, we will complete configuration migrations by walking through: media types and image styles, roles and permissions, and text and input formats. Once the remaining configuration is in place, we will be ready to work with content.

Image by Mohamed Hassan from Pixabay

Oct 17 2024
Oct 17

Series Overview & ToC | Previous Article | Next Article - coming soon!

We executed the last field-related migrations in the previous article, but we are not done with field configuration yet. Back in article 17, we used the Migrate Skip Fields module to prevent the automatic migration from importing image and YouTube fields. Today, we are going to use Drupal recipes to create media types and manually add media reference fields where needed.

Drupal recipes

The Recipes API,introduced in Drupal 10.3, allows installing modules and themes, importing configuration and content, and altering existing configuration. Recipes can also depend on other recipes, making them composable and highly flexible. Another benefit is the potential to replace installation profiles. This not only saves time but can bring consistency across different projects. In fact, Core's standard installation profile was replicated as a set of recipes. We are going to use a couple of those recipes to add media types to our Drupal 10 project.

Drupal recipes can validate that configuration elements are in a known state before the recipe is applied. Once a recipe is applied, the imported configuration is handled by the site itself. Any updates should follow standard configuration management practices.

Take a look at the core/recipes folder in Drupal 10’s docroot to better understand the anatomy of a recipe. Each one is contained in a folder with a required recipe.yml file. They can optionally contain config and content folders to import configuration and content respectively. We could certainly write a whole series on Drupal recipes, but for now we are going to focus on what is applicable to our example project.

Technical note: Recipes are a first-class Composer project type: drupal-recipe. They can be required as any other Composer package.

Applying a Drupal recipe

Drupal Core provides a built-in script for applying recipes. Starting with Drush 13, a recipe command is available. When executed from a Drupal 10 docroot, any of these commands can be used to apply a recipe:

php core/scripts/drupal recipe /path/to/recipe_folder
drush recipe /path/to/recipe_folder

We are going to use the Drush approach since applying recipes from the host into the Docker container requires some extra arguments. For reference, refer to this documentation to apply recipes when using DDEV.

First, we will apply a recipe to use images as media entities. From the Drupal 10 folder in your host machine, run the following command:

ddev drush recipe core/recipes/image_media_type

If things go as expected, you will see a message indicating that the Image media type applied successfully. This should create an image media type, add an image field to it, and configure the default and media_library view and form modes. Visit https://migration-drupal10.ddev.site/admin/structure/media/manage/image/fields to see how things were set up.

Manage Form Display page

These changes required adding new configuration to the site. Remember to export and commit the changes as with any other configuration change. If the recipe failed to apply, refer to the troubleshooting section below.

With one recipe applied, we will now do another that will allow YouTube videos to be embedded. From the Drupal 10 folder in your host machine, run the following command:

ddev drush recipe core/recipes/remote_video_media_type

When applied, the recipe will create a remote_video media type, add a plain text field to it, and configure the default and media_library view and form modes. The text field is used to store a link to the remote video URL. YouTube and Vimeo are supported out of the box. Visit https://migration-drupal10.ddev.site/admin/structure/media/manage/remote_video/fields to see how things were set up. As you would expect, the site configuration has been updated. Export the changes and commit them to the repository.

With media types already created, we are going to manually add media reference fields where appropriate. Per the site audit document referenced in article 3, these are the fields to add:

  1. In the Article content type, add a media reference field to images.
  2. In the Venue content type, add a media reference field to images.
  3. In the Session content type, add a media reference field to remote videos. Add this field to the Resources group.

This is a site building exercise readers should be able to do on their own. Refer to the code repository for the final configuration.

Troubleshooting recipe application

Recipes verify that included configuration does not exist or that existing configuration matches the recipe definition exactly. This check is also performed for dependent recipes.

In the case of existing configuration, the check is based on machine names. Any variation will prevent the recipe from applying. For example, the image_media_type recipe depends on the large image style. If we update its label from Large (480×480) to Large 480×480 px, the following error will be triggered when trying to apply the recipe:

In ConfigConfigurator.php line 47:


 The configuration 'image.style.large' exists already and does not match the recipe's configuration

Our label change might not be meaningful, but what if we had made changes to the image effects used in that image style? We certainly would not want to lose those customizations! As a general rule, recipes would not overwrite any configuration element if its current value differs from the recipe definition. Instead, a validation error is yielded. This might seem limiting. What is the point of using recipes then?

Remember that recipes are meant to be starting points. You can install a site from recipes. When there is no existing configuration, no conflicts can arise. That being said, applying recipes on existing sites is a valid and useful feature. In addition to those provided by Core, there are contributed recipes that you can use on your projects today.

Note: As of Drupal 10.4, recipes can opt out of strict comparisons with existing config. At the time of publishing, a strict comparison is still the default. Changing to making the configuration comparison lenient by default is being discussed in this issue.

Should we use recipes in migration projects?

It depends on your project requirements and the desired content model.

In our case, our Drupal 7 project did not use the Media module, but we still wanted to use media entities in Drupal 10. Recipes are available for creating media types modeled after the standard installation profile. No need to reinvent the wheel here!

Even so, put on your site builder hat as we take a deeper look at the implications of using these recipes.

Our example Drupal 7 project is arguably very simple. It is based on the standard installation profile and there are not many customizations. No custom image styles or text formats, nor changes to those provided out of the box. Only one custom role (Editor) and no WYSIWYG configuration. We could definitely use many Core recipes modeled after the standard installation profile, but should we?

For the sake of the example, consider image styles. Drupal Core provides a migration for image styles from Drupal 7. If we were to use it, the migration will overwrite any image style to match its Drupal 7 definition. In the case of Core image styles, Drupal 10 uses a WebP converter. That feature did not exist before. Since we are not customizing the Core image styles, and we do not have any custom one, for our example project it is better not to migrate image styles. That way, we take advantage of the optimizations that come with WebP in Drupal 10.

If you have custom image styles, use the upgrade_d7_image_styles migration from the ref_migrations folder. In this case, the image style migration needs to happen after applying the image_media_type recipe. Otherwise, updates to existing image styles will make the configuration validation fail and the recipe would not be applied. While this might seem like a chicken and egg problem, good planning goes a long way into determining the correct order to apply recipes, migrate configuration, and do manual configuration changes.

Technical note: Most source plugins for upgrading from Drupal 7 connect directly to the database to fetch data. Drupal 7 allowed some configuration to be defined in code, either by modules or features. When that configuration is in its default state, only the code representation exists. The database would not hold a reference to it. That is the case for the image styles in our example. Checking the status of the upgrade_d7_image_styles reveals there are no records to migrate, but we know that image styles do exist in Drupal 7. Those present only exist in code. For them to exist in the database, you would need to overwrite them. This also happens with views, field groups, and other configurations that can be represented in code. Take this into account if a migration reports no records to migrate or the total count is lower than expected.

To answer the question posed at the start of this section, it is ok to use recipes when they can be cleanly applied. If subsequent migrations might overwrite configuration elements created by the recipes, make sure the new configuration is truly what you want. If we export and commit configuration changes after every step, git should show us if anything was overridden. Keep in eye on functionality that did not exist in Drupal 7 and could be lost. That should not stop you from using the migration. If anything, manually apply the configuration that was overwritten by the migration.

Today, we've covered the basics of the Recipes API, how to apply recipes, and used them for creating media types. In our upcoming articles, we’ll walk through migrating user roles, permissions, and text and input formats to your new Drupal 10 site.

Image by Hans from Pixabay

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web