Skip to main content

Blog

We will send you very occasional dispatches from our perspective on various overlapping movements for cooperation, freedom and justice as workers and as passionate observers.

Get the most out of (and into) your page cache: Leave AJAX disabled in your Views, especially with exposed filters

Enabling AJAX for a Views page can have a performance-harming side effect one might not think of. On a recently built site we observed a relatively low Varnish cache hit rate of 30% using the Munin plugin for Varnish. This hit rate was much lower than expected after prelaunch tests with Jmeter. (The site has almost exclusively anonymous visitors and if caching the pages worked efficiently the same low cost server could handle a lot more traffic.)

An analysis of the most visited paths on the live site showed one ranking two orders of magnitude above all else: views/ajax.

The Views pages on Studio Daniel Libeskind have exposed filters, and with AJAX enabled new data is fetched via POST request to views/ajax when a visitor applies a filter. This happens because the Drupal AJAX Framework leveraged by views exclusively uses POST requests. See issue Ensure it is possible to use AJAX with GET requests for a good explanation of why it is currently this way and the effort to allow GET requests in later versions of Drupal.

As a consequence of all AJAX views using the same path and all filter information being hidden in the request body, Varnish has no straightforward means of caching the content coming from views/ajax. Another downside: It's not easy to share a link to a filtered version of such a page.

If AJAX is not enabled (which is the default) filters are implemented as query parameters in the URL so there's a unique URL for each filtered page. That plays well with reverse proxy caches like Varnish and works well for people wanting to share links, so we disabled AJAX again and the Varnish page cache hit rate has risen to over 90% since.

Presentations and Workshops:

2020

  • Boston College online interview on AI and Free Software
  • WMBR - Online interview on Free Software solutions for communications
  • Platform Cooperative Ideathon
  • MayFirst Need to Know Series

2019

2018

2017

  • Open.coop 2017 - London University, London, UK
    • Panel: Empowering digital collaboration: Introducing the open app ecosystem
    • Workshop: Designing interoperable apps for the open app ecosystem

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

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.

 

 

 

 

 

 

 

 

The movements and networks that Micky is a part of

Here are all the links from the slide Micky told you not to try to write everything down from.

Agarics are members of a few networks and movements both local and global:

Additional groups and movements

And some that didn't make the slides, that other Agarics are a part of:

The Agaric team sitting in front of Seattle's iconic "black hole" statue with our hands on each other's shoulders. Ben, in character, placing his hand on a non-existent person's shoulder next to him.

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 9 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!

Libre Planet 2019.

LibrePlanet is an annual conference hosted by the Free Software Foundation for free software enthusiasts and anyone who cares about the intersection of technology and social justice. We've attended and spoken at LibrePlanet many times over the year. This year's theme is "Trailblazing Free Software" and in that spirit Micky is speaking on the Orwellian future that has arrived and what tech justice movements we should be supporting and joining to fight for a freedom-loving, solidarity-based future.

LibrePlanet Keynote: How can we prevent the Orwellian 1984 digital world?
Sunday, March 24th
5:15pm-6:00pm
Stata Center, Massachusetts Institute of Technology Room 32-123
Cambridge, MA

We are living in a society where -- as mere individuals -- it seems out of our control and in the hands of those who have the power to publish and distribute information swiftly and widely, or who can refuse to publish or distribute information. Algorithms now sort us into Global databases like PRISM or ECHELON, and there are devices such as StingRay cell phone trackers used to categorize our every movement. We may build our own profiles online, but we do not have access to the meta-profile built by the corporate entities that our queries traverse as we navigate online, purchasing goods and services as well as logging into sites where we have accounts. The level of intrusion into our most private thoughts should be alarming, yet most fail to heed the call as they feel small, alone, and unable to defy the scrutiny of disapproval from the powers that govern societal norms and their peers. Together, we can change this.

Micky will engage your mind on a journey to open an ongoing discussion to rediscover and reawaken your own creative thought processes. Together, we build a conversation that should never end as it will join us together transparently maintaining our freedoms, with free software as the foundation. Where do we find our personal power, and how do we use it as developers? Do we have a collective goal? Have you checked your social credit rating lately? Others have.

 

Timeline of trainings

Sea turtle as the bat-signal Batman logo.

Training: Upgrading to Drupal 8 & Drupal 9

From Drupal 6 or Drupal 7 using the Migrate API

Surviving a civil war has a way of making a person focus on the present. Putting in a solid day of work and taking time with family tend to come before putting items on an agenda for a board meeting, even if one owns the company.

Most of the 30 workers at Brookline-based A Yard and a Half Landscaping, who have chosen to take ownership of their company and transform it into a cooperative, are immigrants from El Salvador. From 1980 to 1992, El Salvador endured a civil war in which 80,000 people died—more than two percent of the population—including many, many noncombatants, most killed by the US- and oligarch-backed anti-Communist military government. The violence still echoes.

