Skip to main content

Blog

In a previous article, we presented a list of properties per content entity in Drupal core and some contributed modules. This time we will provide a similar list for Drupal Commerce. 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 Drupal Commerce product variations you can specify the SKU, price, list price, etc. In the case of promotions, you can set the start and end dates. 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 Commerce and some related contributed modules.

 

 

 

 

List of Drupal Commerce content entities.

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 only Drupal Commerce related 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 with Drupal Commerce related modules enabled. By default, the commerce_product entity adds a bodyfield. 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.

If you are migrating into Drupal Commerce, make sure to check the Commerce Migrate module. It offers migrate destination field handlers for commerce fields and a plugin for commerce product types. It also provides a migration path from Commerce 1 (Drupal 7), Ubercart, and other e-commerce platforms. It is even possible to import data from other platforms like WooCommerce, Magento, and Shopify via CSV exports.

Store entity

Module: Commerce Store (part of commerce module)
Class: Drupal\commerce_store\Entity\Store

List of base field definitions:

  1. store_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. langcode: (language) Language.
  4. type: (entity_reference to commerce_store_type) Type. The store type.
  5. uid: (entity_reference to user) Owner. The store owner.
  6. name: (string) Name. The store name.
  7. mail: (email) Email. Store email notifications are sent from this address.
  8. default_currency: (entity_reference to commerce_currency) Default currency. The default currency of the store.
  9. timezone: (list_string) Timezone. Used when determining promotion and tax availability.
  10. address: (address) Address. The store address.
  11. billing_countries: (list_string) Supported billing countries. Allows unlimited values.
  12. path: (path) URL alias. The store URL alias.
  13. is_default: (boolean) Default. Whether this is the default store.
  14. default_langcode: (boolean) Default translation. A flag indicating whether this is the default translation.
  15. shipping_countries: (list_string) Supported shipping countries. Allows unlimited values.
  16. prices_include_tax: (boolean) Prices are entered with taxes included.
  17. tax_registrations: (list_string) Tax registrations. The countries where the store is additionally registered to collect taxes. Allows unlimited values.

Product entity

Module: Commerce Product (part of commerce module)
Class: Drupal\commerce_product\Entity\Product

List of base field definitions:

  1. product_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. langcode: (language) Language.
  4. type: (entity_reference to commerce_product_type) Product type.
  5. status: (boolean) Published.
  6. stores: (entity_reference to commerce_store) Stores. The product stores. Allows unlimited values.
  7. uid: (entity_reference to user) Author. The product author.
  8. title: (string) Title. The product title.
  9. variations: (entity_reference to commerce_product_variation) Variations. The product variations. Allows unlimited values.
  10. created: (created) Created. The time when the product was created.
  11. changed: (changed) Changed. The time when the product was last edited.
  12. default_langcode: (boolean) Default translation. A flag indicating whether this is the default translation.

List of field storage configurations:

  1. body: text_with_summary field.

Product variation entity

Module: Commerce Product (part of commerce module)
Class: Drupal\commerce_product\Entity\ProductVariation

List of base field definitions:

  1. variation_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. langcode: (language) Language.
  4. type: (entity_reference to commerce_product_variation_type) Product variation type.
  5. status: (boolean) Published.
  6. uid: (entity_reference to user) Author. The variation author.
  7. product_id: (entity_reference to commerce_product) Product. The parent product.
  8. sku: (string) SKU. The unique, machine-readable identifier for a variation.
  9. title: (string) Title. The variation title.
  10. list_price: (commerce_price) List price. The list price.
  11. price: (commerce_price) Price. The price
  12. created: (created) Created. The time when the variation was created.
  13. changed: (changed) Changed. The time when the variation was last edited.
  14. default_langcode: (boolean) Default translation. A flag indicating whether this is the default translation.

Product attribute value entity

Module: Commerce Product (part of commerce module)
Class: Drupal\commerce_product\Entity\ProductAttributeValue

List of base field definitions:

  1. attribute_value_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. langcode: (language) Language.
  4. attribute: (entity_reference to commerce_product_attribute) Attribute.
  5. name: (string) Name. The attribute value name.
  6. weight: (integer) Weight. The weight of this attribute value in relation to others.
  7. created: (created) Created. The time when the attribute value was created.
  8. changed: (changed) Changed. The time when the attribute value was last edited.
  9. default_langcode: (boolean) Default translation. A flag indicating whether this is the default translation.

Order entity

Module: Commerce Order (part of commerce module)
Class: Drupal\commerce_order\Entity\Order

List of base field definitions:

  1. order_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. type: (entity_reference to commerce_order_type) Order type.
  4. order_number: (string) Order number. The order number displayed to the customer.
  5. store_id: (entity_reference to commerce_store) Store. The store to which the order belongs.
  6. uid: (entity_reference to user) Customer. The customer.
  7. mail: (email) Contact email. The email address associated with the order.
  8. ip_address: (string) IP address. The IP address of the order.
  9. billing_profile: (entity_reference_revisions) Billing information. Billing profile
  10. order_items: (entity_reference to commerce_order_item) Order items. The order items. Allows unlimited values.
  11. adjustments: (commerce_adjustment) Adjustments. Allows unlimited values.
  12. total_price: (commerce_price) Total price. The total price of the order.
  13. total_paid: (commerce_price) Total paid. The total paid price of the order.
  14. state: (state) State. The order state.
  15. data: (map) Data. A serialized array of additional data.
  16. locked: (boolean) Locked.
  17. created: (created) Created. The time when the order was created.
  18. changed: (changed) Changed. The time when the order was last edited.
  19. placed: (timestamp) Placed. The time when the order was placed.
  20. completed: (timestamp) Completed. The time when the order was completed.
  21. cart: (boolean) Cart.
  22. checkout_flow: (entity_reference to commerce_checkout_flow) Checkout flow.
  23. checkout_step: (string) Checkout step.
  24. payment_gateway: (entity_reference to commerce_payment_gateway) Payment gateway. The payment gateway.
  25. payment_method: (entity_reference to commerce_payment_method) Payment method. The payment method.
  26. coupons: (entity_reference to commerce_promotion_coupon) Coupons. Coupons that have been applied to order. Allows unlimited values.

