---
title: "Main entity of a web page"
manual: "schema"
version: "main"
permalink: "https://docs.typo3.org/permalink/brotkrueml/schema:main-entity-of-web-page@main"
source: "Developer/MainEntity.rst"
rendered: "2026-09-23T16:29:19+00:00"
---

# Main entity of a web page {#main-entity-of-web-page}

Target group: **Developers**

**Table of Contents**

-   [Introduction](https://docs.typo3.org/permalink/brotkrueml/schema:introduction@main)
-   [Using the API](https://docs.typo3.org/permalink/brotkrueml/schema:using-the-api@main)
-   [Using the view helpers](https://docs.typo3.org/permalink/brotkrueml/schema:using-the-view-helpers@main)
-   [Prioritisation](https://docs.typo3.org/permalink/brotkrueml/schema:prioritisation@main)

## Introduction {#introduction}

A `WebPage` type provides a property `mainEntity`, which indicates the
primary content of a page. Every type is allowed - although some types does not
make sense (for example, a breadcrumb cannot be the primary content).

> [!NOTE]
> Technically, there can be more than one main entity at a time. For example,
> if you have a `FAQPage` you will usually assign [more than one question](https://developers.google.com/search/docs/data-types/faqpage)
> as `mainEntity`.

## Using the API {#using-the-api}

The main entity of a web page can be defined with the API. Let's start with an
example that specifies a product as the primary content:

**EXT:my_extension/Classes/Controller/MyController.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Controller;

use Brotkrueml\Schema\Manager\SchemaManager;
use Brotkrueml\Schema\Type\TypeFactory;

final class MyController
{
    public function __construct(
        private readonly SchemaManager $schemaManager,
        private readonly TypeFactory $typeFactory,
    ) {}

    public function addMainEntity(): void
    {
        // ...

        $aggregateRating = $this->typeFactory->create('AggregateRating')
            ->setProperty('ratingValue', '4')
            ->setProperty('reviewCount', '126');

        $product = $this->typeFactory->create('Product')
            ->setProperties([
                'name' => 'Some fancy product',
                'color' => 'blue',
                'material' => 'wood',
                'image' => 'https://example.org/some-fancy-product.jpg',
                'aggregateRating' => $aggregateRating,
            ]);

        $this->schemaManager->addMainEntityOfWebPage($product);

        // ...
    }
}

```

The above example is rendered as JSON-LD. Let's assume the `WebPage` type is
set to `ItemPage` \- either in the page properties or via the API or a view
helper.

```json
{
   "@context": "https://schema.org/",
   "@type": "ItemPage",
   "mainEntity": {
      "@type": "Product",
      "aggregateRating": {
         "@type": "AggregateRating",
         "ratingValue": "4",
         "reviewCount": "126"
      },
      "color": "blue",
      "image": "https://example.org/some-fancy-product.jpg",
      "material": "wood",
      "name": "Some fancy product"
   }
}
```

> [!NOTE]
> If the `WebPage` type is not defined because the
> [appropriate setting](https://docs.typo3.org/permalink/brotkrueml/schema:configuration-automaticwebpageschemageneration@main)
> is disabled in the extension configuration, the main entity is rendered as
> a root type.

## Using the view helpers {#using-the-view-helpers}

You can define the main entity also in a view helper:

```html
<schema:type.product
   -as="mainEntity"
   -isMainEntityOfWebPage="1"
   name="Some fancy product"
   color="blue"
   material="wood"
   image="https://example.org/some-fancy-product.jpg"
>
   <schema:type.aggregateRating
      -as="aggregateRating"
      ratingValue="4"
      reviewCount="126"
   />
</schema:type.product>
```

### Remark {#remark}

You can set the view helper argument `-isMainEntityOfWebPage` only in the
main type view helper, not in a child type view helper.

## Prioritisation {#main-entity-prioritisation}

Main entities can be prioritised. This is sometimes necessary when different
main entities are defined in different places (for example in a controller,
a Fluid page template or in a content element).

Let's look at an example: In a page template for a blog post, the main entity
is defined as type `BlogPosting`. There are content elements on the page that
display questions and answers for a FAQ. The content element sets the web page
type to 'FAQPage' and also defines the questions as the main entities (to
display as rich snippets on the search results page). However, Google Search
Console shows an error because `BlogPosting` is not allowed as the main entity
of a `FAQPage`.

### With the API {#with-the-api}

The main entity of the API example above can be prioritised by setting the
second argument to `true`:

```php
$schemaManager->addMainEntityOfWebPage($product, true);
```

### With view helpers {#with-view-helpers}

Let's look at the example described in the introduction. In a page template, a
`BlogPosting` type is defined as the main entity of the page:

```html
<!-- This is defined in a page template -->
<schema:type.blogPosting
   -isMainEntityOfWebPage="1"
   name="A blog post"
/>
```

And the FAQ is rendered in the template of a content element. To prioritise
these types, `-isMainEntityOfWebPage` is set to `2`:

```html
<!-- This is defined in a content element template -->
<schema:type.fAQPage/>
<f:for each="{questions}" as="question">
   <schema:type.question
      -isMainEntityOfWebPage="2"
      name="{question.title}"
   />
</f:for>
```

This results in the following output:

```json
{
   "@context": "https://schema.org/",
   "@graph": [{
      "@type": "FAQPage",
      "mainEntity":[{
         "@type": "Question",
         "name": "Question #1"
      }, {
         "@type": "Question",
         "name": "Question #2"
      }]
   }, {
      "@type": "BlogPosting",
      "name": "A blog post"
   }]
}
```
