Drupal In the News: Drupal Association Launches Drupal Steward Program To Increase Protection For Site Owners

The Drupal Steward Program enhances the security of Drupal Sites by protecting sites from exploits even before they are able to patch, and supports the sustainability of the Drupal Security Team and Drupal Association.

PORTLAND, Ore. July 7, 2020—The Drupal Association is announcing the launch of the Drupal Steward security program, together with founding partners Acquia and Pantheon, two of the largest hosting platforms for Drupal, and major contributors to the project. This is a paid service offered to further enhance the sites built on Drupal. A portion of the proceeds from both the founding partners and the community tier are used to support the Drupal Security Team and Drupal Association.

The Drupal Steward program answers the most pressing concern that keeps CIOs/CTOs up at night – “How do I protect my sites from the next unknown vulnerability?” In today’s world, a Public Service Announcement of a critical vulnerability means disruption to existing engineering roadmaps, overtime hours, and all-hands on deck waiting for a patch release so that it can be deployed before bad actors reverse engineer the vulnerability.

Drupal Steward addresses this issue by putting in place a network-level mitigation strategy that prevents many of these kinds of highly critical vulnerabilities from being exploited, even before the patch has been applied. While there may be some rare vulnerabilities that cannot be mitigated with this technique – most of the highly critical vulnerabilities in Drupal’s past would have been mitigated with this method.

“I am proud that we can advance Drupal’s commitment to enterprise-grade security,” said Heather Rocker, Executive Director of the Drupal Association. “The Drupal Steward program and its security protections should give the world the confidence to build the next generation of digital experiences on open source technology.”

Drupal sites hosted with the Drupal Steward Founding Partners Acquia and Pantheon will be directly protected by those partners. For sites not hosted by the Drupal Steward founding partners, Drupal site owners will be able to subscribe to the Community tier of the Drupal Steward program directly through the Drupal Association at an affordable cost, with discounts provided to clients of Drupal Association supporting partners with a record of contribution to the project in the form of time, talent, or treasure.

Learn more about Drupal Steward

For complete details about the Drupal Steward program, including how to sign up – please visit https://www.drupal.org/security-team/steward

Powered by a global community

Drupal is a true open source project, leveraging the expertise of tens of thousands of developers around the world. Drupal has a proven track record for strong security practices, with a strong belief that the transparency of open source leads to more secure software.

About Drupal and the Drupal Association

Drupal is the open source content management software used by millions of people and organizations around the world, made possible by a community of 100,000-plus contributors and enabling more than 1.3 million users on Drupal.org. The Drupal Association is the non-profit organization dedicated to accelerating the Drupal software project, fostering the community, and supporting its growth.

###

For more information contact secwg-partnerships@association.drupal.org 

Amazee Labs: Join us at DrupalCon Global

<img src=”https://www.amazeelabs.com/sites/default/files/styles/leading_image/public/images/current-affairs/AL-Going-to-DrupalCon-Global-Blogs.jpg?h=994a2424&amp;itok=j5e9gWaA” width=”1120″ height=”630″ alt=”Join us at DrupalCon Global ” title=”Join us at DrupalCon Global ” class=”image-style-leading-image” />

DrupalCon Global 2020 is just a few days away, and we’re excitedly prepping up for what’s sure to be a virtual event like nothing the community has seen before. To say the least, it’s been a strange few months for everyone on the planet, but we at Amazee Labs think nothing exemplifies the resilient and persistent spirit of the open-source community like the innovative skills and organizational determination it took to bring DrupalCon Global 2020 and all its global attendees together.

Agaric Collective: Drupal migrations reference: List of properties per content entity

In a previous article we explained the syntax used to write Drupal migrations. When migrating into content entities, these define several properties that can be included in the process section to populate their values. For example, when importing nodes you can specify the title, publication status, creation date, etc. In the case of users, you can set the username, password, timezone, etc. Finding out which properties are available for an entity might require some Drupal development knowledge. To make the process easier, in today’s article we are presenting a reference of properties available in content entities provided by Drupal core and some contributed modules.

Example migrations mapping of content entity properties

For each entity we will present: the module that provides it, the class that defines it, and the available properties. For each property we will list its name, field type, a description, and a note if the field allows unlimited values (i.e. it has an unlimited cardinality). The list of properties available for a content entity depend on many factors. For example, if the entity is revisionable (e.g. revision_default), translatable (e.g. langcode), or both (e.g. revision_translation_affected). The modules that are enabled on the site can also affect the available properties. For instance, if the “Workspaces” module is installed, it will add a workspace property to many content entities. This reference assumes that Drupal was installed using the standard installation profile and all modules that provide content entities are enabled.

It is worth noting that entity properties are divided in two categories: base field definitions and field storage configurations. Base field configurations will always be available for the entity. On the other hand, the presence of field storage configurations will depend on various factors. For one, they can only be added to fieldable entities. Attaching the fields to the entity can be done manually by the user, by a module, or by an installation profile. Again, this reference assumes that Drupal was installed using the standard installation profile. Among other things, it adds a user_picture image field to the user entity and body, comment, field_image, and field_tags fields to the node entity. For entities that can have multiple bundles, not all properties provided by the field storage configurations will be available in all bundles. For example, with the standard installation profile all content types will have a body field associated with it, but only the article content type has the field_image, and field_tags fields. If subfields are available for the field type, you can migrate into them.

