Skip to main content

Working on a decoupled React / Drupal 9 site.

Aim: Adjust the output of curated content for the Work Resources page.  So the icon is displayed with a path.  Enabling React developers to select whether to use the image or icon.

Tools

Drupal 9.4
React  

 

Currently, the JSON output 

{
  "id": "content_reference",
  "title": "Forms",
  "summary": null,
  "columns": "3",
  "cta": {
    "text": "View all",
    "href": "https://www.google.com/"
  },
  "content": [
    {
      "id": "custom_content_tile",
      "title": "Joint mental health commissions and leaders communique",
      "summary": "The mental health commissions and leaders across Australia have come together during the time of the pandemic",
      "link": {
        "text": "Read more",
        "href": "/news/working-together-create-mentally-healthy-and-safe-workplaces"
      },
      "image": {
        "alt": "Test Curated Content two",
        "title": "",
        "href": "https://localhost:8006/sites/default/files/styles/desktop/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202.png?itok=F9TbZoH1",
        "styles": {
          "laptop": {
            "href": "https://localhost:8006/sites/default/files/styles/laptop/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202.png?itok=28KzCLbs",
            "width": 210,
            "height": 196
          },
          "tablet": {
            "href": "https://localhost:8006/sites/default/files/styles/tablet/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202.png?itok=BEH519Q4",
            "width": 210,
            "height": 196
          },
          "mobile": {
            "href": "https://localhost:8006/sites/default/files/styles/mobile/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202.png?itok=ooF3HwDk",
            "width": 210,
            "height": 196
          }
        },
        "width": 210,
        "height": 196
      }
    },
    {
      "id": "custom_content_tile",
      "title": "Joint mental health commissions and leaders communique",
      "summary": "The mental health commissions and leaders across Australia have come together during the time of the pandemic",
      "link": {
        "text": "Read more",
        "href": "https://www.google.com/"
      },
      "image": {
        "alt": "Test Curated Content two",
        "title": "",
        "href": "https://localhost:8006/sites/default/files/styles/desktop/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202_0.png?itok=l19DECi_",
        "styles": {
          "laptop": {
            "href": "https://localhost:8006/sites/default/files/styles/laptop/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202_0.png?itok=nYahgAE1",
            "width": 210,
            "height": 196
          },
          "tablet": {
            "href": "https://localhost:8006/sites/default/files/styles/tablet/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202_0.png?itok=MEQvOPPI",
            "width": 210,
            "height": 196
          },
          "mobile": {
            "href": "https://localhost:8006/sites/default/files/styles/mobile/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202_0.png?itok=vOhvi_b3",
            "width": 210,
            "height": 196
          }
        },
        "width": 210,
        "height": 196
      }
    },
  ]
},

 

Introduction

As the document already exists in the system, I don't want a solution where the content admin can manually set the icon.  Otherwise, all too early they could set conflicting icons.

So moving towards a solution, I'll grab the content href link and lookup the relevant node nid.  This will then enable the correct document type being accessed.

 

Approach to resolution

I'll focus on the link (field_cta) and check if the href element is an internal or external link.  This will be achieved by checking the string /node/###.  Where ### is the node.nid value.  If the nid is not null, then load node and get the node type.  From this node type, the icon path can be generated.

This output has changed by adjusting the two areas of the PHP code.

First through the paragraph tile code:


    use ParagraphTrait;

    /**
     * {@inheritdoc}
     */
    public function process()
    {
        $this->processConfig();

        $this->setData('title', $this->entity->field_title->value);
        $this->setData('summary', $this->entity->field_summary->value);
        $link = $this->helper->getField($this->entity, 'field_cta');
        $this->setData('link', $link);
        $this->setData('image', $this->helper->getFieldImageUrl($this->entity, 'field_image') ?: $this->helper->getFallbackImage());
        // If an internal link, get the type and icon.
        $nid = $this->helper->getNodeNidFromAlias($link['href'], '/node/');
        if (!is_null($nid)) {
            $node = \Drupal\node\Entity\Node::load($nid);
            $this->setData('type', $node->getType());
            $this->setData('icon', $this->helper->getIconFromNode($node));
        }
    }

 

