Love Huria: Creating your own React Boilerplate – For Beginners

Well, It’s been a while working on React, still learning and it feels pretty awesome. We all understand how important it is to interpret the basic concepts before we set our path to work with any framework or library.

Usually what happens, even as a beginner we tend to jump on things without understanding how it works, to see the practical usage, fancy stuff etc and hey You are not alone!

But sometimes, it’s good to come back on time and try to understand the underlying pieces. There are tons of boilerplates available which are really helpful to kickstart…

Community Working Group posts: Balancing Accountability and Compassion in the Drupal Community

“For me, forgiveness and compassion are always linked: how do we hold people accountable for wrongdoing and yet at the same time remain in touch with their humanity enough to believe in their capacity to be transformed?”

–bell hooks

One of the questions that we hear regularly at the Drupal Community Working Group (CWG) is how we handle people who have been banned from various spaces in the Drupal community for violations of our community Code of Conduct.

As our conflict resolution policy and process states, one of the potential actions that the CWG can take is to impose permanent or temporary bans from some or all Drupal community spaces, which may be both physical (DrupalCamps and other meetups) and virtual (community Slack channels,, etc.).

While we work to avoid bans whenever possible, sometimes they are unavoidable as an individual’s behavior can have impacts that go far beyond just those individuals who may be directly involved. While the CWG’s original charter focused on interpersonal conflicts, the updated version we adopted at the end of last year makes it clear that the group’s primary responsibility is for the overall health of the community, which means that we need to consider the impact of a person’s ongoing participation on others in the community, not just on those who may have raised concerns.

In those cases where an individual is banned, we keep records in case they need to be reviewed in the future or additional action is required. However, we do not maintain a comprehensive “master list” of banned individuals.

If and when the CWG needs to issue an indefinite ban (or when an individual chooses to leave the community on their own, rather than working with us), we always let the individual involved know that they can reach out to us at any time. We generally try to avoid using the term “permanent ban”, as we recognize that people can transform and change over time; however, we are clear that indefinite bans remain in effect until such time as we agree to lift them, and that any attempts to circumvent bans may result in additional action.

On those occasions when a banned individual reaches out to us expressing interest in rejoining the community, we begin an established process where we start by examining the situation very carefully before agreeing to proceed. This involves reviewing the individual’s past history and the interactions they have had with other community members since their ban, as well as reaching out to those who have filed past reports and/or others who we are aware may have been impacted by this person’s past words and actions to get their feedback. If we are aware that the individual has already taken action in both public and private settings to address their past behavior before coming to us, that is a very positive sign.

To be clear, however, what we are looking for is for the individual to not just show remorse or regret for their actions, but also demonstrate a commitment to address and repair the damage their past behavior has caused. They need to be willing to take responsibility for their words and actions and the impact they have on others. In addition to demonstrating the ability to hold themselves accountable, they must also agree to allow others in the community to hold them accountable. If the CWG is not confident that these conditions can be met, we will not proceed further, instead recommending that the individual engage in additional reflection before coming back to us.

If and when we agree that the individual is ready to move forward with reintegration into the community, the next step is to collaboratively develop an action plan with clear goals and milestones. This plan must not only satisfy the questions and concerns that have been raised by others, but also include safeguards to address any potential for relapses in negative behavior, such as regular check-ins with the CWG and/or others and limitations in access to various Drupal community spaces. As the individual continues to demonstrate consistently positive behavior and is able to re-establish trust with more members of the community, they may gain additional access and privileges over time. However, if they engage in behavior that violates the Code of Conduct at any point in the process, they remain subject to immediate reinstatement of previous bans and/or other actions.

This process is difficult and hard, and it’s not for everyone. We understand that, and we don’t blame anyone who chooses to walk away. For those who are willing to be open and vulnerable, face their mistakes head on, and learn from them, we’re there every step of the way. As our values and principles state, “The expectation of leaders is not that they are perfect or have years of experience. The expectation of leaders is that they learn from their mistakes, rise to the challenge, support others ahead of their own needs or ego, and continuously work to improve themselves.”

Drupal Association blog: DrupalCon Amsterdam – Marketing Contribution on October 31

The Promote Drupal team invites you to take part in a 15 minute 1:1 interview contributing to growing our understanding of your needs during the evaluation process. 
We have made great strides with the Promote Drupal initiative to provide product and project information resources that highlight the value of Drupal in helping enterprises and agencies leverage an open source CMS platform for their businesses. We want to learn from you in order to continue to deliver a project that offers significant value and that meets organizations’ needs.  

Calling all members of the Drupal Community

The Promote Drupal team invites you to also take part in a 15 minute 1:1 interview contributing to growing our understanding of your marketing needs. From agencies to developers, we value your insight as we work to advance the Promote Drupal initiative. We have made great strides with this initiative, including:

Come with your ideas, thoughts on the initiative and where you think our focus should be for the next 12 months!

Texas Creative: Drupal 8 Basic Media and Media Browser Setup for beginners

This is a beginner’s tutorial that will quickly get you up and running with media entities and a media entity browser in Drupal 8.