Order item entity

Module: Commerce Order (part of commerce module)
Class: Drupal\commerce_order\Entity\OrderItem

List of base field definitions:

  1. order_item_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. type: (entity_reference to commerce_order_item_type) Order item type.
  4. order_id: (entity_reference to commerce_order) Order. The parent order.
  5. purchased_entity: (entity_reference to node) Purchased entity. The purchased entity.
  6. title: (string) Title. The order item title.
  7. quantity: (decimal) Quantity. The number of purchased units.
  8. unit_price: (commerce_price) Unit price. The price of a single unit.
  9. overridden_unit_price: (boolean) Overridden unit price. Whether the unit price is overridden.
  10. total_price: (commerce_price) Total price. The total price of the order item.
  11. adjustments: (commerce_adjustment) Adjustments. Allows unlimited values.
  12. uses_legacy_adjustments: (boolean) Uses legacy adjustments.
  13. data: (map) Data. A serialized array of additional data.
  14. created: (created) Created. The time when the order item was created.
  15. changed: (changed) Changed. The time when the order item was last edited.

Payment method entity

Module: Commerce Payment (part of commerce module)
Class: Drupal\commerce_payment\Entity\PaymentMethod

List of base field definitions:

  1. method_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. type: (string) Payment method type.
  4. payment_gateway: (entity_reference to commerce_payment_gateway) Payment gateway. The payment gateway.
  5. payment_gateway_mode: (string) Payment gateway mode. The payment gateway mode.
  6. uid: (entity_reference to user) Owner. The payment method owner.
  7. remote_id: (string) Remote ID. The payment method remote ID.
  8. billing_profile: (entity_reference_revisions) Billing profile. Billing profile
  9. reusable: (boolean) Reusable. Whether the payment method is reusable.
  10. is_default: (boolean) Default. Whether this is the user's default payment method.
  11. expires: (timestamp) Expires. The time when the payment method expires. 0 for never.
  12. created: (created) Created. The time when the payment method was created.
  13. changed: (changed) Changed. The time when the payment method was last edited.

Payment entity

Module: Commerce Payment (part of commerce module)
Class: Drupal\commerce_payment\Entity\Payment

List of base field definitions:

  1. payment_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. type: (string) Payment type.
  4. payment_gateway: (entity_reference to commerce_payment_gateway) Payment gateway. The payment gateway.
  5. payment_gateway_mode: (string) Payment gateway mode. The payment gateway mode.
  6. payment_method: (entity_reference to commerce_payment_method) Payment method. The payment method.
  7. order_id: (entity_reference to commerce_order) Order. The parent order.
  8. remote_id: (string) Remote ID. The remote payment ID.
  9. remote_state: (string) Remote State. The remote payment state.
  10. amount: (commerce_price) Amount. The payment amount.
  11. refunded_amount: (commerce_price) Refunded amount. The refunded payment amount.
  12. state: (state) State. The payment state.
  13. authorized: (timestamp) Authorized. The time when the payment was authorized.
  14. expires: (timestamp) Expires. The time when the payment expires. 0 for never.
  15. completed: (timestamp) Completed. The time when the payment was completed.
  16. test: (boolean) Test. Whether this is a test payment.
  17. captured: (timestamp) Captured. The time when the payment was captured.

Promotion entity

Module: Commerce Promotion (part of commerce module)
Class: Drupal\commerce_promotion\Entity\Promotion

List of base field definitions:

  1. promotion_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. langcode: (language) Language.
  4. name: (string) Name. The promotion name.
  5. display_name: (string) Display name. If provided, shown on the order instead of "Discount".
  6. description: (string_long) Description. Additional information about the promotion to show to the customer
  7. order_types: (entity_reference to commerce_order_type) Order types. The order types for which the promotion is valid. Allows unlimited values.
  8. stores: (entity_reference to commerce_store) Stores. The stores for which the promotion is valid. Allows unlimited values.
  9. offer: (commerce_plugin_item:commerce_promotion_offer) Offer type.
  10. conditions: (commerce_plugin_item:commerce_condition) Conditions. Allows unlimited values.
  11. condition_operator: (list_string) Condition operator. The condition operator.
  12. coupons: (entity_reference to commerce_promotion_coupon) Coupons. Coupons which allow promotion to be redeemed. Allows unlimited values.
  13. usage_limit: (integer) Usage limit. The maximum number of times the promotion can be used. 0 for unlimited.
  14. start_date: (datetime) Start date. The date the promotion becomes valid.
  15. end_date: (datetime) End date. The date after which the promotion is invalid.
  16. compatibility: (list_string) Compatibility with other promotions.
  17. status: (boolean) Status. Whether the promotion is enabled.
  18. weight: (integer) Weight. The weight of this promotion in relation to others.
  19. default_langcode: (boolean) Default translation. A flag indicating whether this is the default translation.

Coupon entity

Module: Commerce Promotion (part of commerce module)
Class: Drupal\commerce_promotion\Entity\Coupon

List of base field definitions:

  1. id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. promotion_id: (entity_reference to commerce_promotion) Promotion. The parent promotion.
  4. code: (string) Coupon code. The unique, machine-readable identifier for a coupon.
  5. usage_limit: (integer) Usage limit. The maximum number of times the coupon can be used. 0 for unlimited.
  6. status: (boolean) Status. Whether the coupon is enabled.

Log entity

Module: Commerce Log (part of commerce module)
Class: Drupal\commerce_log\Entity\Log

List of base field definitions:

  1. log_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. uid: (entity_reference to user) User. The user for the log.
  4. template_id: (string) Log template ID. The log template plugin ID
  5. category_id: (string) Log category ID. The log category plugin ID
  6. source_entity_id: (integer) Source entity ID. The source entity ID
  7. source_entity_type: (string) Source entity type. The source entity type
  8. params: (map) Params. A serialized array of parameters for the log template.
  9. created: (created) Created. The time when the log was created.

