hook_form_alter bypasses weight system

Created on 12 December 2022, about 2 years ago
Updated 29 May 2024, 7 months ago

Problem/Motivation

The change introduced by this issue https://www.drupal.org/project/field_group/issues/3222507 β†’ created a situation where the field_group form alter always runs last. This however makes it impossible for any form_alter that needs to opperate on the field group from being able to get in line behind it. It circumvented Drupal's weight system and was a breaking change for many existing sites.

/**
 * Implements hook_module_implements_alter().
*/
function field_group_module_implements_alter(&$implementations, $hook) {
  switch ($hook) {
    // Move our hook_form_alter() implementation to the end of the list.
    case 'form_alter':
      $group = $implementations['field_group'];
      unset($implementations['field_group']);
      $implementations['field_group'] = $group;
      break;
  }
}

I did not see anywhere in the translation issue β†’ where weights were even discussed, so I do not know for certain whether a weighting would have solved the translation problem.

This should be remedied to return some Drupal methods to the heart of the solution so that this does not remain a breaking change.

Steps to reproduce

Proposed resolution

  1. remove field_group_module_implements_alter
  2. Set module weight to 800 in hook_install (to cover new installs)
  3. Set module weight to 800 in hook_update_N (to cover existing installs)
  4. Have hook ^^ return the message "field_group module's assigned weight set to 800. If you have a form_alter that needs to run after field_group, you will need to set your module's weight to higher than 800"
  5. Add it to release note.

Remaining tasks

none

User interface changes

none

API changes

none

Data model changes

none

πŸ› Bug report
Status

Active

Version

3.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States swirt Florida

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡ΈπŸ‡°Slovakia lubwn

    I actually stubled upon this issue when writing my own module and adding some fields programativally to fieldset created by form_group module. I am unable to set weight of field programatically on a field which is wrapped in fieldset by admin UI.

    I can actually solve this by simple JS on client-side but I wanted to solve this in backend. What is the proposed resolution in this case? Can my form alter hook run after the field_group module form alter hook?

  • πŸ‡¬πŸ‡§United Kingdom james.williams

    @lubwn - two suggestions: either use hook_module_implements_alter(), to get your hook_form_alter to act after field_group. Or add a #pre_render or #after_build callback to the form in your hook_form_alter. Those can then change things in the form array, after the form_alter stage.

  • πŸ‡ΊπŸ‡ΈUnited States mrweiner

    either use hook_module_implements_alter(), to get your hook_form_alter to act after field_group.

    This actually is not possible without modifying module weights, because field_group_module_implements_alter is run after custom implementations. So even if you do implement it, field group's will run later, causing field_group_form_alter to run last.

  • πŸ‡©πŸ‡°Denmark ramlev

    @mrweiner you should add a #pre_render to your form_alter and add a class implementing Drupal\Core\Security\TrustedCallbackInterface

    user_module.module

    <?php
    
    use Drupal\user_module\YourCustomFormAlterBuilder;
    
    function user_module_form_FORM_ID_alter(&$form, $form_state) {
      $form['#pre_render'][] = [YourCustomFormAlterBuilder::class, 'preRender'];
    }
    

    Add something like this in your modules src/ folder.

    YourCustomFormAlterBuilder.php

    <?php
    
    namespace Drupal\user_module;
    
    use Drupal\Core\Security\TrustedCallbackInterface;
    
    class YourCustomFormAlterBuilder implements TrustedCallbackInterface {
    
      public static function trustedCallbacks() {
        return ['preRender'];
      }
    
      public static function preRender($form) {
        // Alter the form here.
        return $form;
    }
    
  • πŸ‡¨πŸ‡¦Canada No Sssweat

    Thanks #8 did the trick, but needed a tweak for the .module code

    <?php
    
    use Drupal\user_module\YourCustomFormAlterBuilder;
    
    function user_module_form_FORM_ID_alter(&$form, $form_state) {
      $form['#pre_render'][] = [new YourCustomFormAlterBuilder, 'preRender'];
    }
  • πŸ‡ͺπŸ‡ΈSpain psf_ Huelva

    Great solution in #8. Maybe it should be added to the documentation?

Production build 0.71.5 2024