1 | <?php |
||||||||
2 | /** |
||||||||
3 | * SEOmatic plugin for Craft CMS 3.x |
||||||||
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\services; |
||||||||
13 | |||||||||
14 | use Craft; |
||||||||
15 | use craft\base\Component; |
||||||||
16 | use craft\elements\Asset; |
||||||||
17 | use craft\elements\db\MatrixBlockQuery; |
||||||||
18 | use craft\elements\db\TagQuery; |
||||||||
19 | use craft\helpers\Template; |
||||||||
20 | use craft\web\twig\variables\Paginate; |
||||||||
21 | use nystudio107\seomatic\base\InheritableSettingsModel; |
||||||||
22 | use nystudio107\seomatic\helpers\DynamicMeta as DynamicMetaHelper; |
||||||||
23 | use nystudio107\seomatic\helpers\ImageTransform as ImageTransformHelper; |
||||||||
24 | use nystudio107\seomatic\helpers\Schema as SchemaHelper; |
||||||||
25 | use nystudio107\seomatic\helpers\Text as TextHelper; |
||||||||
26 | use nystudio107\seomatic\helpers\UrlHelper; |
||||||||
27 | use nystudio107\seomatic\models\MetaBundle; |
||||||||
28 | use nystudio107\seomatic\Seomatic; |
||||||||
29 | use yii\base\Exception; |
||||||||
30 | use yii\base\InvalidConfigException; |
||||||||
31 | |||||||||
32 | /** |
||||||||
33 | * Helper functions for SEOmatic |
||||||||
34 | * An instance of the service is available via [[`Seomatic::$plugin->helper`|`seomatic.helper`]] |
||||||||
35 | * |
||||||||
36 | * @author nystudio107 |
||||||||
37 | * @package Seomatic |
||||||||
38 | * @since 3.0.0 |
||||||||
39 | */ |
||||||||
40 | class Helper extends Component |
||||||||
41 | { |
||||||||
42 | // Constants |
||||||||
43 | // ========================================================================= |
||||||||
44 | |||||||||
45 | const TWITTER_TRANSFORM_MAP = [ |
||||||||
46 | 'summary' => 'twitter-summary', |
||||||||
47 | 'summary_large_image' => 'twitter-large', |
||||||||
48 | 'app' => 'twitter-large', |
||||||||
49 | 'player' => 'twitter-large', |
||||||||
50 | ]; |
||||||||
51 | |||||||||
52 | // Public Methods |
||||||||
53 | // ========================================================================= |
||||||||
54 | |||||||||
55 | /** |
||||||||
56 | * Return a base URL to the $path, removing any language segments that may |
||||||||
57 | * be present, for files like robots.txt that must be served from the root |
||||||||
58 | * |
||||||||
59 | * @param $path |
||||||||
60 | * @return string |
||||||||
61 | * @throws Exception |
||||||||
62 | */ |
||||||||
63 | public static function baseSiteUrl($path): string |
||||||||
64 | { |
||||||||
65 | $baseUrl = UrlHelper::hostInfo(UrlHelper::siteUrl($path)); |
||||||||
66 | |||||||||
67 | return rtrim($baseUrl, '/') . '/' . ltrim($path, '/'); |
||||||||
68 | } |
||||||||
69 | |||||||||
70 | /** |
||||||||
71 | * Sanitize user input by decoding any HTML Entities, URL decoding the text, |
||||||||
72 | * then removing any newlines, stripping tags, stripping Twig tags, and changing |
||||||||
73 | * single {}'s into ()'s |
||||||||
74 | * |
||||||||
75 | * @param $str |
||||||||
76 | * @return string |
||||||||
77 | */ |
||||||||
78 | public static function sanitizeUserInput($str): string |
||||||||
79 | { |
||||||||
80 | return TextHelper::sanitizeUserInput($str); |
||||||||
81 | } |
||||||||
82 | |||||||||
83 | /** |
||||||||
84 | * Return the appropriate Twitter Transform based on the current $metaGlobalVars->twitterCard |
||||||||
85 | * |
||||||||
86 | * @return string |
||||||||
87 | */ |
||||||||
88 | public static function twitterTransform(): string |
||||||||
89 | { |
||||||||
90 | $transform = 'twitter-summary'; |
||||||||
91 | $metaGlobalVars = Seomatic::$plugin->metaContainers->metaGlobalVars; |
||||||||
92 | if ($metaGlobalVars) { |
||||||||
93 | $transform = self::TWITTER_TRANSFORM_MAP[$metaGlobalVars->twitterCard] ?? $transform; |
||||||||
94 | } |
||||||||
95 | |||||||||
96 | return $transform; |
||||||||
97 | } |
||||||||
98 | |||||||||
99 | /** |
||||||||
100 | * Return the proper content for the `query-input` JSON-LD property |
||||||||
101 | * |
||||||||
102 | * @return string |
||||||||
103 | */ |
||||||||
104 | public static function siteLinksQueryInput(): string |
||||||||
105 | { |
||||||||
106 | $result = ''; |
||||||||
107 | |||||||||
108 | $metaSiteVars = Seomatic::$plugin->metaContainers->metaSiteVars; |
||||||||
109 | if ($metaSiteVars && !empty($metaSiteVars->siteLinksQueryInput)) { |
||||||||
110 | $result = 'required name=' . $metaSiteVars->siteLinksQueryInput; |
||||||||
111 | } |
||||||||
112 | |||||||||
113 | return $result; |
||||||||
114 | } |
||||||||
115 | |||||||||
116 | /** |
||||||||
117 | * Return whether this is a preview request of any kind |
||||||||
118 | * |
||||||||
119 | * @return bool |
||||||||
120 | */ |
||||||||
121 | public static function isPreview(): bool |
||||||||
122 | { |
||||||||
123 | $isPreview = false; |
||||||||
124 | $request = Craft::$app->getRequest(); |
||||||||
125 | if (Seomatic::$craft32) { |
||||||||
126 | $isPreview = $request->getIsPreview(); |
||||||||
127 | } |
||||||||
128 | $isLivePreview = $request->getIsLivePreview(); |
||||||||
129 | |||||||||
130 | return ($isPreview || $isLivePreview); |
||||||||
131 | } |
||||||||
132 | |||||||||
133 | /** |
||||||||
134 | * Return the Same As Links info as an array or null |
||||||||
135 | * |
||||||||
136 | * @param string $handle |
||||||||
137 | * @return array|null |
||||||||
138 | */ |
||||||||
139 | public static function sameAsByHandle(string $handle) |
||||||||
140 | { |
||||||||
141 | $result = null; |
||||||||
142 | |||||||||
143 | $sameAs = Seomatic::$plugin->metaContainers->metaSiteVars->sameAsLinks; |
||||||||
144 | if (!empty($sameAs) && !empty($handle)) { |
||||||||
145 | foreach ($sameAs as $sameAsInfo) { |
||||||||
146 | if (!empty($sameAsInfo) && is_array($sameAsInfo) && !empty($sameAsInfo['handle'])) { |
||||||||
147 | if ($sameAsInfo['handle'] === $handle) { |
||||||||
148 | return $sameAsInfo; |
||||||||
149 | } |
||||||||
150 | } |
||||||||
151 | } |
||||||||
152 | } |
||||||||
153 | |||||||||
154 | return $result; |
||||||||
155 | } |
||||||||
156 | |||||||||
157 | /** |
||||||||
158 | * Return the canonical URL for the request, with the query string stripped |
||||||||
159 | * |
||||||||
160 | * @return string |
||||||||
161 | */ |
||||||||
162 | public static function safeCanonicalUrl(): string |
||||||||
163 | { |
||||||||
164 | $url = ''; |
||||||||
0 ignored issues
–
show
Unused Code
introduced
by
![]() |
|||||||||
165 | try { |
||||||||
166 | $url = Craft::$app->getRequest()->getPathInfo(); |
||||||||
167 | } catch (InvalidConfigException $e) { |
||||||||
168 | Craft::error($e->getMessage(), __METHOD__); |
||||||||
169 | } |
||||||||
170 | |||||||||
171 | return DynamicMetaHelper::sanitizeUrl(UrlHelper::absoluteUrlWithProtocol($url)); |
||||||||
172 | } |
||||||||
173 | |||||||||
174 | /** |
||||||||
175 | * Return the site URL for a given URL. This gives SEOmatic a chance to override it |
||||||||
176 | * |
||||||||
177 | * @param string $path |
||||||||
178 | * @param array|string|null $params |
||||||||
179 | * @param string|null $scheme |
||||||||
180 | * @param int|null $siteId |
||||||||
181 | * @return string |
||||||||
182 | * @throws Exception if|null $siteId is invalid |
||||||||
183 | */ |
||||||||
184 | public static function siteUrl(string $path = '', $params = null, string $scheme = null, int $siteId = null): string |
||||||||
0 ignored issues
–
show
The parameter
$siteId is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() The parameter
$scheme is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() The parameter
$params is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. ![]() |
|||||||||
185 | { |
||||||||
186 | return UrlHelper::siteUrl($path); |
||||||||
187 | } |
||||||||
188 | |||||||||
189 | /** |
||||||||
190 | * Paginate based on the passed in Paginate variable as returned from the |
||||||||
191 | * Twig {% paginate %} tag: |
||||||||
192 | * https://docs.craftcms.com/v3/templating/tags/paginate.html#the-pageInfo-variable |
||||||||
193 | * |
||||||||
194 | * @param Paginate $pageInfo |
||||||||
195 | */ |
||||||||
196 | public static function paginate(Paginate $pageInfo) |
||||||||
197 | { |
||||||||
198 | DynamicMetaHelper::paginate($pageInfo); |
||||||||
199 | } |
||||||||
200 | |||||||||
201 | /** |
||||||||
202 | * Truncates the string to a given length. If $substring is provided, and |
||||||||
203 | * truncating occurs, the string is further truncated so that the substring |
||||||||
204 | * may be appended without exceeding the desired length. |
||||||||
205 | * |
||||||||
206 | * @param string $string The string to truncate |
||||||||
207 | * @param int $length Desired length of the truncated string |
||||||||
208 | * @param string $substring The substring to append if it can fit |
||||||||
209 | * |
||||||||
210 | * @return string with the resulting $str after truncating |
||||||||
211 | */ |
||||||||
212 | public static function truncate($string, $length, $substring = '…'): string |
||||||||
213 | { |
||||||||
214 | return TextHelper::truncate($string, $length, $substring); |
||||||||
215 | } |
||||||||
216 | |||||||||
217 | /** |
||||||||
218 | * Truncates the string to a given length, while ensuring that it does not |
||||||||
219 | * split words. If $substring is provided, and truncating occurs, the |
||||||||
220 | * string is further truncated so that the substring may be appended without |
||||||||
221 | * exceeding the desired length. |
||||||||
222 | * |
||||||||
223 | * @param string $string The string to truncate |
||||||||
224 | * @param int $length Desired length of the truncated string |
||||||||
225 | * @param string $substring The substring to append if it can fit |
||||||||
226 | * |
||||||||
227 | * @return string with the resulting $str after truncating |
||||||||
228 | */ |
||||||||
229 | public static function truncateOnWord($string, $length, $substring = '…'): string |
||||||||
230 | { |
||||||||
231 | return TextHelper::truncateOnWord($string, $length, $substring); |
||||||||
232 | } |
||||||||
233 | |||||||||
234 | /** |
||||||||
235 | * Return a list of localized URLs that are in the current site's group |
||||||||
236 | * The current URI is used if $uri is null. Similarly, the current site is |
||||||||
237 | * used if $siteId is null. |
||||||||
238 | * The resulting array of arrays has `id`, `language`, `ogLanguage`, |
||||||||
239 | * `hreflangLanguage`, and `url` as keys. |
||||||||
240 | * |
||||||||
241 | * @param string|null $uri |
||||||||
242 | * @param int|null $siteId |
||||||||
243 | * |
||||||||
244 | * @return array |
||||||||
245 | */ |
||||||||
246 | public static function getLocalizedUrls(string $uri = null, int $siteId = null): array |
||||||||
247 | { |
||||||||
248 | return DynamicMetaHelper::getLocalizedUrls($uri, $siteId); |
||||||||
249 | } |
||||||||
250 | |||||||||
251 | /** |
||||||||
252 | * Allow setting the X-Robots-Tag and Link headers on static files as per: |
||||||||
253 | * https://moz.com/blog/how-to-advanced-relcanonical-http-headers |
||||||||
254 | * |
||||||||
255 | * @param $url |
||||||||
256 | * @param string $robots |
||||||||
257 | * @param string $canonical |
||||||||
258 | * @param bool $inline |
||||||||
259 | * |
||||||||
260 | * @return \Twig\Markup |
||||||||
261 | * @throws \yii\base\Exception |
||||||||
262 | */ |
||||||||
263 | public static function seoFileLink($url, $robots = '', $canonical = '', $inline = true): \Twig\Markup |
||||||||
264 | { |
||||||||
265 | // Get the file name |
||||||||
266 | $path = parse_url($url, PHP_URL_PATH); |
||||||||
267 | $fileName = pathinfo($path, PATHINFO_BASENAME); |
||||||||
268 | // Set some defaults |
||||||||
269 | $robots = empty($robots) ? 'all' : $robots; |
||||||||
270 | $canonical = empty($canonical) ? $url : $canonical; |
||||||||
271 | $inlineStr = $inline === true ? '1' : '0'; |
||||||||
272 | // Compose the base64 encoded URL |
||||||||
273 | $seoFileLink = 'seomatic/seo-file-link/' |
||||||||
274 | . base64_encode($url) |
||||||||
275 | . '/' |
||||||||
276 | . base64_encode($robots) |
||||||||
277 | . '/' |
||||||||
278 | . base64_encode($canonical) |
||||||||
279 | . '/' |
||||||||
280 | . $inlineStr |
||||||||
281 | . '/' |
||||||||
282 | . $fileName; |
||||||||
0 ignored issues
–
show
Are you sure
$fileName of type array|string can be used in concatenation ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||||
283 | |||||||||
284 | return Template::raw(UrlHelper::siteUrl($seoFileLink)); |
||||||||
285 | } |
||||||||
286 | |||||||||
287 | /** |
||||||||
288 | * Load the appropriate meta containers for the given $uri and optional |
||||||||
289 | * $siteId |
||||||||
290 | * |
||||||||
291 | * @param string $uri |
||||||||
292 | * @param int|null $siteId |
||||||||
293 | */ |
||||||||
294 | public static function loadMetadataForUri(string $uri = '', int $siteId = null) |
||||||||
295 | { |
||||||||
296 | Seomatic::$plugin->metaContainers->loadMetaContainers($uri, $siteId); |
||||||||
297 | } |
||||||||
298 | |||||||||
299 | /** |
||||||||
300 | * Get the URL to the $siteId's sitemap index |
||||||||
301 | * |
||||||||
302 | * @param int|null $siteId |
||||||||
303 | * |
||||||||
304 | * @return string |
||||||||
305 | */ |
||||||||
306 | public static function sitemapIndexForSiteId(int $siteId = null): string |
||||||||
307 | { |
||||||||
308 | return Seomatic::$plugin->sitemaps->sitemapIndexUrlForSiteId($siteId); |
||||||||
309 | } |
||||||||
310 | |||||||||
311 | /** |
||||||||
312 | * Return a sitemap for each site in the same site group |
||||||||
313 | * |
||||||||
314 | * @return string |
||||||||
315 | */ |
||||||||
316 | public static function sitemapIndex(): string |
||||||||
317 | { |
||||||||
318 | return Seomatic::$plugin->sitemaps->sitemapIndex(); |
||||||||
319 | } |
||||||||
320 | |||||||||
321 | /** |
||||||||
322 | * Return a sitemap for each site in the same site group |
||||||||
323 | * |
||||||||
324 | * @return string |
||||||||
325 | * @deprecated use sitemapIndex() instead |
||||||||
326 | */ |
||||||||
327 | public static function siteGroupSitemaps(): string |
||||||||
328 | { |
||||||||
329 | return Seomatic::$plugin->sitemaps->sitemapIndex(); |
||||||||
330 | } |
||||||||
331 | |||||||||
332 | /** |
||||||||
333 | * @param string $sourceType |
||||||||
334 | * @param string $sourceHandle |
||||||||
335 | * @param int|null $siteId |
||||||||
336 | * |
||||||||
337 | * @return string |
||||||||
338 | */ |
||||||||
339 | public static function sitemapUrlForBundle(string $sourceType, string $sourceHandle, int $siteId = null, int $page = 0): string |
||||||||
340 | { |
||||||||
341 | return Seomatic::$plugin->sitemaps->sitemapUrlForBundle($sourceType, $sourceHandle, $siteId, $page); |
||||||||
342 | } |
||||||||
343 | |||||||||
344 | /** |
||||||||
345 | * Extract plain old text from a field |
||||||||
346 | * |
||||||||
347 | * @param $field |
||||||||
348 | * |
||||||||
349 | * @return string |
||||||||
350 | */ |
||||||||
351 | public static function extractTextFromField($field = null): string |
||||||||
352 | { |
||||||||
353 | return TextHelper::extractTextFromField($field); |
||||||||
354 | } |
||||||||
355 | |||||||||
356 | /** |
||||||||
357 | * Extract concatenated text from all of the tags in the $tagElement and |
||||||||
358 | * return as a comma-delimited string |
||||||||
359 | * |
||||||||
360 | * @param TagQuery $tagQuery |
||||||||
361 | * |
||||||||
362 | * @return string |
||||||||
363 | */ |
||||||||
364 | public static function extractTextFromTags($tagQuery = null): string |
||||||||
365 | { |
||||||||
366 | return TextHelper::extractTextFromTags($tagQuery); |
||||||||
367 | } |
||||||||
368 | |||||||||
369 | /** |
||||||||
370 | * Extract text from all of the blocks in a matrix field, concatenating it |
||||||||
371 | * together. |
||||||||
372 | * |
||||||||
373 | * @param MatrixBlockQuery $matrixQuery |
||||||||
374 | * @param string $fieldHandle |
||||||||
375 | * |
||||||||
376 | * @return string |
||||||||
377 | */ |
||||||||
378 | public static function extractTextFromMatrix($matrixQuery = null, $fieldHandle = ''): string |
||||||||
379 | { |
||||||||
380 | return TextHelper::extractTextFromMatrix($matrixQuery, $fieldHandle); |
||||||||
381 | } |
||||||||
382 | |||||||||
383 | /** |
||||||||
384 | * Return the most important keywords extracted from the text as a comma- |
||||||||
385 | * delimited string |
||||||||
386 | * |
||||||||
387 | * @param string $text |
||||||||
388 | * @param int $limit |
||||||||
389 | * @param bool $useStopWords |
||||||||
390 | * |
||||||||
391 | * @return string |
||||||||
392 | */ |
||||||||
393 | public static function extractKeywords($text = '', $limit = 15, $useStopWords = true): string |
||||||||
394 | { |
||||||||
395 | return TextHelper::extractKeywords($text, $limit, $useStopWords); |
||||||||
396 | } |
||||||||
397 | |||||||||
398 | /** |
||||||||
399 | * Extract a summary consisting of the 3 most important sentences from the |
||||||||
400 | * text |
||||||||
401 | * |
||||||||
402 | * @param string $text |
||||||||
403 | * @param bool $useStopWords |
||||||||
404 | * |
||||||||
405 | * @return string |
||||||||
406 | */ |
||||||||
407 | public static function extractSummary($text = '', $useStopWords = true): string |
||||||||
408 | { |
||||||||
409 | return TextHelper::extractSummary($text, $useStopWords); |
||||||||
410 | } |
||||||||
411 | |||||||||
412 | /** |
||||||||
413 | * Return a period-delimited schema.org path from the $settings |
||||||||
414 | * |
||||||||
415 | * @param $settings |
||||||||
416 | * |
||||||||
417 | * @return string |
||||||||
418 | */ |
||||||||
419 | public static function getEntityPath($settings): string |
||||||||
420 | { |
||||||||
421 | return SchemaHelper::getEntityPath($settings); |
||||||||
422 | } |
||||||||
423 | |||||||||
424 | /** |
||||||||
425 | * Return a flattened, indented menu of the given $path |
||||||||
426 | * |
||||||||
427 | * @param string $path |
||||||||
428 | * |
||||||||
429 | * @return array |
||||||||
430 | */ |
||||||||
431 | public static function getTypeMenu($path): array |
||||||||
432 | { |
||||||||
433 | return SchemaHelper::getTypeMenu($path); |
||||||||
434 | } |
||||||||
435 | |||||||||
436 | /** |
||||||||
437 | * Return a single menu of schemas starting at $path |
||||||||
438 | * |
||||||||
439 | * @param string $path |
||||||||
440 | * |
||||||||
441 | * @return array |
||||||||
442 | */ |
||||||||
443 | public static function getSingleTypeMenu($path): array |
||||||||
444 | { |
||||||||
445 | return SchemaHelper::getSingleTypeMenu($path); |
||||||||
446 | } |
||||||||
447 | |||||||||
448 | /** |
||||||||
449 | * Transform the $asset for social media sites in $transformName and |
||||||||
450 | * optional $siteId |
||||||||
451 | * |
||||||||
452 | * @param int|Asset $asset the Asset or Asset ID |
||||||||
453 | * @param string $transformName the name of the transform to apply |
||||||||
454 | * @param int|null $siteId |
||||||||
455 | * @param string $transformMode |
||||||||
456 | * |
||||||||
457 | * @return string URL to the transformed image |
||||||||
458 | */ |
||||||||
459 | public function socialTransform($asset, $transformName = '', $siteId = null, $transformMode = null): string |
||||||||
460 | { |
||||||||
461 | return ImageTransformHelper::socialTransform($asset, $transformName, $siteId, $transformMode); |
||||||||
462 | } |
||||||||
463 | |||||||||
464 | /** |
||||||||
465 | * Get the width of the transformed social image for $transformName and |
||||||||
466 | * optional $siteId |
||||||||
467 | * |
||||||||
468 | * @param int|Asset $asset the Asset or Asset ID |
||||||||
469 | * @param string $transformName the name of the transform to apply |
||||||||
470 | * @param int|null $siteId |
||||||||
471 | * @param string $transformMode |
||||||||
472 | * |
||||||||
473 | * @return string URL to the transformed image |
||||||||
474 | */ |
||||||||
475 | public function socialTransformWidth( |
||||||||
476 | $asset, |
||||||||
477 | $transformName = '', |
||||||||
478 | $siteId = null, |
||||||||
479 | $transformMode = null |
||||||||
480 | ): string { |
||||||||
481 | return ImageTransformHelper::socialTransformWidth($asset, $transformName, $siteId, $transformMode); |
||||||||
482 | } |
||||||||
483 | |||||||||
484 | /** |
||||||||
485 | * Get the height of the transformed social image for $transformName and |
||||||||
486 | * optional $siteId |
||||||||
487 | * |
||||||||
488 | * @param int|Asset $asset the Asset or Asset ID |
||||||||
489 | * @param string $transformName the name of the transform to apply |
||||||||
490 | * @param int|null $siteId |
||||||||
491 | * @param string $transformMode |
||||||||
492 | * |
||||||||
493 | * @return string URL to the transformed image |
||||||||
494 | */ |
||||||||
495 | public function socialTransformHeight( |
||||||||
496 | $asset, |
||||||||
497 | $transformName = '', |
||||||||
498 | $siteId = null, |
||||||||
499 | $transformMode = null |
||||||||
500 | ): string { |
||||||||
501 | return ImageTransformHelper::socialTransformHeight($asset, $transformName, $siteId, $transformMode); |
||||||||
502 | } |
||||||||
503 | |||||||||
504 | /** |
||||||||
505 | * Return whether we are running Craft 3.1 or later |
||||||||
506 | * |
||||||||
507 | * @return bool |
||||||||
508 | */ |
||||||||
509 | public function craft31(): bool |
||||||||
510 | { |
||||||||
511 | return Seomatic::$craft31; |
||||||||
512 | } |
||||||||
513 | |||||||||
514 | /** |
||||||||
515 | * Return whether we are running Craft 3.2 or later |
||||||||
516 | * |
||||||||
517 | * @return bool |
||||||||
518 | */ |
||||||||
519 | public function craft32(): bool |
||||||||
520 | { |
||||||||
521 | return Seomatic::$craft32; |
||||||||
522 | } |
||||||||
523 | |||||||||
524 | /** |
||||||||
525 | * Return whether we are running Craft 3.3 or later |
||||||||
526 | * |
||||||||
527 | * @return bool |
||||||||
528 | */ |
||||||||
529 | public function craft33(): bool |
||||||||
530 | { |
||||||||
531 | return Seomatic::$craft33; |
||||||||
532 | } |
||||||||
533 | |||||||||
534 | /** |
||||||||
535 | * Given a list of meta bundles in order of descending distance, return the bundle that has inheritable value. |
||||||||
536 | * |
||||||||
537 | * @param array $inheritedValues |
||||||||
538 | * @param string $settingName |
||||||||
539 | * @param string $collectionName The name off the collection to search |
||||||||
540 | * @return MetaBundle|null |
||||||||
541 | * @since 3.4.0 |
||||||||
542 | */ |
||||||||
543 | public function findInheritableBundle(array $inheritedValues, string $settingName, string $collectionName = "metaGlobalVars") |
||||||||
544 | { |
||||||||
545 | if (in_array($collectionName, ['metaGlobalVars', 'metaSitemapVars'], true)) { |
||||||||
546 | foreach ($inheritedValues as $bundle) { |
||||||||
547 | /** @var $bundle MetaBundle */ |
||||||||
548 | if (isset($bundle->{$collectionName}[$settingName])) { |
||||||||
549 | if (is_bool($bundle->{$collectionName}[$settingName]) || !empty($bundle->{$collectionName}[$settingName])) { |
||||||||
550 | return $bundle; |
||||||||
551 | } |
||||||||
552 | } |
||||||||
553 | } |
||||||||
554 | } |
||||||||
555 | |||||||||
556 | return null; |
||||||||
557 | } |
||||||||
558 | |||||||||
559 | /** |
||||||||
560 | * Return true if a setting is inherited. |
||||||||
561 | * |
||||||||
562 | * @param InheritableSettingsModel $settingCollection |
||||||||
563 | * @param $settingName |
||||||||
564 | * @return bool |
||||||||
565 | * @since 3.4.0 |
||||||||
566 | */ |
||||||||
567 | public function isInherited(InheritableSettingsModel $settingCollection, $settingName) |
||||||||
568 | { |
||||||||
569 | $explicitInherit = array_key_exists($settingName, (array)$settingCollection->inherited); |
||||||||
570 | $explicitOverride = array_key_exists($settingName, (array)$settingCollection->overrides); |
||||||||
571 | |||||||||
572 | if ($explicitInherit || $explicitOverride) { |
||||||||
573 | return $explicitInherit && !$explicitOverride; |
||||||||
574 | } |
||||||||
575 | |||||||||
576 | return empty($settingCollection->{$settingName}); |
||||||||
577 | } |
||||||||
578 | } |
||||||||
579 |