How to programmatically check Generate automatic URL alias

Components

If you want to programmatically check the Pathauto's Generate automatic URL alias checkbox you can do something like this:

use Drupal\pathauto\PathautoState;

$entity_type = 'node';
$entity_storage = \Drupal::entityTypeManager()->getStorage($entity_type);
$nodes = $entity_storage->loadMultiple();

foreach($nodes as $node) {
  $node->path->pathauto = PathautoState::CREATE;
  $node->save();
}

For terms just change the entity type to this:

$entity_type = 'taxonomy_term';

To uncheck the field instead of CREATE use SKIP constant:

$node->path->pathauto = PathautoState::SKIP;

In summary, the code snippets provided outline the process of programmatically toggling the automatic URL alias generation feature in Drupal using the Pathauto module. 

How to programmatically render entity form

Components

Programatically rendering entity form in Drupal 8, 9 and 10 is easy, provided that you want to render it using the default form mode.

// Load existing node
$node = \Drupal\node\Entity\Node::load(1);
// or create a new node
$node = \Drupal::entityTypeManager()->getStorage('node')->create(['type' => 'article']);

$form = \Drupal::service('entity.form_builder')->getForm($node);

If you want to render it using any other form mode like this for example:

$node = \Drupal\node\Entity\Node::load(1);
$form = \Drupal::service('entity.form_builder')->getForm($node, 'compact');

you will have to alter the entity definition and add your own form handler. Otherwise, you'll get the following error:

Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException: The "node" entity type did not specify a "compact" form class.

To add your own form class you can use the hook_entity_type_alter hook like this:

/**
 * Implements hook_entity_type_alter().
 *
 * Alters the entity definition and adds our own form handlers.
 */
function MY_MODULE_entity_type_alter(array &$entity_types) {
  $form_modes = \Drupal::service('entity_display.repository')
    ->getAllFormModes();

  foreach ($form_modes as $entity_type => $display_modes) {
    if ($entity_type !== 'node') {
      continue;
    }

    $type = $entity_types[$entity_type];
    foreach ($display_modes as $machine_name => $form_display) {
      if (isset($type->getHandlerClasses()['form']['default'])) {
        $default_handler_class = $type->getHandlerClasses()['form']['default'];
        $type->setFormClass($machine_name, $default_handler_class);
      }
    }
  }
}

In summary, while rendering an entity form programmatically in Drupal 8, 9 and 10 is straightforward with the default form mode, using custom form modes requires altering the entity definition and specifying appropriate form handlers to avoid errors. 

How to get all field names of field type

Components

To obtain a list of all field names for fields of a specific type, such as image, you can use the entity_field.manager service:

$field_map = \Drupal::service('entity_field.manager')->getFieldMapByFieldType('image');

The $field_map array will contain a list of fields organized by entity type.

Image

In summary, the entity_field.manager service in Drupal can be utilized to fetch field names based on their field type, offering a systematic way to categorize and manage fields.

How to programmatically change order status

Components

Changing the order state in Drupal Commerce 2.x like this:

$order->set('state', 'canceled');
$order->save();

is not a good idea because you are not dispatching transition events. And some modules depend on those events. The proper way to change the order state is to apply state transition like this:

$order = \Drupal::entityTypeManager()
  ->getStorage('commerce_order')
  ->load(1);
$order->getState()->applyTransitionById('cancel');
$order->save();

You can find the list of transition IDs in the workflows file.

How to programmatically add a language

Components

Sometimes you have to add a new language in Drupal 8/9 programmatically. For example, maybe you need to write an update hook that will add a new language. This is how you can do it:

use Drupal\language\Entity\ConfigurableLanguage;

$language = ConfigurableLanguage::createFromLangcode('sr');
$language->save();

If you don't know the langcode, you can find it by inspecting the select box on the /admin/config/regional/language/add page. 

How to set price field value programmatically in Drupal Commerce

Components

Price in Drupal Commerce 2.x is not a number but a class. This class has a price number and currency code properties, and both are strings. So, to set the product price programmatically you have to first instantiate the Price class:

$price = new \Drupal\commerce_price\Price('9.99', 'EUR');

and then use created Price object to set the product price:

$product_variation = \Drupal\commerce_product\Entity\ProductVariation::load(1);
$product_variation->set('price', $price);
$product_variation->save();

To get the price number and currency code you can use appropriate getters methods:

