How can I "form alter" fields in a nested Paragraph, depending on where the field is used I have these entity types:


A node type: nodepage
A Paragraph type: pg_a
A Paragraph type: pg_b
A Paragraph type: pg_child


I have a content model which is:

nodepage
  -&gt;field_a
    Referenced bundles: pg_a
      -&gt;field_child
        Referenced bundles: pg_child
  -&gt;field_b
    Referenced bundles: pg_b
      -&gt;field_child
        Referenced bundles: pg_child


You can see that pg_a and pg_b both have a field called field_child which allows a reference to pg_child. This has great semantic meaning to the site architecture.

Now something I would like to do is form alter pg_child, but only when it is referenced from pg_a and not from pg_b.

In hook_field_widget_form_alter, where I think I should be doing my alters, I can do the following:

$field_definition = $context['items']-&gt;getFieldDefinition();

// Get the current field widget being built, eg `field_child_thing`.
$name = $field_definition-&gt;getName();

// Get the bundle, ie. `pg_child`
$targetBundle = $field_definition-&gt;getTargetBundle();

// Get the bundle that $targetBundle is attached to in this instance...
$instance = ???


I thought I could look further into the $context variable, but so far this has alluded me. The best candidate so far is #parents in the form, but when I only find a reference to field_child which is ambiguous.

I now suspect I can inject more $context from somewhere, maybe in the parent build.
In this scenario, we have field_caption being used in various places inside a cta paragraph. The business has asked to limit field_caption to 25 charaters, but only when it is being used in a node on an entity reference field called field_foo_cta.

First we add a #process callback to the widget based on whatever rule, by implementing hook_field_widget_form_alter:

function mymodule_field_widget_form_alter(&amp;$element, FormStateInterface $form_state, &amp;$context) {
  $field_definition = $context['items']-&gt;getFieldDefinition();

  if ($field_definition instanceof FieldConfig) {
    $config = $field_definition-&gt;id();
    list ($entity_type, $bundle, $field_name) = explode('.', $config);

    if ($entity_type == 'paragraph' &amp;&amp; $field_name == 'field_caption') {
      $element['#process'][] = ['\Drupal\mymodule\BusinessRules', 'alterFieldCaption'];
    }

  }
}


Then we create a new class in src directory of the module.

namespace Drupal\mymodule;

class BusinessRules {

  public static function alterFieldCaption(array &amp;$element, FormStateInterface &amp;$form_state, array &amp;$complete_form) {

    // Use whatever logic to target instances of `field_caption`.
    if (reset($element['#parents']) == 'field_foo_cta') {
      $element['value']['#maxlength'] = 25;
    }
    return $element;

  }

}


Thanks @larowlan for help on this.