Test Failed
Push — v5 ( ec28e0...e66c40 )
by Andrew
54:30 queued 27:51
created

Sitemap::getElementListSitemap()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 0
c 0
b 0
f 0
dl 0
loc 2
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
namespace nystudio107\seomatic\helpers;
4
5
use benf\neo\elements\Block as NeoBlock;
6
use Craft;
7
use craft\base\Element;
8
use craft\base\Event;
9
use craft\console\Application as ConsoleApplication;
10
use craft\db\Paginator;
11
use craft\elements\Asset;
0 ignored issues
show
Bug introduced by
The type craft\elements\Asset was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use craft\elements\Entry;
13
use craft\errors\SiteNotFoundException;
14
use craft\fields\Assets as AssetsField;
15
use DateTime;
16
use nystudio107\seomatic\base\SeoElementInterface;
17
use nystudio107\seomatic\events\IncludeSitemapEntryEvent;
18
use nystudio107\seomatic\fields\SeoSettings;
19
use nystudio107\seomatic\helpers\Field as FieldHelper;
20
use nystudio107\seomatic\models\MetaBundle;
21
use nystudio107\seomatic\models\SitemapTemplate;
22
use nystudio107\seomatic\Seomatic;
23
use Throwable;
24
use yii\base\Exception;
25
use yii\helpers\Html;
26
use function array_intersect_key;
27
use function count;
28
use function in_array;
29
30
/**
31
 * @author    nystudio107
32
 * @package   Seomatic
33
 * @since     3.4.18
34
 */