$price_number = $price->getNumber();
$currency_code = $price->getCurrencyCode();

You can also create a Price object by using the static method:

$price = Price::fromArray(['number' => '9.99', 'currency_code' => 'EUR']);

In summary, in Drupal Commerce 2.x, prices are managed using the Price class, which encapsulates both the price number and currency code, allowing for programmatic manipulation and retrieval of product prices. 

How to customize the Drupal Commerce order receipt email subject

Components

At the moment you can't configure the order receipt email subject. The subject is hardcoded in the OrderReceiptMail service.

There is an issue to fix this, but until that happens the only way to alter the email subject is to use the hook_mail_alter().

/**
 * Implements hook_mail_alter().
 */
function MY_MODULE_mail_alter(&$message) {
  if ($message['key'] == 'order_receipt' && !empty($message['params']['order'])) {
    /** @var \Drupal\commerce_order\Entity\OrderInterface $order */
    $order = $message['params']['order'];

    $message['from'] = 'noreply@example.com';
    $message['subject'] = t('Receipt for Order ID: @number', [
      '@number' => $order->getOrderNumber(),
    ]);
  }
}

In summary, while the order receipt email subject in Drupal Commerce is currently hardcoded, it can be customized using the hook_mail_alter() function until the underlying issue is resolved.

How to generate masquerade link programmatically

Components

The Masquerade module allows website admins to switch users and visit the website as that user. This is helpful for developers and site builders when trying to find out what a client might see when logged into the website. To create the unmasquerade programmatically use this:

if (
  \Drupal::moduleHandler()->moduleExists('masquerade') && 
  \Drupal::service('masquerade')->isMasquerading()
){
  $links['unmasquerade'] = [
    '#type' => 'link',
    '#title' => t('Unmasquerade'),
    '#url' => Url::fromRoute('masquerade.unmasquerade'),
    '#weight' => 1500,
  ];
}

Drupal and Guzzle HTTP client library

Components

Making a simple HTTP Get request in Drupal 8, 9 or 10 is super easy thanks to the Guzzle library. This library has been added to Drupal core a long time ago, and it replaced the much less powerful drupal_http_request() function. Let's see how to get some data from the Star Wars API:

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

$client = new Client();
$people = [];

try {
  $response = $client->get('https://swapi.dev/api/people');
  $result = json_decode($response->getBody(), TRUE);
  foreach($result['results'] as $item) {
    $people[] = $item['name']; 
  }
}
catch (RequestException $e) {
  // log exception
}

Guzzle can also be accessed through the http_client service and the helper method:

$client = \Drupal::httpClient();

Sending a POST request is also simple and easy.

public function sendOrder(OrderInterface $order) {
  try {
    $response = $this->httpClient->post($url, [
      'form_params' => $data,
    ]);
    $response_data = json_decode($response->getBody()->getContents(), TRUE);

    // do something with data
  }
  catch (RequestException $e) {
    // log exception
  }
}

If you want to log the exception don't use $e->getMessage() because the error message will be truncated. Instead, use this:

$e->getResponse()->getBody()->getContents();

You can also use Guzzle to send files. To send an image file you can do something like this:

try {
  $client = new Client(['headers' => ['X-Auth-Secret-Token' => 'my-secret-token']]);
  $options = [
    'multipart' => [
      [
        'Content-type' => 'multipart/form-data',
        'name' => 'image',
        'contents' => fopen($image->getFileUri(), 'r'),
        'filename' => basename($image->getFileUri()),
      ],
    ],
  ];
  $response = $client->post($api_base_url . 'api/v1/images', $options);
}
catch (\Exception $e) {
  // log exception
}

In this case, the $image variable is an instance of Drupal\file\Entity\File class.

Change status message text

Components

Let's say that a contrib module is showing a message like this: Your message has been created, and you want to change it to something like this: Message created. To do this you don't have to hack the contrib module, you can use the hook_preprocess_HOOK() to alter the message.

/**
 * Implements hook_preprocess_HOOK().
 */
function MY_MODULE_preprocess_status_messages(&$variables) {
  if (isset($variables['message_list']['status'])){
    $status_messages = $variables['message_list']['status'];
    foreach($status_messages as $delta => $message) {
      if (strpos((string) $message, 'Your message has been created.') !== FALSE) {
        $variables['message_list']['status'][$delta] = t('Message created.');
      }
    }
  }
}