One of the best parts of Drupal 8 is the in-core feature of media entities. This allows Drupal to manage resources that otherwise it would not be able to. It accomplishes this by creating a bridge relationship between Drupal’s CMS, media files and external sources. It’s basically an entity referencing all kinds of media files like images, videos, documents or other external sources like Tweets, embed videos, etc.

Read More

Texas Creative: Basic Migration of File Fields to Media Entities Fields in Drupal 8

The Migrate File to Media module provides an easy way to migrate old file fields like images, files, videos, etc, into the media entities with a few drush commands.

So you can have an understanding of how the migration process works, In this tutorial, we will run through a few quick step-by-step instructions on how to migrate specific image field types to image entity reference fields.

Media Module

The core media module is what creates the “media” entity types. If you haven’t set this up yet, or if you are not too familiar with media entity setup, I highly recommend following this tutorial “Drupal 8 Basic Media And Media Browser Setup For Beginners”, before you continue with this tutorial. 

Read More

Jacob Rockowitz: Deploying an enterprise Drupal website with minimal downtime

When it comes to slow and broken digital user experiences, none of us has any patience. When someone can’t access a website to get the information they need, they click the browser’s back button and move on to the next link in their search results. Drupal has continually improved performance by adding a powerful cache management layer to Drupal 8. Meanwhile, any time database changes are deployed to a Drupal website, the recommended and default behavior is to display the below maintenance page across the entire website including the homepage.

There are technical reasons why Drupal’s maintenance page exists – end-users don’t care about the technical reasons behind a maintenance page. End-users come to a website to get information. To their minds, if they can’t get this information immediately (from their perspective) the website is broken. Sure, the maintenance page can provide some more information and reasons why the website is unavailable. Still, a website’s digital door is temporarily shut. The expectation is that the internet superhighway is available 24/7, yet in the Drupal community we are okay with a little downtime every week or so.

Why does maintenance mode exist?

The best metaphor as to why Drupal needs to display a maintenance page when deploying code and database changes is…

Putting a Drupal site in maintenance mode is part of the steps to updating core, modules, and themes. Drush, Drupal’s command-line interface, automatically switches a site into maintenance mode when deploying database changes.

Drupal’s maintenance mode has been around since Drupal…Read More

Spinning Code: Drupal Salesforce Suite Custom Field Mapping Types

The Drupal 8 Salesforce Suite allows you to map Drupal entities to Salesforce objects using a 1-to-1 mapping. To do this it provides a series of field mapping types that allow you to select how you want to relate the data between the two systems. Each field type provides handling to help ensure the data is handled correctly on each side of the system.

As of this writing the suite provides six usable field mapping types:

  • Properties — The most common type to handle mapping data fields.
  • Record Type — A special handler to support Salesforce record type settings when needed.
  • Related IDs — Handles translating SFIDs to Drupal Entity IDs when two objects are related in both systems.
  • Related Properties — For handling properties across a relationship (when possible).
  • Constant — A constant value on the Drupal side that can be pushed to Salesforce.
  • Token — A value set via Drupal Token.

There is a seventh called Broken to handle mappings that have changed and need a fallback until its fixed. The salesforce_examples module also includes a very simple example called Hardcoded the shows how to create a mapping with a fixed value (similar to, but less powerful than, Constant field).

These six handle the vast majority of use cases but not all.  Fortunately the suite was designed using Drupal 8 annotated plugins , so you can add your own as needed. There is an example in the suite’s example module, and you can review the code of the ones that are included, but I think some people would find an overview helpful.