35
class Sitemap
36
{
37
    /**
38
     * @event IncludeSitemapEntryEvent The event that is triggered when an entry is
39
     * about to be included in a sitemap
40
     *
41
     * ---
42
     * ```php
43
     * use nystudio107\seomatic\events\IncludeSitemapEntryEvent;
44
     * use nystudio107\seomatic\helpers\Sitemap;
45
     * use yii\base\Event;
46
     * Event::on(Sitemap::class, Sitemap::EVENT_INCLUDE_SITEMAP_ENTRY, function(IncludeSitemapEntryEvent $e) {
47
     *     $e->include = false;
48
     * });
49
     * ```
50
     */
51
    public const EVENT_INCLUDE_SITEMAP_ENTRY = 'includeSitemapEntry';
52
53
    /**
54
     * @const The number of assets to return in a single paginated query
55
     */
56
    public const SITEMAP_QUERY_PAGE_SIZE = 100;
57
58
    /**
59
     * Generate a sitemap with the passed in $params
60
     *
61
     * @param array $params
62
     * @return string
63
     * @throws SiteNotFoundException
64
     */
65
    public static function generateSitemap(array $params): ?string
66
    {
67
        $groupId = $params['groupId'];
68
        $type = $params['type'];
69
        $handle = $params['handle'];
70
        $siteId = $params['siteId'];
71
        $page = $params['page'];
72
73
        // Get an array of site ids for this site group
74
        $groupSiteIds = [];
75
76
        if (Seomatic::$settings->siteGroupsSeparate) {
77
            if (empty($groupId)) {
78
                try {
79
                    $thisSite = Craft::$app->getSites()->getSiteById($siteId);
80
                    if ($thisSite !== null) {
81
                        $group = $thisSite->getGroup();
82
                        $groupId = $group->id;
83
                    }
84
                } catch (Throwable $e) {
85
                    Craft::error($e->getMessage(), __METHOD__);
86
                }
87
            }
88
            $siteGroup = Craft::$app->getSites()->getGroupById($groupId);
89
            if ($siteGroup !== null) {
90
                $groupSiteIds = $siteGroup->getSiteIds();
91
            }
92
        }
93
94
        if (empty($groupSiteIds)) {
95
            $groupSiteIds = Craft::$app->getSites()->allSiteIds;
96
        }
97
98
        $lines = [];
99
        // Sitemap index XML header and opening tag
100
        $lines[] = '<?xml version="1.0" encoding="UTF-8"?>';
101
        $lines[] = '<?xml-stylesheet type="text/xsl" href="sitemap.xsl"?>';
102
        // One sitemap entry for each element
103
        $metaBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceHandle(
104
            $type,
105
            $handle,
106
            $siteId
107
        );
108
        // If it doesn't exist, exit
109
        if ($metaBundle === null) {
110
            return null;
111
        }
112
        $multiSite = count($metaBundle->sourceAltSiteSettings) > 1;
113
        $totalElements = null;
114
        $urlsetLine = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"';
115
        if ($metaBundle->metaSitemapVars->sitemapAssets) {
116
            $urlsetLine .= ' xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"';
117
            $urlsetLine .= ' xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"';
118
        }
119
        if ($multiSite) {
120
            $urlsetLine .= ' xmlns:xhtml="http://www.w3.org/1999/xhtml"';
121
        }
122
        if ((bool)$metaBundle->metaSitemapVars->newsSitemap) {
123
            $urlsetLine .= ' xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"';
124
        }
125
        $urlsetLine .= '>';
126
        $lines[] = $urlsetLine;
127
128
        // Get all of the elements for this meta bundle type
129
        $seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType($metaBundle->sourceBundleType);
130
131
        if ($seoElement !== null) {
132
            // Ensure `null` so that the resulting element query is correct
133
            if (empty($metaBundle->metaSitemapVars->sitemapLimit)) {
134
                $metaBundle->metaSitemapVars->sitemapLimit = null;
135
            }
136
137
            $totalElements = $seoElement::sitemapElementsQuery($metaBundle)->count();
138
            if ($metaBundle->metaSitemapVars->sitemapLimit && ($totalElements > $metaBundle->metaSitemapVars->sitemapLimit)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $metaBundle->metaSitemapVars->sitemapLimit of type integer|null is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
139
                $totalElements = $metaBundle->metaSitemapVars->sitemapLimit;
140
            }
141
        }
142
143
        // If no elements exist, just exit
144
        if (!$totalElements) {
145
            return null;
146
        }
147
148
        // Stash the sitemap attributes so they can be modified on a per-entry basis
149
        $stashedSitemapAttrs = $metaBundle->metaSitemapVars->getAttributes();
0 ignored issues
show
Bug introduced by
The method getAttributes() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

149
        /** @scrutinizer ignore-call */ 
150
        $stashedSitemapAttrs = $metaBundle->metaSitemapVars->getAttributes();

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.

Loading history...
150
        $stashedGlobalVarsAttrs = $metaBundle->metaGlobalVars->getAttributes();
0 ignored issues
show
Bug introduced by
The method getAttributes() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

150
        /** @scrutinizer ignore-call */ 
151
        $stashedGlobalVarsAttrs = $metaBundle->metaGlobalVars->getAttributes();

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.

Loading history...
151
        // Use craft\db\Paginator to paginate the results so we don't exceed any memory limits
152
        // See batch() and each() discussion here: https://github.com/yiisoft/yii2/issues/8420
153
        // and here: https://github.com/craftcms/cms/issues/7338
154
155
        $elementQuery = $seoElement::sitemapElementsQuery($metaBundle);
156
        $sitemapPageSize = $metaBundle->metaSitemapVars->sitemapPageSize;
157
        $elementQuery->limit($metaBundle->metaSitemapVars->sitemapLimit ?? null);
158
159
        // If this is not a paged sitemap, go through full resultss
160
        if (is_null($sitemapPageSize)) {
161
            $pagedSitemap = false;
162
            $paginator = new Paginator($elementQuery, [
163
                'pageSize' => self::SITEMAP_QUERY_PAGE_SIZE,
164
            ]);
165
            $elements = $paginator->getPageResults();
166
        } else {
167
            $sitemapPage = empty($page) ? 1 : $page;
168
            $pagedSitemap = true;
169
            $elementQuery->limit($sitemapPageSize);
170
            $elementQuery->offset(($sitemapPage - 1) * $sitemapPageSize);
171
            $elements = $elementQuery->all();
172
            $totalElements = $sitemapPageSize;
173
            $paginator = new Paginator($elementQuery, [
174
                'pageSize' => $sitemapPageSize,
175
            ]);
176
        }
177
178
        $currentElement = 1;
179
180
        do {
181
            if (Craft::$app instanceof ConsoleApplication) {
182
                if ($pagedSitemap) {
183
                    $message = sprintf('Query %d elements', $sitemapPageSize);
184
                } else {
185
                    $message = sprintf('Query %d / %d - elements: %d',
186
                        $paginator->getCurrentPage(),
187
                        $paginator->getTotalPages(),
188
                        $paginator->getTotalResults());
189
                }
190
                echo $message . PHP_EOL;
191
            }
192
            /** @var Element $element */
193
            foreach ($elements as $element) {
194
                // Output some info if this is a console app
195
                if (Craft::$app instanceof ConsoleApplication) {
196
                    echo "Processing element {$currentElement}/{$totalElements} - {$element->title}" . PHP_EOL;
197
                }
198
199
                $metaBundle->metaSitemapVars->setAttributes($stashedSitemapAttrs, false);
200
                $metaBundle->metaGlobalVars->setAttributes($stashedGlobalVarsAttrs, false);
201
                // Combine in any per-entry type settings
202
                self::combineEntryTypeSettings($seoElement, $element, $metaBundle);
203
                // Make sure this entry isn't disabled
204
                self::combineFieldSettings($element, $metaBundle);
205
                // Special case for the __home__ URI
206
                $path = ($element->uri === '__home__') ? '' : $element->uri;
207
                // Check to see if robots is `none` or `no index`
208
                $robotsEnabled = true;
209
                if (!empty($metaBundle->metaGlobalVars->robots)) {
210
                    $robotsEnabled = $metaBundle->metaGlobalVars->robots !== 'none' &&
211
                        $metaBundle->metaGlobalVars->robots !== 'noindex';
212
                }
213
                $enabled = $element->getEnabledForSite($metaBundle->sourceSiteId);
214
                $enabled = $enabled && $path !== null && $metaBundle->metaSitemapVars->sitemapUrls && $robotsEnabled;
215
                $event = new IncludeSitemapEntryEvent([
216
                    'include' => $enabled,
217
                    'element' => $element,
218
                    'metaBundle' => $metaBundle,
219
                ]);
220
                Event::trigger(self::class, self::EVENT_INCLUDE_SITEMAP_ENTRY, $event);
221
                // Only add in a sitemap entry if it meets our criteria
222
                if ($event->include) {
223
                    // Get the url and canonicalUrl
224
                    try {
225
                        $url = UrlHelper::siteUrl($path, null, null, $metaBundle->sourceSiteId);
226
                    } catch (Exception $e) {
227
                        $url = '';
228
                    }
229
                    $url = UrlHelper::absoluteUrlWithProtocol($url);
230
                    if (Seomatic::$settings->excludeNonCanonicalUrls) {
231
                        Seomatic::$matchedElement = $element;
232
                        MetaValue::cache();
233
                        $path = $metaBundle->metaGlobalVars->parsedValue('canonicalUrl');
234
                        try {
235
                            $canonicalUrl = UrlHelper::siteUrl($path, null, null, $metaBundle->sourceSiteId);
236
                        } catch (Exception $e) {
237
                            $canonicalUrl = '';
238
                        }
239
                        $canonicalUrl = UrlHelper::absoluteUrlWithProtocol($canonicalUrl);
240
                        if ($url !== $canonicalUrl) {
241
                            Craft::info("Excluding URL: {$url} from the sitemap because it does not match the Canonical URL: {$canonicalUrl} - " . $metaBundle->metaGlobalVars->canonicalUrl . " - " . $element->uri);
0 ignored issues
show
Bug introduced by
Are you sure $metaBundle->metaGlobalVars->canonicalUrl of type object|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 ignore-type  annotation

241
                            Craft::info("Excluding URL: {$url} from the sitemap because it does not match the Canonical URL: {$canonicalUrl} - " . /** @scrutinizer ignore-type */ $metaBundle->metaGlobalVars->canonicalUrl . " - " . $element->uri);
Loading history...
242
                            continue;
243
                        }
244
                    }
245
                    $dateUpdated = $element->dateUpdated ?? $element->dateCreated ?? new DateTime();
246
                    $lines[] = '<url>';
247
                    // Standard sitemap key/values
248
                    $lines[] = '<loc>';
249
                    $lines[] = Html::encode($url);
250
                    $lines[] = '</loc>';
251
                    $lines[] = '<lastmod>';
252
                    $lines[] = $dateUpdated->format(DateTime::W3C);
253
                    $lines[] = '</lastmod>';
254
                    $lines[] = '<changefreq>';
255
                    $lines[] = $metaBundle->metaSitemapVars->sitemapChangeFreq;
256
                    $lines[] = '</changefreq>';
257
                    $lines[] = '<priority>';
258
                    $lines[] = $metaBundle->metaSitemapVars->sitemapPriority;
259
                    $lines[] = '</priority>';
260
                    // Handle alternate URLs if this is multi-site
261
                    if ($multiSite && $metaBundle->metaSitemapVars->sitemapAltLinks) {
262
                        $primarySiteId = Craft::$app->getSites()->getPrimarySite()->id;
263
                        foreach ($metaBundle->sourceAltSiteSettings as $altSiteSettings) {
264
                            if (in_array($altSiteSettings['siteId'], $groupSiteIds, false) && SiteHelper::siteEnabledWithUrls($altSiteSettings['siteId'])) {
265
                                $altElement = null;
266
                                if ($seoElement !== null) {
267
                                    /** @var Element $altElement */
268
                                    $altElement = $seoElement::sitemapAltElement(
269
                                        $metaBundle,
270
                                        $element->id,
271
                                        $altSiteSettings['siteId']
272
                                    );
273
                                }
274
                                // Make sure to only include the `hreflang` if the element exists,
275
                                // and sitemaps are on for it
276
                                if (Seomatic::$settings->addHrefLang && $altElement && $altElement->url) {
277
                                    list($altSourceId, $altSourceBundleType, $altSourceHandle, $altSourceSiteId, $altTypeId)
278
                                        = Seomatic::$plugin->metaBundles->getMetaSourceFromElement($altElement);
279
                                    $altMetaBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceId(
280
                                        $altSourceBundleType,
281
                                        $altSourceId,
282
                                        $altSourceSiteId
283
                                    );
284
                                    if ($altMetaBundle) {
285
                                        $altEnabled = $altElement->getEnabledForSite($altMetaBundle->sourceSiteId);
286
                                        // Make sure this entry isn't disabled
287
                                        self::combineFieldSettings($altElement, $altMetaBundle);
288
                                        if ($altEnabled && $altMetaBundle->metaSitemapVars->sitemapUrls) {
289
                                            try {
290
                                                $altUrl = UrlHelper::siteUrl($altElement->url, null, null, $altSourceId);
291
                                            } catch (Exception $e) {
292
                                                $altUrl = $altElement->url;
293
                                            }
294
                                            $altUrl = UrlHelper::absoluteUrlWithProtocol($altUrl);
295
                                            // If this is the primary site, add it as x-default, too
296
                                            if ($primarySiteId === $altSourceSiteId && Seomatic::$settings->addXDefaultHrefLang) {
297
                                                $lines[] = '<xhtml:link rel="alternate"'
298
                                                    . ' hreflang="x-default"'
299
                                                    . ' href="' . Html::encode($altUrl) . '"'
300
                                                    . ' />';
301
                                            }
302
                                            $lines[] = '<xhtml:link rel="alternate"'
303
                                                . ' hreflang="' . $altSiteSettings['language'] . '"'
304
                                                . ' href="' . Html::encode($altUrl) . '"'
305
                                                . ' />';
306
                                        }
307
                                    }
308
                                }
309
                            }
310
                        }
311
                    }
312
                    // Handle any Assets
313
                    if ($metaBundle->metaSitemapVars->sitemapAssets) {
314
                        // Regular Assets fields
315
                        $assetFields = FieldHelper::fieldsOfTypeFromElement(
316
                            $element,
317
                            FieldHelper::ASSET_FIELD_CLASS_KEY,
318
                            true
319
                        );
320
                        foreach ($assetFields as $assetField) {
321
                            $assets = $element[$assetField]->all();
322
                            /** @var Asset[] $assets */
323
                            foreach ($assets as $asset) {
324
                                self::assetSitemapItem($asset, $metaBundle, $lines);
325
                            }
326
                        }
327
                        // Assets embeded in Block fields
328
                        $blockFields = FieldHelper::fieldsOfTypeFromElement(
329
                            $element,
330
                            FieldHelper::BLOCK_FIELD_CLASS_KEY,
331
                            true
332
                        );
333
                        foreach ($blockFields as $blockField) {
334
                            $blocks = $element[$blockField]->all();
335
                            /** @var Entry[]|NeoBlock[]|object[] $blocks */
336
                            foreach ($blocks as $block) {
337
                                $assetFields = [];
338
                                if ($block instanceof Entry) {
339
                                    $assetFields = FieldHelper::matrixFieldsOfType($block, AssetsField::class);
340
                                }
341
                                if ($block instanceof NeoBlock) {
342
                                    $assetFields = FieldHelper::neoFieldsOfType($block, AssetsField::class);
343
                                }
344
                                foreach ($assetFields as $assetField) {
345
                                    foreach ($block[$assetField]->all() as $asset) {
346
                                        self::assetSitemapItem($asset, $metaBundle, $lines);
347
                                    }
348
                                }
349
                            }
350
                        }
351
                    }
352
                    $lines[] = '</url>';
353
                }
354
                // Include links to any known file types in the assets fields
355
                if ($metaBundle->metaSitemapVars->sitemapFiles) {
356
                    // Regular Assets fields
357
                    $assetFields = FieldHelper::fieldsOfTypeFromElement(
358
                        $element,
359
                        FieldHelper::ASSET_FIELD_CLASS_KEY,
360
                        true
361
                    );
362
                    foreach ($assetFields as $assetField) {
363
                        $assets = $element[$assetField]->all();
364
                        foreach ($assets as $asset) {
365
                            self::assetFilesSitemapLink($asset, $metaBundle, $lines);
366
                        }
367
                    }
368
                    // Assets embeded in Block fields
369
                    $blockFields = FieldHelper::fieldsOfTypeFromElement(
370
                        $element,
371
                        FieldHelper::BLOCK_FIELD_CLASS_KEY,
372
                        true
373
                    );
374
                    foreach ($blockFields as $blockField) {
375
                        $blocks = $element[$blockField]->all();
376
                        /** @var Entry[]|NeoBlock[]|object[] $blocks */
377
                        foreach ($blocks as $block) {
378
                            $assetFields = [];
379
                            if ($block instanceof Entry) {
380
                                $assetFields = FieldHelper::matrixFieldsOfType($block, AssetsField::class);
381
                            }
382
                            if ($block instanceof NeoBlock) {
383
                                $assetFields = FieldHelper::neoFieldsOfType($block, AssetsField::class);
384
                            }
385
                            foreach ($assetFields as $assetField) {
386
                                foreach ($block[$assetField]->all() as $asset) {
387
                                    self::assetFilesSitemapLink($asset, $metaBundle, $lines);
388
                                }
389
                            }
390
                        }
391
                    }
392
                }
393
                $currentElement++;
394
            }
395
396
            if ($pagedSitemap) {
397
                break;
398
            }
399
400
            if ($paginator->getCurrentPage() == $paginator->getTotalPages()) {
401
                break;
402
            }
403
404
            $paginator->currentPage++;
405
            $elements = $paginator->getPageResults();
406
        } while (!empty($elements));
407
408
        // Sitemap closing tag
409
        $lines[] = '</urlset>';
410
411
        return implode('', $lines);
412
    }
413
414
415
    /**
416
     * Combine any per-entry type field settings from $element with the passed in
417
     * $metaBundle
418
     *
419
     * @param SeoElementInterface|string $seoElement
420
     * @param Element $element
421
     * @param MetaBundle $metaBundle
422
     */
423
    protected static function combineEntryTypeSettings($seoElement, Element $element, MetaBundle $metaBundle)
424
    {
425
        if (!empty($seoElement::typeMenuFromHandle($metaBundle->sourceHandle))) {
426
            list($sourceId, $sourceBundleType, $sourceHandle, $sourceSiteId, $typeId)
427
                = Seomatic::$plugin->metaBundles->getMetaSourceFromElement($element);
428
            $entryTypeBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceId(
429
                $sourceBundleType,
430
                $sourceId,
431
                $sourceSiteId,
432
                $typeId
433
            );
434
            // Combine in any settings for this entry type
435
            if ($entryTypeBundle) {
436
                // Combine the meta sitemap vars
437
                $attributes = $entryTypeBundle->metaSitemapVars->getAttributes();
0 ignored issues
show
Bug introduced by
The method getAttributes() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

437
                /** @scrutinizer ignore-call */ 
438
                $attributes = $entryTypeBundle->metaSitemapVars->getAttributes();

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.

Loading history...
438
                $attributes = array_filter(
439
                    $attributes,
440
                    [ArrayHelper::class, 'preserveBools']
441
                );
442
                $metaBundle->metaSitemapVars->setAttributes($attributes, false);
443
444
                // Combine the meta global vars
445
                $attributes = $entryTypeBundle->metaGlobalVars->getAttributes();
0 ignored issues
show
Bug introduced by
The method getAttributes() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

445
                /** @scrutinizer ignore-call */ 
446
                $attributes = $entryTypeBundle->metaGlobalVars->getAttributes();

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.

Loading history...
446
                $attributes = array_filter(
447
                    $attributes,
448
                    [ArrayHelper::class, 'preserveBools']
449
                );
450
                $metaBundle->metaGlobalVars->setAttributes($attributes, false);
451
            }
452
        }
453
    }
454
455
    /**
456
     * Combine any SEO Settings field settings from $element with the passed in
457
     * $metaBundle
458
     *
459
     * @param Element $element
460
     * @param MetaBundle $metaBundle
461
     */
462
    protected static function combineFieldSettings(Element $element, MetaBundle $metaBundle)
463
    {
464
        $fieldHandles = FieldHelper::fieldsOfTypeFromElement(
465
            $element,
466
            FieldHelper::SEO_SETTINGS_CLASS_KEY,
467
            true
468
        );
469
        foreach ($fieldHandles as $fieldHandle) {
470
            if (!empty($element->$fieldHandle)) {
471
                /** @var SeoSettings $seoSettingsField */
472
                $seoSettingsField = Craft::$app->getFields()->getFieldByHandle($fieldHandle);
473
                /** @var MetaBundle $metaBundle */
474
                $fieldMetaBundle = $element->$fieldHandle;
475
                if ($seoSettingsField !== null) {
476
                    if ($seoSettingsField->sitemapTabEnabled) {
477
                        Seomatic::$plugin->metaBundles->pruneFieldMetaBundleSettings($fieldMetaBundle, $fieldHandle);
478
                        // Combine the meta sitemap vars
479
                        $attributes = $fieldMetaBundle->metaSitemapVars->getAttributes();
480
481
                        // Get the explicitly inherited attributes
482
                        $inherited = array_keys(ArrayHelper::remove($attributes, 'inherited', []));
0 ignored issues
show
Bug introduced by
It seems like nystudio107\seomatic\hel..., 'inherited', array()) can also be of type null; however, parameter $array of array_keys() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

482
                        $inherited = array_keys(/** @scrutinizer ignore-type */ ArrayHelper::remove($attributes, 'inherited', []));
Loading history...
483
484
                        $attributes = array_intersect_key(
485
                            $attributes,
486
                            array_flip((array)$seoSettingsField->sitemapEnabledFields)
487
                        );
488
                        $attributes = array_filter(
489
                            $attributes,
490
                            [ArrayHelper::class, 'preserveBools']
491
                        );
492
493
                        foreach ($inherited as $inheritedAttribute) {
494
                            unset($attributes[$inheritedAttribute]);
495
                        }
496
497
                        $metaBundle->metaSitemapVars->setAttributes($attributes, false);
498
                    }
499
                    // Combine the meta global vars
500
                    $attributes = $fieldMetaBundle->metaGlobalVars->getAttributes();
501
                    $attributes = array_filter(
502
                        $attributes,
503
                        [ArrayHelper::class, 'preserveBools']
504
                    );
505
                    $metaBundle->metaGlobalVars->setAttributes($attributes, false);
506
                }
507
            }
508
        }
509
    }