Price list entity

Module: Commerce Pricelist
Class: Drupal\commerce_pricelist\Entity\PriceList

List of base field definitions:

  1. id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. type: (string) Price list bundle.
  4. uid: (entity_reference to user) Owner. The user that owns this price list.
  5. name: (string) Name. The name of the price list.
  6. stores: (entity_reference to commerce_store) Stores. The stores for which the price list is valid. Allows unlimited values.
  7. customer: (entity_reference to user) Customer. The customer for which the price list is valid.
  8. customer_roles: (entity_reference to user_role) Customer roles. The customer roles for which the price list is valid. Allows unlimited values.
  9. start_date: (datetime) Start date. The date the price list becomes valid.
  10. end_date: (datetime) End date. The date after which the price list is invalid.
  11. weight: (integer) Weight. The weight of this price list in relation to other price lists.
  12. status: (boolean) Status. Whether the price list is enabled.
  13. changed: (changed) Changed. The time when the price list was last edited.

Price list item entity

Module: Commerce Pricelist
Class: Drupal\commerce_pricelist\Entity\PriceListItem

List of base field definitions:

  1. id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. type: (string) Price list item bundle.
  4. uid: (entity_reference to user) Owner. The user that owns this price list item.
  5. price_list_id: (entity_reference to commerce_pricelist) Price list. The parent price list.
  6. purchasable_entity: (entity_reference to commerce_product_variation) Purchasable entity. The purchasable entity.
  7. quantity: (decimal) Quantity. The quantity tier.
  8. list_price: (commerce_price) List price. The list price.
  9. price: (commerce_price) Price. The price.
  10. status: (boolean) Status. Whether the price list item is enabled.
  11. changed: (changed) Changed. The time when the price list item was last edited.

Shipment entity

Module: Shipping
Class: Drupal\commerce_shipping\Entity\Shipment

List of base field definitions:

  1. shipment_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. type: (entity_reference to commerce_shipment_type) Shipment type.
  4. order_id: (entity_reference to commerce_order) Order. The parent order.
  5. package_type: (string) Package type. The package type.
  6. shipping_method: (entity_reference to commerce_shipping_method) Shipping method. The shipping method
  7. shipping_service: (string) Shipping service. The shipping service.
  8. shipping_profile: (entity_reference_revisions) Shipping information.
  9. title: (string) Title. The shipment title.
  10. items: (commerce_shipment_item) Items. Allows unlimited values.
  11. weight: (physical_measurement) Weight.
  12. original_amount: (commerce_price) Original amount. The original amount.
  13. amount: (commerce_price) Amount. The amount.
  14. adjustments: (commerce_adjustment) Adjustments. Allows unlimited values.
  15. tracking_code: (string) Tracking code. The shipment tracking code.
  16. state: (state) State. The shipment state.
  17. data: (map) Data. A serialized array of additional data.
  18. created: (created) Created. The time when the shipment was created.
  19. changed: (changed) Changed. The time when the shipment was last updated.
  20. shipped: (timestamp) Shipped. The time when the shipment was shipped.

Shipping method entity

Module: Shipping
Class: Drupal\commerce_shipping\Entity\ShippingMethod

List of base field definitions:

  1. shipping_method_id: (integer) ID.
  2. uuid: (uuid) UUID.
  3. langcode: (language) Language.
  4. stores: (entity_reference to commerce_store) Stores. The stores for which the shipping method is valid. Allows unlimited values.
  5. plugin: (commerce_plugin_item:commerce_shipping_method) Plugin.
  6. name: (string) Name. The shipping method name.
  7. conditions: (commerce_plugin_item:commerce_condition) Conditions. Allows unlimited values.
  8. condition_operator: (list_string) Condition operator. The condition operator.
  9. weight: (integer) Weight. The weight of this shipping method in relation to others.
  10. status: (boolean) Enabled. Whether the shipping method is enabled.
  11. default_langcode: (boolean) Default translation. A flag indicating whether this is the default translation.

Available properties for other content entities

This reference includes Drupal Commerce content entities and some provided by related contributed modules. The previous article included a reference for Drupal core 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 provided by Drupal Commerce? 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.

 

 

 

 

 

 

 

 

Centro de Tratamiento de Cólera GHESKIO

MASS Design Group

Investigar, construir y defender una arquitectura que promueva la justicia y la dignidad humana.

Sign up to be notified when Agaric gives a migration training:

Learning objectives

  • Step through the Drupal installation process.
  • Create nodes and understand their properties.
  • Create content types and add fields.
  • Configure fields of different types.
  • Create taxonomy vocabularies and terms.
  • Create views to display listings of content.
  • Create, place, and control the visibility of blocks.
  • Override the presentation of nodes with Layout Builder.
  • Understand the user and permission system.
  • Understand the taxonomy system.
  • Understand the menu system.
  • Install and configure contributed modules and themes.
  • Understand how Drupal can be extended to meet specific project needs.

Prerequisites

No previous experience with Drupal is needed.

Setup instructions

A working Drupal 11 installation. You can have a local installation using the quick-start command. Alternatively, you can use a tool like DrupalVM, Lando, DDEV, or Docksal. Online services like https://pantheon.io/ can be used.

This training will be provided over Zoom. You can ask questions via text chat or audio. Sharing your screen, but you might want to do it to get assistance on a specific issue. Sharing your camera is optional.

What to expect

Women looking at map

Prior to the training

Attendees will receive detailed instructions on how to setup their development environment. In addition, they will be able to join a support video call days before the training event to make the the local development environment is ready. This prevents losing time fixing problems with environment set up during the training.

On the days of the training

  • The training totals 7 hours of instruction, which we usually split into 2 sessions
  • A team of developers available to answer questions and help with training-related issues

After the training

  • Attendees will receive a copy of the training recording.
  • Attendees will receive a certificate of completion.

Using a collaborative, co-design process grounded in design justice principles, Agaric will move your website to have mobile-first design, powerful content management capabilities, and built-in accessibility. The site will continually be improved with new features, strengthened security, and more joyous experience of use.

