Drupal feeds
Talking Drupal: Talking Drupal #521 - Tugboat
Today we are talking about Tugboat, What it does, and how it can super charge your ci/cd process with guest James Sansbury. We’ll also cover ShURLy as our module of the week.
For show notes visit: https://www.talkingDrupal.com/521
Topics- Celebrating 20 Years with Drupal
- Introduction to Tugboat
- Comparing Tugboat with Other Solutions
- Tugboat's Unique Advantages
- Standardizing Workflows with Tugboat
- Handling Hosting and Development Delays
- Troubleshooting and Knowledge Transfer
- Client Base and Use Cases
- Agency Partnerships and Payment Structures
- Unique and Interesting Use Cases
- Challenges and Limitations of Tugboat
- Setting Up and Onboarding with Tugboat
- The Tugboat Origin Story
- Compliance and Security Considerations
- Tugboat
- Tugboat FEDRamp
- Lullabot Sells Tugboat Platform to Enable Independent Growth
- Shurly
- Talking Drupal #390 - Employee Owned Companies
Nic Laflin - nLighteneddevelopment.com nicxvan John Picozzi - epam.com johnpicozzi James Sansbury - tugboatqa.com q0rban
MOTW CorrespondentMartin Anderson-Clutz - mandclu.com mandclu
- Brief description:
- Have you ever wanted to use Drupal as a URL shortening service? There’s a module for that.
- Module name/project name:
- Brief history
- How old: created in Aug 2010 by Jeff Robbins (jjeff) though recent releases are by João Ventura (jcnventura) of Portugal
- Versions available: 8.x-1.0-beta4 which supports Drupal 9.3, 10, and 11
- Maintainership
- Minimally maintained, maintenance fixes only. Also, the project page says that the 8.x branch is not ready for production use. So a big caveat emptor if you decide to try it
- Number of open issues: 18 open issues, 5 of which are bugs against the current branch
- Usage stats:
- 730 sites
- Module features and usage
- With the ShURLly module installed, you can specify a long URL you want shortened, optionally also providing a case-sensitive short URL you want to use. If none is provided a short URL will be automatically generated
- The module provides usage data for the short URLs, and and a user you can see a list the ones you’ve created as well as their click data
- I was a little surprised to see that created short URLs are stored in a custom db table instead of as entities, but the module is able to avoid a full bootstrap of Drupal before issuing the intended redirects
- The module provides blocks for creating short URLs, a bookmarklet to save a short URL, and URL history. There is also Views integration for listing the short URLs, by user or in whatever way will be useful in your site
- There is also a submodule to provide web services for generating short URLs, or potentially expand a short URL back into its long form. The services support output as text, JSON, JSONP, XML, or PHP serialized array
- The module allows provides a variety of permissions to allow fine-grained access to the capabilities it provides, and also has features like per-role rate limiting, APIs to alter redirection logic, and support for the Google Safe Browsing API, and Google Analytics
- It’s worth mentioned that ShURLy is intended to run in a site on its own instead of within a Drupal site that is also serving content directly, but it will attempt to avoid collisions with existing site paths
- Today’s guest, James, is one of the maintainers of ShURLy, but Nic, you mentioned before the show that you have a customer using this module. What can you tell us about the customer’s use case and your experience working with ShURLy?
Freelock Blog: Use Drupal Flake for PHPUnit testing
Drupal Flake is a new way of doing local Drupal development (running a self-contained Drupal site on your desktop or laptop).
Dev Corner Read MoreFreelock Blog: Use Group Purl on your Group site!
One big missing part of the Group module is setting up friendly URLs that contain the group in the path for group content. You can't set this up in Pathauto -- the tokens are too limited to handle this correctly.
Dev Corner Read MoreFreelock Blog: Easy unit testing with Drupal Flake and AI - Group PURL, a case study
AI does not replace system engineering. Stories abound about AI running amok, deleting production databases, exposing private data, failing to deliver on promises.
Dev Corner Read MoreComputerMinds.co.uk: Rendering plugin blocks the right way
On a recent client website, I needed to programmatically load and render 3 blocks. Plugin blocks to be precise. In modern Drupal, there are 3 types of block you can load/render:
- Content blocks
- Config blocks
- Plugin blocks
And today we're interested in plugin blocks.
Plugin blocks are blocks defined by the block plugin API in Drupal. They typically extend the BlockBase class and reside in a modules src/plugin/Block directory.
Now, with that in mind, I hadn't done this sort of block load/rendering/creating for quite some time so I was kinda lost! I needed to load 2 views blocks and 1 webform block. After a little while of scratching my head, it occured to me that I need to look into the src/plugin/Block directory of the views/webform module to work what I needed. Initially I was struggling with the plugin_id value of the createInstance method on the plugin.manager.block service.
Step 1Looking at the plugin definition of each block type I was able to finally workout the ID needed to get an instance of each block. For views, it was views_block:<view_machine_name>-<view_display>. This was particularly tricky because the plugin definition doesn't actually tell you what the exact plugin id is. Sure, it gives you the first part e.g. views_block and for most plugin blocks that would have sufficed. But not with Views. During debugging, I noticed that I wasn't getting anything back from ->createInstance('views_block') so I had to go hunting for what wasn't working. Turns out the ID is made up in the pattern I outlined above. I found this via the deriver class within ViewsBlock (the plugin's class) and found these lines of code:
// Add a block plugin definition for each block display. if (isset($display) && !empty($display->definition['uses_hook_block'])) { $delta = $view->id() . '-' . $display->display['id'];It was then I knew the makeup of the plugin_id. I said it before, it's tricky and this was fairly well hidden. Nowhere is this documented!
The webform ID is thankfully quite different, it was just webform_block but required making use of the second parameter of createInstance(): $configuration. This is an array of information/settings that you can configure manually in the blocks UI. In this case, webform wanted me to pass in a webform_id key with the ID of the webform I wanted in the block. Again I found this via debugging the class for the plugin Drupal\webform\Plugin\Block and saw the webform_id key inside the defaultConfiguration() method.
You can already see the difficulty here: no two plugin block definitions are the same. Views was quite happy for me to pass in the view I wanted in the $plugin_id parameter, whereas webform wanted the webform I wanted to use to be passed into the createInstance() method via the $configuration parameter.
Step 2Really easy step this, once you've sorted out your plugin_id and you're happy that you get something back that resembles what you would expect, you now need to call ->build() on your new block instance. Don't worry, a full example will be shown below.
Step 3Now that you've (hopefully) got a render array of your block, you can now add some of the configurations you would expect to see if you were placing a block in the UI (/admin/structure/block). E.g. you can set the block level config like the label (via #configuration), the ID of the block, attributes etc plus other block_plugin related configuration.
Step 4Render your block, simples! Assign your block to the $variables array (if you're in a preprocess for example) and then print your block out in a twig template. Done :)
<div>{{ my_plugin_block }}</div>Code examples // A webform block example $configuration = [ 'label' => 'Contact us', 'label_display' => BlockPluginInterface::BLOCK_LABEL_VISIBLE, 'webform_id' => 'contact_us', 'provider' => 'webform', ]; $contact_form_instance = $plugin_block_manager->createInstance('webform_block', $configuration); $contact_form_render['content'] = $contact_form_instance->build(); $contact_form_render += [ '#theme' => 'block', '#id' => 'block-webform-contact-us', '#attributes' => [], '#contextual_links' => [], '#configuration' => $configuration, '#plugin_id' => $contact_form_instance->getPluginId(), '#base_plugin_id' => $contact_form_instance->getBaseId(), '#derivative_plugin_id' => $contact_form_instance->getDerivativeId(), ]; $variables['contact_form_block'] = $contact_form_render;// A view block example $related_posts_block_instance = $plugin_block_manager->createInstance('views_block:blog-related_blog_posts'); $related_posts_block_instance['content'] = $related_posts_block_instance->build(); $related_posts_block_instance += [ '#theme' => 'block', '#id' => 'block-blog-releated-blog-posts', '#attributes' => [], '#contextual_links' => [], '#configuration' => ['provider' => 'views_block'], '#plugin_id' => $related_posts_block_instance->getPluginId(), '#base_plugin_id' => $related_posts_block_instance->getBaseId(), '#derivative_plugin_id' => $related_posts_block_instance->getDerivativeId(), ]; $variables['related_posts_block'] = $related_posts_block_instance; Tips and tricks- If you're still strugging to work out what your plugin_id should be, you can run this handy drush command to get a list of definitions:
2. After a quick win? You can make use of the twig tweak module to produce a 1 liner to render out a plugin block. See this article on how to do it.
GotchasAs with anything these days, not all is as it seems.... there are a few things you should be aware of when loading/rendering blocks like this:
- Some hooks won't fire with plugin blocks that are loaded in the way outlined in this article. Blocks like (and not limited to) hook_block_view() and hook_block_build_alter() won't run for these types of blocks. And they're really common hooks, too! So just be mindful. If you're in a hook and it's not running when you expect it to (for a plugin block you've loaded) this is likely the reason why.
- Be careful with access. Some blocks may have their own access checks and this method of loading can bypass those - whenever loading blocks like this just double check you're correctly following - or reimplementing - the access that was originally intended with that blocks.
- Views blocks might lose the context that was originally intended for them. Contexts such as arguments etc may need to be re-set so the block can function properly.
- The same goes for caching. You may need to re-implement the caching that was originally set for the block you've loaded. it should be as simple as using the following code snippet:
The Drop Times: The Server Renders Again
HTMX in Drupal shifts the conversation from big architectural battles to something more practical: making the most of HTML sent directly from the server. Drupal already brings strengths like flexible content modeling, caching, and structured views. HTMX builds on that by letting site builders add interactivity with simple HTML attributes, rather than heavy front-end frameworks. As Ron Northcutt notes, the result is efficiency: the server does the work once, the response can be cached, and users get faster pages that are easier to manage. For editors, the payoff is immediate. A content preview can be swapped in with a click, a list item can update in place, and new dynamic features can be built without ever leaving the CMS. Fewer scripts in the browser also means better accessibility and less complexity for smaller teams.
Still, this is not a silver bullet. When HTML becomes the main way to deliver updates, teams must treat it carefully, just as they would an API. Without good standards, the code can get messy. Not every feature can rely on server-rendered HTML either. Personalized content, offline use, or real-time updates may still require more traditional JavaScript solutions. And while HTMX can live comfortably alongside Drupal’s existing systems, it takes planning to avoid conflicts and keep things smooth.
The real value is in balance. Ron’s efficiency argument rings true if developers approach HTMX with a server-first mindset and a focus on performance. But the bigger conversation is about knowing where to use it. HTMX in Drupal is ideal for enhancing editorial workflows and everyday site interactions, while leaving room for more advanced front-end approaches when they are truly needed. If teams treat this as a disciplined practice instead of a passing trend, Drupal can unlock new levels of speed and simplicity without losing its flexibility.
DISCOVER DRUPAL- New Way of Writing Hooks in Drupal 11 Explained
- Unmanaged Files in Drupal: Building a Random File Handler (Part 2)
- Drupal AI Initiative Calls for Use Cases from Agencies, Developers, and End Users
- Vivek P R Releases “Views Node Title Selector” Drupal Module for Easier Node Title Filtering
- Kubernetes Platform Built in 6 Days Leads to New Drupal Kafka Module
- Glenn Hilton Prepares to Join Drupal Association Board of Directors
- London Drupal Users Group Relaunches with Hybrid Meetup on September 24
- Drupal Business Dinner in Vienna Set for October 15, 2025 Ahead of DrupalCon
- Early Bird Registration Opens for DrupalCon Chicago 2026 at $575
- DrupalFit Challenge Vienna Edition Opens Ahead of DrupalCon 2025
- Acquia and Drupal Association to Host Live Session on Advanced Drupal Canvas Capabilities
- Early-bird Sponsorship Opens for DrupalCamp Italy 2025; Confirm by Sept. 29
- Droptica Releases Open Intranet 1.5.0 with Drupal 11.2 Upgrade and Gin 5 Theme
- Pantheon Releases Public Preview of Google Docs-Based Content Publisher With Free Trial
We acknowledge that there are more stories to share. However, due to selection constraints, we must pause further exploration for now. To get timely updates, follow us on LinkedIn, Twitter, Bluesky, and Facebook. You can also join us on Drupal Slack at #thedroptimes.
Thank you.
Sincerely,
Alka Elizabeth,
Sub-editor, The DropTimes.
Drupal Association blog: Meet Dominique De Cooman and his vision for open digital experiences
We’re thrilled to introduce Dominique De Cooman, one of the newest members elected to the Drupal Association Board, with his term beginning 1 November 2025.
Dominique is the co-founder, CTO, and co-CEO of Dropsolid, where for more than a decade he has been a driving force behind the company’s vision and growth. His work has focused on digital transformation, open digital experiences, and more recently AI transformation, helping companies, organisations, and governments stay innovative and sovereign in a fast-changing world.
In addition to leading Dropsolid, Dominique has been an active contributor to the open source community. He serves as a Mautic Council member, is involved in the Drupal AI initiative, and advocates for open DXP by bringing together Drupal, Mautic, and emerging AI frameworks. His passion for entrepreneurship, sales, and marketing is matched by his background as a developer and solution architect, which allows him to bridge the business and technical sides of the community.
We are thrilled to have Dominique bring this perspective to the Board. Here are his thoughts as he begins this new chapter:
What are you most excited about when it comes to joining the Drupal Association Board?
Being part of something greater like Drupal is exciting, especially in times like these with AI transforming everything. It is a challenging but impactful time to be part of the Board. Guiding Drupal into the AI age is a massive opportunity.
What do you hope to accomplish during your time on the board?
I would like to contribute in:
- Trying new things like the Drupal AI funding initiative, finding new ways to promote and fund open source and Drupal.
- Helping Drupal and its business ecosystem transition through the great agency unbundling.
- Building bridges with other open source ecosystems, because together we are stronger.
What specific skill or perspective do you contribute to the board?
As the owner of both a Drupal services company and a platform company, I bring a unique perspective on the market. I understand the dynamics in SME and enterprise markets where Drupal is strong. As an entrepreneur, I also bring a try, fail, retry attitude rather than over-analysing and getting stuck. Sometimes you just have to try something new or out of the box. Concerning skills, I am strong in sales, marketing, funding and have a background as a developer and solution architect, so I can relate to both the business and the tech part of the community.
How has Drupal impacted your life or career?
It is my career. And in life, the ability to contribute through daily work has been a continuous source of energy that created many opportunities for myself and others.
Tell us something that the Drupal community might not know about you.
I have been skateboarding since I was 6 years old, it helped me learn to try, fail, retry. I am also a practicing Buddhist and this has helped me to try, fail, retry in another way.
Share a favorite quote or piece of advice that has inspired you.
The only thing that you need to know is the knowing itself.
We look forward to the contributions Dominique will make during his time on the Drupal Association Board. Thank you, Dominique, for sharing your time and expertise with the Drupal community. You can connect with Dominique on LinkedIn.
About the Drupal Association Board of DirectorsThe Drupal Association Board of Directors comprises 13 members with nine nominated for staggered three-year terms, two elected by Drupal Association members, and one seat is reserved for the Drupal Project Founder, Dries Buytaert. One seat is reserved for the immediate past chair as a non-voting member. All Board terms start on 1 November of each year.
The Board meets twice in person for weekend retreat and about 5 times virtually each year. The Board provides strategic guidance to the Drupal Association and oversight of the Association’s management, policy development, management, budget, and fundraising efforts.
Drupal AI Initiative: Drupal AI Development Progress Week 36-37
The last two weeks have had a huge focus on getting the providers into the new 1.2.0 structure, beta blockers done and manipulating the AI Agents system so it handles specific cases that we see happen when we are working on the Canvas AI module.
Progress Service for AgentsWhen setting up a user interface for agents, complex agents can take several minutes to load. If users are shown only a loading spinner during this time, many will assume the system has failed and abandon the page.
Another challenge arises during development, when we need to debug the agent’s behaviour. A useful debug tool should be able to display the agent’s progress, which tools it has used, the contexts it has added, and other relevant details.
A third use case is that you might want to log the progress of the agent, so that you can see what it did, and if something went wrong, you can figure out what happened.
We have a progress service for this, that makes it possible!
The Progress Service can give you very granular and optional information about what a specific agent is up to, while it's running. This means that in your user interface, you can give back information on what the agent is doing, has done and is planning to do.
OpenAI can now read PDF’sIf you use the OpenAI provider, it has had the capability to read PDF files for some time, however a Drupal solution has been missing.
If you use the latest 1.2.x version with AI 1.2.x, you can now upload a PDF in the Chat Explorer or your custom code, to use a PDF as context for your specific task.
Agents can give back structured outputWhen setting up an agent, you can also configure it to return a structured JSON output once it has completed its context gathering, reasoning, modifications, or other processing steps.
This means that if you invoke a custom agent, you can rely on receiving its response in a predictable, structured format.
In the UI of the Agents a form has been added where you can provide a json-schema of the output that you want.
Chat History Form Element addedWe have multiple debug and testing modules that require replicating a chat history, capturing the full sequence of actions an agent takes, or the complete conversation history. Examples include the AI API Explorer, AI Agents Test, and AI Agents Explorer. Potential future use cases could include ECA. Currently, each module implements this functionality independently.
To address this, we have created a reusable form element. Instead of rewriting the same logic for every module, you can now set up and manage chat histories with a single line of code, providing a standardised and reusable way to replicate and manipulate interaction histories across all relevant modules.
Pexels Tools - create new media via ChatYou might have already started building agents that can search your local media library using semantic search. This is really cool, but what happens when you simply do not have an image that fits what you are looking for?
The Pexel AI module offers the function calls that gives you the ability to search and create media entities from the popular royalty free stock photo database Pexels.
This means that you can ask for an image from your local database, but when the Chatbot doesn’t find anything you could follow up with an “Could you please search if Pexels has some images for this?” and it will give you back suggestions that you can then follow up by saying that you want to download.
Tool calling is now available with streamingOne issue with streaming an output, is that once your website starts responding, you do not really know what you are going to get. It could be a textual message, but it could also be a decision to use a tool.
The agent's logic relies heavily on knowing whether a tool is being used, in order to determine if it should continue looping. However, we cannot wait for the entire message to stream before sending it to the end user, that defeats the purpose.
We have now added the ability for any code that starts an agent to include callbacks, which are triggered once streaming is complete. That way it will know if it should keep the connection alive for streaming out more content or finish the output buffer.
Other notable fixes:- Chatbot first message is now translatable
- Common method for suggestions in Field Widget Actions
- Simplified the code for events
- AI core drush command supports copy, paste and multiline
- Override the description of tools to give your specific agent better reliability for a specific use case
The Drop Times: How Drupal Plans to Beat Commercial CMS Platforms with AI-First Approach
1xINTERNET blog: Preparing your website for the future of AI search with llms.txt
AI search is evolving fast. Learn how to boost your website's visibility in AI search and stay competitive.
The Accidental Coder: Unmanaged Files - Part 2
The Drop Times: Unmanaged Files in Drupal: Building a Random File Handler (Part 2)
Pivale: Drupal SDC Single Directory Components vs Storybook: a component library showdown
The Accidental Coder: Unmanaged Files - Part 1
Dripyard Premium Drupal Themes: The challenge of building premium Drupal themes with zero dependencies
When we started building Dripyard themes, we made the decision early on to not have any dependencies outside of Drupal core. We wanted to avoid depending on contributed modules, npm build processes, and external libraries so that our premium Drupal themes could adapt to any development workflow. Additionally, we wanted to prevent having our own companion module required for Dripyard themes so we can offer a complete package you can download, drop in, and enable.
In this article, we explore the hurdles we faced along the way and how we dealt with them.
Metadrop: Aljibe: quality and testing for Drupal developments with DDEV
Aljibe is a DDEV add-on that provides tools and a curated base for developing Drupal projects. It's what we use at Metadrop as the foundation for every project. Although it's tailored to our needs, making it opinionated, it follows the Drupal way, and we think it can be useful for many other developers and teams.
It's built as a set of DDEV add-ons, with Aljibe being the main one. Many of the tools it offers are provided by a DDEV add-on that can be used alone if you don't want to use Aljibe. Check the plug-ins we provide in our our DDEV Add-on Registry.
Additionally, Aljibe uses Metadrop/drupal-dev to declare the dependencies of all the tools it provides. It is jut a Composer package, not a DDV add-on. You can use it directly, if you wish, or gather inspiration from it to create your own project base stack.
The main goal of Aljibe, aside from speeding up project kick-offs, is to provide a solid base with lots of QA tools for high-quality projects. That's the real Aljibe focus: quality.
Among the tools it provides, you'll find Behat, BackstopJS, PHPStan, …
Nonprofit Drupal posts: September Drupal for Nonprofits Chat
Join us THURSDAY, September 18 at 1pm ET / 10am PT, for our regularly scheduled call to chat about all things Drupal and nonprofits.(Convert to your local time zone.)
We don't have anything specific on the agenda this month, so we'll have plenty of time to discuss anything that's on our minds at the intersection of Drupal and nonprofits. Got something specific you want to talk about? Feel free to share ahead of time in our collaborative Google document!
All nonprofit Drupal devs and users, regardless of experience level, are always welcome on this call.
This free call is sponsored by NTEN.org and open to everyone.
Information on joining the meeting can be found in our collaborative Google document.
Security public service announcements: Third-Party Libraries and Supply Chains - PSA-2025-09-17
NPM packages have been targeted in maintainer account takeover attacks. Attackers have deployed an automatic credential scanning tool. The scanning tool tries to find secret keys that may have been published to public systems like build automation and continuous integration (CI) systems and sends such credentials back to the attacker. From there, the vulnerable NPM packages are downloaded, modified to insert a trojan-like script bundle, and then republished. These maliciously modified packages can then be used to exploit any application that has installed these packages.
Coverage and advice on remediation:
- The Hacker News - 40 NPM Packages Compromised
- Socket.dev - Supply Chain Attack
- Aikido - S1ngularity/nx attackers strike again
- Aikido - npm debug and chalk packages compromised
- Wiz.io - Shai-Halud npm supply chain attack
While this attack has targeted NPM packages, the same strategy could be used to exploit other packages as well.
Managing supply-chain securityWebsite owners should actively manage their dependencies, potentially leveraging a Software Bill of Materials (SBOM) or scanner services. Other relevant tools include CSP and SRI.
It is the policy of the Drupal Security Team that site owners are responsible for monitoring and maintaining the security of third-party libraries and any non-Drupal components of the stack. In rare cases, the Drupal Security Team will post an informational public service announcement (PSA) such as this one, but the remit of the Drupal Security Team remains limited to code hosted on Drupal.org’s systems. Previous PSAs on third-party code in the Drupal ecosystem include:
- External libraries and plugins - PSA-2011-002
- Various Third-Party Vulnerabilities - PSA-2019-09-04
- Third-Party Libraries and Supply Chains - PSA-2024-06-26
Drupal's infrastructure maintainers, the Drupal Security Team, and Drupal core maintainers have received tips about this situation from several sources. Individuals in those groups have evaluated their exposure and we believe the Drupal project itself is not affected by this issue. If you have information about concerns that Drupal is affected please reach out to us.
This post is likely to be be updated as the situation evolves and more information is available.
Reported By: Coordinated By:- Greg Knaddison (greggles) of the Drupal Security Team
- Tim Hestenes Lehnen (hestenet)
- Dave Long (longwave) of the Drupal Security Team
- Drew Webber (mcdruid) of the Drupal Security Team
- Jess (xjm) of the Drupal Security Team
- cilefen of the Drupal Security Team
jofitz: How to add a Composer package from a GitHub repository
Sometimes you want to add a Composer package that is not available through drupal.org or Asset Packagist. This article shows you how to add a package directly from its version control repository.
Read morePages
