• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / Yoast-SEO-for-TYPO3 / 24723291290

21 Apr 2026 12:50PM UTC coverage: 10.457% (+9.2%) from 1.275%
24723291290

push

github

web-flow
Merge pull request #632 from Yoast/feature/yoast-v12

[FEATURE] Version 12.0.0, added v14 support, removed v11 support including php8.0 and php8.1, rewrote backend javascript functionality to typescript and webcomponents

40 of 806 new or added lines in 69 files covered. (4.96%)

40 existing lines in 23 files now uncovered.

284 of 2716 relevant lines covered (10.46%)

0.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Classes/StructuredData/StructuredDataProviderManager.php
1
<?php
2

3
/**
4
 * This file is part of the "yoast_seo" extension for TYPO3 CMS.
5
 *
6
 * For the full copyright and license information, please read the
7
 * LICENSE.txt file that was distributed with this source code.
8
 */
9

10
declare(strict_types=1);
11

12
namespace YoastSeoForTypo3\YoastSeo\StructuredData;
13

14
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
15
use TYPO3\CMS\Core\Service\DependencyOrderingService;
16
use TYPO3\CMS\Core\SingletonInterface;
17
use TYPO3\CMS\Core\TypoScript\TypoScriptService;
18
use TYPO3\CMS\Core\Utility\GeneralUtility;
19
use YoastSeoForTypo3\YoastSeo\Service\Frontend\FrontendServiceInterface;
20

21
class StructuredDataProviderManager implements SingletonInterface
22
{
23
    public function __construct(
24
        protected FrontendInterface $pageCache,
25
        protected FrontendServiceInterface $frontendService,
26
        protected DependencyOrderingService $dependencyOrderingService,
27
        protected TypoScriptService $typoScriptService,
UNCOV
28
    ) {}
×
29

30
    /**
31
     * @param array<string, mixed> $params
32
     */
33
    public function render(array &$params, object $pObj): void
34
    {
NEW
35
        if (!$this->frontendService->isFrontendRequest()) {
×
36
            return;
×
37
        }
38

39
        $data = $this->getStructuredData();
×
40

41
        $params['headerData']['StructuredDataManager']
×
42
            = $this->getSourceComment() . PHP_EOL . $this->buildJsonLdBlob($data);
×
43
    }
44

45
    /**
46
     * @param array<string, array<string, mixed>> $src
47
     */
48
    protected function buildJsonLdBlob(array $src): string
49
    {
NEW
50
        $data = $src ? array_merge(...array_values($src)) : [];
×
51

NEW
52
        return $data
×
NEW
53
            ? '<script type="application/ld+json">' . json_encode($data) . '</script>'
×
NEW
54
            : '';
×
55
    }
56

57
    /**
58
     * @return array<string, array<string, mixed>>
59
     */
60
    public function getStructuredData(): array
61
    {
62
        $structuredData = [];
×
63
        foreach ($this->getOrderedStructuredDataProviders() as $provider => $configuration) {
×
NEW
64
            $cacheIdentifier = $this->frontendService->getCacheIdentifier('-structured-data-' . $provider);
×
NEW
65
            $data = $this->pageCache->get($cacheIdentifier);
×
NEW
66
            if ($data !== false) {
×
NEW
67
                $structuredData[$provider] = $data;
×
NEW
68
                continue;
×
69
            }
70
            $structuredDataProviderObject = $this->getStructuredDataProviderObject($configuration);
×
71
            if ($structuredDataProviderObject === null) {
×
72
                continue;
×
73
            }
74

75
            if ($data = $structuredDataProviderObject->getData()) {
×
76
                $this->pageCache->set(
×
77
                    $cacheIdentifier,
×
78
                    $data,
×
NEW
79
                    ['pageId_' . $this->frontendService->getPageUid()],
×
NEW
80
                    $this->frontendService->getCacheTimeout(),
×
UNCOV
81
                );
×
82
            }
83

84
            if (!empty($data)) {
×
85
                $structuredData[$provider] = $data;
×
86
            }
87
        }
88

89
        return $structuredData;
×
90
    }
91

92
    /**
93
     * @param array<string, mixed> $configuration
94
     */
95
    protected function getStructuredDataProviderObject(array $configuration): StructuredDataProviderInterface|null
96
    {
97
        if (!class_exists($configuration['provider']) || !is_subclass_of($configuration['provider'], StructuredDataProviderInterface::class)) {
×
98
            return null;
×
99
        }
100

101
        $providerObject = GeneralUtility::makeInstance($configuration['provider']);
×
102
        if (method_exists($providerObject, 'setConfiguration')) {
×
103
            $providerObject->setConfiguration($configuration);
×
104
        }
105
        return $providerObject;
×
106
    }
107

108
    /**
109
     * @return array<string, array<string, mixed>>
110
     */
111
    private function getOrderedStructuredDataProviders(): array
112
    {
113
        $structuredDataProviders = $this->getStructuredDataProviderConfiguration();
×
114
        $structuredDataProviders = $this->setProviderOrder($structuredDataProviders);
×
115

NEW
116
        return $this->dependencyOrderingService->orderByDependencies($structuredDataProviders);
×
117
    }
118

119
    /**
120
     * @return array<string, array<string, mixed>>
121
     */
122
    private function getStructuredDataProviderConfiguration(): array
123
    {
NEW
124
        $config = $this->typoScriptService->convertTypoScriptArrayToPlainArray(
×
NEW
125
            $this->frontendService->getTyposcriptConfiguration()
×
UNCOV
126
        );
×
127

128
        return $config['structuredData']['providers'] ?? [];
×
129
    }
130

131
    /**
132
     * @param array<string, array<string, mixed>> $orderInformation
133
     * @return array<string, array<string, mixed>>
134
     */
135
    protected function setProviderOrder(array $orderInformation): array
136
    {
137
        foreach ($orderInformation as $provider => &$configuration) {
×
138
            if (isset($configuration['before'])) {
×
139
                $configuration['before'] = $this->getOrderConfiguration($provider, $configuration, 'before');
×
140
            }
141
            if (isset($configuration['after'])) {
×
142
                $configuration['after'] = $this->getOrderConfiguration($provider, $configuration, 'after');
×
143
            }
144
        }
145
        return $orderInformation;
×
146
    }
147

148
    /**
149
     * @param array<string, mixed> $configuration
150
     * @return string[]
151
     */
152
    private function getOrderConfiguration(string $provider, array $configuration, string $key): array
153
    {
154
        if (is_string($configuration[$key])) {
×
155
            return GeneralUtility::trimExplode(',', $configuration[$key], true);
×
156
        }
157
        if (!is_array($configuration[$key])) {
×
158
            throw new \UnexpectedValueException(
×
159
                'The specified "' . $key . '" order configuration for provider "' . $provider . '" is invalid.',
×
160
                1551014599
×
161
            );
×
162
        }
163
        return $configuration[$key];
×
164
    }
165

166
    protected function getSourceComment(): string
167
    {
168
        return '<!-- This site is optimized with the Yoast SEO for TYPO3 plugin - https://yoast.com/typo3-extensions-seo/ -->';
×
169
    }
170
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc