Hide fields in Inline Entity Form

Components

If you want to hide a field inside the Inline Entity Form you have to use the hook_inline_entity_form_entity_form_alter() hook – standard form alter hook won’t work. For example, to hide the status field you can do something like this:

/**
 * Implements hook_inline_entity_form_entity_form_alter().
 */
function MY_MODULE_inline_entity_form_entity_form_alter(&$entity_form, &$form_state) {
  if (in_array($entity_form['#entity_type'], ['YOUR_ENTITY_TYPE_1', 'YOUR_ENTITY_TYPE_2'])) {
    $entity_form['status']['#access'] = FALSE;
  }
}

Disable Add to Cart button based on flag

Components

Hiding the Add to Cart button in Drupal Commerce 2.x is easy. Just alter the commerce_order_item_add_to_cart_form form, and set the disabled property of the button to true.

use Drupal\Core\Form\FormStateInterface;

function MY_MODULE_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if (strpos($form_id, 'commerce_order_item_add_to_cart_form') !== FALSE) {
    $product = $form_state->getFormObject()->getEntity()->getPurchasedEntity()->getProduct();
    
    $flag_service = \Drupal::service('flag');
    $flag = $flag_service->getFlagById('sold_out');
    $flagging = $flag_service->getFlagging($flag, $product);

    if ($flagging !== NULL ) {
      $form['actions']['submit']['#value'] = t('Out of stock');
      $form['actions']['submit']['#disabled'] = TRUE;
    }
  }
}

Always show payment methods

Components

If you have only one payment method, then Drupal Commerce 2.x will hide it. We can change that behavior in the form alter hook.

use Drupal\Core\Form\FormStateInterface;

function MY_MODULE_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == 'commerce_checkout_flow_multistep_default') {
    if (isset($form['payment_information']['payment_method']['#access'])) {
      $form['payment_information']['payment_method']['#access'] = TRUE;
    }
  }
}

Programatically add recaptcha to Drupal Commerce checkout form

Components

If you are using the UI you can add a Recaptcha only to the entire checkout form, and that usually is not what you want. Fortunately, adding a Recaptcha to a certain step is easy:

use Drupal\Core\Form\FormStateInterface;

function MY_MODULE_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  if ($form_id == 'commerce_checkout_flow_multistep_default' && $form['#step_id'] == 'order_information') {
    $form['captcha'] = [
      '#type' => 'captcha',
      '#captcha_type' => 'recaptcha/reCAPTCHA',
    ];
  }
}

Add a role on user create

Components

In some cases, you may want to add a role when a new user is created regardless of how the user is created (UI, GraphQL, Rest API, or something else). The hook_ENTITY_TYPE_presave() hook is perfect for this.

use Drupal\user\UserInterface;

function MY_MODULE_user_presave(UserInterface $user) {
  if ($user->isNew() && !$user->hasRole('frontend_app')) {
    $user->addRole('frontend_app');
  }
}

Add a menu link to existing menu

Components

Adding a menu link to some existing menu programmatically (for example in an update hook) is something I have to do fairly often. Here's how you can add a new menu link to the main menu:

use Drupal\menu_link_content\Entity\MenuLinkContent;

function MY_MODULE_update_8001() {
  MenuLinkContent::create([
    'title' => 'About',
    'link' => ['uri' => 'internal:/about'],
    'menu_name' => 'main',
    'weight' => -50,
  ])->save();
}

And if you want to add a submenu link you first have to load the parent link and then create a submenu link:

use Drupal\menu_link_content\Entity\MenuLinkContent;

function MY_MODULE_update_8001() {
  $menu_link_parents = \Drupal::entityTypeManager()
    ->getStorage('menu_link_content')
    ->loadByProperties([
      'title' => 'Dashboard',
      'menu_name' => 'main',
    ]);

  $menu_link_parent = reset($menu_link_parents);

  if ($menu_link_parent) {
    MenuLinkContent::create([
      'title' => 'Add tasks',
      'link' => ['uri' => 'internal:/add-task'],
      'menu_name' => 'main',
      'weight' => -50,
      'parent' => $menu_link_parent->getPluginId(),
    ])->save();
  }
}

Render a menu in a form

Components

Rendering a menu in a form requires a little bit more lines of code than rendering a View, but it is also very easy thanks to the menu.link_tree service. In the following example, we are rendering the main menu.

use Drupal\Core\Menu\MenuTreeParameters;

$menu_parameters = new MenuTreeParameters();
$manipulators = [
  ['callable' => 'menu.default_tree_manipulators:checkNodeAccess'],
  ['callable' => 'menu.default_tree_manipulators:checkAccess'],
  ['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
];
$tree = \Drupal::menuTree()->load('main', $menu_parameters);
$tree = \Drupal::menuTree()->transform($tree, $manipulators);

$form['content'] = \Drupal::menuTree()->build($tree);

Render a View in a form

Components

Rendering Views in a form is super easy thanks to the buildRenderable() method, which builds the render array for the given display. To render a View, you just need to know the machine name of the View and display ID (usually page_1 or block_1). To render the Content View do this:

use Drupal\views\Views;
$view = Views::getView('content');
$form['content'] = $view->buildRenderable('page_1');

Get the list of fields for an entity type

Components

To get the field definitions of any entity type use the following code. We first get all bundles, and then for each bundle we are getting the field definitions.

$bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('node');

foreach ($bundles as $bundle => $data) {
  $fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', $bundle);
}

Add CSS and JS to Admin pages

Components

Adding CSS or JS to admin pages is easy. Just create a new library, create CSS and JS files, and then attach the library in the hook_page_attachments() hook.

MY_MODULE.libraries.yml

admin_styling:
  version: VERSION
  css:
    theme:
      css/admin-styling.css: {}
  js:
    js/admin-script.js: {}

MY_MODULE.module

/**
 * Implements hook_page_attachments().
 */
function MY_MODULE_page_attachments(array &$attachments) {
  if (\Drupal::service('router.admin_context')->isAdminRoute()) {
    $attachments['#attached']['library'][] = 'MY_MODULE/admin_styling';
  }
}