The use of third party settings could really use better documentation and I'd be happy to help with that but first I need to understand it myself. :) So I'm posting my findings in the hopes of getting some clarification of how this all works.

In this comment , yched says:

It should be the entity form's responsibility to create the container for the "third party settings" entry, and place it in the form (weight, etc...). Then, having 3rd party modules add their elements in that container with a simple form_alter() is fine.

It seems like this has been implemented but possibly only for fields. If I form alter a field, I can add my own data to the form under "$form['field']['third_party_settings']['module_name']['data_name']" and it is automatically saved along with the field configuration.

From what I can tell, though, this only works for fields. In trying to make it work with the contact form, I noticed there is no existing third_party_settings element in the $form array. I tried adding it to the $form array in various places but it does not automatically save with the other form data.

The core content translation module uses "$form['field']['third_party_settings']['content_translation']['translation_sync'] = $element;" to do the autosaving of third party data on fields but then it uses "$config->setThirdPartySetting('content_translation', 'enabled', $value)->save();" when it wants to add third party settings to something that is not a field.

I have been trying to figure out what makes fields different but keep getting in over my head. Is this actually implemented differently for fields or am I just missing something? If it is different, was that intentional or is it unfinished or an oversight that the others don't have the automatic saving?

Comments

larowlan’s picture

There is a test in core that does exactly what you're after to a contact form, that should be a good reference point

Michelle’s picture

That test looks a lot like your lightening talk. ;)

Ok, so I got it working adding TPS to the contact form so that solves my problem (thanks!) but there's still the larger issue of documenting this and why it is different for fields than for other config entities. Any idea? I could document it as is but I'd like to understand why the difference.

Also, is there a reason for using #entity_builders for saving the TPS rather than #submit? I hadn't seen #entity_builders before your talk and I could find very little info on it. Content translation is doing it in the submit.

Michelle’s picture

Adding a third thing that needs documenting: third party settings on base fields. I think I found the issue that allows it but I'm a long way from understanding enough to document how to use it and am especially confused by the lack of a UI to attach to.

larowlan’s picture

That test looks a lot like your lightening talk. ;)

Yep I think I wrote it over in #2342551: Implement ThirdPartySettingsInterface in contact module for contact form config entity

jhodgdon’s picture

Status: Active » Postponed (maintainer needs more info)

I'm a bit confused here. Where is this documentation proposed to be added/improved?

If it's pages on drupal.org, then please go ahead and edit them, or else move the issue to the Documentation project. You can tag with "d8 docs" and "developer".

If it's stuff in Drupal Core files, the issue should remain here.

Michelle’s picture

Project: Drupal core » Documentation
Version: 8.0.x-dev »
Component: documentation » Missing documentation
Assigned: Unassigned » Michelle
Status: Postponed (maintainer needs more info) » Active

I was looking for some help from devs that have worked on core to understand this better so that I had the knowledge to document it. I guess there isn't going to be any more of that forthcoming so I'll go ahead and move the issue. I still intend to document this but I still don't understand all the pieces. I've moved away from this at work so will need to wait until I can scrounge up some of my own time to finish digging into this.

jhodgdon’s picture

No one but me really looks at issues in the documentation component, so. You'll be better off pinging people directly in IRC. Not sure who to ask, but you can ping one of the people in the know to figure that out.

larowlan’s picture

fwiw the phrase "the core devs" creates barriers and implies there are different classes of contributors. We are all Drupal contributors. Please avoid it.

Can we work to turn the example in the contact module tests 'send me a pony' into documentation?

Michelle’s picture

Sorry for being old school. I changed my comment to be politically correct. ;)

As for the example, that's a good start but that's only one of the 3 ways that TPS works. And is also the one I understand the best. I'll write up a skeleton doc with everything I know and mark what I don't and see about finding some help for the stuff I don't. It might not be until this weekend, though. Work owns my brain this week.

mikejw’s picture

Hi,