Content (Node) entity

Module: Node (Drupal Core)
Class: DrupalnodeEntityNode
Related article: Writing your first Drupal migration

List of base field definitions:

  1. nid: (integer) The node ID.
  2. uuid: (uuid) The node UUID.
  3. vid: (integer) Revision ID.
  4. langcode: (language) Language code (e.g. en).
  5. type: (entity_reference to node_type) Content type machine name.
  6. revision_timestamp: (created) The time that the current revision was created.
  7. revision_uid: (entity_reference to user) The user ID of the author of the current revision.
  8. revision_log: (string_long) Briefly describe the changes you have made.
  9. status: (boolean) Node published when set to TRUE.
  10. uid: (entity_reference to user) The user ID of the content author.
  11. title: (string) Title.
  12. created: (created) The time that the node was created.
  13. changed: (changed) The time that the node was last edited.
  14. promote: (boolean) Node promoted to front page when set to TRUE.
  15. sticky: (boolean) Node sticky at top of lists when set to TRUE.
  16. default_langcode: (boolean) A flag indicating whether this is the default translation.
  17. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  18. revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.
  19. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

List of field storage configurations:

  1. body: text_with_summary field.
  2. comment: comment field.
  3. field_image: image field.
  4. field_tags: entity_reference field.

User entity

Module: User (Drupal Core)
Class: DrupaluserEntityUser
Related articles: Migrating users into Drupal – Part 1 and Migrating users into Drupal – Part 2

List of base field definitions:

  1. uid: (integer) The user ID.
  2. uuid: (uuid) The user UUID.
  3. langcode: (language) The user language code.
  4. preferred_langcode: (language) The user’s preferred language code for receiving emails and viewing the site.
  5. preferred_admin_langcode: (language) The user’s preferred language code for viewing administration pages.
  6. name: (string) The name of this user.
  7. pass: (password) The password of this user (hashed).
  8. mail: (email) The email of this user.
  9. timezone: (string) The timezone of this user.
  10. status: (boolean) Whether the user is active or blocked.
  11. created: (created) The time that the user was created.
  12. changed: (changed) The time that the user was last edited.
  13. access: (timestamp) The time that the user last accessed the site.
  14. login: (timestamp) The time that the user last logged in.
  15. init: (email) The email address used for initial account creation.
  16. roles: (entity_reference to user_role) The roles the user has. Allows unlimited values.
  17. default_langcode: (boolean) A flag indicating whether this is the default translation.

List of field storage configurations:

  1. user_picture: image field.

Taxonomy term entity

Module: Taxonomy (Drupal Core)
Class: DrupaltaxonomyEntityTerm
Related article: Migrating taxonomy terms and multivalue fields into Drupal

List of base field definitions:

  1. tid: (integer) The term ID.
  2. uuid: (uuid) The term UUID.
  3. revision_id: (integer) Revision ID.
  4. langcode: (language) The term language code.
  5. vid: (entity_reference to taxonomy_vocabulary) The vocabulary to which the term is assigned.
  6. revision_created: (created) The time that the current revision was created.
  7. revision_user: (entity_reference to user) The user ID of the author of the current revision.
  8. revision_log_message: (string_long) Briefly describe the changes you have made.
  9. status: (boolean) Published.
  10. name: (string) Name.
  11. description: (text_long) Description.
  12. weight: (integer) The weight of this term in relation to other terms.
  13. parent: (entity_reference to taxonomy_term) The parents of this term. Allows unlimited values.
  14. changed: (changed) The time that the term was last edited.
  15. default_langcode: (boolean) A flag indicating whether this is the default translation.
  16. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  17. revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.
  18. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

File entity

Module: File (Drupal Core)
Class: DrupalfileEntityFile
Related articles: Migrating files and images into Drupal, Migrating images using the image_import plugin, and Migrating images using the image_import plugin

List of base field definitions:

  1. fid: (integer) The file ID.
  2. uuid: (uuid) The file UUID.
  3. langcode: (language) The file language code.
  4. uid: (entity_reference to user) The user ID of the file.
  5. filename: (string) Name of the file with no path components.
  6. uri: (file_uri) The URI to access the file (either local or remote).
  7. filemime: (string) The file’s MIME type.
  8. filesize: (integer) The size of the file in bytes.
  9. status: (boolean) The status of the file, temporary (FALSE) and permanent (TRUE).
  10. created: (created) The timestamp that the file was created.
  11. changed: (changed) The timestamp that the file was last changed.

Media entity

Module: Media (Drupal Core)
Class: DrupalmediaEntityMedia