Aproach

Agaric adheres to high standards of collaboration, communication, active client participation, and transparency.

Using design and development processes that center the people who will be affected by the website, a core team from Agaric will work closely with you to define overall goals, key outcomes, and user stories.

Through collaborative design, which will proceed iteratively throughout the project, we will identify and build a minimum viable product, and subject that to a round of feedback and further research. In this context, as Zora Neale Hurston put it, "Research is formalized curiosity. It is poking and prying with a purpose." Critically, this is research with people using the website. We then take what we learned and use that to identify and build the next minimum viable improvement.

This learning is not just for us building the site but for everyone who has a stake in success for the goals for which the site is being built. The learning covers both the website's usability and its effectiveness in reaching your goals, including effectiveness in communicating to colleagues and the general public your values and goals. Ideally, Agaric's research with you and the people who are or will be visiting the site is continuous and collaborative, constantly informing continued development.

In the steps of clarifying need and customizing the solution (leveraging state of the art open source libre software), we prefer to write and work off of user stories that clearly define the website's purpose. This helps ensure that product owners, designers, and developers are on the same page. User stories describe software functionality from the perspective of the person using the software, including motivation or benefit, such as "A visitor can ".

We use an agile methodology to prioritize with you to put critical functionality first, getting a functional website in your hands as soon as possible for review. We continue this iterative and collaborative development cycle, typically in two week sprints, always building the highest impact functionality first.

Comparative analysis

No one is doing exactly what you will do, but identifying quality peers and reviewing their respective content helps you get a wider perspective both on what potential visitors may have seen elsewhere and what seems to be working for others— we can start thinking together about where to emulate and where to differentiate, informing all aspects of building the site to achieve your goals needs.

Content strategy

Building on the review of competitors, Agaric will briefly interview people who should be interacting with your site (from content creators to potential visitors) and develop personas and user stories.

Content style guide

Along with bringing consistency to cooperative output (and saving time sweating the details every time they come up), a good content (copywriting) style guide incorporates suggestions for clear and effective writing and helps your unique aspects shine through. It can help tell your story in a consistent way and help let your individual personalities show through while maintaining collective coherence.

Agaric's content style guide has not received the dedicated attention we recommend for our clients, but can still be a useful starting point for you.

Services

From our discussion and review of your goals and audiences we recommend the following services, to be provided by Agaric in collaboration with the Drutopia cooperative web platform. Our agile method allows for flexibility throughout the project.

The Drutopia initiative builds powerful website software for grassroots groups and offers a Libre Software as a Service platform to make getting a website even easier for these groups. Drutopia members benefit from the collective development and maintenance of the software and platform; currently under the aegis of a not-for-profit, Drutopia plans to grow into its own cooperative.

May First Movement Technology is a non-profit cooperative which builds movements by advancing the strategic use and collective control of technology for local struggles, global transformation, and emancipation without borders. Together, through the cooperative, members buy information technology equipment to run websites, email, email lists, and just about everything else we do on the Internet. Drutopia is hosted on May First infrastructure, and Drutopia members become May First members.

Building on and with these cooperative initiatives, Agaric can focus our energy towards custom design or development that will benefit you.

Included Features

Cutting-Edge Website Capabilities

