Customizing Yoast SEO's structured data with schema API part 1
Tags: wordpress, yoast, schemaapi
Published: 2022-06-04 15:08:30

One of the features of [Yoast SEO for Wordpress](https://yoast.com/wordpress/plugins/seo/) is structured data/schema. But, how do you customize this data. What if for example you would like to add a phone number or a sponsor to the `Organization` schema? Or maybe you don't want to use gravatars in the `Person` schema? This is what this series is about.

This first part gives an introduction on how Yoast implemented structured data. This is important because you need to understand the structure of the json-ld before you can alter it. Parts 2 to 4 will deal with actual customization.
 
*A sidenote*: this article assumes you know about structured data/schema, json-ld, yoast SEO and wordpress. But, we take our time to explain the code.

## Interlinked pieces

The team at yoast implemented a **modular** and **flexible** approach to json-ld. They pulled apart all the structured data into single reusable schemas (modular) called a `pieces`. These pieces are linked to each other through ID's (flexible) and get outputted as inline json.

```html
<script type="application/ld+json" class="yoast-schema-graph">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://www.mycompany.com/#Organization",
      "url": "https://www.mycompany.com/",
      "name": "My Company"
    }
  ]
}
</script>
```

The "@graph" property is an array that holds all of the different pieces. Currently it holds only one piece, an `Organization` (simplified example):

* the "type" property refers to <https://schema.org/Organization>.
* the "id" property is an auto generated unique identifier: "site url" + "#organisation".

Let's add 2 more pieces: `Website` and `Webpage`:

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://www.mycompany.com/#Organization",
      "url": "https://www.mycompany.com/",
      "name": "My Company"
    },
    {
      "@type": "Website",
      "@id": "https://www.mycompany.com/#Website",
      "url": "https://www.mycompany.com/",
      "name": "My Company",
      "publisher": {
        "@id": "https://www.mycompany.com/#Organization"
      }
    },
    {
      "@type": "Webpage",
      "@id": "https://www.mycompany.com/page1/",
      "url": "https://www.mycompany.com/page1/",
      "name": "Page 1",
      "description": "Page 1 description",
      "isPartOf": {
        "@id": "https://www.mycompany.com/#Website"
      }
    }
  ]
}
```

Both `Website` and `Webpage` have their own @types and IDs. Crucial to notice here are the properties that link these pieces together. `Website` has a property "publisher" which refers to the id of the `Organization`. `Webpage` has a property "isPartOf" that refers to the `Website` id.

`Webpage` refers to `Website`. `Website` refers to `Organization`. This is a clever but not obvious solution. Referring is not obvious because there is no official way of doing this. Json-ld is messy, it's not clearly documented.

A solution without referring would involve having to repeat entire schemas, nested inside other schemas.

* `Organization`
* `Website`
  * publisher: `Organization` all over again
* `Webpage`
  * isPartOf: `Website` all over again
    * publisher: `Organization` all over again

It would be a bloated mess. Yoast solved this for us by using IDs. But, this also means that the json-ld is interconnected and you should be carefull before altering it.

## The basic schemas

The second thing you need to understand about structured data in Yoast SEO is that it uses 3 basic pieces on every page, post, taxonomy, custom post type,... These 3 pieces are the ones we already used as examples:

* `Organization` (or a subtype like `Corporation`, `LocalBusiness` or a *subsubtype* like `Store`, `Restaurant`,...)
* `Website`
* `Webpage` 

I have to admit. When I first saw these basic schemas I thought `Website` and `Webpage` were unnecessary and my first instinct was to remove them. I was wrong. They don't seem very important on their own but are needed to hold everything together. 

Let's take a look at a simplified `Article` piece as an example:

```json
{
  "@type": "Article",
  "@id": "https://www.mycompany.com/blog/hello-world/#article",
  "isPartOf": {
      "@id": "https://www.mycompany.com/blog/hello-world/#webpage"
  },
  "author": {
      "@id": "https://www.mycompany.com/#/schema/person/2fa9055e7ef234fa04dd717e6aaed799"
  },
  "headline": "Hello world!",
  "publisher": {
      "@id": "https://www.mycompany.com/#Organization"
  }
},
```

You can see that `Article` has a lot of referrals. It's linked to `WebPage`, `Organization` and a `Person` piece. But, it is not directly linked to `Website`.

Yoast has thought this through for us and came up with this structure. It might seem a bit overwhelming at first but it works. Simply removing a piece would break the chain of referrals and leave us with `404 Piece not Found` situations.

## Summary

When you first look into the json-ld that Yoast SEO renders onto the page it may be a bit confusing. The structured data is modular: different pieces are linked using IDs.

The second thing that may be confusing is that every page uses the same 3 basic pieces: `Organization` (or a subtype), `Website` and `Webpage`. Accept this basic structure because it ties in with other pieces that Yoast SEO outputs and you can also use it for your own custom pieces.

Now that you understand this we can talk about customizing. [Part 2](https://dev.to/peterlidee/customizing-yoast-seos-structured-data-with-schema-api-part-2-591f) of this series covers adding, changing or removing piece properties and removing a piece. [Part 3](https://dev.to/peterlidee/customizing-yoast-seos-structured-data-with-schema-api-part-3-1i7d) and [part 4](https://dev.to/peterlidee/customizing-yoast-seos-structured-data-with-schema-api-part-4-2bdf) will show you how to add a piece.