510
511
    /**
512
     * @param Asset $asset
513
     * @param MetaBundle $metaBundle
514
     * @param array $lines
515
     */
516
    protected static function assetSitemapItem(Asset $asset, MetaBundle $metaBundle, array &$lines)
517
    {
518
        if ((bool)$asset->enabledForSite && $asset->getUrl() !== null) {
519
            switch ($asset->kind) {
520
                case 'image':
521
                    $transform = Craft::$app->getImageTransforms()->getTransformByHandle($metaBundle->metaSitemapVars->sitemapAssetTransform ?? '');
522
                    $lines[] = '<image:image>';
523
                    $lines[] = '<image:loc>';
524
                    $lines[] = Html::encode(UrlHelper::absoluteUrlWithProtocol($asset->getUrl($transform, true)));
525
                    $lines[] = '</image:loc>';
526
                    // Handle the dynamic field => property mappings
527
                    foreach ($metaBundle->metaSitemapVars->sitemapImageFieldMap as $row) {
528
                        $fieldName = $row['field'] ?? '';
529
                        $propName = $row['property'] ?? '';
530
                        if (!empty($fieldName) && !empty($asset[$fieldName]) && !empty($propName)) {
531
                            $lines[] = '<image:' . $propName . '>';
532
                            $lines[] = Html::encode($asset[$fieldName]);
533
                            $lines[] = '</image:' . $propName . '>';
534
                        }
535
                    }
536
                    $lines[] = '</image:image>';
537
                    break;
538
539
                case 'video':
540
                    $lines[] = '<video:video>';
541
                    $lines[] = '<video:content_loc>';
542
                    $lines[] = Html::encode(UrlHelper::absoluteUrlWithProtocol($asset->getUrl()));
543
                    $lines[] = '</video:content_loc>';
544
                    // Handle the dynamic field => property mappings
545
                    foreach ($metaBundle->metaSitemapVars->sitemapVideoFieldMap as $row) {
546
                        $fieldName = $row['field'] ?? '';
547
                        $propName = $row['property'] ?? '';
548
                        if (!empty($fieldName) && !empty($asset[$fieldName]) && !empty($propName)) {
549
                            $lines[] = '<video:' . $propName . '>';
550
                            $lines[] = Html::encode($asset[$fieldName]);
551
                            $lines[] = '</video:' . $propName . '>';
552
                        }
553
                    }
554
                    $lines[] = '</video:video>';
555
                    break;
556
            }
557
        }
558
    }