As a member organization of Drutopia, the your website will automatically gain access to the following features:

  • Configurable homepage - that include but is not limited to any of the following: prominent elevator pitch, recent news feed, featured resources, upcoming events, partner organizations list, and a list of current campaigns.
  • Actions
  • Campaigns
  • Events
  • Fundraising
  • Groups
  • News and/or Blog
  • Profile pages
  • Social media integration
  • SSL (all pages on the site reachable at secure, privacy-protecting https:// URLs)

Highly Secure Internal Tools

In addition to these benefits, we recommend [membership in May First Movement Technology] and will discount your Drutopia membership by the amount of a standard organization membership in May First ($50/year). As a result of this membership, you will gain access to additional services beyond the website, including the following:

  • E-mail boxes and forwards
  • Webmail
  • NextCloud Files and Gallery (similar to Dropbox or Google Drive)
  • OnlyOffice (integrated with NextCloud for online editing of word documents and spreadsheets)
  • NextCloud Calendar and Tasks
  • NextCloud Contacts
  • NextCloud Bookmarks and Notes
Content Strategy and Information Architecture Approach

We will work closely with your team to define an effective content strategy for your website and a clean, scalable information architecture. These will result in the following deliverables:

  • Website goals
  • User personas
  • Content style guide
  • Sitemap
  • Technical architecture
Design Approach

Building off of the content strategy and information architecture work, we will work with your team to provide a compelling a theme that speaks to your audience and reinforces your brand.

We begin with our clean, responsive theme, with the following features baked in:

  • Clean - simple design that puts your content first
  • Secure - covered by the Drupal security team
  • Accessible - works with assistive devices and keyboard-only navigation
  • Responsive - looks beautiful on any device
  • Extensible - well organized templates and Sass (style sheets)

We then identify and implement the customizations that will set your website apart and best tell your story, reflecting the unique voice and tone of your organization.

Development Approach

By leveraging Drutopia, we are able to quickly prototype with your team. After defining the information architecture we turn on all relevant features, and stub out the pages in the sitemap. We put on a collaborative training on how to work with the site and then allow your team to add content, test out the features and make note of any adjustments that would be helpful to the project.

We will then work closely together to prioritize remaining enhancements to be made to the website. Enhancements that do not make it into the initial build are added to our backlog for the Drutopia project as a whole.

Content Migration

Agaric staff will work with the you to move content from an existing website to your .

This plan will consist of manual migration work to move content from existing pages into the new website. Additionally, optional programmatic migration processes are available for moving user data and other content into Drupal. A redirect strategy will also be put in place for pages that are being culled from the old site.

Accessibility

It is critical that your site be accessible to as many people as possible, including those using screen readers. To that end, all of our work is built to support compliance with W3C Web Content Accessibility Guidelines (WCAG) 2.0. The WCAG Guidelines, however, are not comprehensive and so we go beyond those guidelines to ensure high accessibility. Lastly, much of what makes a site accessible happens on the content entry and management side. We will provide resources for your content team so that after the site launches, you can rest assured that what you are creating is reaching as many people as possible.

SEO

Our developers will also follow SEO best-practice development and utilize Drupal's range of SEO-related features that allow administrators to edit page titles, implement human-readable and editable URLs, enter meta tags, and more. For further SEO-related services, we can also recommend SEO consultants.

Drutopia Membership and Continuous Improvements & Support

Launching with a site on Drutopia means more than getting all of the features and functionality Drutopia has to offer. It also means joining a platform cooperative of like-minded people. The cooperative consists of a one member one vote model and an accountable leadership team. Joining the Drutopia platform includes:

  • Secure hosting with timely security updates
  • The ability to request new features and endorse existing ideas
  • Quarterly updates on the project
  • Ability to coordinate with fellow members to crowdfund special development sprints

When joining Drutopia your site launch is not the end, but rather the beginning. Drutopia is in continual communication with all its members about what enhancements team members should work on next. Drutopia's roadmap is public to all so you know where the project is heading.

Agaric, as both your partner in maintaining your website and as a Drutopia partner, is well positioned to help see your priorities become realized.

Deliverables and Budget

Content Strategy documents

Information Architecture

Design

Development

Migrating content into a Drutopia typically takes an additional 10 to 50 hours ($1,500 to $15,000), varying

We are experts in Drupal migrations. We can move content from your old site to your Drutopia site so that you can keep working with all of your old content, all while gaining access to the flexibility and functionality of Drupal.

For a potentially much lower cost option, in four hours ($600) we can make a static archive of your old site, remove interactive features, add a link to the new site, place the old site at a subdomain, and configure your site to allow visitors looking for pages that exist on the old site but not on the new site to pass through and reach the old site.

We do not charge extra for hosting the static site.

Drutopia Membership, Hosting & Services $50/month or $500/year.

There will be no license fees for any software.

Agaric, founded in 2006, is a worker-owned web development cooperative headquartered in Boston (USA), with worker-owners also in Minneapolis and in Managua, Nicaragua. We help organizations meet their goals and strengthen the free software movement by providing consulting in online technology strategy, by building and customizing high quality software, by training people and by speaking at events. We use design justice principles to help your online presence meet your goals and make real world impact. We build with proven software that gives you power and control over your website and online presence. We use and contribute to libre software whenever possible, creative commons license our documentation, and work under an open organization model.

We look forward to creating a better website for building a better world with you!

Thanks for signing up to hear from Agaric on matters involving movements for justice and liberty!

In the previous posts we talked about option to manage migrations as configuration entities and some of the benefits this brings. Today, we are going to learn another useful feature provided by the Migrate Plus module: migration groups. We are going to see how they can be used to execute migrations together and share configuration among them. Let’s get started.

Example definition of a migration group.

Understanding migration groups

The Migrate Plus module defines a new configuration entity called migration group. When the module is enabled, each migration can define one group they belong to. This serves two purposes:

  1. It is possible to execute operations per group. For example, you can import or rollback all migrations in the same group with one Drush command provided by the Migrate Tools module.
  2. It is is possible to declare shared configuration for all the migrations within a group. For example, if they use the same source file, the value can be set in a single place: the migration group.

To demonstrate how to leverage migration groups, we will convert the CSV source example to use migrations defined as configuration and groups. You can get the full code example at https://github.com/dinarcon/ud_migrations The module to enable is UD configuration group migration (CSV source) whose machine name is ud_migrations_config_group_csv_source. It comes with three migrations: udm_config_group_csv_source_paragraph, udm_config_group_csv_source_image, and  udm_config_group_csv_source_node. Additionally, the demo module provides the udm_config_group_csv_source group.

Note: The Migrate Tools module provides a user interface for managing migrations defined as configuration. It is available under “Structure > Migrations” at /admin/structure/migrate. This user interface will be explained in a future entry. For today’s example, it is assumed that migrations are executed using the Drush commands provided by Migrate Plus. In the past we have used the Migrate Run module to execute migrations, but this module does not offer the ability to import or rollback migrations per group.

Creating a migration group

The migration groups are defined in YAML files using the following naming convention: migrate_plus.migration_group.[migration_group_id].yml. Because they are configuration entities, they need to be placed in the config/install directory of your module. Files placed in that directory following that pattern will be synced into Drupal’s active configuration when the module is installed for the first time (only). If you need to update the migration groups, you make the modifications to the files and then sync the configuration again. More details on this workflow can be found in this article. The following snippet shows an example migration group:

uuid: e88e28cc-94e4-4039-ae37-c1e3217fc0c4
id: udm_config_group_csv_source
label: 'UD Config Group (CSV source)'
description: 'A container for migrations about individuals and their favorite books. Learn more at https://understanddrupal.com/migrations.'
source_type: 'CSV resource'
shared_configuration: null

The uuid key is optional. If not set, the configuration management system will create one automatically and assign it to the migration group. Setting one simplifies the workflow for updating configuration entities as explained in this article. The id key is required. Its value is used to associate individual migrations to this particular group.

The label, description, and source_type keys are used to give details about the migration. Their value appear in the user interface provided by Migrate Tools. label is required and serves as the name of the group. description is optional and provides more information about the group. source_type is optional and gives context about the type of source you are migrating from. For example, "Drupal 7", "WordPress", "CSV file", etc.

To associate a migration to a group, set the migration_group key in the migration definition file: For example:

uuid: 97179435-ca90-434b-abe0-57188a73a0bf
id: udm_config_group_csv_source_node
label: 'UD configuration host node migration for migration group example (CSV source)'
migration_group: udm_config_group_csv_source
source: ...
process: ...
destination: ...
migration_dependencies: ...

Note that if you omit the migration_group key, it will default to a null value meaning the migration is not associated with any group. You will still be able to execute the migration from the command line, but it will not appear in the user interface provided by Migrate Tools. If you want the migration to be available in the user interface without creating a new group, you can set the migration_group key to default. This group is automatically created by Migrate Plus and can be used as a generic container for migrations.

Organizing and executing migrations

Migration groups are used to organize migrations. Migration projects usually involve several types of elements to import. For example, book reports, events, subscriptions, user accounts, etc. Each of them might require multiple migrations to be completed. Let’s consider a news articles migration. The "book report" content type has many entity reference fields: book cover (image), support documents (file), tags (taxonomy term), author (user), citations (paragraphs). In this case, you will have one primary node migration that depends on five migrations of multiple types. You can put all of them in the same group and execute them together.

It is very important not to confuse migration groups with migration dependencies. In the previous example, the primary book report node migration should still list all its dependencies in the migration_dependencies section of its definition file. Otherwise, there is no guarantee that the five migrations it depends on will be executed in advance. This could cause problems if the primary node migration is executed before images, files, taxonomy terms, users, or paragraphs have already been imported into the system.

It is possible to execute all migrations in a group by issuing a single Drush with the --group flag. This is supported by the import and rollback commands exposed by Migrate Tools. For example, drush migrate:import --group='udm_config_group_csv_source'. Note that as of this writing, there is no way to run all migrations in a group in a single operation from the user interface. You could import the main migration and the system will make sure that if any explicit dependency is set, they will be run in advance. If the group contained more migrations than the ones listed as dependencies, those will not be imported. Moreover, migration dependencies are only executed automatically for import operations. Dependent migrations will not be rolled back automatically if the main migration is rolled back individually.

Note: This example assumes you are using Drush to execute the migrations. At the time of this writing, it is not possible to rollback a CSV migration from the user interface. See this issue in the Migrate Source CSV for more context.

Sharing configuration with migration groups

Arguably, the major benefit of migration groups is the ability to share configuration among migrations. In the example, there are three migrations all reading from CSV files. Some configurations like the source plugin and header_offset can be shared. The following snippet shows an example of declaring shared configuration in the migration group for the CSV example:

uuid: e88e28cc-94e4-4039-ae37-c1e3217fc0c4
id: udm_config_group_csv_source
label: 'UD Config Group (CSV source)'
description: 'A container for migrations about individuals and their favorite books. Learn more at https://understanddrupal.com/migrations.'
source_type: 'CSV resource'
shared_configuration:
  dependencies:
    enforced:
      module:
        - ud_migrations_config_group_csv_source
  migration_tags:
    - UD Config Group (CSV Source)
    - UD Example
  source:
    plugin: csv
    # It is assumed that CSV files do not contain a headers row. This can be
    # overridden for migrations where that is not the case.
    header_offset: null

Any configuration that can be set in a regular migration definition file can be set under the shared_configuration key. When the migrate system loads the migration, it will read the migration group it belongs to, and pull any shared configuration that is defined. If both the migration and the group provide a value for the same key, the one defined in the migration definition file will override the one set in the migration group. If a key only exists in the group, it will be added to the migration when the definition file is loaded.

In the example, dependencies, migration_tag, and source options are being set. They will apply to all migrations that belong to the udm_config_group_csv_source group. If you updated any of these values, the changes would propagate to every migration in the group. Remember that you would need to sync the migration group configuration for the update to take effect. You can do that with partial configuration imports as explained in this article.

Any configuration set in the group can be overridden in specific migrations. In the example, the header_offset is set to null which means the CSV files do not contain a header row. The node migration uses a CSV file that contains a header row so that configuration needs to be redeclared. The following snippet shows how to do it:

uuid: 97179435-ca90-434b-abe0-57188a73a0bf
id: udm_config_group_csv_source_node
label: 'UD configuration host node migration for migration group example (CSV source)'
# Any configuration defined in the migration group can be overridden here
# by re-declaring the configuration and assigning a value.
# dependencies inherited from migration group.
# migration_tags inherited from migration group.
migration_group: udm_config_group_csv_source
source:
  # plugin inherited from migration group.
  path: modules/custom/ud_migrations/ud_migrations_csv_source/sources/udm_people.csv
  ids: [unique_id]
  # This overrides the header_offset defined in the group. The referenced CSV
  # file includes headers in the first row. Thus, a value of 0 is used.
  header_offset: 0
process: ...
destination: ...
migration_dependencies: ...

Another example would be multiple migrations reading from a remote JSON. Let’s say that instead of fetching a remote file, you want to read a local file. The only file you would have to update is the migration group. Change the data_fetcher_plugin key to file and the urls array to the path to the local file. You can try this with the ud_migrations_config_group_json_source module from the demo repository.

What did you learn in today’s blog post? Did the know that migration groups can be used to share configuration among different migrations? Share your answers in the comments. Also, I would be grateful if you shared this blog post with others.

Next: What is the difference between migration tags and migration groups in Drupal?

This blog post series, cross-posted at UnderstandDrupal.com as well as here on Agaric.coop, is made possible thanks to these generous sponsors. Contact Understand Drupal if your organization would like to support this documentation project, whether it is the migration series or other topics.

Mauricio head photo

If you would like me to speak at your event, et me know the details below.

In recent articles, we have presented some recommendations and tools to debug Drupal migrations. Using a proper debugger is definitely the best way to debug Drupal be it migrations or other substems. In today’s article, we are going to learn how to configure XDebug inside DrupalVM to connect to PHPStorm. First, via the command line using Drush commands. And then, via the user interface using a browser. Let’s get started.

Important: User interfaces tend to change. Screenshots and referenced on-screen text might differ in new versions of the different tools. They can also vary per operating system. This article uses menu items from Linux. Refer the the official DrupalVM documentation for detailed installation and configuration instructions. For this article, it is assumed that VirtualBox, Vagrant, and Ansible are already installed. If you need help with those, refer to the DrupalVM’s installation guide.

Getting DrupalVM

First, get a copy of DrupalVM by cloning the repository or downloading a ZIP or TAR.GZ file from the available releases. If you downloaded a compressed file, expand it to have access to the configuration files. Before creating the virtual machine, make a copy of default.config.yml into a new file named config.yml. The latter will be used by DrupalVM to configure the virtual machine (VM). In this file, make the following changes:

# config.yml file
# Based off default.config.yml
vagrant_hostname: migratedebug.test
vagrant_machine_name: migratedebug
# For dynamic IP assignment the 'vagrant-auto_network' plugin is required.
# Otherwise, use an IP address that has not been used by any other virtual machine.
vagrant_ip: 0.0.0.0

# All the other extra packages can remain enabled.
# Make sure the following three get installed by uncommenting them.
installed_extras:
  - drupalconsole
  - drush
  - xdebug

php_xdebug_default_enable: 1
php_xdebug_cli_disable: no

The vagrant_hostname is the URL you will enter in your browser’s address bar to access the Drupal installation. Set vagrant_ip to an IP that has not been taken by another virtual machine. If you are unsure, you can set the value to 0.0.0.0 and install the vagrant-auto_network plugin. The plugin will make sure that an available IP is assigned to the VM. In the installed_extras section, uncomment xdebug and drupalconsole. Drupal Console is not necessary for getting XDebug to work, but it offers many code introspection tools that are very useful for Drupal debugging in general. Finally, set php_xdebug_default_enable to 1 and php_xdebug_cli_disable to no. These last two settings are very important for being able to debug Drush commands.

Then, open a terminal and change directory to where the DrupalVM files are located. Keep the terminal open are going to execute various commands from there. Start the virtual machine by executing vagrant up. If you had already created the VM, you can still make changes to the config.yml file and then reprovision. If the virtual machine is running, execute the command: vagrant provision. Otherwise, you can start and reprovision the VM in a single command: vagrant up --provision. Finally, SSH into the VM executing vagrant ssh.

By default, DrupalVM will use the Drupal composer template project to get a copy of Drupal. That means that you will be managing your module and theme dependencies using composer. When you SSH into the virtual machine, you will be in the /var/www/drupalvm/drupal/web directory. That is Drupal’s docroot. The composer file that manages the installation is actually one directory up. Normally, if you run a composer command from a directory that does not have a composer.json file, composer will try to find one up in the directory hierarchy. Feel free to manually go one directory up or rely on composer’s default behaviour to locate the file.

For good measure, let’s install some contributed modules. Inside the virtual machine, in Drupal’s docroot, execute the following command: composer require drupal/migrate_plus drupal/migrate_tools. You can also create directory in /var/www/drupalvm/drupal/web/modules/custom and place the custom module we have been working on throughout the series. You can get it at https://github.com/dinarcon/ud_migrations.

To make sure things are working, let’s enable one example modules by executing: drush pm-enable ud_migrations_config_entity_lookup_entity_generate. This module comes with one migration: udm_config_entity_lookup_entity_generate_node. If you execute drush migrate:status the example migration should be listed.

Configuring PHPStorm

With Drupal already installed and the virtual machine running, let’s configure PHPStorm. Start a new project pointing to the DrupalVM files. Feel free to follow your preferred approach to project creation. For reference, one way to do it is by going to "Files > Create New Project from Existing Files". In the dialog, select "Source files are in a local directory, no web server is configured yet." and click next. Look for the DrupalVM directory, click on it, click on “Project Root”, and then “Finish”. PHPStorm will begin indexing the files and detect that it is a Drupal project. It will prompt you to enable the Drupal coding standards, indicate which directory contains the installation path, and if you want to set PHP include paths. All of that is optional but recommended, especially if you want to use this VM for long term development.

Now the important part. Go to “Files > Settings > Language and Frameworks > PHP”. In the panel, there is a text box labeled “CLI Interpreter”. In the right end, there is a button with three dots like an ellipsis (...). The next step requires that the virtual machine is running because PHPStorm will try to connect to it. After verifying that it is the case, click the plus (+) button at the top left corner to add a CLI Interpreter. From the list that appears, select “From Docker, Vagrant, VM, Remote...”. In the “Configure Remote PHP Interpreter” dialog select “Vagrant”. PHPStorm will detect the SSH connection to connect to the virtual machine. Click “OK” to close the multiple dialog boxes. When you go back to the “Languages & Frameworks” dialog, you can set the “PHP language level” to match the same version from the Remote CLI Interpreter.

Remote PHP interpreter.

CLI interpreters.

You are almost ready to start debugging. There are a few things pending to do. First, let’s create a breakpoint in the import method of the MigrateExecutable class. You can go to “Navigate > Class” to the project by class name. Or click around in the Project structure until you find the class. It is located at ./drupal/web/core/modules/migrate/src/MigrateExecutable.php in the VM directory. You can add a breakpoint by clicking on the bar to the left of the code area. A red circle will appear, indicating that the breakpoint has been added.

Then, you need to instruct PHPStorm to listen for debugging connections. For this, click on “Run > Start Listening for PHP Debugging Connections”. Finally, you have to set some server mappings. For this you will need the IP address of the virtual machine. If you configured the VM to assign the IP dynamically, you can skip this step momentarily. PHPStorm will detect the incoming connection, create a server with the proper IP, and then you can set the path mappings.

Triggering the breakpoint

Let’s switch back to the terminal. If you are not inside the virtual machine, you can SSH into the VM executing vagrant ssh. Then, execute the following command (everything in one line):

XDEBUG_CONFIG="idekey=PHPSTORM" /var/www/drupalvm/drupal/vendor/bin/drush migrate:import udm_config_entity_lookup_entity_generate_node

For the breakpoint to be triggered, the following needs to happen:

  • You must execute Drush from the vendor directory. DrupalVM has a globally available Drush binary located at /usr/local/bin/drush. That is not the one to use. For debugging purposes, always execute Drush from the vendor directory.
  • The command needs to have XDEBUG_CONFIG environment variable set to “idekey=PHPSTORM”. There are many ways to accomplish this, but prepending the variable as shown in the example is a valid way to do it.
  • Because the breakpoint was set in the import method, we need to execute an import command to stop at the breakpoint. The migration in the example Drush command is part of the example module that was enabled earlier.

When the command is executed, a dialog will appear in PHPStorm. In it, you will be asked to select a project or a file to debug. Accept what is selected by default for now.  By accepting the prompt, a new server will be configured using the proper IP of the virtual machine.  After doing so, go to “Files > Settings > Language and Frameworks > PHP > Servers”. You should see one already created. Make sure the “Use path mappings” option is selected. Then, look for the direct child of “Project files”. It should be the directory in your host computer where the VM files are located. In that row, set the “Absolute path on the server” column to  /var/www/drupalvm. You can delete any other path mapping. There should only be one from the previous prompt. Now, click “OK” in the dialog to accept the changes.

Incoming Drush connection.

Path mappings

Finally, run the Drush command from inside the virtual machine once more. This time the program execution should stop at the breakpoint. You can use the Debug panel to step over each line of code and see how the variables change over time. Feel free to add more breakpoints as needed. In the previous article, there are some suggestions about that. When you are done, let PHPStorm know that it should no longer listen for connections. For that, click on “Run > Stop Listening for PHP Debugging Connections”. And that is how you can debug Drush commands for Drupal migrations.

Path mappings.

Debugging from the user interface

If you also want to be able to debug from the user interface, go to this URL and generate the bookmarklets for XDebug: https://www.jetbrains.com/phpstorm/marklets/ The IDE Key should be PHPSTORM. When the bookmarklets are created, you can drag and drop them into your browser’s bookmarks toolbar. Then, you can click on them to start and stop a debugging session. The IDE needs to be listening for incoming debugging connections as it was the case for Drush commands.

PHPStorm bookmarlets generator

Note: There are browser extensions that let you start and stop debugging sessions. Check the extensions repository of your browser to see which options are available.

Finally, set breakpoints as needed and go to a page that would trigger them. If you are following along with the example, you can go to http://migratedebug.test/admin/structure/migrate/manage/default/migrations/udm_config_entity_lookup_entity_generate_node/execute Once there, select the “Import” operation and click the “Execute” button. This should open a prompt in PHPStorm to select a project or a file to debug. Select the index.php located in Drupal’s docroot. After accepting the connection, a new server should be configured with the proper path mappings. At this point, you should hit the breakpoint again.

Incoming web connections.

 

Happy debugging! :-)