List of base field definitions:

  1. mid: (integer) The media ID.
  2. uuid: (uuid) The media UUID.
  3. vid: (integer) Revision ID.
  4. langcode: (language) Language code (e.g. en).
  5. bundle: (entity_reference to media_type) Media type.
  6. revision_created: (created) The time that the current revision was created.
  7. revision_user: (entity_reference to user) The user ID of the author of the current revision.
  8. revision_log_message: (string_long) Briefly describe the changes you have made.
  9. status: (boolean) Published.
  10. uid: (entity_reference to user) The user ID of the author.
  11. name: (string) Name.
  12. thumbnail: (image) The thumbnail of the media item.
  13. created: (created) The time the media item was created.
  14. changed: (changed) The time the media item was last edited.
  15. default_langcode: (boolean) A flag indicating whether this is the default translation.
  16. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  17. revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.
  18. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

List of field storage configurations:

  1. field_media_audio_file: file field.
  2. field_media_document: file field.
  3. field_media_image: image field.
  4. field_media_oembed_video: string field.
  5. field_media_video_file: file field.

Comment entity

Module: Comment (Drupal Core)
Class: DrupalcommentEntityComment

List of base field definitions:

  1. cid: (integer) The comment ID.
  2. uuid: (uuid) The comment UUID.
  3. langcode: (language) The comment language code.
  4. comment_type: (entity_reference to comment_type) The comment type.
  5. status: (boolean) Published.
  6. uid: (entity_reference to user) The user ID of the comment author.
  7. pid: (entity_reference to comment) The parent comment ID if this is a reply to a comment.
  8. entity_id: (entity_reference to node) The ID of the entity of which this comment is a reply.
  9. subject: (string) Subject.
  10. name: (string) The comment author’s name.
  11. mail: (email) The comment author’s email address.
  12. homepage: (uri) The comment author’s home page address.
  13. hostname: (string) The comment author’s hostname.
  14. created: (created) The time that the comment was created.
  15. changed: (changed) The time that the comment was last edited.
  16. thread: (string) The alphadecimal representation of the comment’s place in a thread, consisting of a base 36 string prefixed by an integer indicating its length.
  17. entity_type: (string) The entity type to which this comment is attached.
  18. field_name: (string) The field name through which this comment was added.
  19. default_langcode: (boolean) A flag indicating whether this is the default translation.

List of field storage configurations:

  1. comment_body: text_long field.

Aggregator feed entity

Module: Aggregator (Drupal Core)
Class: DrupalaggregatorEntityFeed

List of base field definitions:

  1. fid: (integer) The ID of the aggregator feed.
  2. uuid: (uuid) The aggregator feed UUID.
  3. langcode: (language) The feed language code.
  4. title: (string) The name of the feed (or the name of the website providing the feed).
  5. url: (uri) The fully-qualified URL of the feed.
  6. refresh: (list_integer) The length of time between feed updates. Requires a correctly configured cron maintenance task.
  7. checked: (timestamp) Last time feed was checked for new items, as Unix timestamp.
  8. queued: (timestamp) Time when this feed was queued for refresh, 0 if not queued.
  9. link: (uri) The link of the feed.
  10. description: (string_long) The parent website’s description that comes from the element in the feed.
  11. image: (uri) An image representing the feed.
  12. hash: (string) Calculated hash of the feed data, used for validating cache.
  13. etag: (string) Entity tag HTTP response header, used for validating cache.
  14. modified: (timestamp) When the feed was last modified, as a Unix timestamp.

Aggregator feed item entity

Module: Aggregator (Drupal Core)
Class: DrupalaggregatorEntityItem

List of base field definitions:

  1. iid: (integer) The ID of the feed item.
  2. langcode: (language) The feed item language code.
  3. fid: (entity_reference to aggregator_feed) The aggregator feed entity associated with this item.
  4. title: (string) The title of the feed item.
  5. link: (uri) The link of the feed item.
  6. author: (string) The author of the feed item.
  7. description: (string_long) The body of the feed item.
  8. timestamp: (created) Posted date of the feed item, as a Unix timestamp.
  9. guid: (string_long) Unique identifier for the feed item.

Custom block entity

Module: Custom Block (Drupal Core)
Class: Drupalblock_contentEntityBlockContent

List of base field definitions:

  1. id: (integer) The custom block ID.
  2. uuid: (uuid) The custom block UUID.
  3. revision_id: (integer) The revision ID.
  4. langcode: (language) The custom block language code.
  5. type: (entity_reference to block_content_type) The block type.
  6. revision_created: (created) The time that the current revision was created.
  7. revision_user: (entity_reference to user) The user ID of the author of the current revision.
  8. revision_log: (string_long) The log entry explaining the changes in this revision.
  9. status: (boolean) Published.
  10. info: (string) A brief description of your block.
  11. changed: (changed) The time that the custom block was last edited.
  12. reusable: (boolean) A boolean indicating whether this block is reusable.
  13. default_langcode: (boolean) A flag indicating whether this is the default translation.
  14. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  15. revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.
  16. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

List of field storage configurations:

  1. body: text_with_summary field.

Contact message entity

Module: Contact (Drupal Core)
Class: DrupalcontactEntityMessage