As an example I’m using the plugin I created to add support for related entities to the webform submodule of the suite (I’m referencing the patch in #10 cause that’s current as of this writing, but you should actually use whatever version is most recent or been accepted).

Like all good annotated plugins to tell Drupal about it all we have to do is create the file in the right place. In this case that is: [my_module_root]/src/Plugins/SalesforceMappingField/[ClassName] or more specifically: salesforce_webform/src/Plugin/SalesforceMappingField/WebformEntityElements.php

At the top of the file we need to define the namespace, add some use statements.

Next we need to provide the required annotation for the plugin manager to use. In this case it just provides the plugin’s ID, which needs to be unique across all plugins of this type, and a translated label.

 * Adapter for Webform elements.
 * @Plugin(
 *   id = "WebformEntityElements",
 *   label = @Translation("Webform entity elements")
 * )

Now we define the class itself which must extend SalesforceMappingFieldPluginBase.

class WebformEntityElements extends SalesforceMappingFieldPluginBase {

With those things in place we can start the real work.  The mapping field plugins are made up of a few parts: 

  • The configuration form elements which display on the mapping settings edit form.
  • A value function to provide the actual outbound value from the field.
  • Nice details to limit when the mapping should be used, and support dependency management.

The buildConfigurationForm function returns an array of form elements. The base class provides some basic pieces of that array that you should plan to use and modify. So first we call the function on that parent class, and then make our changes:

   * {@inheritdoc}
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $pluginForm = parent::buildConfigurationForm($form, $form_state);
    $options = $this->getConfigurationOptions($form['#entity']);
    if (empty($options)) {
      $pluginForm['drupal_field_value'] += [
        '#markup' => t('No available webform entity reference elements.'),
    else {
      $pluginForm['drupal_field_value'] += [
        '#type' => 'select',
        '#options' => $options,
        '#empty_option' => $this->t('- Select -'),
        '#default_value' => $this->config('drupal_field_value'),
        '#description' => $this->t('Select a webform entity reference element.'),
    // Just allowed to push.
    $pluginForm['direction']['#options'] = [
      MappingConstants::SALESFORCE_MAPPING_DIRECTION_DRUPAL_SF => $pluginForm['direction']['#options'][MappingConstants::SALESFORCE_MAPPING_DIRECTION_DRUPAL_SF],
    $pluginForm['direction']['#default_value'] =
    return $pluginForm;

In this case we are using a helper function to get us a list of entity reference fields on this plugin (details are in the patch and unimportant to this discussion). We then make those fields the list of Drupal fields for the settings form. The array we got from the parent class already provides a list of Salesforce fields in $pluginForm[‘salesforce_field’] so we don’t have to worry about that part.  Since the salesforce_webform module is push-only on its mappings, this plugin was designed to be push only as well, and so limits to direction options to be push only. The default set of options is:    

'#options' => [
    MappingConstants::SALESFORCE_MAPPING_DIRECTION_DRUPAL_SF => t('Drupal to SF'),
    MappingConstants::SALESFORCE_MAPPING_DIRECTION_SF_DRUPAL => t('SF to Drupal'),
    MappingConstants::SALESFORCE_MAPPING_DIRECTION_SYNC => t('Sync'),

And you can limit those anyway that makes sense for your plugin.

With the form array completed, we now move on to the value function. This is generally the most interesting part of the plugin since it does the work of actually setting the value returned by the mapping.

   * {@inheritdoc}
  public function value(EntityInterface $entity, SalesforceMappingInterface $mapping) {
    $element_parts = explode('__', $this->config('drupal_field_value'));
    $main_element_name = reset($element_parts);
    $webform = $this->entityTypeManager->getStorage('webform')->load($mapping->get('drupal_bundle'));
    $webform_element = $webform->getElement($main_element_name);
    if (!$webform_element) {
      // This reference field does not exist.
    try {
      $value = $entity->getElementData($main_element_name);
      $referenced_mappings = $this->mappedObjectStorage->loadByDrupal($webform_element['#target_type'], $value);
      if (!empty($referenced_mappings)) {
        $mapping = reset($referenced_mappings);
        return $mapping->sfid();
    catch (Exception $e) {
      return NULL;

In this case we are finding the entity referred to in the webform submission, loading any mapping objects that may exist for that entity, and returning the Salesforce ID of the mapped object if it exists.  Yours will likely need to do something very different.

There are actually two related functions defined by the plugin interface, defined in the base class, and available for override as needed for setting pull and push values independently:

   * An extension of ::value, ::pushValue does some basic type-checking and
   * validation against Salesforce field types to protect against basic data
   * errors.
   * @param DrupalCoreEntityEntityInterface $entity
   * @param Drupalsalesforce_mappingEntitySalesforceMappingInterface $mapping
   * @return mixed
  public function pushValue(EntityInterface $entity, SalesforceMappingInterface $mapping);
   * An extension of ::value, ::pullValue does some basic type-checking and
   * validation against Drupal field types to protect against basic data
   * errors.
   * @param DrupalsalesforceSObject $sf_object
   * @param DrupalCoreEntityEntityInterface $entity
   * @param Drupalsalesforce_mappingEntitySalesforceMappingInterface $mapping
   * @return mixed
  public function pullValue(SObject $sf_object, EntityInterface $entity, SalesforceMappingInterface $mapping);

But be careful overriding them directly. The base class provides some useful handling of various data types that need massaging between Drupal and Salesforce, you may lose that if you aren’t careful. I encourage you to look at the details of both pushValue and pullValue before working on those.

Okay, with the configuration and values handled, we just need to deal with programmatically telling Drupal when it can pull and push these fields. Most of the time you don’t need to do this, but you can simplify some of the processing by overriding pull() and push() to make sure the have the right response hard coded instead of derived from other sources. In this case pulling the field would be bad, so we block that:

   * {@inheritdoc}
  public function pull() {
    return FALSE;

Also, we only want this mapping to appear as an option if the site has the webform module enabled. Without it there is no point in offering it at all. The plugin interface provides a function called isAllowed() for this purpose:

   * {@inheritdoc}
  public static function isAllowed(SalesforceMappingInterface $mapping) {
    return Drupal::service('module_handler')->moduleExists('webform');

You can also use that function to limit a field even more tightly based on the mapping itself.

To further ensure the configuration of this mapping entity defines its dependencies correctly we can define additional dependencies in getDependencies(). Again here we are tied to the Webform module and we should enforce that during and config exports:

   * {@inheritdoc}
  public function getDependencies(SalesforceMappingInterface $mapping) {
    return ['module' => ['webform']];

And that is about it.  Once the class exists and is properly setup, all you need to do is rebuild the caches and you should see your new mapping field as an option on your Salesforce mapping objects (at least when isAllowed() is returning true).