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

TYPO3-Headless / headless / 26439917307

26 May 2026 07:58AM UTC coverage: 70.455% (-5.0%) from 75.459%
26439917307

Pull #893

github

web-flow
Merge 00997f766 into 79b7c5472
Pull Request #893: [TASK] Reintroduce missing features, extension cleanup

360 of 523 new or added lines in 32 files covered. (68.83%)

167 existing lines in 7 files now uncovered.

1364 of 1936 relevant lines covered (70.45%)

7.36 hits per line

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

97.62
/Classes/Seo/MetaTag/AbstractMetaTagManager.php
1
<?php
2

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

10
declare(strict_types=1);
11

12
namespace FriendsOfTYPO3\Headless\Seo\MetaTag;
13

14
use FriendsOfTYPO3\Headless\Utility\HeadlessModeInterface;
15
use Psr\Http\Message\ServerRequestInterface;
16
use TYPO3\CMS\Core\Type\DocType;
17
use TYPO3\CMS\Core\Utility\GeneralUtility;
18

19
use function array_merge;
20
use function json_encode;
21

22
use const JSON_THROW_ON_ERROR;
23

24
/**
25
 * Overridden core version with headless implementation
26
 */
27
abstract class AbstractMetaTagManager extends \TYPO3\CMS\Core\MetaTag\AbstractMetaTagManager
28
{
29
    private ?HeadlessModeInterface $headlessMode = null;
30

31
    private function getHeadlessMode(): HeadlessModeInterface
32
    {
33
        return $this->headlessMode ??= GeneralUtility::makeInstance(HeadlessModeInterface::class);
2✔
34
    }
35

36
    public function renderAllProperties(?DocType $docType = null): string
37
    {
38
        if ($this->isHeadlessRequest()) {
1✔
39
            return $this->renderAllHeadlessProperties();
1✔
40
        }
41

42
        return parent::renderAllProperties($docType);
1✔
43
    }
44

45
    public function renderProperty(string $property, ?DocType $docType = null): string
46
    {
47
        if ($this->isHeadlessRequest()) {
2✔
48
            return $this->renderHeadlessProperty($property);
2✔
49
        }
50

51
        return parent::renderProperty($property, $docType);
1✔
52
    }
53

54
    private function isHeadlessRequest(): bool
55
    {
56
        $request = $GLOBALS['TYPO3_REQUEST'] ?? null;
2✔
57
        return $request instanceof ServerRequestInterface
2✔
58
            && $this->getHeadlessMode()->isEnabledFor($request);
2✔
59
    }
60

61
    /**
62
     * Render a meta tag for a specific property
63
     *
64
     * @param string $property Name of the property
65
     */
66
    public function renderHeadlessProperty(string $property): string
67
    {
68
        return json_encode($this->renderHeadlessPropertyAsArray($property), JSON_THROW_ON_ERROR);
2✔
69
    }
70

71
    /**
72
     * @return array<int, array<string, string>>
73
     */
74
    public function renderHeadlessPropertyAsArray(string $property): array
75
    {
76
        $property = strtolower($property);
3✔
77
        $metaTags = [];
3✔
78

79
        $nameAttribute = $this->defaultNameAttribute;
3✔
80
        if (isset($this->handledProperties[$property]['nameAttribute'])
3✔
81
            && !empty((string)$this->handledProperties[$property]['nameAttribute'])) {
3✔
82
            $nameAttribute = (string)$this->handledProperties[$property]['nameAttribute'];
1✔
83
        }
84

85
        $contentAttribute = $this->defaultContentAttribute;
3✔
86
        if (isset($this->handledProperties[$property]['contentAttribute'])
3✔
87
            && !empty((string)$this->handledProperties[$property]['contentAttribute'])) {
3✔
88
            $contentAttribute = (string)$this->handledProperties[$property]['contentAttribute'];
1✔
89
        }
90

91
        if (!$nameAttribute || !$contentAttribute) {
3✔
NEW
92
            return $metaTags;
×
93
        }
94

95
        foreach ($this->getProperty($property) as $propertyItem) {
3✔
96
            $metaTags[] = [
3✔
97
                htmlspecialchars($nameAttribute) => htmlspecialchars($property),
3✔
98
                htmlspecialchars($contentAttribute) => htmlspecialchars($propertyItem['content']),
3✔
99
            ];
3✔
100

101
            if (!count($propertyItem['subProperties'])) {
3✔
102
                continue;
3✔
103
            }
104
            foreach ($propertyItem['subProperties'] as $subProperty => $subPropertyItems) {
1✔
105
                foreach ($subPropertyItems as $subPropertyItem) {
1✔
106
                    $metaTags[] = [
1✔
107
                        htmlspecialchars($nameAttribute) => htmlspecialchars($property . $this->subPropertySeparator . $subProperty),
1✔
108
                        htmlspecialchars($contentAttribute) => htmlspecialchars((string)$subPropertyItem),
1✔
109
                    ];
1✔
110
                }
111
            }
112
        }
113

114
        return $metaTags;
3✔
115
    }
116

117
    /**
118
     * Render all registered properties of this manager
119
     */
120
    public function renderAllHeadlessProperties(): string
121
    {
122
        return json_encode($this->renderAllHeadlessPropertiesAsArray(), JSON_THROW_ON_ERROR);
1✔
123
    }
124

125
    /**
126
     * @return array<int, array<string, string>>
127
     */
128
    public function renderAllHeadlessPropertiesAsArray(): array
129
    {
130
        $metaTags = [];
1✔
131
        foreach (array_keys($this->properties) as $property) {
1✔
132
            $metaTags = array_merge($metaTags, $this->renderHeadlessPropertyAsArray($property));
1✔
133
        }
134
        return $metaTags;
1✔
135
    }
136
}
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