List of base field definitions:

  1. uuid: (uuid) The message UUID.
  2. langcode: (language) The message language code.
  3. contact_form: (entity_reference to contact_form) The ID of the associated form.
  4. name: (string) The name of the person that is sending the contact message.
  5. mail: (email) The email of the person that is sending the contact message.
  6. subject: (string) Subject.
  7. message: (string_long) Message.
  8. copy: (boolean) Whether to send a copy of the message to the sender.
  9. recipient: (entity_reference to user) The ID of the recipient user for personal contact messages.

Content moderation state entity

Module: Content Moderation (Drupal Core)
Class: Drupalcontent_moderationEntityContentModerationState

List of base field definitions:

  1. id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. revision_id: (integer) Revision ID.
  4. langcode: (language) Language.
  5. uid: (entity_reference to user) The username of the entity creator.
  6. workflow: (entity_reference to workflow) The workflow the moderation state is in.
  7. moderation_state: (string) The moderation state of the referenced content.
  8. content_entity_type_id: (string) The ID of the content entity type this moderation state is for.
  9. content_entity_id: (integer) The ID of the content entity this moderation state is for.
  10. content_entity_revision_id: (integer) The revision ID of the content entity this moderation state is for.
  11. default_langcode: (boolean) A flag indicating whether this is the default translation.
  12. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  13. revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.

URL alias entity

Module: Path alias (Drupal Core)
Class: Drupalpath_aliasEntityPathAlias

List of base field definitions:

  1. id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. revision_id: (integer) Revision ID.
  4. langcode: (language) Language.
  5. path: (string) The path that this alias belongs to.
  6. alias: (string) An alias used with this path.
  7. status: (boolean) Published.
  8. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  9. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

Shortcut link entity

Module: Shortcut (Drupal Core)
Class: DrupalshortcutEntityShortcut

List of base field definitions:

  1. id: (integer) The ID of the shortcut.
  2. uuid: (uuid) The UUID of the shortcut.
  3. langcode: (language) The language code of the shortcut.
  4. shortcut_set: (entity_reference to shortcut_set) The bundle of the shortcut.
  5. title: (string) The name of the shortcut.
  6. weight: (integer) Weight among shortcuts in the same shortcut set.
  7. link: (link) The location this shortcut points to.
  8. default_langcode: (boolean) A flag indicating whether this is the default translation.

Workspace entity

Module: Workspaces (Drupal Core)
Class: DrupalworkspacesEntityWorkspace

List of base field definitions:

  1. id: (string) The workspace ID.
  2. uuid: (uuid) UUID.
  3. revision_id: (integer) Revision ID.
  4. uid: (entity_reference to user) The workspace owner.
  5. label: (string) The workspace name.
  6. parent: (entity_reference to workspace) The parent workspace.
  7. changed: (changed) The time that the workspace was last edited.
  8. created: (created) The time that the workspace was created.
  9. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.

Module: Custom Menu Links (Drupal Core)
Class: Drupalmenu_link_contentEntityMenuLinkContent

List of base field definitions:

  1. id: (integer) The entity ID for this menu link content entity.
  2. uuid: (uuid) The content menu link UUID.
  3. revision_id: (integer) Revision ID.
  4. langcode: (language) The menu link language code.
  5. bundle: (string) The content menu link bundle.
  6. revision_created: (created) The time that the current revision was created.
  7. revision_user: (entity_reference to user) The user ID of the author of the current revision.
  8. revision_log_message: (string_long) Briefly describe the changes you have made.
  9. enabled: (boolean) A flag for whether the link should be enabled in menus or hidden.
  10. title: (string) The text to be used for this link in the menu.
  11. description: (string) Shown when hovering over the menu link.
  12. menu_name: (string) The menu name. All links with the same menu name (such as “tools”) are part of the same menu.
  13. link: (link) The location this menu link points to.
  14. external: (boolean) A flag to indicate if the link points to a full URL starting with a protocol, like http:// (1 = external, 0 = internal).
  15. rediscover: (boolean) Indicates whether the menu link should be rediscovered.
  16. weight: (integer) Link weight among links in the same menu at the same depth. In the menu, the links with high weight will sink and links with a low weight will be positioned nearer the top.
  17. expanded: (boolean) If selected and this menu link has children, the menu will always appear expanded. This option may be overridden for the entire menu tree when placing a menu block.
  18. parent: (string) The ID of the parent menu link plugin, or empty string when at the top level of the hierarchy.
  19. changed: (changed) The time that the menu link was last edited.
  20. default_langcode: (boolean) A flag indicating whether this is the default translation.
  21. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  22. revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.
  23. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

Paragraph entity

Module: Paragraphs module
Class: DrupalparagraphsEntityParagraph
Related article: Introduction to paragraphs migrations in Drupal