559
560
    /**
561
     * @param Asset $asset
562
     * @param MetaBundle $metaBundle
563
     * @param array $lines
564
     */
565
    protected static function assetFilesSitemapLink(Asset $asset, MetaBundle $metaBundle, array &$lines)
566
    {
567
        if ((bool)$asset->enabledForSite && $asset->getUrl() !== null) {
568
            if (in_array($asset->kind, SitemapTemplate::FILE_TYPES, false)) {
569
                $dateUpdated = $asset->dateUpdated ?? $asset->dateCreated ?? new DateTime();
570
                $lines[] = '<url>';
571
                $lines[] = '<loc>';
572
                $lines[] = Html::encode(UrlHelper::absoluteUrlWithProtocol($asset->getUrl()));
573
                $lines[] = '</loc>';
574
                $lines[] = '<lastmod>';
575
                $lines[] = $dateUpdated->format(DateTime::W3C);
576
                $lines[] = '</lastmod>';
577
                $lines[] = '<changefreq>';
578
                $lines[] = $metaBundle->metaSitemapVars->sitemapChangeFreq;
579
                $lines[] = '</changefreq>';
580
                $lines[] = '<priority>';
581
                $lines[] = $metaBundle->metaSitemapVars->sitemapPriority;
582
                $lines[] = '</priority>';
583
                $lines[] = '</url>';
584
            }
585
        }
586
    }
587
588
    protected static function getElementListSitemap(array $elements)
0 ignored issues
show
Unused Code introduced by
The parameter $elements 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 ignore-unused  annotation

588
    protected static function getElementListSitemap(/** @scrutinizer ignore-unused */ array $elements)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
589
    {
590
    }
591
}
592