diff --git a/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml b/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml
index 8a527769443ef110bbcf407d68b4a85bea9e83c8..741667e9700cf319abb6d601770489db0721f2db 100644
--- a/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml
+++ b/.ddev/addon-metadata/ddev-drupal-contrib/manifest.yaml
@@ -1,7 +1,7 @@
 name: ddev-drupal-contrib
 repository: ddev/ddev-drupal-contrib
-version: 1.0.0-rc22
-install_date: "2024-10-28T09:48:30+02:00"
+version: 1.0.0-rc23
+install_date: "2025-01-15T14:35:04+02:00"
 project_files:
     - commands/web/eslint
     - commands/web/expand-composer-json
diff --git a/.ddev/commands/web/eslint b/.ddev/commands/web/eslint
index 571bc345ffc49350523d2d0e4705648293bfd39d..fb663f663c1fa62a985892f1a8ec537f85813d83 100755
--- a/.ddev/commands/web/eslint
+++ b/.ddev/commands/web/eslint
@@ -12,11 +12,9 @@ if "$DDEV_DOCROOT/core/node_modules/.bin/eslint" --version >/dev/null ; then
   test -e .prettierrc.json || ln -s $DDEV_DOCROOT/core/.prettierrc.json .
   test -e .prettierignore || echo '*.yml' > .prettierignore
   # Change directory to the project root folder
-  # cd "$DDEV_DOCROOT/modules/custom/$DDEV_SITENAME" || exit
-  # Anticipating https://github.com/ddev/ddev-drupal-contrib/pull/81
   cd "$DDEV_DOCROOT/modules/custom/${DDEV_SITENAME//-/_}" || exit
-  "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/node_modules/.bin/eslint" --no-error-on-unmatched-pattern --ignore-pattern="*.es6.js" --resolve-plugins-relative-to=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core --ext=.js,.yml . "$@"
+  "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/node_modules/.bin/eslint" --config="../../../core/.eslintrc.passing.json" --no-error-on-unmatched-pattern --ignore-pattern="*.es6.js" --resolve-plugins-relative-to=$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core --ext=.js,.yml . "$@"
 else
-  echo "eslint is not available. You may need to 'ddev yarn --cwd $DDEV_DOCROOT/core install'"
+  echo "eslint is not available. You may need to 'ddev exec \"cd $DDEV_DOCROOT/core && yarn install\"'"
   exit 1
 fi
diff --git a/.ddev/commands/web/expand-composer-json b/.ddev/commands/web/expand-composer-json
index d24d8a0252e4b795474cf50a2816cef64cc4ff4c..48a8840f6e46df7f3856df101b80924f8aeed400 100755
--- a/.ddev/commands/web/expand-composer-json
+++ b/.ddev/commands/web/expand-composer-json
@@ -10,5 +10,12 @@
 export _WEB_ROOT=$DDEV_DOCROOT
 cd "$DDEV_COMPOSER_ROOT" || exit
 curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/scripts/expand_composer_json.php
+if [[ ! -f composer.json ]]; then
+  echo "{}" > composer.json
+  _ddev_drupal_contrib_empty_composer=true
+fi
 php expand_composer_json.php "$DDEV_SITENAME"
 rm -f expand_composer_json.php
+if [ "$_ddev_drupal_contrib_empty_composer" = true ];  then
+  rm -f composer.json
+fi
diff --git a/.ddev/commands/web/phpcbf b/.ddev/commands/web/phpcbf
index 9c1013ca93deecc49fa6631f9547083c0d819489..756d2b4cbbec274a9913b30238c21f4dedb472dd 100755
--- a/.ddev/commands/web/phpcbf
+++ b/.ddev/commands/web/phpcbf
@@ -12,4 +12,4 @@ if ! command -v phpcbf >/dev/null; then
   exit 1
 fi
 test -e phpcs.xml.dist || curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpcs.xml.dist
-phpcbf -s --report-full --report-summary --report-source web/modules/custom "$@"
+phpcbf -s --report-full --report-summary --report-source $DDEV_DOCROOT/modules/custom "$@"
diff --git a/.ddev/commands/web/phpcs b/.ddev/commands/web/phpcs
index 672888682ac272081d77da40a83a8f009c09f1a6..5df1fa9b147ff5fa225777ae519645a269a4eb3a 100755
--- a/.ddev/commands/web/phpcs
+++ b/.ddev/commands/web/phpcs
@@ -12,4 +12,4 @@ if ! command -v phpcs >/dev/null; then
   exit 1
 fi
 test -e phpcs.xml.dist || curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpcs.xml.dist