The focus of the above is to extract the node nid from the URL where the URL is an alias.  Through the line

$this->helper->getNodeNidFromAlias($link['href'], '/node/');

Then the icon and its relative path are sourced by a function getIconFromNode()

$this->setData('icon', $this->helper->getIconFromNode($node));

As noted these two functions with the code in full


    /**
     * Load the node nid from the URL alias.
     *
     * @param string $url URL string.
     *
     * @return any
     */
    public function getNodeNidFromAlias($url, $phrase)
    {
        // Default values.
        $nid = null;
        $path = \Drupal::service('path_alias.manager')->getPathByAlias($url);
        $strlen = strlen($phrase);
        if (substr($path, 0, $strlen) === $phrase) {
            $nid = substr($path, $strlen, strlen($path) - $strlen);
        }

        return $nid;
    }

    /**
     * Get the node type.
     *
     * @param any $nid Node nid.
     *
     * @return any
     */
    public function getIconFromNode($node)
    {
        if (is_null($node)) {
            return null;
        }

        return $this->getIcons($node);
    }

 

Subsequently, post the changes above the JSON is now:

{
  "id": "content_reference",
  "title": "Forms",
  "summary": null,
  "columns": "3",
  "cta": {
    "text": "View all",
    "href": "https://www.google.com/"
  },
  "content": [
    {
      "id": "custom_content_tile",
      "title": "Joint mental health commissions and leaders communique",
      "summary": "The mental health commissions and leaders across Australia have come together during the time of the pandemic",
      "link": {
        "text": "Read more",
        "href": "/news/working-together-create-mentally-healthy-and-safe-workplaces"
      },
      "image": {
        "alt": "Test Curated Content two",
        "title": "",
        "href": "https://localhost:8006/sites/default/files/styles/desktop/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202.png?itok=F9TbZoH1",
        "styles": {
          "laptop": {
            "href": "https://localhost:8006/sites/default/files/styles/laptop/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202.png?itok=28KzCLbs",
            "width": 210,
            "height": 196
          },
          "tablet": {
            "href": "https://localhost:8006/sites/default/files/styles/tablet/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202.png?itok=BEH519Q4",
            "width": 210,
            "height": 196
          },
          "mobile": {
            "href": "https://localhost:8006/sites/default/files/styles/mobile/public/2022-06/Test%20Curated%20Content%20Work%20Resources%202.png?itok=ooF3HwDk",
            "width": 210,
            "height": 196
          }
        },
        "width": 210,
        "height": 196
      },
      "type": "news",
      "icon": "sites/default/files/icons/News.svg"
    },
  ]
},

The new elements to the JSON are

      "type": "news",
      "icon": "sites/default/files/icons/News.svg"

 

Note, that the image element remains.  React frontend can use either the icon or image path.

Related articles

Andrew Fletcher04 Apr 2025
Managing .gitignore changes
When working with Git, the .gitignore file plays a critical role in controlling which files and folders are tracked by version control. Yet, many developers are unsure when changes to .gitignore take effect and how to manage files that are already being tracked. This uncertainty can lead to...
Andrew Fletcher26 Mar 2025
How to fix the ‘Undefined function t’ error in Drupal 10 or 11 code
Upgrading to Drupal 10.4+ you might have noticed a warning in their code editor stating “Undefined function ‘t’”. While Drupal’s `t()` function remains valid in procedural code, some language analysis tools — such as Intelephense — do not automatically recognise Drupal’s global functions. This...
Andrew Fletcher17 Mar 2025
Upgrading to PHP 8.4 challenges with Drupal contrib modules
The upgrade from PHP 8.3.14 to PHP 8.4.4 presents challenges for Drupal 10.4 websites, particularly when dealing with contributed modules. While Drupal core operates seamlessly, various contrib modules have not yet been updated to accommodate changes introduced in PHP 8.4.x. This has resulted in...