What did you learn in today’s blog post? Did you know how to debug Drush commands? Did you know how to trigger a debugging session from the browser? Share your answers in the comments. Also, I would be grateful if you shared this blog post with others.

And don't miss the final blog post in the series, on the many modules available for migrations to Drupal.

This blog post series, cross-posted at UnderstandDrupal.com as well as here on Agaric.coop, is made possible thanks to these generous sponsors: Drupalize.me by Osio Labs has online tutorials about migrations, among other topics, and Agaric provides migration trainings, among other services.  Contact Understand Drupal if your organization would like to support this documentation project, whether it is the migration series or other topics.

Thank you for being awesome!  Use this page to register with your discount. If you want to attend more than one training, fill out the form once per training.

The contextual filter configuration screen.

Quick and dirtiest

mkdir ~/sandbox
cd ~/sandbox

Now copy the four commands beginning with php from the top of Composer's quick install documentation. Paste them into the terminal in your sandbox directory. It's best to use Composer's commands, which they update to verify the hash after every release, which is why we don't have the commands for you to copy here. Once that is done, continue:

php composer.phar create-project drupal-composer/drupal-project:8.x-dev just-drupal --no-interaction
cd just-drupal
php ../composer.phar require drush/drush

If that works, you're good to go!

To use Drush:

vendor/bin/drush

To start PHP's built-in webserver and see the site, use:

php web/core/scripts/drupal quick-start standard

If it works, it will install Drupal with the Standard installation profile and log you in, opening your local site in your browser. Your terminal window, meanwhile, is dedicated to running the server. Open a new tab in your terminal, at the same location (cd ~/sandbox/just-drupal in our example) to be able to run more composer or other commands.

In the migration training for instance we have people use composer to get the code for the address module, so from ~/sandbox/just-drupal in our example we would run:

php ../composer.phar require drupal/address

And to enable the address module downloaded just above:

vendor/bin/drush en address

Note that the site must be 'running' with the php web/core/scripts/drupal quick-start command you can run at any time to get things started and log back in (don't worry if you get "Access Denied" while also seeing the administration menu (starting with "Manage" at the top left of your screen; this just means you were already logged in).

Caveat

This minimalist approach might not work either for your computer! If it doesn't, there may be more PHP things to install. For instance, if you run into an error about SQLite, you may need to enable or install SQLite with PHP first.  We'll update this blog post with further fixes and workarounds as they come up for our content migration or other training students.

Quick and just slightly polished

You may have noticed that typing php ../composer.phar and vendor/bin/drush is pretty ugly. This can be fixed while retaining essentially the same setup as above by installing Composer globally (for GNU/Linux and Mac OS X, or with the Windows installer for Microsoft Windows) and installing the Drush launcher. Once you've done that, you'll be able to use composer instead of php ../composer.phar and drush instead of vendor/bin/drush.

Warning and reminder

This is for a local development environment or sandbox testing site only!  PHP's built-in server, which is relied upon in the above, is absolutely not intended to be used in production environments.  Neither, for Drupal, is SQLite, which we're also using.  To repeat, this is not meant to be used live!

Prior art

Updated.  I knew it was out there, but didn't find this when i started writing.  This is very similar in approach to an article last year by MediaCurrent celebrating this capability coming to Drupal.  The main difference is that in our blog post here we use the Composer template for Drupal 8 projects.  This avoids having Git as a requirement (but you should always develop by committing to Git!) and also starts with a best-practices composer setup.  Distributions like Drutopia take the same approach.

Estudiantes marchando en la calle por la huelga climática.

350.org

Equipar a activistas de justicia climática con herramientas de movilización.