The Yard and a Half landscapers are laying a new path of owning and managing the company themselves. To do so successfully, they must cultivate a culture of involvement in decision-making. Carolyn Edsell-Vetter is the first CEO and President of A Yard and a Half Landscaping Cooperative after its transition from ownership by its founder. Carolyn, who was the featured speaker at the Boston worker coop meetup on November 17, is determined to work herself out of presidency of the board. Along with ownership, all worker-owners must take on more leadership roles, including board officerships (all worker-owners are already on the board of directors).

For many at the meetup, the challenges Carolyn recounted about making a cooperative work matched experiences of our own, even though none of the rest of us were part of a transition from a non-coop company. Indeed, those of us in and out of cooperatives found much to discuss, from democracy to dollars.

People at the worker-owner meetup.

How we talk about work and other things in worker-owned cooperatives was itself a topic of interest. Part of this is treating everyone with respect and trying to remove oppressive language, words and phrases or statements that intentionally or unintentionally reinforce racism, sexism, classism, ableism, and gender conformity.

"We spend about 30 minutes a working day working on our language," said James Bachez of Boston Collective Delivery, "and not the lunch hour." Collective organization calls for a "whole new language just beginning to understand." James stood up and paced while he thought and spoke. "Capitalist businesses talk about culture all the time," as something set from the top. Company culture is key for cooperatives too, but it comes from everyone. "The coop develops its culture. It's there. Whatever bubbles up to the top. I feel far more effective as part of a cooperative."

Most agreed that working on communication needs to be a constant, conscious effort. Collaboration, like other skills, should not be left to chance. Carolyn's praise of the AORTA Collective for its help with cooperative assistance was echoed by other cooperatives in attendance. Carolyn further thanked the Boston Interpreters Collective for making multilingual workshops possible.

The business of co-owning a business calls for financial literacy for all workers, too. "Everyone needs to know how to read a P&L", said Carolyn, referring to a statement that shows the profit and loss of a business. Used to see and estimate sales and expenses, it is fundamental to understanding any business's financial health.

We talked a great deal about fair compensation and balancing effort and types of work. A Yard and A Half does not have the same pay rate for all workers, and exactly what to pay everyone "has been really contentious. We inherited the wage structure from the previous owner," said Carolyn. They wanted their starting wages to be higher, but now people coming in can get almost as much as a crew leader who has been working for ten years. Either all pay rates have to bump up proportionately, or pay differentials have to flatten and everyone needs to be all right with that. "Thirty-five percent of cost to field labor would make us uncompetitive."

People at the worker-owner meetup.

Like Carolyn, most felt there could be fair tiered systems in cooperatives, but no one felt they had one permanent answer. "This is how worker cooperatives reconcile the valuation of our labor in a capitalist system," said James, "while building something new." Most felt equal pay to be a good goal, but also that more experience, more responsibility, or just doing boring work no one else wanted to do could all justify more money. Sharing skills and sharing different kinds of work might be ideal, but isn't always practical and different work can be treated differently to have an overall just outcome. One attendee said she learned in Argentina that retirement age for physical labor is set lower, at 50 years.

Whatever the pay, there's no replacement for enjoying what one does. "Landscaping, you just have to love it," Carolyn said, "to make it through one season. We've had people come to [start their first day of] work and turn in their work clothes at lunch break." For those who like all that physical work, changing landscapes, making things beautiful, are extremely worthwhile.

A final big topic we talked about was hierarchy. A cooperative does not mean you don't have one person in charge of certain domains. Hierarchies help accomplish specific tasks efficiently, but they need not be permanent, and the structure adopted for a specific purpose or project in a cooperative is "a consensual hierarchy".

As interesting as our common ground was, the transition-specific experiences were also fascinating. A Yard and a Half has some great advantages coming from a transition— an established, profitable business and the passed-on wisdom from their founder, including advice which Carolyn said they are just beginning to recognize the truth of: "You either have to grow or you'll lose ground." The clientele is largely friendly to the progressive business that was built and the worker cooperative that it has become: hippies done good, people who want their kids or grandkids to be able to run around on the grass and eat dirt without being poisoned, thanks to a decision to stop using chemical pesticides and adopt organic practices.

Unexpected challenges of A Yard and a Half's transition to a cooperative corporation included having to re-establish the company's credit. Some businesses wanted personal guarantees from all of the owners for debts. They had to discuss and ultimately accept that some worker-owners—with homes and credit cards—were putting more at risk than others.

Transitioning from a hierarchical structure or creating a new worker cooperative both mean learning to self-govern. It is work that all in attendance recognized as hard but affirmed as worthwhile. Worker cooperatives offer control over our own work, increased control over our lives, and the promise of, perhaps, an economic base that can support collective liberty and justice.

A Yard and a Half Landscaping was not the only inspiring worker-owned cooperative we got to learn about that night. Boston Collective Delivery is one of three cooperatives in a fledgling federation that plans to grow, and in five years or so apply to be accepted into Mondragon, the largest federation of worker-owned cooperatives in the world— but we hope to learn and write about more on that later. There's no reason for you to wait if you're anywhere near Boston though! Meetup coordinator Micky Metts, James, many other attendees, and many more look forward to meeting interested people at WORC'N's holiday party this evening at Industry Lab. Join the meetup group for notice of new events or the WORC'N discussion list for discussion of worker cooperatives in the Boston area, including notice of these meetups.