-phpcs -s --report-full --report-summary --report-source web/modules/custom --ignore=*/.ddev/* "$@"
+phpcs -s --report-full --report-summary --report-source $DDEV_DOCROOT/modules/custom --ignore=*/.ddev/* "$@"
diff --git a/.ddev/commands/web/phpstan b/.ddev/commands/web/phpstan
index ae151f6c418aac8b0693b866b403eefe6d5b3836..7c73132e7e9e7915494c44d18da0eb4b30839c8c 100755
--- a/.ddev/commands/web/phpstan
+++ b/.ddev/commands/web/phpstan
@@ -5,7 +5,6 @@
 ## Description: Run phpstan inside the web container
 ## Usage: phpstan [flags] [args]
 ## Example: "ddev phpstan" or "ddev phpstan -n"
-## ProjectTypes: drupal,drupal8,drupal9,drupal10
 ## ExecRaw: true
 
 if ! command -v phpstan >/dev/null; then
@@ -13,6 +12,8 @@ if ! command -v phpstan >/dev/null; then
   exit 1
 fi
 test -e phpstan.neon || curl -OL https://git.drupalcode.org/project/gitlab_templates/-/raw/default-ref/assets/phpstan.neon
+# See https://git.drupalcode.org/project/gitlab_templates/-/commit/a107b7f1f79af12e0b09f70be47b68e3f69b4504
+sed -i 's/BASELINE_PLACEHOLDER/phpstan-baseline.neon/g' phpstan.neon
 # Add an empty baseline file to ensure it exists.
 test -e phpstan-baseline.neon || touch phpstan-baseline.neon
 phpstan analyse $DDEV_DOCROOT/modules/custom "$@"
diff --git a/.ddev/commands/web/stylelint b/.ddev/commands/web/stylelint
index f8af5b5ece83aaac5f0d9a21fcdf3b3980e48c42..99d082c3302dceaba7b7fd98764ae8695a454145 100755
--- a/.ddev/commands/web/stylelint
+++ b/.ddev/commands/web/stylelint
@@ -7,12 +7,11 @@
 ## Example: "ddev stylelint"
 ## ExecRaw: true
 
-# Changed to follow https://github.com/ddev/ddev-drupal-contrib/pull/83
 if $DDEV_DOCROOT/core/node_modules/.bin/stylelint --version >/dev/null ; then
-   # Change directory to the project root folder
-   cd "$DDEV_DOCROOT/modules/custom/${DDEV_SITENAME//-/_}" || exit
-   "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/node_modules/.bin/stylelint" --color --config "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/.stylelintrc.json" "./**/*.css" "$@"
+  # Change directory to the project root folder
+  cd "$DDEV_DOCROOT/modules/custom/${DDEV_SITENAME//-/_}" || exit
+  "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/node_modules/.bin/stylelint" --color --config "$DDEV_COMPOSER_ROOT/$DDEV_DOCROOT/core/.stylelintrc.json" "./**/*.css" "$@"
 else
-  echo "stylelint is not available. You may need to 'ddev yarn --cwd $DDEV_DOCROOT/core install'"
+  echo "stylelint is not available. You may need to 'ddev exec \"cd $DDEV_DOCROOT/core && yarn install\"'"
   exit 1
 fi
diff --git a/.ddev/config.contrib.yaml b/.ddev/config.contrib.yaml
index d56746136685a6fbd4cd04afcc8db066cdc1f60c..e9e7b24cb9605d6a65660c6ddd4036db96e22952 100644
--- a/.ddev/config.contrib.yaml
+++ b/.ddev/config.contrib.yaml
@@ -1,7 +1,8 @@
 #ddev-generated
 ## Command provided by https://github.com/ddev/ddev-drupal-contrib
 web_environment:
-  # If desired, override to a different version of Drupal core in via the project's DDEV config
+  # To change the Drupal core version, see the README:
+  # https://github.com/ddev/ddev-drupal-contrib/blob/main/README.md#changing-the-drupal-core-version
   - DRUPAL_CORE=^11
   - SIMPLETEST_DB=mysql://db:db@db/db
   - SIMPLETEST_BASE_URL=http://web
diff --git a/.gitignore b/.gitignore
index 2b9dc5aae04a4a614122dbb7bef8ca480fa82ba0..9ff6d3358bb76c7379605e06bfa9ba1f14d24019 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,5 +5,6 @@
 /.prettierrc.json
 /phpstan-baseline.neon
 /phpstan.neon
+/recipes/
 /vendor/
 /web/