just wondering if this was ever completed - I am looking for some help on using TPS.

Cheers.

mikejw’s picture

Ok in my case I wanted to add in the TPS into the field settings form... this is how it is done:

function my_module_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  $entity = $form_state->getFormObject()->getEntity();

  $form['third_party_settings']['my_module']['my_field_setting'] = array(
    '#type' => 'textfield',
    '#title' => t('My custom field setting'),
    '#default_value' => $entity->getThirdPartySetting('my_module', 'my_field_setting'),
  );
}

Obviously you will need a way to check that it is the right field in my case I just name them in particular way and I query the field_name.

Michelle’s picture

I'm sorry, I haven't done this yet. The D8 project I was on launched and that was the last I worked on D8. :( I still want to do this but TPS aren't fresh in my mind anymore so it will take me time to really dive into it again and I don't know when I'll be able to do that. If I can turn it into a blog post, I can get some work time for it. That's not ideal as documentation, I realize, but it would at least get it all out there and could be turned into documentation from that.

mikejw’s picture

I am currently on a D8 project so it may be feasible for me to have a shot at writing the documentation. As far as I can see the previousnext lightning talk covers one part of it and what I have done above covers another part.

mikeryan’s picture

+1 for actually documenting this, as I deal with #2613336: Convert migration_group to a third party setting.

geek-merlin’s picture

stanoreke’s picture

Please how do i retrieve the value the user selects? I want to be able to make some comparison based on the value selected in my template.twig file. I have set this in a custom module

E.g, {% set value = $block->getThirdPartySetting('helper_module', 'collapse') %}

Michelle’s picture

Assigned: Michelle » Unassigned

Unassigning myself since I never got to this and it's been so long I don't remember how it works anymore. :(

geek-merlin’s picture

Hmm, puzzling with this too. As far as i can see,

@Michelle asked in the summary:

The core content translation module uses "$form['field']['third_party_settings']['content_translation']['translation_sync'] = $element;" to do the autosaving of third party data on fields but then it uses "$config->setThirdPartySetting('content_translation', 'enabled', $value)->save();" when it wants to add third party settings to something that is not a field.

I have been trying to figure out what makes fields different but keep getting in over my head. Is this actually implemented differently for fields or am I just missing something? If it is different, was that intentional or is it unfinished or an oversight that the others don't have the automatic saving?

* core.entity_view_display.*.*.*::third_party_settings are a builtin of any config entity, defined in core.config_entity schema in drupal/core/config/schema/core.data_types.schema.yml and supported by builtin \Drupal\Core\Config\Entity\ConfigEntityBase::getThirdPartySettings
* OTOH core.entity_view_display.*.*.*::content.*.third_party_settings is defined in core.entity_view_display.*.*.* schema in drupal/core/config/schema/core.entity.schema.yml and *not* supported by a builtin config entity method

@Michelle asked in #2:

Also, is there a reason for using #entity_builders for saving the TPS rather than #submit?

I think it is just more natural to
* prepare the entity content in #entity_builders
* store tne entity content in #submit

If this is not documented, it really should.

Hope this helpz.

Anybody’s picture

Hi @axel.rutz and all others,
thank you very much for the discussion.

I still couldn't find any general documentation in TPS yet. Only this issue. What I'd need is first of all general information about TPS and what to (not) use it for.

General questions could be:

  • What are third party settings?
  • What are third party settings intended for? Which problem do they solve?
  • What's typical use of third party settings? (Usage examples / showcases from modules)
  • What's typical misuse of third party settings?
  • Are third party settings saved into the database automatically using set() or are they only runtime? (which might also be helpful in some cases) - like variable_get and variable_set TPS might be used wrongly.

And perhaps others...

Who could answer that for a first documentation? I only recognized TPC in kint so far and I'm afraid of misuing them...

If there is a documentation page already, please link it here and close the issue.

nightlife2008’s picture

Daniel Sipos wrote an excellent tutorial on this:

https://www.sitepoint.com/drupal-8-third-party-settings-and-pseudo-fields/

Perhaps parts can be taken over for Drupal-Docs.

Pasqualle’s picture

mandclu’s picture

I agree 100% that the third party settings system needs to be better documented. Some feedback on the most recently post links:
- The post in #20 took a very long time to get to the actual usage of TPS, it seemed to be focused on a very narrow case using entirely custom forms. The page was so loaded with ads that I had trouble scrolling through, and Chrome warned me of two separate embedded ad page that had crashed the browser
- The post in #21 was much more succinct, but specified the definition and use of a save handler, which isn't really necessary if you're just adding something into a field's config

The reference in #11 was perfect for me. When I needed to retrieve the setting with the code for my custom field, I only needed to do this:

$field_def = $this->fieldDefinition;
$allow_recurring = $field_def->getThirdPartySetting('my_module', 'my_field_setting');
stefan.korn’s picture

I totally agree with @mandclu, especially in that #21 is an absolutely helpful (working) documentation that's straight up to the point and would surely make a good candidate for documentation on drupal.org as well, maybe additionally sorting out in which case it's necessary to use the entity_builders callback.

rick.kowal’s picture

Thanks @mandclu for the TLDR; version.
In D8.9.1 for a content type form (ie /admin/structure/types/manage/*), I needed to add a submit handler to save the value:

function my_module_form_alter(&$form, &$form_state, $form_id) {
if ($form_id === 'node_type_edit_form') {
$entity = $form_state->getFormObject()->getEntity();
$form['third_party_settings']['my_module']['my_field'] = array(
'#type' => 'textfield',
'#title' => t('My Field'),
'#default_value' => $entity->getThirdPartySetting('my_module', 'my_field'),
);
$form['actions']['submit']['#submit'][] = 'my_module_submit_node_type_form';
}
}

function my_module_submit_node_type_form(&$form, FormStateInterface $form_state) {
$entity = $form_state->getFormObject()->getEntity();
$entity->setThirdPartySetting('my_module', 'my_field', $form_state->getValue('my_field'));
$entity->save(); //didn't work without saving here
}

To get the value in my twig:
function my_module_preprocess_node(&$variables) {
$type = $variables['node']->getType();
$node_type = \Drupal::entityManager()->getStorage('node_type')->load($type);
$variables['my_field'] = $node_type->getThirdPartySetting('my_module', 'my_field');
}

stefan.korn’s picture

@rick.kowal: You should probably better use the "entity_builders" callback in form_alter

$form['#entity_builders'][] = 'your_module_node_type_builder'; (naming is up to you)

see link from #21: https://www.heididev.com/how-alter-configuration-entity-data-drupal-8-or...

That way no entity->save() should be necessary (which imho can lead to serious problems if used during the regular entity processing).

Anybody’s picture

ebeyrent’s picture

The part I'm struggling with is base fields on a custom entity type. I'm not using the Drupal UI; instead I'm using vuejs and need to set third party settings on base fields. Since form api isn't used, form_alter hooks doesn't help me much.

I would have thought something like this would work, but it doesn't:

$fields['my_field'] = BaseFieldDefinition::create('boolean')
      ->setLabel(new TranslatableMarkup('My Field))
      ->setDefaultValue(TRUE)
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE)
      ->setRequired(TRUE)
      ->setSetting('on_label', t('Enabled'))
      ->setSetting('off_label', t('Disabled'))
      ->setDisplayConfigurable('view', TRUE)
      ->setDisplayConfigurable('form', TRUE)
      ->setDisplayOptions('form', [
        'type' => 'options_buttons',
        'weight' => 0,
        'third_party_settings' => [
          'my_field' => [
            'widget_options' => [
              'buttons' => TRUE,
            ],
          ],
        ],
      ]);
Berdir’s picture

There are no third party settings for base fields. But you can still expose the field ui admin route for your entity type and then manage the third party settings there for the form display.