List of base field definitions:

  1. id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. revision_id: (integer) Revision ID.
  4. langcode: (language) The paragraphs entity language code.
  5. type: (entity_reference to paragraphs_type) Paragraph type.
  6. status: (boolean) Published.
  7. created: (created) The time that the Paragraph was created.
  8. parent_id: (string) The ID of the parent entity of which this entity is referenced.
  9. parent_type: (string) The entity parent type to which this entity is referenced.
  10. parent_field_name: (string) The entity parent field name to which this entity is referenced.
  11. behavior_settings: (string_long) The behavior plugin settings
  12. default_langcode: (boolean) A flag indicating whether this is the default translation.
  13. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  14. revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.
  15. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

List of field storage configurations:

  1. field_reusable_paragraph: entity_reference field.

Paragraphs library item entity

Module: Paragraphs Library (part of paragraphs module)
Class: Drupalparagraphs_libraryEntityLibraryItem

List of base field definitions:

  1. id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. revision_id: (integer) Revision ID.
  4. langcode: (language) Language.
  5. revision_created: (created) The time that the current revision was created.
  6. revision_uid: (entity_reference to user) The user ID of the author of the current revision.
  7. revision_log: (string_long) Briefly describe the changes you have made.
  8. status: (boolean) Published.
  9. label: (string) Label.
  10. paragraphs: (entity_reference_revisions) Paragraphs.
  11. created: (created) The time that the library item was created.
  12. changed: (changed) The time that the library item was last edited.
  13. uid: (entity_reference to user) The user ID of the library item author.
  14. default_langcode: (boolean) A flag indicating whether this is the default translation.
  15. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  16. revision_translation_affected: (boolean) Indicates if the last edit of a translation belongs to current revision.
  17. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

Profile entity

Module: Profile module
Class: DrupalprofileEntityProfile

List of base field definitions:

  1. profile_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. revision_id: (integer) Revision ID.
  4. type: (entity_reference to profile_type) Profile type.
  5. revision_created: (created) The time that the current revision was created.
  6. revision_user: (entity_reference to user) The user ID of the author of the current revision.
  7. revision_log_message: (string_long) Briefly describe the changes you have made.
  8. status: (boolean) Whether the profile is active.
  9. uid: (entity_reference to user) The user that owns this profile.
  10. is_default: (boolean) Whether this is the default profile.
  11. data: (map) A serialized array of additional data.
  12. created: (created) The time when the profile was created.
  13. changed: (changed) The time when the profile was last edited.
  14. revision_default: (boolean) A flag indicating whether this was a default revision when it was saved.
  15. workspace: (entity_reference to workspace) Indicates the workspace that this revision belongs to.

Available properties for other content entities

This reference includes all core content entities and some provided by contributed modules. The next article will include a reference for Drupal Commerce content entities. That being said, it would be impractical to cover all contributed modules. To get a list of yourself for other content entities, load the entity_type.manager service and call its getFieldStorageDefinitions() method passing the machine name of the entity as a parameter. Although this reference only covers content entities, the same process can be used for configuration entities.

What did you learn in today’s article? Did you know that there were so many entity properties in Drupal core? Were you aware that the list of available properties depend on factors like if the entity is fieldable, translatable, and revisionable? Did you know how to find properties for content entities from contributed modules? Please share your answers in the comments. Also, we would be grateful if you shared this article with your friends and colleagues.

Read more and discuss at agaric.coop.

OSTraining: How to Use the Recaptcha Module in Drupal 8

How to Use the Recaptcha Module in Drupal 8

The reCAPTCHA module for Drupal 8 integrates the reCAPTCHA service provided by Google with your Drupal site. This service provides additional protection by detecting if the user accessing your site is a real person or a robot. 

Keep reading to learn how to use this module!

PreviousNext: Testing Twig templates and custom JavaScript with Jest

Jest is the defacto standard for testing in modern JavaScript but we’ve traditionally not been able to leverage it for testing in Drupal.

But with twig-testing-library, we can now test our twig templates and any dynamic behaviours added by Javascript using Jest.

In this article we will go through the process of adding Jest based testing to an existing accordion component.

by
lee.rowlands
/

Installation

Firstly we need to install twig-testing-library and jest

npm i --save-dev twig-testing-library jest

And we’re also going to add additional dom-based Jest asserts using jest-dom

npm i --save-dev @testing-library/jest-dom

Now we need to configure Jest by telling it how to find our tests as well as configuring transpiling.

In this project, we’ve got all of our components in folders in a /packages sub directory.

So we create a jest.config.js file in the root with the following contents:


// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html

module.exports = {
  clearMocks: true, // Clear mocks on each test.
  testMatch: ['/packages/**/src/__tests__/**.test.js'], // How to find our tests.
  transform: {
    '^.+\.js?$': `/jest-preprocess.js`, // Babel transforms.
  },
  setupFilesAfterEnv: [`/setup-test-env.js`], // Additional setup.
};

For transpiling we’re just using babel-jest and then chaining with our projects presets. The contents of jest-preprocess.js is as follows:

const babelOptions = {
  presets: ['@babel/preset-env'],
};

module.exports = require('babel-jest').createTransformer(babelOptions);

As we’re going to also use the Jest dom extension for additional Dom based assertions, our setup-test-environment takes care of that as well as some globals that Drupal JS expects to exist. The contents of our setup-test-env.js file is as follows:

import '@testing-library/jest-dom/extend-expect';

global.Drupal = {
  behaviors: {},
};

Writing our first test

Now we have the plumbing done, let’s create our first test

As per the pattern above, these need to live in a __tests__ folder inside the src folder of our components

So let’s create a test for the accordion component, by creating packages/accordion/src/__tests__/accordion.test.js

Let’s start with a basic test that the accordion should render and match a snapshot. This will pickup when there are changes in the markup and also verify that the template is valid.

Here’s the markup in the twig template

div class="accordion js-accordion">
  {% block button %}
    button class="button button--primary accordion__toggle">{{ title | default('Open Me') }}button>
  {% endblock %}
  div class="accordion__content">
    {% block content %}
      h1>Accordion Contenth1>
      p>This content is hidden inside the accordion body until it is disclosed by clicking the accordion toggle.p>
    {% endblock %}
  div>
div>

So let’s render that with twig-testing-library and assert some things in packages/accordion/src/__tests__/accordion.test.js


import { render } from 'twig-testing-library';

describe('Accordion functionality', () => {
  it('Should render', async () => {
    expect.assertions(2);
    const { container } = await render(
      './packages/accordion/src/accordion.twig',
      {
        title: 'Accordion',
        open: false,
      },
    );
    expect(container).toMatchSnapshot();
    expect(container.querySelectorAll('.accordion__toggle')).toHaveLength(1);
  });
});


Running the tests

So let’s run our first test by adding a jest command to our package.json under “scripts”


"jest": "jest --runInBand"

Now we run with

npm run jest

