We've created setting types with multiple fields - example: Company Contact Data.

The goal was to print out the whole entity like:

[site_settings:contact--contact:rendered:teaser]

[site_settings:contact--contact:0:rendered:teaser]

So we are able to use the template file (or maybe layout builder) to structure it + have different view modes - in other words: The full power of entities ;)

Currently the token browser just shows up the single fields of the entity.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

thomas.frobieter created an issue. See original summary.

anybody’s picture

well that absolutely makes sense and would improve this module a lot. I guess that something similar already exists through token.tokens.inc general entity implementations like:


  // Add [token:url] tokens for any URI-able entities.
  $entities = \Drupal::entityTypeManager()->getDefinitions();
  foreach ($entities as $entity => $entity_info) {
    // Do not generate tokens if the entity doesn't define a token type or is
    // not a content entity.
    if (!$entity_info->get('token_type') || (!$entity_info instanceof ContentEntityTypeInterface)) {
      continue;
    }

    $token_type = $entity_info->get('token_type');
    if (!isset($info['types'][$token_type]) || !isset($info['tokens'][$token_type])) {
      // Define tokens for entity type's without their own integration.
      $info['types'][$entity_info->id()] = [
        'name' => $entity_info->getLabel(),
        'needs-data' => $entity_info->id(),
        'module' => 'token',
      ];
    }

[...]

and

// Entity tokens.
  if (!empty($data[$type]) && $entity_type = \Drupal::service('token.entity_mapper')->getEntityTypeForTokenType($type)) {
    /* @var \Drupal\Core\Entity\EntityInterface $entity */
    $entity = $data[$type];

    foreach ($tokens as $name => $original) {
      switch ($name) {
        case 'url':
          if (_token_module($type, 'url') === 'token' && !$entity->isNew() && $entity->hasLinkTemplate('canonical')) {
            $replacements[$original] = $entity->toUrl('canonical')->toString();
          }
          break;

        case 'original':
          if (_token_module($type, 'original') == 'token' && !empty($entity->original)) {
            $label = $entity->original->label();
            $replacements[$original] = $label;
          }
          break;
      }
    }

So we could use a lot of that code but provide it globally and not just in the context of the entity.

The rendered entity could be retrieved like this for example, but I guess token.tokens.inc has a better solution...

$entity_type = 'site_setting_entity';
$entity_id = 4; // static for example purpose
$view_mode = 'default';         

$entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id);
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('site_setting_entity');
$pre_render = $view_builder->view($entity, $view_mode);
return render($pre_render);
scott_euser’s picture

I wonder if this would have performance impacts given settings are passed to all templates.

A possible prerequisite for this:
https://www.drupal.org/project/site_settings/issues/2945236

I otherwise like the idea of token instead of full render array so it is 'on demand' rather than default:
https://www.drupal.org/project/site_settings/issues/3021720

anybody’s picture

Thank you @scott_euser,

I absolutely agree. The current tokens should stay of course, we could simply add the new ones. I think there are already solutions for these kind of tokens in other modules and of course they should be lazy-loaded, perhaps through not yet rendered render arrays.

I hope we or someone else will find the time for this soon, but we're very busy, like everyone...

As I saw the patch in comment #7 of #2943440: How to get rendered value of Site Settings formatted text field in token? does a huge part of the job already, but renders in hook_tokens, which might cause performance problems?

scott_euser’s picture

In terms of just using the site setting entity directly as a token, this seemed to work fine for me in a form controller or a form alter:

// Add token types to a field.
$form['my_field'] = [
  '#type' => 'textfield',
  '#title' => t('My field'),
  '#token_types' => ['site_settings_entity'],
];

// Make a 'Browse available tokens' link available.
$form['token_help_body'] = [
  '#theme' => 'token_tree_link',
  '#weight' => -1,
  '#token_types' => ['site_settings_entity'],
];

DieterHolvoet made their first commit to this issue’s fork.

dieterholvoet’s picture

Status: Active » Needs review

I added tokens exposing all site settings entities and their fields.

dieterholvoet’s picture

StatusFileSize
new2.37 KB

Here's a patch of the current state of the MR for easy inclusion in projects.

anybody’s picture

Or as dynamic patch: https://git.drupalcode.org/project/site_settings/-/merge_requests/3.diff

@scott_euser how to proceed here?

scott_euser’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

Thanks both! I think we just need a method added to https://git.drupalcode.org/project/site_settings/-/blob/8.x-1.x/tests/sr... to avoid regression on this in the future. Otherwise looks good! I'll give this a final manual test as well once we have the automated test in place.

dieterholvoet’s picture

StatusFileSize
new5.8 KB
dieterholvoet’s picture

I added a test but it's failing because of the token module dependency missing. I don't really understand why, I added it to test_dependencies.

scott_euser’s picture

StatusFileSize
new5.66 KB
new1.01 KB

Apologies for the delay in getting to this. I have been running the tests locally and getting:

1) Drupal\Tests\site_settings\Functional\EntityTokensTest::testEntityTokens
Undefined offset: -1

It's the $has_index bit here, but I am struggling to understand what the preg_match is attempting to achieve. Is it possible to put some additional comments in with examples of what we are trying to find, and why we need ($index - 1) into here.

/**
 * Implements hook_tokens().
 */
function site_settings_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
  $replacements = [];

  if ($type == 'site_settings_entity') {
    $storage = \Drupal::entityTypeManager()->getStorage('site_setting_entity');

    foreach ($tokens as $name => $original) {
      $parts = explode(':', $name);
      $site_setting_name = array_shift($parts);
      $has_index = preg_match('#^(?<site_setting_name>.+)-(?<index>\d+)$#', $site_setting_name, $matches);

      if ($has_index) {
        $index = (int) $matches['index'];
        $site_setting_name = $matches['site_setting_name'];
      }

      $ids = $storage->getQuery()
        ->condition('type', $site_setting_name)
        ->accessCheck(TRUE)
        ->sort('id')
        ->execute();
      $site_setting_entities = $storage->loadMultiple($ids);

      if ($has_index) {
        $site_setting_entity = array_values($site_setting_entities)[$index - 1];
      } else {
        $site_setting_entity = reset($site_setting_entities);
      }

In the meantime I have been doing some coding standards and deprecations fixing on the module itself, updated patch as is with these coding standards and deprecations fixes to within the patch.

anybody’s picture

Thank you very much @scoot_euser! In the meantime, we switched to the "config_pages" module for this task as it better fitted our needs. Perhaps @DieterHolvoet can help.

Thanks and sorry.

dieterholvoet’s picture

scott_euser’s picture

Merged latest into the merge request. Same test failure though as in #16. Thanks for the progress on this and apologies for the silence!

scott_euser’s picture

Version: 8.x-1.x-dev » 2.0.x-dev

I added the test_dependency to the 2.0.x branch as, looking at other contrib modules like here, it is the only way to get past that bit of the test failure in order to see true test failures like you would if running locally. Ie, we should now see the test failure from my comment above.

scott_euser’s picture

Some phpcs/phpstan issues also flagged.

scott_euser’s picture

Status: Needs work » Fixed

Okay finally got around to this, thanks everyone!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.