diff --git a/composer.json b/composer.json
index 3a5a8003c3cf685741f46aff82e9186e97a3573a..ebbef38d8732af20820b28692b3427fabc846006 100644
--- a/composer.json
+++ b/composer.json
@@ -22,6 +22,7 @@
         "drupal/message_notify": "^1.0"
     },
     "require-dev": {
+        "drupal/coder": "8.3.26",
         "drupal/rules": "^4.0",
         "drupal/symfony_mailer_lite": "^2.0",
         "drush/drush": "^12.5 || ^13.3"
diff --git a/modules/private_message_notify/private_message_notify.services.yml b/modules/private_message_notify/private_message_notify.services.yml
index 45c72776fa029f0d53df5a02e13121249ead4ba9..93e34d85eeab946080929c270f617c8f3363f2eb 100644
--- a/modules/private_message_notify/private_message_notify.services.yml
+++ b/modules/private_message_notify/private_message_notify.services.yml
@@ -1,5 +1,4 @@
 services:
-
   _defaults:
     autoconfigure: true
     autowire: true
diff --git a/private_message.libraries.yml b/private_message.libraries.yml
index 59c26e6ee9ca278daf59b41de8d5c968e8b721e8..7cd72ee99d0605e5b2254a935d6d468977afb88a 100644
--- a/private_message.libraries.yml
+++ b/private_message.libraries.yml
@@ -14,22 +14,22 @@ utils:
 
 slide:
   js:
-    js/private_message_slide.js: { }
+    js/private_message_slide.js: {}
   dependencies:
     - core/drupal
 
 fader:
   js:
-    js/private_message_fader.js: { }
+    js/private_message_fader.js: {}
   dependencies:
     - core/drupal
 
 dimmer:
   js:
-    js/private_message_dimmer.js: { }
+    js/private_message_dimmer.js: {}
   css:
     theme:
-      css/private_message_dimmer.css: { }
+      css/private_message_dimmer.css: {}
   dependencies:
     - core/drupal
     - private_message/fader
diff --git a/private_message.services.yml b/private_message.services.yml
index ba9c4c535ea0e2200dbbb8c6869a62d1d3fcec32..48fa027f65ed7d0338c013e48518d470d973453e 100644
--- a/private_message.services.yml
+++ b/private_message.services.yml
@@ -1,5 +1,4 @@
 services:
-
   _defaults:
     autoconfigure: true
     autowire: true
diff --git a/src/Mapper/PrivateMessageMapper.php b/src/Mapper/PrivateMessageMapper.php
index 24a086c207b45fbb23a3e3ecb1b23b6b94cce944..d00e10ac740048c43cf0bd75d0d911699ffe532d 100644
--- a/src/Mapper/PrivateMessageMapper.php
+++ b/src/Mapper/PrivateMessageMapper.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\private_message\Mapper;
 
-@trigger_error(__CLASS__ . ' is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
+@trigger_error(__NAMESPACE__ . '\PrivateMessageMapper is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Database\Query\SelectInterface;
diff --git a/src/Mapper/PrivateMessageMapperInterface.php b/src/Mapper/PrivateMessageMapperInterface.php
index 45294330e1c3cda369bc27a4f4e13873144eca4c..a7144ec0220f847347a81b5dacc6d4afef12a3b1 100644
--- a/src/Mapper/PrivateMessageMapperInterface.php
+++ b/src/Mapper/PrivateMessageMapperInterface.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\private_message\Mapper;
 
-@trigger_error(__CLASS__ . ' is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
+@trigger_error(__NAMESPACE__ . '\PrivateMessageMapperInterface is deprecated in private_message:4.0.0 and is removed from private_message:5.0.0. No replacement is provided. See https://www.drupal.org/node/3490530', E_USER_DEPRECATED);
 
 use Drupal\private_message\Entity\PrivateMessageInterface;
 use Drupal\user\UserInterface;
diff --git a/tests/src/Kernel/EntityDeleteTest.php b/tests/src/Kernel/EntityDeleteTest.php
index be7e603c07a7d67d084247a780ed195045d59a6c..57152288c05e8c40bc3a92a7534e6608cc3481ca 100644
--- a/tests/src/Kernel/EntityDeleteTest.php
+++ b/tests/src/Kernel/EntityDeleteTest.php
@@ -127,7 +127,7 @@ final class EntityDeleteTest extends KernelTestBase {
    * @return array[]
    *   The test data.
    */
-  public function testBannedMessagesProvider(): array {
+  public static function testBannedMessagesProvider(): array {
     return [
       // User A is logged in, which is the user that created the messages.
       ['a'],