Planet Drupal
Peoples Blog: Usage of PHPCS on Github via Pull Request for Drupal Applications
Peoples Blog: Store Secrets Securely on Pantheon for Drupal Application
mark.ie: Cloning Content in a LocalGov Drupal website
This week as part of my "Editor Experience" work for LocalGov Drupal, I worked on creating a feature to allow editors to clone pages of their sites.
Annertech: DrupalCon Barcelona: Our highlights
DrupalCon Barcelona 2024 was one of our busiest yet. We were a platinum sponsor, sponsored the contribution room, had numerous social activities (including Trivia Night), and Annertechies took to the mic at least seven times.
CTI Digital: Drupal CMS: A New Era for Non-Technical Users
Drupal CMS (formerly known as Drupal Starshot) is set to revolutionise how non-technical users engage with Drupal, enabling them to get started with just a few clicks. From installing Drupal directly in the browser to swiftly selecting Recipes that tailor the site to their specific needs, along with utilising AI-driven site-building tools, Drupal CMS is transforming the introduction of non-developers to the platform.
Unsurprisingly, Drupal CMS was a hot topic at DrupalCon, where an entire track of talks was dedicated to the various initiatives that constitute one of the most ambitious changes in Drupal's history. Dries Buytaert, the co-founder of Drupal and an influential leader in the open-source community, provided invaluable insights in his keynote presentation, showcasing the latest enhancements in Drupal CMS.
1xINTERNET blog: 1xINTERNET at DrupalCon Barcelona 2024
This year, DrupalCon took place in Barcelona, and we were proud to be Platinum Sponsors. DrupalCon is a vibrant celebration of the Drupal community, bringing together developers, designers, marketers, and business leaders to share ideas, collaborate and innovate. This year we thoroughly enjoyed connecting with other Drupal users and makers.
Droptica: Drupal 7 to the latest version migration – Droptica’s top recommended enhancements
Upgrading from Drupal 7 to the latest version opens up a range of benefits, allowing you to leverage a modern CMS. By enhancing areas like content structure, SEO, and security during migration, you can maximize the impact of your investment. But, without Drupal expertise, deciding what to change and improve can be overwhelming during the migration process. Our free checklist, built on Droptica’s experience with clients, helps you explore common migration improvements and decide which ones fit your needs.
Capellic: Migrating critical keys from Lockr to Pantheon Secrets
Drupal Core News: Coding standards proposals for final discussion on 23 October 2024
The Technical Working Group (TWG) is announcing one coding standards change for final discussion. Feedback will be reviewed at the meeting scheduled for 23 October 2024 UTC.
Issues for discussionThe Coding Standards project page outlines the process for changing Drupal coding standards.
Join the team working on Coding StandardsJoin #coding-standards in Drupal Slack to meet and work with others on improving the Drupal coding standards. We work on improving our standards as well as implementing them in the core software.
Smartbees: How to Add Google Maps in Drupal (Best Modules)
Maps on websites are a useful addition, allowing users to reach, for example, your company headquarters in a simple way. Depending on the requirements, you can implement them in many different ways. This article will show you how to embed Google Maps in a Drupal website.
Talking Drupal: Talking Drupal #470 - Creating Recipes
Today we are talking about Creating Recipes, What Recipes already exist, and helpful tips and tricks with guest Jim Birch. We’ll also cover Features as our module of the week.
For show notes visit: https://www.talkingDrupal.com/470
Topics- What are recipes
- How do you recommend someone get started writing recipes
- Where can people find recipes
- Can you include sub recipes
- How should you test recipes
- Any tools that make writing recipes easier
- What recipes are needed that do not exist
- How can people move recipes forward
- Recipe Author Guide
- Drupal Core Recipes
- Preconditions for recipes
- Drupal Recipes Cookbook
- Recipes Packagist
- Recipe type
- Phase 2 roadmap
- Umami profile recipes
- Minimal profile recipes
Jim Birch - linkedin.com/in/jimbirch thejimbirch
HostsNic Laflin - nLighteneddevelopment.com nicxvan John Picozzi - epam.com johnpicozzi Aubrey Sambor - star-shaped.org starshaped
MOTW CorrespondentMartin Anderson-Clutz - mandclu.com mandclu
- Brief description:
- Have you ever wanted an admin UI to manage sets of configuration, to version and share across Drupal sites? There’s a module for that.
- Module name/project name:
- Brief history
- How old: created in Mar 2009 by yhahn, though recent releases are by Dave Reid
- Versions available: 7.x-2.15 and 8.x-3.14, the latter of which works with Drupal 9.4 and 10
- Maintainership
- Minimally maintained
- Security coverage
- Test coverage
- Documentation: Has a documentation guide and probably hundreds if not thousands of of tutorials available
- Number of open issues: 610 open issues, 54 of which are bugs against the 8.x branch
- Usage stats:
- Almost 117,000 sites, though the majority are using the D7 version
- Module features and usage
- Many listeners will remember Features as the de facto solution for configuration management in Drupal 7 and earlier
- As the name implies, it was really intended to share common capabilities across different Drupal sites
- Unlike recipes, Features can have version numbers, because there is a path to sync configuration updates across sites using a Feature, though this is where a lot of teams found Features could be complex to use
- We did previously cover Features as MOTW all the way back in episode #147, but I thought it was relevant to today’s discussion because of the way it provides a UI for organizing and exporting specific sets of configuration
- There is an open issue for Features to directly export recipes, because it already does a lot of the time-consuming work of collecting together necessary config files, including dependencies
- Even its current state, it could be a time saver for anyone wanting to start creating their own recipes
Twin Cities Drupal Camp: After Camp: Stay connected with our Mid-Day Meetup
We're restarting our Mid-Day Meetup: a remote-only meetup we have over Zoom. You can RSVP to attend.
https://groups.drupal.org/node/537103
We'll be talking about the knowledge shared at the recent Twin Cities Drupal Camp and Drupalcon Barcelona. We're also trying to expand the reach of our Mid-Day meetup beyond our regional meetup and welcome everybody into our remote hour of Drupal chatter.
Agenda- 15m - Meet and Greet
- 30m - Discuss new stuff going on in Drupal / Drupalcon Barcelona's "Mother of all Demos"
- 15m - cosmicdreams is hoping to do a demo of adapting an existing component library system to Single Directory Components (SDC).
Help us spread the word of these Mid-Day meetups by sharing this with your coworkers.
Posted In Drupal Planet
Wim Leers: XB week 20: 0.1.0-alpha during DrupalCon!
DrupalCon week! On Monday, we landed the last issue to achieve the 0.1 milestone: The XB annotations and labels should not change size when zooming — thanks Utkarsh “utkarsh_33”, Atul “soaratul” Dubey and Bálint “balintbrews” Kléri for guiding it across the finish line!
That was the only noteworthy commit of the week, because of Acquia’s team working full-time on Experience Builder (XB), Ben “bnjmnm” Mullins, Jesse “jessebaker” Baker, Lauri “lauriii” Timmanee and Bálint (he helped us achieve 0.1 on Monday and traveled on Tuesday!) were attending DrupalCon. Also at DrupalCon was Dave “longwave” Long, who we’re sponsoring part time.
So it was with a lot of satisfaction that I tagged the 0.1.0-alpha1 release on the morning of the DriesNote :)
Not at DrupalCon: research modeWith roughly half of the team at DrupalCon this week, and with 0.1.0 done, the rest of us pivoted to preparing for the next milestone: 0.2.0. Many technical details need to be figured out for the next batch of product requirements that Lauri prioritized (together with Alex “effulgentsia” Bronstein).
We started research on:
- #3475672: auto-saving, drafts, and all possible ways to achieve that, led by Ted “tedbow” Bowman and with the much-needed help of both Travis “traviscarden” Carden and Dave
- #3475363: in-UI (JS) component creation Proof-of-Concept using StackBlitz by Harumi “hooroomoo” Jang and (newly joined!) Xinran “xinran” Cao, led by Alex
- #3475584: blocks-as-XB-components, led by Feliksas “f.mazeikis” Mazeikis and with the help of Dave and I, while reusing and building on top of the work that Lee “larowlan” Rowlands did ~2 months ago
- #3446434: Document “Semi-Coupled Theme Engine” and “Redux-integrated Field Widgets” components, kickstarted by me, because we proved this can work but now it’s time to mature this; this will be led by Ben, with again input from Dave 1
During DrupalCon, Lauri, Ted, Alex, I met with with core committers Alex Pott, catch and Dave met to discuss XB’s JSON-based data storage model that XB currently implements. We’re not yet fully aligned (catch pointed out the search index aspect is important to support — the question is how to support that without compromising the UX Lauri envisions), but the discussion is much clearer today than it was in June, because there’s now concrete code to point to. That removed a lot of confusion on both “sides” (we’re all on the same side: we want the brightest future for Drupal!).
The meeting we had during DrupalCon led to:
- Alex Bronstein identifying a possible alternative implementation that would meet both the original goals, and address most concerns: #3477428: Refactor the XB field type to be multi-valued, to de-jsonify the tree, and to reference the field_union type of the prop values.
- Me unpostponing the #3467870: Support {type: array, …} prop shapes issue and pushing it forward. First making this work would help prevent #3477428 (see prior point) going in a direction that would make it impossible to support type: array Single Directory Component (SDC) props, which should be represented by multi-value fields (fields configured for multiple cardinality). I made the back-end pieces work during DrupalCon, but to make it work end-to-end additional infrastructure on the client side is needed first. For that: see the last “research” bullet above.
Missed a prior week? See all posts tagged Experience Builder.
Goal: make it possible to follow high-level progress by reading ~5 minutes/week. I hope this empowers more people to contribute when their unique skills can best be put to use!
For more detail, join the #experience-builder Slack channel. Check out the pinned items at the top!
Presentations at DrupalConOf course, Dries included and demonstrated Experience Builder 0.1.0 during the DriesNote:
The XB section of the DriesNote starts at 50:44.
Lauri talked about what’s been happening with XB and what will happen next:
Many of the things Lauri shared with all of you had only been seen by Lauri, not by anybody else! :D
After his session, Lauri had many hallway conversations that increased our conviction that we’re on the right track with XB! :)
And in my humble opinion the most inspiring — Ben’s session about how XB uses parts of the JSX theme engine and Redux:
Ben walks you through how XB leverages React and Redux to achieve the UX we need, while using existing Drupal field widgets. This will become even more important once we integrate the content entity form, with field widgets for base and bundle fields.
You have to watch the 20 seconds starting at 1:37 — pure genius: not the predictable AI-generated images to illustrate his talk, instead … his son’s drawings! :D
I hope to follow in his footsteps at a future DrupalCon, because I too am becoming a dad, very soon! :D I’ll be working at a very reduced rate during my paternity leave, but will be keeping these weekly blog posts going — it’s my way of keeping myself in the loop as well as all of you. That is also why I’ve shifted attention to meta things, to ensure the right expertise is present in areas that need to keep moving during my upcoming paternity leave :)
Week 20 was September 23–29, 2024.
-
We’re asking Dave to weigh in on a number of areas, to point his critical, independent core committer eye to key decisions early on. ↩︎
ImageX: Integrate Zoom Meetings Seamlessly into Your Drupal Website via Our Developer’s Module
Authored by: Nadiia Nykolaichuk and Leonid Bogdanovych.
Zoom is a key player in the sphere of online meetings. They have the power to dissolve geographical barriers, uniting individuals and teams across vast distances for communication and collaboration. What can be more convenient than using a robust video conferencing platform? Using it in the comfort of your own Drupal website!
Promet Source: DUSWDS: Your Agency's USWDS-Aligned CMS Solution
Golems GABB: Drupal integrations with Popular Cloud Services: AWS vs MS Azure vs GCP
Welcome to the world of cloud integration, where popular cloud services such as AWS, Azure, and GCP are the keys to a Drupal site's success.
Imagine that you've finished your Drupal website. It turned out fantastic, but the basic options are not enough for you. So you can't wait to unleash its full potential. This is where cloud services come into play. They are your site's superhero assistants.
Today, our Drupal team plans to look at the benefits of these cloud services and how AWS, Azure, and GCP can take your Drupal website to a new performance, scalability, and security. Get ready to revolutionize your online presence and, of course, leave your competitors behind.
ImageX: Under the Barcelona Sun: A Recap of Our Team’s Journey at DrupalCon Europe 2024
Authored by Nadiia Nykolaichuk.
mark.ie: My LocalGov Drupal contributions for week-ending October 4th, 2024
This week, I spent my time mostly looking at issues tagged with "Editor Experience".
Tag1 Consulting: Migrating Your Data from D7 to D10: Migrating field formatter settings
If you have been following our series, you have already migrated view modes—a prerequisite for field formatters. 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.
Read more mauricio Thu, 10/03/2024 - 04:01PreviousNext: Entity theming with Pinto
Learn how to make entity theming a breeze using the Pinto module. If you haven’t already, check out the first part of this series for an introduction to all things Pinto.
by adam.bramley / 3 October 2024In our last post, we discussed Pinto concepts and how to use Theme objects to encapsulate theming logic in a central place for a component. Next, we’ll apply that knowledge to theming an entity. This will demonstrate the power of Pinto and how it will dramatically improve the velocity of delivering new components.
One of the hardest things about theming Drupal is outputting markup that matches your design system.
For example:
- Removing the “div soup” of Drupal fields
- Adding custom classes or attributes to field output
- Wrapping fields in custom tags (e.g. an h2)
While there are plenty of modules to alleviate this, it can often mean you have a mix of YAML configuration for markup, preprocess hooks, overridden templates, etc., to pull everything together. Pinto allows you to easily render an entity while reusing your frontender’s perfect template!
We need to cover a few more concepts and set things up to pull this all together. Once set up, new bundles or entity types can be added with ease.
We'll continue our Card component example from the previous post and cover:
- Setting up a bundle class. In this example, we will implement it as a Block Content bundle
- Using a custom entity view builder
- Theming a Card block using Pinto
In case you’re not aware, Drupal introduced the concept of Bundle classes almost three years ago. They essentially allow business logic for each bundle to be encapsulated in its own PHP class and benefit from regular PHP concepts such as code sharing via Traits, Interfaces, etc.
At PreviousNext, our go-to for implementing bundle classes is the BCA module, which allows you to define a class as a custom Bundle class via an attribute, removing the need for hook_entity_bundle_info_alter.
Our standard setup on projects is:
- An Interface per entity type (e.g MyProjectBlockContentInterface)
- An abstract base class per entity type (e.g. MyProjectBlockContentBase)
- A Bundle class per bundle
- Traits and interfaces for any shared fields/logic (e.g. BodyTrait for all bundles that have a Body field)
My preferred approach is to have a directory structure that matches the entity type located inside the project’s profile (e.g. src/Entity/BlockContent/Card.php. Feel free to set this up however you like. For example, some people may prefer to separate entity types into different modules.
Let’s set up our Card bundle class:
namespace Drupal\my_project_profile\Entity\BlockContent; use Drupal\bca\Attribute\Bundle; use Drupal\my_project_profile\Traits\DescriptionTrait; use Drupal\my_project_profile\Traits\ImageTrait; use Drupal\my_project_profile\Traits\TitleTrait; #[Bundle(entityType: self::ENTITY_TYPE_ID, bundle: self::BUNDLE)] final class Card extends MyProjectBlockContentBase { use TitleTrait; use DescriptionTrait; use ImageTrait; public const string BUNDLE = 'card'; }Here we use the Bundle attribute provided by the BCA module to automatically register this class as the bundle class for the card bundle. We’re using constants here to make it easy to reference this machine name anywhere in our codebase. The ENTITY_TYPE_ID constant comes from the parent interface.
NOTE: I won’t go into too much detail about how the interfaces, base classes, and traits are set up. There are plenty of examples of how you might write these. Check out the change record for some basic examples!
In our case, each trait is a getter/setter pair for each of our fields required to build our Card component:
- Title - a plain text field
- Description - another plain text field
- Image - a Media reference field.
EntityViewBuilders are PHP classes that contain logic on how to build (or render) an entity. Entity types can have custom EntityViewBuilders; for example BlockContent has its own defined in core. These are defined in the view_builder handler in an entity type's annotation and can also be overridden by using hook_entity_type_alter.
By default, the view builder class takes all of your configuration in an entity view display (i.e. field formatter settings, view modes, etc.) and renders it. We are using a custom view builder class to bypass all of that and simply return a render array via a Pinto object.
The function that drives this is getBuildDefaults so that’s all we need to override.
For this example, a custom view builder for the block content entity type can be as simple as:
namespace Drupal\my_project_profile\Handler; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Entity\EntityInterface; use Drupal\block_content\BlockContentViewBuilder; use Drupal\my_project_profile\Entity\Interface\BuildableEntityInterface; class MyProjectBlockContentViewBuilder extends BlockContentViewBuilder { /** * {@inheritdoc} */ public function getBuildDefaults(EntityInterface $entity, $view_mode) { $build = parent::getBuildDefaults($entity, $view_mode); if (!$entity instanceof BuildableEntityInterface || !$entity->shouldBuild($view_mode)) { return $build; } $cache = CacheableMetadata::createFromRenderArray($build); $build = $entity->build($view_mode); $cache->merge(CacheableMetadata::createFromRenderArray($build)) ->applyTo($build); return $build; } }Here, we check for a custom BuildableEntityInterface and call a shouldBuild method. If either of those are FALSE then we fall back to Drupal’s default behaviour. Otherwise, we gather cacheable metadata from both the default build and the result of calling the build method, and then return the output. We will cover these in more detail shortly.
Now we just need an alter hook to wire things up:
use Drupal\my_project_profile\Handler\MyProjectBlockContentViewBuilder; /** * Implements hook_entity_type_alter(). */ function my_project_profile_entity_type_alter(array &$entity_types): void { /** @var \Drupal\Core\Entity\ContentEntityType $blockContentDefinition */ $blockContentDefinition = $entity_types['block_content']; // Override view builder class. $blockContentDefinition->setViewBuilderClass(MyProjectBlockContentViewBuilder::class); }Pro tip: Use the Hux module to do this in a Hooks class.
Now, any BlockContent bundle class that implements BuildableEntityInterface and returns TRUE from its shouldBuild method will completely bypass Drupal’s standard entity rendering and instead just return whatever we want from its build method.
BuildableEntityInterfacenamespace Drupal\my_project_profile\Entity\Interface; /** * Interface for entities which override the view builder. */ interface BuildableEntityInterface { /** * Default method to build an entity. */ public function build(string $viewMode): array; /** * Determine if the entity should be built for the given view mode. */ public function shouldBuild(string $viewMode): bool; }This interface can be added to the Bundle class itself or the custom entity type interface we discussed earlier to keep all bundles consistent. This doesn’t just apply to the Block content entity type; you can use this for Paragraphs, Media, or your custom entity types. You’ll just need to override the view builder for each.
It is generally not recommended to use this for Node since you’re more likely to get value out of something like Layout Builder for rendering nodes. Those layouts would then have block content added to them, which in turn will be rendered via this method.
Back to our Card example. It was extending a custom base class MyProjectBlockContentBase. That class may look something like this:
namespace Drupal\my_project_profile\Entity\BlockContent; use Drupal\block_content\BlockContentTypeInterface; use Drupal\block_content\Entity\BlockContent; abstract class MyProjectBlockContentBase extends BlockContent implements MyProjectBlockContentInterface { /** * {@inheritdoc} */ public function shouldBuild(string $viewMode): bool { return TRUE; } }Our base class extends core’s BlockContent class and implements our custom interface.
That custom interface can then extend BuildableEntityInterface.
The shouldBuild method is an optional implementation detail, but it is nice if you have multiple view modes for a bundle, which need to have differing logic. For example, you might have a media_library view mode that you want to continue to use Drupal’s standard rendering.
Now, all we need to do is implement the build method on our BlockContent bundle classes.
Let’s look at the Card example:
use Drupal\my_project_ds\ThemeObject\Card as PintoCard; final class Card extends MyProjectBlockContentBase { // Trimmed for easy reading. /** * {@inheritdoc} */ public function build(string $viewMode): array { return PintoCard::createFromCardBlock($this)(); } }Here, we’re simply returning the render array that results from invoking our Card Pinto object (aliased as PintoCard via the use statement).
We have also introduced a factory method createFromCardBlock on the Pinto theme object, which takes the entity and injects its data into the object.
This is what the fully implemented Pinto object would look like
namespace Drupal\my_project_ds\ThemeObject; use Drupal\Core\Cache\CacheableDependencyInterface; use Drupal\my_project_profile\Entity\BlockContent\Card as CardBlock; use Drupal\my_project_ds\MyProjectDs\MyProjectObjectTrait; use Pinto\Attribute\ThemeDefinition; #[ThemeDefinition([ 'variables' => [ 'title' => '', 'description' => '', 'image' => '', ], ])] final class Card implements CacheableDependencyInterface { use MyProjectObjectTrait; private function __construct( private readonly string $title, private readonly array $image, private readonly ?string $description, ) {} public static function createFromCardBlock(CardBlock $card): static { return new static( $card->getTitle(), $card->getImage(), $card->getDescription(), ); } protected function build(mixed $build): mixed { return $build + [ '#title' => $this->title, '#description' => $this->description, '#image' => $this->image, ]; } }The build and constructor methods were covered in our previous Pinto post. All that’s new here is the createFromCardBlock method, where we use the getters from the bundle class traits to inject the entity’s data into the constructor.
We also briefly mentioned cacheable metadata in our last post. Since our Pinto object implements CacheableDependencyInterface, we can add that metadata directly to the theme object. For example, you should enhance the bundle class’ build method to add the Image media entity as a cacheable dependency. That way if the media entity is updated, the Card output is invalidated.
/** * {@inheritdoc} */ public function build(string $viewMode): array { $build = PintoCard::createFromCardBlock($this); $image = $this->image->entity; if ($image) { $build->addCacheableDependency($image); } return $build(); }Now, we have end-to-end rendering of a Drupal entity using Pinto Theme objects to render templates defined in a Storybook design system.
New bundles are simple to implement. All that’s needed is to click together the fields in the UI to build the content model, add the new Theme object, and wire that together with a bundle class.
I can’t overstate how much this has sped up our backend development. My latest project utilised Pinto from the very beginning, and it has made theming the entire site extremely fast and even… fun! 😀