Using the ThirdPartySettings API in Drupal

By Kevin, June 25th, 2019

The ThirdPartySettings API in Drupal 8 is a useful way to store extra configuration or information to a configuration entity. This allows you to attach your extra configuration on and make it available on the entity from anywhere in code.

To demonstrate this, here is an example. On a recent project we had a requirement that called for a node type label to be linked to a page anytime the label of the node type was output anywhere in the theme.

First, we need to modify the node type form and add our new option. A plain textfield will do just fine:


<?php

declare(strict_types = 1);

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\node\Entity\NodeType;

/**
 * Implements hook_form_node_type_form_alter().
 */
function mymodule_content_type_link_form_node_type_form_alter(&$form, FormStateInterface $form_state) {
  $bundle = $form_state->getFormObject()->getEntity();

  $form['label_link'] = array(
    '#type' => 'details',
    '#title' => t('Label Link'),
    '#group' => 'label_link',
  );

  $form['label_link']['content_type_link'] = array(
    '#type' => 'textfield',
    '#title' => t('Link'),
    '#description' => t('When used in a display, where should this content type link to? Leave blank for no link. Please use relative urls like /path/to/page.'),
    '#default_value' => $bundle->getThirdPartySetting('mymodule_content_type_link', 'content_type_link'),
  );

  $form['actions']['submit']['#submit'][] = 'mymodule_content_type_link_form_submit';
}

/**
 * Form submit handler function for mymodule_content_type_link_form_node_type_form_alter().
 */
function mymodule_content_type_link_form_submit(&$form, FormStateInterface $form_state) {
  $bundle = $form['type']['#default_value'];
  $node_type = NodeType::load($bundle);
  $node_type->setThirdPartySetting('mymodule_content_type_link', 'content_type_link', $form['label_link']['content_type_link']['#value']);
  $node_type->save();
}

The form alter sets up the node type form to display our new form field under a new tab, and presents a textfield to capture a value to use as a link.

So, if we have a node type called "Program", assume the site editor wants to always link this node type label to a page they have created at a path of '/about-us/our-offerings/programs'. They would enter that in the form, save it, and the value is then saved to the configuration of the 'Program' node type.

Upon exporting the site configuration, you will see it attached:


langcode: en
status: true
dependencies:
  module:
    - mymodule_content_type_link
third_party_settings:
  mymodule_content_type_link:
    content_type_link: /about-us/our-offerings/programs
name: Program
type: program
description: 'Create a program that is offered in different periods of the year.'
help: ''
new_revision: false
preview_mode: 1
display_submitted: false

Great! Now we have a way to capture this new setting for any node type from the admin area and export it to configuration to store it.

The next thing the module needs to do is provide a function to retrieve this value. Better yet, the function should just return the label to us with the link. That way, we can use it easily from the theme layer:


/**
 * Returns a linked content type label, or just the label if no link provided.
 */
function mymodule_content_type_link_get_link(string $bundle) {
  $node_type = NodeType::load($bundle);
  $label = $node_type->label();
  $path = $node_type->getThirdPartySetting('mymodule_content_type_link', 'content_type_link')

  if (isset($path)) {
    try {
      $url = Url::fromUserInput($path);
      $label = Link::fromTextAndUrl($label, $url);
    } catch (Exception $e) {
      \Drupal::logger('mymodule_content_type_link')
        ->error('There was an error trying to create a link from provided value "@path" for content type "@type". Error was @error.', [
          '@path' => $path,
          '@type' => $label,
          '@error' => $e->getMessage()
        ]);
    }
  }

  return $label;
}

Now, if our themer wants to get this linked label and use it in a template, they just need to create a variable and assign it the value of the function above:


$variables['label'] = mymodule_content_type_link_get_link($node->getType());

The result after the template has been rendered:


<a href="/about-us/our-offerings/programs">Program</a>

The function returns the linked label, if there was no value provided, then it remains the plain text label.

Using the ThirdPartySettings API is a very useful technique to implement a practical solution like this. Use cases, in this example, allow us or the site editor to change where a node type label is linked to whenever they want - without a code or template change required. Underneath, the data is stored with its respective node type, and not tucked away elsewhere in the admin or configuration file(s).

Tags