> jest --runInBand

 PASS  packages/accordion/src/__tests__/accordion.test.js
  Accordion functionality
    ✓ Should render (43 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        4.62 s, estimated 6 s
Ran all test suites.

Testing dynamic behaviour

Now we know our template renders, and we’re seeing some expected output, let’s test that we can expand and collapse our accordion.

Our accordion JS does the following:

  • On click of the accordion title, expands the element by adding accordion–open class and sets the aria-expanded attribute
  • On click again, closes the accordion by removing the class and attribute

So let’s write a test for that – by adding this to our existing test:


  it('Should expand and collapse', async () => {
    expect.assertions(4);
    const { container, getByText } = await render(
      './packages/accordion/src/accordion.twig',
      {
        title: 'Open accordion',
      },
    );
    const accordionElement = container.querySelector(
      '.accordion:not(.processed)',
    );
    const accordion = new Accordion(accordionElement);
    accordion.init();
    const accordionToggle = getByText('Open accordion');
    fireEvent.click(accordionToggle);
    expect(accordionElement).toHaveClass('accordion--open');
    expect(accordionToggle).toHaveAttribute('aria-expanded', 'true');
    fireEvent.click(accordionToggle);
    expect(accordionElement).not.toHaveClass('accordion--open');
    expect(accordionToggle).toHaveAttribute('aria-expanded', 'false');
  });

Now let’s run that

npm run jest
packages/accordion/src/__tests__/accordion.test.es6.js
  Accordion functionality
    ✓ Should render (29 ms)
    ✓ Should expand and collapse (20 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   1 passed, 1 total
Time:        5.031 s, estimated 6 s
Ran all test suites.

Neat! We now have some test coverage for our accordion component

Next steps

So the neat thing about Jest is, it can collect code-coverage, let’s run that

npm run jest -- --coverage
packages/accordion/src/__tests__/accordion.test.es6.js
  Accordion functionality
    ✓ Should render (28 ms)
    ✓ Should expand and collapse (13 ms)

-------------------|---------|----------|---------|---------|--------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------------|---------|----------|---------|---------|--------------------
All files          |   29.55 |    11.27 |   24.14 |      30 |
 accordion/src     |     100 |    85.71 |     100 |     100 |
  accordion.es6.js |     100 |    85.71 |     100 |     100 | 53
 base/src          |   11.43 |     3.13 |    4.35 |   11.65 |
  utils.es6.js     |   11.43 |     3.13 |    4.35 |   11.65 | 14,28,41-48,58-357
-------------------|---------|----------|---------|---------|--------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   1 passed, 1 total
Time:        2.813 s, estimated 5 s
Ran all test suites.

Pretty nice hey?

What’s happening behind the scenes

If you’ve worked on a React project before, you’ve probably encountered Dom testing library and React testing library. Twig testing library aims to provide the same developer ergonomics as both of these libraries. If you’ve familiar with either of those, you should find Twig testing library’s API’s comparable.

Under the hood it’s using Twig.js for Twig based rendering in JavaScript and Jest uses jsdom for browser JavaScript APIs.

A longer introduction

I did a session on using this for a Drupal South virtual meetup, here’s the recording of it.

Get involved

If you’d like to get involved, come say hi on github.

Mobomo: How Drupal manages Accessibility

argument-open-source

Businesses and governments build websites for one reason: to provide value to their users. But what if your website was incapable of reaching millions of your users? 25% of Americans live with disabilities. For some of them, the simple act of navigating websites, digesting information, and understanding your content is difficult. Yet, despite brands increasing spending on web design and digital marketing, less than 10% of websites actually follow accessibility standards. Businesses are spending significant money to capture an audience, yet they’re not ensuring that their audience can engage with their website.

It’s a problem—a big one.

You don’t want to exclude customers. It’s bad for business, and it’s bad for your brand. Better yet, accessibility features help improve your SEO, reduce your website complexity, and increase your ability to connect with your loyal audience. But accessibility standards aren’t always baked into the architecture of websites.

Luckily, there are some content management systems (CMS) that let you create hyper-accessible websites without even trying. Drupal comes equipped with a variety of accessibility features — each of which helps make your website more accessible for your customers.

Understanding the Importance of Website Accessibility

Creating an accessible website may sound vague, but there’s already a worldwide standard you can follow. The Web Content Accessibility Guidelines (WCAG) — which is maintained by The World Wide Web Consortium — is the global standard for web accessibility used by companies, governments, and merchants across the world.

Sure! Following the WCAG standard helps you reach a wider audience. But it also keeps you out of legal hot water. Not only has the ADA made it abundantly clear that compliance requires website accessibility. A United States District Court in Florida ruled that WCAG standards are the de facto standards of web accessibility. And there are already cases of businesses getting sued for failing to adhere to them.

  • The DOJ sues H&R Block over its website’s accessibility.
  • WinnDixie.com was sued for accessibility, and the judge required them to update their website.
  • The National Museum of Crime and Punishment was required to update its website accessibility.

The list goes on. Adhering to WCAG web accessibility standards helps protect your brand against litigation. But, more importantly, it opens doors to millions of customers who need accessibility to navigate and engage with your amazing content.

One-third of individuals over the age of 65 have hearing loss. Around 15% of Americans struggle with vision loss. And millions have issues with mobility. The CDC lists six forms of disability:

  • Mobility (difficulty walking or climbing)
  • Cognition (difficult remembering, making decisions, or concentrating)
  • Hearing (difficulty hearing)
  • Vision (difficulty seeing)
  • Independent living (difficulty doing basic errands)
  • Self-care (difficulty bathing, dressing, or taking care of yourself)

Web accessibility touches all of those types of disabilities. For those with trouble seeing, screen readers help them comprehend websites. But, screen readers strip away the CSS layer. Your core content has to be accessible for them to be able to comprehend it. Those with mobility issues may need to use keyboard shortcuts to help them navigate your website. Hearing-impaired individuals may require subtitles and captions. Those with cognitive issues may need your website to be built with focusable elements and good contrasting.

There are many disabilities. WCAG creates a unified guideline that helps government entities and businesses build websites that are hyper-accessible to people with a wide range of these disabilities.

Drupal is WCAG-compliant

WCAG is vast. A great starting point is the Accessibility Principles document. But, creating an accessible website doesn’t have to be a time-consuming and expensive process. Drupal has an entire team dedicated to ensuring that their platform is WCAG compliant. In fact, Drupal is both WCAG 2.0 compliant and Authoring Tool Accessibility Guidelines (ATAG 2.0) compliant. The latter deals with the tools developers use to build websites. So, Drupal has accessibility compliance on both ends.

What Accessibility Features Does Drupal Have?

Drupal’s accessibility compliance comes in two forms:

  1. Drupal has built-in compliance features that are native to every install (7+).
  2. Drupal supports and enables the community to develop accessibility modules.

Drupal’s Built-in Compliance Features

Drupal 7+ comes native with semantic markup. To keep things simple, semantic markup helps clarify the context of content. At Mobomo, we employ some of the best designers and website developers on the planet. So, we could make bad HTML markup nearly invisible to the average user with rich CSS and superb visuals. But when people use screen readers or other assistive technology, that CSS goes out-of-the-window. They’re looking at the core HTML markup. And if it’s not semantic, they may have a difficult time navigating it. With Drupal, markup is automatically semantic — which breeds comprehension for translation engines, search engines, and screen readers.

Drupal’s accessibility page also notes some core changes made to increase accessibility. These include things such as color contrasting. WCAG requires that color contrasting be at least 4.5:1 for normal text and 7:1 for enhanced contrast. Drupal complies with those guidelines. Many other changes are on the developer side, such as drag and drop functions and automated navigation buttons.

Of course, Drupal also provides developer handbooks, theming guides, and instructional PDFs for developers. Some of the accessibility is done on the developer’s end, so it’s important to work with a developer who leverages accessibility during their design process.

Drupal’s Support for the Accessibility Community

In addition to following WCAG guidelines, Drupal supports community-driven modules that add additional accessibility support. Here are a few examples of Drupal modules that focus on accessibility:

There are hundreds. The main thing to remember is that Drupal supports both back-end, front-end, and community-driven accessibility. And they’ve committed to continuously improving their accessibility capabilities over time. Drupal’s most recent update — the heavily anticipated Drupal 9 — carries on this tradition. Drupal has even announced that Drupal 10 will continue to expand upon accessibility.

Do You Want to Build an Accessible Website

Drupal is on the cutting-edge of CMS accessibility. But they can’t make you accessible alone. You need to build your website from the ground up to comply with accessibility. A good chunk of the responsibility is in the hands of your developer. Are you looking to build a robust, functional, beautiful, and accessible website? 

Contact us. We’ll help you expand your reach.

The post How Drupal manages Accessibility appeared first on .

Tag1 Consulting: How Drupal can make true shared components a reality – part 1

Front-end development workflows have seen considerable innovation in recent years, with technologies like React disseminating revolutionary concepts like declarative components in JSX and more efficient document object model (DOM) diffing through Virtual DOMs. Nonetheless, while this front-end development revolution has led to significant change in the developer experiences we see in the JavaScript landscape and to even more momentum in favor of decoupled Drupal architectures in the Drupal community, it seems that many traditional CMSs have remained behind the curve when it comes to enabling true shared component ecosystems through developer experiences that focus on facilitating shared development practices across back and front end. At DrupalCon Amsterdam 2019, Fabian Franz (Senior Technical Architect and Performance Lead at Tag1) delivered a session entitled “Components everywhere: Bridging the gap between back end and front end” that delved into his ideal vision for enabling such shared components in Drupal’s own native rendering layer. Fabian joined Michael Meyers (Managing Director at Tag1), and me (Preston So, Editor in Chief at Tag1; Senior Director, Product Strategy at Oracle; and author of Decoupled Drupal in Practice) for a Tag1 Team Talks episode highlighting the progress other ecosystems have made in the face of this problem space…

preston
Wed, 07/08/2020 – 05:59

OpenSense Labs: Why Low Code Development Is Not As Great As We Think

Why Low Code Development Is Not As Great As We Think
Tuba Ayyubi
Tue, 07/07/2020 – 18:00

Low-code development replaces the traditional method of hard coding and allows us to create our own applications without any help from the IT developers. It requires minimal hand-coding and enables faster delivery of applications with the help of pre-packaged templates, drag and drop tools, and graphic design techniques.

From leading low-code development platforms like Mendix and Outsystems to Acquia Cohesion (suited for Drupal websites), the low-code approach has been making waves as a great option for easy application development.

A square divided in four with small dark blue circles

I am sure after reading the above lines you are left confused, that if low-code is an easy way out then why does the title talk about low code not being the right code. Well, if anything looks too good to be true, it’s not always that great. Let me tell you why!

Functionality-first and user needs later

Even though low code is a great help in making the lives of developers easier, it is unfortunate that it puts user experience at stake. A design-led approach or a progressive approach becomes harder to achieve with low code. Functionality over the need of the user never ends well.

Low code, as we know, saves time. And hence is said to be efficient. Whereas the truth is that it is efficient only with respect to time. The applications made on low code are hardly optimized for efficiency. If you want your web app to run smooth and fast, low code is not the go-to option for you.

No technical requirement: a myth

Low code is easy and can be done without including the technical team: True
Low code does not require any technical skill: false

For anyone of us to start working with the low code, the understanding of the development of low code is the first and the least requirement. It takes time to learn and understand the process. So, before one starts using the tools, it is important to ensure that they have the basic technical skills that are required.
Limited functions 

In a low code development tool, the number of functions that you can implement is limited. It is definitely a quick way to build applications but in case you want to try out something different, you do not have many options.

Also, once an app is created on low code, it is not very easy to add custom code or any other required functionality to it.

Does it help in cost-cutting?

When it comes to low code, the cost is both a draw and a drawback. 

Because of its flexibility, low code is easier to use and requires a small set of skills. So, you don’t have to specially hire someone and pay a hefty amount to do that.

Although it is easy to drag and drop building blocks that fulfil your requirements, once you need a special feature that is unavailable, you will need custom code. Merging the custom code can cost a lot more than a completely customized solution as a whole.

When a company starts, it starts small, and hence it is advised to have a provision in its low code contract for ramping up in the future. If not, the company has to face major downfall before they are even able to start properly.

Is it secure?

Low code has been giving rise to the question: Is it secure enough?

When you build an application using low code, it requires your complete trust. You don’t have control over data security and privacy and no access to source code which makes it difficult to identify the possibility of any sort of vulnerabilities.

Using low code to produce code that does not adhere to established best practices could violate an organization’s compliance measures. Doesn’t matter if the resulting application is secure.

Vendor Lock-In Risks

Vendor lock-in is one of the major limitations of low code development.

In the case of the teams that use low code, vendor lock-in can create poorly documented or even undocumented code that is difficult to maintain outside of the platform.

Hence, it is important to understand each vendor’s policies before licensing any tool and ensure that you know whether or not you are able to maintain applications outside of the platform.

Conclusion

Low code is indeed a useful tool but it comes with cons you can’t ignore. Platforms that have been using low code will only tell you that it’s faster and easier but lack of options and functions, security risks, and other major drawbacks make us rethink if it is actually the solution that we want for an enterprise application.

blog banner
Colorful lights on a black background

blog image
Black android smartphone

Blog Type
Is it a good read ?
On