So it's time for an upgrade to Drupal 10. You have come to the right place.
The person who completes the estimate may or may not be the same person that actually does the work. If you are the estimator, bear this in mind and try to include as much context as possible in the upgrade ticket.
Process
1. Speak to client to understand needs, concerns, timeline, etc. If you are not already familiar, ascertain their level of technical skill and familiarity with the site. This will factor into the estimate spreadsheet. Obtain approval of 2-3 hours to put together a detailed estimate.
2. Create a ticket in their repo using the template. Include any information you have from the meeting with the client. Do they have a hard launch date? Are they worried about specific custom modules? Include anything that might be important or helpful to know for whoever will be doing the upgrade.
3. Complete steps 1-4 of Part 1 of the ticket. This will entail some code cleanup, creating your update branch, and creating the upgrade and testing spreadsheet.
4. Communicate the estimate to the client or PM/person who manages client interactions. Send along any of the above artifacts that might be helpful in client conversations and bring up any concerns that came up during the estimate process.
5. Once the client has approved the estimate and the work has been allocated, begin Part 2 of the ticket.
6. Before handing the site off to the client for QA, prepare the testing document for them and include testing for any modules or functionality that they should QA.
7. Hand off to the client and address any issues that arise from testing.
8. Once the client has approved, you are free to schedule deployment.
Notes
This article is a place to drop common upgrade issues/fixes, mirroring the same article we wrote for Drupal 9.
There are hints about jQuery.once and Twig updates in this article, which may be relevant for theming - the main takeaway is to replace library calls to core/jquery.once
with core/once
. Additional helpful examples can be found at DrupalBook.
Module testing/estimate document
Additional Resources
Upgrading a composer-based site (D.O.)
Advice and Lessons Learned by Miles Efron
Upgrade Status issues
Most core themes from D8 have been deprecated. ThinkShout uses classy as the base for all of the custom themes we've built to date, therefore we need to add it as a contributed theme. composer require drupal/classy
Similiarly, Seven, our default Admin theme, is deprecated. Drupal recommends upgrading to Claro instead, or you can go with the contrib version of Seven, like classy above.
If you get "web/PHPStan failed", run composer require symfony/phpunit-bridge --dev
Upgrade Checklist
The Drupal 9->10 upgrade process is slightly different from the Drupal 8 -> 9 process. These steps have been incorporated in the ticket template linked above.
- [ ] Make sure you're using PHP 8.1. - [ ] Get the site to the latest Drupal 9 version. - [ ] Remove Bene media (see https://library.thinkshoutlabs.com/articles/how-uninstall-benemedia) - [ ] Install the [upgrade status](https://www.drupal.org/project/upgrade_status) module. - [ ] Review [Deprecated and obsolete](https://www.drupal.org/docs/core-modules-and-themes/deprecated-and-obsolete) article. - [ ] Switch admin to a supported theme such as Claro or [Gin](https://www.drupal.org/project/gin). - [ ] Remove unused modules. - [ ] Remove uninstall deprecated modules. If they have no D10 equivalent, add a "Ghost of" module so you can remove them from Composer at the same time, or do a second deploy to remove them. - [ ] Add deprecated themes such as Classy as [contrib classy](https://www.drupal.org/project/classy), if you've used them as the base for the TS theme (we always do this). - [ ] Review & upgrade custom modules to be D10-compatible, note any that do not currently have D10 versions. - [ ] Upgrade all of the `^8 | ^9` contrib modules to the latest `^9 | ^10` versions. Note: you may need to check the issue queues and 'all releases' for D10 patches or release branches. - [ ] Review the [CKEditor 4 -> 5 D.O. article](https://www.drupal.org/docs/core-modules-and-themes/core-modules/ckeditor-5-module/testing-the-ckeditor-4-to-5-upgrade-path). - [ ] [Add CKEditor 5 before removing CKEditor 4](https://www.drupal.org/project/ckeditor/issues/3331921#comment-14918472). - [ ] After Upgrade Status gives the green light, upgrade core to D10. - [ ] Review the "Common fixes needed section" of https://library.thinkshoutlabs.com/articles/drupal-10-upgrade-notes to see if any are applicable to your site. Note: You can just delete old update hooks if they've already run on Live, as opposed to fixing them.
It is probably best to break up the above into several smaller releases to ensure stability and make any issues easier to test / isolate: PHP8/D9.5 -> D10 Prep -> CKEditor migration -> D10 release
Errors Running Upgrade Command
Your site should have been updated to use Drupal Core Recommended a long time ago. Assuming this is true, once you have your site ready to upgrade to Drupal 10, you will probably use a command like this one:
composer update "drupal/core-*" --with-all-dependencies
OR something like:
composer require drupal/core-recommended:^10 -W
If you use Composer require, make sure to include -W, which is the alias for --update-with-all-dependencies. Otherwise, you'll probably hit several conflicts. You might find it helpful to pin this to a specific version (hopefully the most recent one).
If you are at your wit's end trying to upgrade, one thing you can try is composer removing everything in the require-dev section. That's right, I said EVERYTHING. Once you have done that, try upgrading to Drupal 10 again. If it works, add back everything you removed.
You might also find it helpful to use Drupal's Lenient Composer Endpoint on modules that you are somewhat confident won't break the site if their version constraints are broken. This process is documented at Drupal.org.
For reference (note core and drush versions), here's a successful D10 upgrade. That drush version is important--if you're getting obscure composer errors about guzzlehttp and psr/container, try adding drush 11.3 to the same composer require command as your core update.
If robo seems to be getting you stuck, try wildcarding all of the other dev packages except thinkshout/robo-drupal:dev-php81 and symfony/phpunit-bridge:^6.3 so composer can figure things out:
composer require --dev thinkshout/robo-drupal:dev-php81 symfony/phpunit-bridge:^6.3 dealerdirect/phpcodesniffer-composer-installer:* dmore/behat-chrome-extension:* drupal/coder:* drupal/config_suite:* drupal/stage_file_proxy:* drupal/twig_xdebug:* drupal/upgrade_status:* drush-ops/behat-drush-endpoint:* kint-php/kint:* mglaman/drupal-check:* mikey179/vfsstream:* pantheon-systems/ci-scripts:* phpunit/phpunit:* squizlabs/php_codesniffer:* -W
CKEditor5
You DO NOT need to migrate your formats manually! Per section 2, number 5 in this article, if you simply switch your text editor field from CKEditor to CKEditor 5, your text format configurations will automatically migrate. This will save you a big headache and a lot of time, so take advantage.
Anchor Links (and probably other CKEditor plugins)
A solution has been cobbled together to enable Anchor Link to work on Drupal 10 and CKEditor 5. As of early September, you can follow the steps in this comment to make it work. Do not forget to add both FakeObjects and the CKEditor 5 Anchor Link library in both the repositories and require sections of the composer file. You can find an example in the HSUS repository.
Comments on this solution are tracked in the issue linked above and continue to be active. Please update this step as the procedure evolves.
List of Known Modules with Automated D10 Patches
Common fixes needed:
Fix 1: Twig template for/ifs
We have used this method to loop through children of an element in twig:
{% for key, amount in donationAmounts if key|first != '#' %}
That format is no longer supported, and should be changed to:
{% for key, amount in donationAmounts %}
{% if key|first != '#' %}
Fix 2: Update entity queries
Drupal entity queries that look like this no longer have an access value set by default (see https://www.drupal.org/node/3201242). To fix this add ->accessCheck(TRUE)
to all queries in this form that don't already have an accessCheck call on them:
Old:
\Drupal::entityQuery('node')
OR
\Drupal::entityTypeManager()->getStorage('node')->getQuery()
New:
\Drupal::entityQuery('node')
->accessCheck(TRUE)
OR
\Drupal::entityTypeManager()->getStorage('node')->getQuery()
->accessCheck(TRUE)
Additional resources:
Fix 3: Replace drupal_get_path()
Old:
drupal_get_path('module', 'lvhn_activecal')
New:
\Drupal::service('extension.list.module')->getPath('lvhn_activecal')
Fix 4: replace render()
Old:
render($link)
New:
\Drupal::service('renderer')->render($link)
Fix 5: replace taxonomy_term_load_multiple_by_name()
Old:
taxonomy_term_load_multiple_by_name('Primary Care', 'specialties');
New:
$primary_care_terms = Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([
'name' => 'Primary Care',
'vid' => 'specialties',
]);
Fix 6: Password Compatibility Module
While upgrading HSUS, the client surfaced that users had to reset their passwords. This is a known issue with a fix. (Note: if you just want a command to enable the module, it's drush en phpass.)
Fix 7: Facebook Messenger Chat - D10 version restriction
This module should be compatible with Drupal 10, but we discovered its .info.yml file prevents upgrading to 10.1 or above. A patch is logged here as of early September.
Fix 8: User permissions error
This surfaced in Drupal 9.3, so hopefully it had already been addressed. If you are getting errors that might pertain to something like this, take a look at this issue thread about it.
Fix 9: Replace file_create_url() and file_url_transform_relative()
These functions are deprecated and requires some service injection, some of which is documented.
Fix 10: Replace file_save_data()
Function has been replaced with a service that implements \Drupal\file\FileRepositoryInterface.
Fix 11: Deprecation of strftime and gmstrftime in PHP 8.1
If this site has already been updated to use PHP 8.1, it's possible this has already been addressed. If not, it is documented at php.watch.
Fix 12: Unspecific issues with Brightedge
I'm not sure how many other projects use Brightedge. It caused some issues for HSUS. Take a look at the HSUS PR linked below for any changes that were made to our customized version of that code.
Fix 13: "PHPStan command failed" messages
This came up for CSIS, and I am not totally clear what caused it, but the fix in comment #8 here did the trick. Prior to implementing the fix, I was not actually able to see all of the issues for some of the modules.
Fix 14: If statement in Twig for loop
This seems to have been deprecated back around the time of Drupal 9 upgrades, but if you get an error about this in the Upgrade Status screen, take a look at this documentation for more information on how to fix it.
Fix 15: Drupal Lenient - Module patches not applying
Modules that don't have d10 compliant versions, but can be patched to be compliant, will sometimes run into issues where the patch fails to apply with the upgrade command. Avail yourself of the Using Drupal's Lenient Composer Endpoint documentation to resolve this.
Fix 16: Custom Routes - CacheableAccessDeniedHttpException
Access check deprecated - if you get a 404 on any custom routes and the logs give you a 'CacheableAccessDeniedHttpException', check *.routing.yml
for _node_add_access
and replace it with _entity_create_access
Fix 17: Media browser sidebar not styled in Claro
Most easily seen when you use the Media Embed button on a WYSIWYG field, you may encounter this:
Patch is available at https://www.drupal.org/project/drupal/issues/3404866
Fix 18 : Twig errors
Previously, twig files could have a spaceless tag, as so:
{% spaceless %}
{% endspaceless%}
These need to be changed to this:
{% apply spaceless %}
{% endapply %}
Unexpected token errors. Combined for/if statements have to be separated now, explained in more detail on StackOverflow.
Example PRs
https://github.com/thinkshout/lvhn/pull/5997/files
https://github.com/thinkshout/feeding-america/pull/1753/files
https://github.com/thinkshout/hsus/pull/1926