Een hart voor de Drupal Community

Bij make it fly geloven we sterk in Drupal en Open Source software in het algemeen. We maken dagelijks gebruik van vele open source componenten en de vele Drupal modules die beschikbaar zijn. We dragen actief ons steentje bij aan de community door zelf patches, modules en documentatie te voorzien, daarnaast zijn enkele teamleden ook actief in de Drupal User Group vzw.

Een overzicht van onze bijdragen aan de Drupal community vind je terug op onze Drupal.org pagina. Naast het actief meerwerken aan de Drupal community, zetten we ook andere ontwikkelaars op weg door vragen te beantwoorden op Drupal Answers.

  1. D11.3 regression creating blocks via block_theme_initialize

    Sven Decabooter

    Problem/Motivation

    I am installing Drupal via a Drush site install command, and then applying recipes to it for further configuration. A recipe is installing Claro as the backend theme. After installation, blocks have been copied from the frontend theme towards the claro theme, where they shouldn't have been.

    This had been fixed up until Drupal 11.2 - via the issue #3182716: block_theme_initialize should not create blocks during config sync. But since using Drupal 11.3.0, this appears again.

    The only change I see is that the logic has been moved towards an OOP hook, instead of a regular module hook in D11.2.

  2. Error after upgrading to 11.3 - You have requested a non-existent service "comment.manager".

    Fons

    Problem/Motivation

    After upgrading to 11.3 I get the following error:

    Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "comment.manager". Did you mean one of these: "theme.manager", "context.manager", "config.manager"? in Drupal\Component\DependencyInjection\Container->get() (line 157 of /var/www/html/web/core/lib/Drupal/Component/DependencyInjection/Container.php).

    Trace:

    #0 /var/www/html/web/core/lib/Drupal.php(205): Drupal\Component\DependencyInjection\Container->get()
    #1 /var/www/html/web/core/modules/history/src/Hook/HistoryTokensHooks.php(30): Drupal::service()
    #2 [internal function]: Drupal\history\Hook\HistoryTokensHooks->tokenInfo()
    #3 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(389): call_user_func_array()
    #4 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(340): Drupal\Core\Extension\ModuleHandler->Drupal\Core\Extension\{closure}()
    #5 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(388): Drupal\Core\Extension\ModuleHandler->invokeAllWith()
    #6 /var/www/html/web/modules/contrib/token/src/Token.php(40): Drupal\Core\Extension\ModuleHandler->invokeAll()
    #7 /var/www/html/web/modules/contrib/token/src/Token.php(100): Drupal\token\Token->getInfo()
    #8 /var/www/html/web/modules/contrib/token/src/TokenModuleProvider.php(57): Drupal\token\Token->getTokenInfo()
    #9 /var/www/html/web/core/lib/Drupal/Core/Cache/CacheCollector.php(149): Drupal\token\TokenModuleProvider->resolveCacheMiss()
    #10 /var/www/html/web/modules/contrib/token/src/TokenModuleProvider.php(49): Drupal\Core\Cache\CacheCollector->get()
    #11 /var/www/html/web/modules/contrib/token/token.tokens.inc(1754): Drupal\token\TokenModuleProvider->getTokenModule()
    #12 /var/www/html/web/modules/contrib/token/token.tokens.inc(503): _field_tokens()
    #13 [internal function]: token_tokens()
    #14 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(389): call_user_func_array()
    #15 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(340): Drupal\Core\Extension\ModuleHandler->Drupal\Core\Extension\{closure}()
    #16 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(388): Drupal\Core\Extension\ModuleHandler->invokeAllWith()
    #17 /var/www/html/web/core/lib/Drupal/Core/Utility/Token.php(364): Drupal\Core\Extension\ModuleHandler->invokeAll()
    #18 /var/www/html/web/modules/contrib/token/token.tokens.inc(1097): Drupal\Core\Utility\Token->generate()
    #19 [internal function]: token_tokens()
    #20 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(389): call_user_func_array()
    #21 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(340): Drupal\Core\Extension\ModuleHandler->Drupal\Core\Extension\{closure}()
    #22 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(388): Drupal\Core\Extension\ModuleHandler->invokeAllWith()
    #23 /var/www/html/web/core/lib/Drupal/Core/Utility/Token.php(364): Drupal\Core\Extension\ModuleHandler->invokeAll()
    #24 /var/www/html/web/core/lib/Drupal/Core/Utility/Token.php(245): Drupal\Core\Utility\Token->generate()
    #25 /var/www/html/web/core/lib/Drupal/Core/Utility/Token.php(195): Drupal\Core\Utility\Token->doReplace()
    #26 /var/www/html/web/modules/contrib/metatag/src/MetatagToken.php(66): Drupal\Core\Utility\Token->replace()
    #27 /var/www/html/web/modules/contrib/metatag/src/MetatagManager.php(791): Drupal\metatag\MetatagToken->replace()
    #28 /var/www/html/web/modules/contrib/metatag/src/MetatagManager.php(634): Drupal\metatag\MetatagManager->processTagValue()
    #29 /var/www/html/web/modules/contrib/metatag/src/MetatagManager.php(573): Drupal\metatag\MetatagManager->generateRawElements()
    #30 /var/www/html/web/modules/contrib/metatag/metatag.module(510): Drupal\metatag\MetatagManager->generateElements()
    #31 /var/www/html/web/modules/contrib/metatag/metatag.module(264): metatag_get_tags_from_route()
    #32 /var/www/html/web/modules/contrib/metatag/metatag.module(224): _metatag_remove_duplicate_entity_tags()
    #33 /var/www/html/web/core/lib/Drupal/Core/Extension/ModuleHandler.php(460): metatag_entity_view_alter()
    #34 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityViewBuilder.php(306): Drupal\Core\Extension\ModuleHandler->alter()
    #35 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityViewBuilder.php(240): Drupal\Core\Entity\EntityViewBuilder->buildMultiple()
    #36 [internal function]: Drupal\Core\Entity\EntityViewBuilder->build()
    #37 /var/www/html/web/core/lib/Drupal/Core/Security/DoTrustedCallbackTrait.php(107): call_user_func_array()
    #38 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(910): Drupal\Core\Render\Renderer->doTrustedCallback()
    #39 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(441): Drupal\Core\Render\Renderer->doCallback()
    #40 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(230): Drupal\Core\Render\Renderer->doRender()
    #41 /var/www/html/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(242): Drupal\Core\Render\Renderer->render()
    #42 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(634): Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}()
    #43 [internal function]: Drupal\Core\Render\Renderer::Drupal\Core\Render\{closure}()
    #44 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(649): Fiber->resume()
    #45 /var/www/html/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(235): Drupal\Core\Render\Renderer->executeInRenderContext()
    #46 /var/www/html/web/core/lib/Drupal/Core/Render/MainContent/HtmlRenderer.php(131): Drupal\Core\Render\MainContent\HtmlRenderer->prepare()
    #47 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/MainContentViewSubscriber.php(90): Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse()
    #48 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(246): Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray()
    #49 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(206): Symfony\Component\EventDispatcher\EventDispatcher::Symfony\Component\EventDispatcher\{closure}()
    #50 /var/www/html/vendor/symfony/event-dispatcher/EventDispatcher.php(56): Symfony\Component\EventDispatcher\EventDispatcher->callListeners()
    #51 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(188): Symfony\Component\EventDispatcher\EventDispatcher->dispatch()
    #52 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw()
    #53 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/Session.php(53): Symfony\Component\HttpKernel\HttpKernel->handle()
    #54 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle()
    #55 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle()
    #56 /var/www/html/web/core/modules/big_pipe/src/StackMiddleware/ContentLength.php(32): Drupal\Core\StackMiddleware\ContentLength->handle()
    #57 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(118): Drupal\big_pipe\StackMiddleware\ContentLength->handle()
    #58 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(92): Drupal\page_cache\StackMiddleware\PageCache->pass()
    #59 /var/www/html/vendor/asm89/stack-cors/src/Cors.php(53): Drupal\page_cache\StackMiddleware\PageCache->handle()
    #60 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Asm89\Stack\Cors->handle()
    #61 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle()
    #62 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(53): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle()
    #63 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(54): Drupal\Core\StackMiddleware\AjaxPageState->handle()
    #64 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(745): Drupal\Core\StackMiddleware\StackedHttpKernel->handle()
    #65 /var/www/html/web/index.php(19): Drupal\Core\DrupalKernel->handle()
    #66 {main}

    Workaround

    Disabling the history module is the workaround for now.

    Still have to look into was causes this.

  3. Refactor the `setupAiProvider` config action to be simpler

    Sven Decabooter

    I don't quite get the simpleConfigUpdate part in the code snippet below:

    config:
      actions:
        ai.settings:
          setupAiProvider:
            key_value: ${api_key}
            key_name: ai_api_key
            key_label: 'AI API Key'
            provider: ${provider}
          simpleConfigUpdate:
            openai:
              ai_provider_openai.settings:
                moderation: true
            anthropic:
              ai_provider_anthropic.settings:
                openai_moderation: false
    

    From what I understand, simpleConfigUpdate will then perform logic on the ai.settings config object, whereas it should be on the ai_provider_openai.settings and / or ai_provider_anthropic.settings config...

    Shouldn't that be:

    config:
      actions:
        ai.settings:
          setupAiProvider:
            key_value: ${api_key}
            key_name: ai_api_key
            key_label: 'AI API Key'
            provider: ${provider}
        ai_provider_openai.settings:
          simpleConfigUpdate:
            moderation: true
        ai_provider_anthropic.settings:
          simpleConfigUpdate:
            openai_moderation: false
    

    But those config objects might not exist, based on the provider that was selected... I'm probably missing something here?

  4. Refactor the `setupAiProvider` config action to be simpler

    Sven Decabooter

    Would refactoring the Key storage mechanism also be in scope of this, or is this in another issue? The main reason I'm currently not using the setupAiProvider config action, is that I don't want the API key to be stored in config. This could perhaps be worked around by being able to provide a Key ID (the ID of the Key entity, not the actual API key) to use when setting up, as an alternative to automatically create a Key entity with the provide API key.

  5. Offering to co-maintain Webform Encrypt

    Sven Decabooter

    Problem/Motivation

    would like to become a co-maintainer of this module to merge the Drupal 11 compatibility patch along with any appropriate RTBC issues and create a D11-compatible release. I'd be happy to work with the community to keep this module up to date and going.

    You can view my profile to see my history of work.

    Proposed resolution

    Review my profile and, if approved, add me as co-maintainer with appropriate permissions to merge code, manage issues, and create releases.

    Remaining tasks

    Add me as co-maintainer for this module.

  6. Handeling breadcrumbs in Drupal Canvas

    Fons

    Hello,

    Thank you for this awesome module, I use it a lot.

    I've noticed in Drupal Canvas that in the Page Builder you get a funky breadcrumb trail, I could edit the settings for this special case but it might be good to have a general fix in place to deal with this?

    Page with normal breadcrumb behaviour (as expected):

    Page edit with the funky breadcrumb:

  7. Translated content sometimes gets "html" prefix

    Sven Decabooter

    Problem/Motivation

    I have from time to time experienced the behaviour with AI Translate that a text gets translated, but the result adds the "html" string in front of the translation.

    E.g.

    html
    Todas estas cosas demuestran ...
    

    Steps to reproduce

    It seems to happen more or less randomly. I am getting it with AI 1.2.3 and AI Provider LiteLLM installed - using OpenAI gpt-4o model. It happens more on large pages with a lot of WYSIWYG text fields.

  8. Add GitlabCI config

    Sven Decabooter

    Problem/Motivation

    After the move from being a submodule of the AI module to a standalone project, I noticed there is no Gitlab CI config anymore.

    Proposed resolution

    Copy the .gitlab-ci.yml file from the AI module, and remove the parts that are irrelevant for AI Translate specifically.

  9. Values can be copied to another instance of the custom field item

    Randal

    Problem/Motivation

    I ran into a very strange bug, I have an inline block with a custom field that has one image and one link field. I placed two instances of this inline block in my layout builder layout, the first one does have a link filled in and the second one does NOT have a link. What happens then is that the second item also gets the link value from the first one.

    The strange thing is, during my debugging I've gotten to the `isEmpty()` check in the `CustomItem` class, if I check what's in `$this->getValue()` I get the expected values (empty on the second instance), if I check `$this->get('link')->getValue)`, then I get the value from the first instance. So, seems like as soon as you directly access the link value, it messes up.

    Steps to reproduce

    1. Create an inline block with a custom field with some subfields of which one is a link field (not required)
    2. Place two of those blocks, and leave the link value empty in the second block
    3. See the link of the first instance in the second one

    Remaining tasks

    Identify the root issue and develop a fix.

    PS. I'll provide a screenshot of some dump statements, they're the output of this code on line 899 of the CustomItem class.

        VarDumper::dump($this->getValue());
        VarDumper::dump($this->get('value_2')->getValue());
  10. Require stable custom_field release

    Sven Decabooter

    Problem/Motivation

    I tested installing this recipe, but got stuck on "drupal/custom_field": "^4.0.x-dev" requirement, because I already have 4.0.1 installed.

    I'm not sure why the dev branch was needed, and which release of custom_field didn't yet provide the features required, but from what I can tell this was added over a month ago, and there has since been a 4.0.1 release, which would probably be usable by this recipe.

    Could this be changed to drupal/custom_field:^4.0.1, or is there a reason not to?

  11. Create linkable schema for providers

    Sven Decabooter

    This looks good. I have added some remarks regarding configuration validation. It would be good if they could be taken into account, so we can make sure the schema will be used as intended (and throw validation errors if not).

  12. Move out AI Translate

    Sven Decabooter

    Created an issue in the ai_translate module, to make sure changes in the MR are in sync with the logic in ai_translate, and there is no duplicate logic in both. See https://www.drupal.org/project/ai_translate/issues/3560984

    If the failing tests can be accounted for, this can go to RTBC for me.

  13. Move out AI Translate

    Sven Decabooter

    Are the failing tests related to this changed functionality? I can't see immediately how it's related... The ai 2.0.x branch doesn't have these failing tests though...

  14. Integration with AI 2.0.x

    Sven Decabooter

    Note: I used OOP hooks and made the module 11.x only, as I think it was discussed that AI 2.0.x will be 11.x only also. If that is not the case, then D10 legacy hook support will need to be added.

  15. Integration with AI 2.0.x

    Sven Decabooter

    Problem/Motivation

    As discussed in #3552887: Move out AI Translate, this module will need some work to cleanly integrate with the ai 2.0.x branch, where ai_translate functionality was mostly removed. Make sure integration with the remaining parts keeps on working.

    Proposed resolution

    - Remove ai_prompt config/install configuration - Override / extend ai 2.0.x AIProvider with our own, if possible.

  16. D11: Missing parameter in \Drupal\Core\Form\ConfigFormBase

    Sven Decabooter

    Problem/Motivation

    ArgumentCountError: Too few arguments to function Drupal\Core\Form\ConfigFormBase::__construct(), 1 passed in /var/www/html/web/modules/contrib/api_connection/src/Form/ApiConnectionSettingsForm.php on line 32 and exactly 2 expected in Drupal\Core\Form\ConfigFormBase->__construct() (line 44 of core/lib/Drupal/Core/Form/ConfigFormBase.php).

Sven Decabooter - Drupal Developer

"Onze teamleden bouwen zelf ook mee aan ons geliefde Drupal, en daar zijn we trots op"

Sven Decabooter
Drupal developer

Betrouwbare technologie, naadloze prestaties. Dat zijn onze Drupal-oplossingen.