1 | <?php |
||||
2 | /** |
||||
3 | * SEOmatic plugin for Craft CMS |
||||
4 | * |
||||
5 | * A turnkey SEO implementation for Craft CMS that is comprehensive, powerful, |
||||
6 | * and flexible |
||||
7 | * |
||||
8 | * @link https://nystudio107.com |
||||
9 | * @copyright Copyright (c) 2017 nystudio107 |
||||
10 | */ |
||||
11 | |||||
12 | namespace nystudio107\seomatic\models; |
||||
13 | |||||
14 | use Craft; |
||||
15 | use craft\helpers\Html; |
||||
16 | use nystudio107\seomatic\base\NonceContainer; |
||||
17 | use nystudio107\seomatic\helpers\ImageTransform as ImageTransformHelper; |
||||
18 | use nystudio107\seomatic\Seomatic; |
||||
19 | use yii\caching\TagDependency; |
||||
20 | use yii\web\View; |
||||
21 | |||||
22 | /** |
||||
23 | * @author nystudio107 |
||||
24 | * @package Seomatic |
||||
25 | * @since 3.0.0 |
||||
26 | */ |
||||
27 | class MetaScriptContainer extends NonceContainer |
||||
28 | { |
||||
29 | // Constants |
||||
30 | // ========================================================================= |
||||
31 | |||||
32 | public const CONTAINER_TYPE = 'MetaScriptContainer'; |
||||
33 | |||||
34 | // Public Properties |
||||
35 | // ========================================================================= |
||||
36 | |||||
37 | /** |
||||
38 | * The data in this container |
||||
39 | * |
||||
40 | * @var MetaScript[] $data |
||||
41 | */ |
||||
42 | public $data = []; |
||||
43 | |||||
44 | /** |
||||
45 | * @var int |
||||
46 | */ |
||||
47 | public $position = View::POS_HEAD; |
||||
48 | |||||
49 | // Public Methods |
||||
50 | // ========================================================================= |
||||
51 | |||||
52 | /** |
||||
53 | * @inheritdoc |
||||
54 | */ |
||||
55 | public function includeMetaData($dependency) |
||||
56 | { |
||||
57 | Craft::beginProfile('MetaScriptContainer::includeMetaData', __METHOD__); |
||||
58 | $uniqueKey = $this->handle . $dependency->tags[3] . $this->dataLayerHash(); |
||||
59 | $cache = Craft::$app->getCache(); |
||||
60 | if ($this->clearCache) { |
||||
61 | TagDependency::invalidate($cache, $dependency->tags[3]); |
||||
62 | } |
||||
63 | $tagData = $cache->getOrSet( |
||||
64 | self::CONTAINER_TYPE . $uniqueKey, |
||||
65 | function() use ($uniqueKey) { |
||||
66 | Craft::info( |
||||
67 | self::CONTAINER_TYPE . ' cache miss: ' . $uniqueKey, |
||||
68 | __METHOD__ |
||||
69 | ); |
||||
70 | |||||
71 | return $this->renderInternal(); |
||||
72 | }, |
||||
73 | Seomatic::$cacheDuration, |
||||
74 | $dependency |
||||
75 | ); |
||||
76 | // Invalidate the cache we just created if there were pending image transforms in it |
||||
77 | // or we were asked to clear the cache for this container (because it's a preview request, etc.) |
||||
78 | if ($this->clearCache || ImageTransformHelper::$pendingImageTransforms) { |
||||
79 | TagDependency::invalidate($cache, $dependency->tags[3]); |
||||
80 | } |
||||
81 | // Register the tags |
||||
82 | foreach ($tagData as $config) { |
||||
83 | // Register the tags |
||||
84 | $attrs = $config['tagAttrs'] ?? []; |
||||
85 | if (!empty($config['nonce'])) { |
||||
86 | /** @noinspection SlowArrayOperationsInLoopInspection */ |
||||
87 | $attrs = array_merge($attrs, [ |
||||
88 | 'nonce' => $config['nonce'], |
||||
89 | ]); |
||||
90 | } |
||||
91 | $bodyJs = $config['bodyJs'] ?? false; |
||||
92 | if ($bodyJs) { |
||||
93 | Seomatic::$view->registerHtml( |
||||
0 ignored issues
–
show
|
|||||
94 | $config['js'], |
||||
95 | $config['position'], |
||||
96 | ); |
||||
97 | } else { |
||||
98 | Seomatic::$view->registerScript( |
||||
99 | $config['js'], |
||||
100 | $config['position'], |
||||
101 | $attrs |
||||
102 | ); |
||||
103 | } |
||||
104 | } |
||||
105 | |||||
106 | Craft::endProfile('MetaScriptContainer::includeMetaData', __METHOD__); |
||||
107 | } |
||||
108 | |||||
109 | /** |
||||
110 | * @inheritdoc |
||||
111 | */ |
||||
112 | public function render(array $params = [ |
||||
113 | 'renderScriptTags' => true, |
||||
114 | ]): string |
||||
115 | { |
||||
116 | $html = ''; |
||||
117 | $linebreak = ''; |
||||
118 | // If `devMode` is enabled, make the scripts human-readable |
||||
119 | if (Seomatic::$devMode) { |
||||
120 | $linebreak = PHP_EOL; |
||||
121 | } |
||||
122 | $tagData = $this->renderInternal(); |
||||
123 | // Register the tags |
||||
124 | foreach ($tagData as $config) { |
||||
125 | // Register the tags |
||||
126 | $attrs = $config['tagAttrs'] ?? []; |
||||
127 | if (!empty($config['nonce'])) { |
||||
128 | /** @noinspection SlowArrayOperationsInLoopInspection */ |
||||
129 | $attrs = array_merge($attrs, [ |
||||
130 | 'nonce' => $config['nonce'], |
||||
131 | ]); |
||||
132 | } |
||||
133 | $bodyJs = $config['bodyJs'] ?? false; |
||||
134 | // If `devMode` is enabled, add some positional information |
||||
135 | if (Seomatic::$devMode) { |
||||
136 | $positionNames = [ |
||||
137 | '<head>', |
||||
138 | '<body>', |
||||
139 | '</body>', |
||||
140 | 'jQuery(document).ready()', |
||||
141 | 'jQuery(window).load()', |
||||
142 | ]; |
||||
143 | $position = $positionNames[$config['position'] - 1] ?? 'unknown'; |
||||
144 | $html .= "<!-- Position: {$position} -->" . PHP_EOL; |
||||
145 | } |
||||
146 | if ($bodyJs || !$params['renderScriptTags']) { |
||||
147 | $html .= $config['js']; |
||||
148 | } else { |
||||
149 | $html .= Html::script($config['js'], $attrs); |
||||
150 | } |
||||
151 | $html .= $linebreak; |
||||
152 | } |
||||
153 | |||||
154 | return trim($html); |
||||
155 | } |
||||
156 | |||||
157 | /** |
||||
158 | * @inheritdoc |
||||
159 | */ |
||||
160 | public function normalizeContainerData() |
||||
161 | { |
||||
162 | parent::normalizeContainerData(); |
||||
163 | |||||
164 | /** @var array $config */ |
||||
165 | foreach ($this->data as $key => $config) { |
||||
166 | $config['key'] = $key; |
||||
167 | $this->data[$key] = MetaScript::create($config); |
||||
0 ignored issues
–
show
$config of type nystudio107\seomatic\models\MetaScript is incompatible with the type array expected by parameter $config of nystudio107\seomatic\models\MetaScript::create() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
168 | } |
||||
169 | } |
||||
170 | |||||
171 | // Protected Methods |
||||
172 | // ========================================================================= |
||||
173 | |||||
174 | /** |
||||
175 | * Render all of the scripts out into tagData |
||||
176 | * |
||||
177 | * @return array |
||||
178 | */ |
||||
179 | protected function renderInternal(): array |
||||
180 | { |
||||
181 | $tagData = []; |
||||
182 | if ($this->prepForInclusion()) { |
||||
183 | foreach ($this->data as $metaScriptModel) { |
||||
184 | if ($metaScriptModel->include) { |
||||
185 | // The regular script JS |
||||
186 | $js = $metaScriptModel->render(); |
||||
187 | if (!empty($js)) { |
||||
188 | $scenario = $this->scenario; |
||||
189 | $metaScriptModel->setScenario('render'); |
||||
190 | $options = $metaScriptModel->tagAttributes(); |
||||
191 | $metaScriptModel->setScenario($scenario); |
||||
192 | $tagData[] = [ |
||||
193 | 'js' => $js, |
||||
194 | 'position' => $metaScriptModel->position, |
||||
195 | 'nonce' => $metaScriptModel->nonce ?? null, |
||||
196 | 'tagAttrs' => $options, |
||||
197 | 'bodyJs' => false, |
||||
198 | ]; |
||||
199 | // If `devMode` is enabled, validate the Meta Script and output any model errors |
||||
200 | if (Seomatic::$devMode) { |
||||
201 | $metaScriptModel->debugMetaItem( |
||||
202 | 'Script attribute: ' |
||||
203 | ); |
||||
204 | } |
||||
205 | } |
||||
206 | // The body script JS (has no wrapping <script></script> tags, as it can be arbitrary HTML) |
||||
207 | $bodyJs = $metaScriptModel->renderBodyHtml(); |
||||
208 | if (!empty($bodyJs)) { |
||||
209 | $scenario = $this->scenario; |
||||
210 | $metaScriptModel->setScenario('render'); |
||||
211 | $options = $metaScriptModel->tagAttributes(); |
||||
212 | $metaScriptModel->setScenario($scenario); |
||||
213 | $tagData[] = [ |
||||
214 | 'js' => $bodyJs, |
||||
215 | 'position' => $metaScriptModel->bodyPosition, |
||||
216 | 'nonce' => $metaScriptModel->nonce ?? null, |
||||
217 | 'tagAttrs' => $options, |
||||
218 | 'bodyJs' => true, |
||||
219 | ]; |
||||
220 | // If `devMode` is enabled, validate the Meta Script and output any model errors |
||||
221 | if (Seomatic::$devMode) { |
||||
222 | $metaScriptModel->debugMetaItem( |
||||
223 | 'Script attribute: ' |
||||
224 | ); |
||||
225 | } |
||||
226 | } |
||||
227 | } |
||||
228 | } |
||||
229 | } |
||||
230 | |||||
231 | return $tagData; |
||||
232 | } |
||||
233 | |||||
234 | protected function dataLayerHash(): string |
||||
235 | { |
||||
236 | $data = ''; |
||||
237 | foreach ($this->data as $metaScriptModel) { |
||||
238 | $data .= serialize($metaScriptModel->dataLayer); |
||||
239 | } |
||||
240 | |||||
241 | return md5($data); |
||||
242 | } |
||||
243 | } |
||||
244 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.