Passed
Push — develop ( 8d02f5...9d045c )
by Andrew
12:56
created

SettingsController::prepEntitySettings()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 14
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 18
ccs 0
cts 17
cp 0
crap 20
rs 9.7998
1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS 3.x
4
 *
5
 * @link      https://nystudio107.com/
6
 * @copyright Copyright (c) 2017 nystudio107
7
 * @license   https://nystudio107.com/license
0 ignored issues
show
Coding Style introduced by
@license tag must contain a URL and a license name
Loading history...
8
 */
9
10
namespace nystudio107\seomatic\controllers;
11
12
use nystudio107\seomatic\Seomatic;
13
use nystudio107\seomatic\assetbundles\seomatic\SeomaticAsset;
14
use nystudio107\seomatic\helpers\Field as FieldHelper;
15
use nystudio107\seomatic\helpers\PullField as PullFieldHelper;
16
use nystudio107\seomatic\helpers\Schema as SchemaHelper;
17
use nystudio107\seomatic\helpers\ArrayHelper;
18
use nystudio107\seomatic\helpers\DynamicMeta as DynamicMetaHelper;
19
use nystudio107\seomatic\helpers\ImageTransform as ImageTransformHelper;
20
use nystudio107\seomatic\helpers\PluginTemplate;
21
use nystudio107\seomatic\models\MetaBundle;
22
use nystudio107\seomatic\models\MetaScript;
23
use nystudio107\seomatic\models\MetaScriptContainer;
24
use nystudio107\seomatic\services\FrontendTemplates;
25
use nystudio107\seomatic\services\MetaBundles;
26
27
use Craft;
28
use craft\elements\Asset;
29
use craft\helpers\UrlHelper;
30
use craft\models\Site;
31
use craft\web\Controller;
32
33
use yii\base\InvalidConfigException;
34
use yii\web\NotFoundHttpException;
35
use yii\web\Response;
36
37
/**
38
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
39
 * @package   Seomatic
40
 * @since     3.0.0
41
 */
42
class SettingsController extends Controller
43
{
44
    // Constants
45
    // =========================================================================
46
47
    const DOCUMENTATION_URL = 'https://github.com/nystudio107/craft-seomatic';
48
49
    const SETUP_GRADES = [
50
        ['id' => 'data1', 'name' => 'A', 'color' => '#008002'],
51
        ['id' => 'data2', 'name' => 'B', 'color' => '#9ACD31'],
52
        ['id' => 'data4', 'name' => 'C', 'color' => '#FFA500'],
53
        ['id' => 'data5', 'name' => 'D', 'color' => '#8B0100'],
54
    ];
55
56
    const SEO_SETUP_FIELDS = [
57
        'mainEntityOfPage' => 'Main Entity of Page',
58
        'seoTitle' => 'SEO Title',
59
        'seoDescription' => 'SEO Description',
60
        'seoKeywords' => 'SEO Keywords',
61
        'seoImage' => 'SEO Image',
62
        'seoImageDescription' => 'SEO Image Description',
63
    ];
64
65
    const SITE_SETUP_FIELDS = [
66
        'siteName' => 'Site Name',
67
        'twitterHandle' => 'Twitter Handle',
68
        'facebookProfileId' => 'Facebook Profile ID',
69
    ];
70
71
    const IDENTITY_SETUP_FIELDS = [
72
        'computedType' => 'Identity Entity Type',
73
        'genericName' => 'Identity Entity Name',
74
        'genericDescription' => 'Identity Entity Description',
75
        'genericUrl' => 'Identity Entity URL',
76
        'genericImage' => 'Identity Entity Brand',
77
    ];
78
79
    // Protected Properties
80
    // =========================================================================
81
82
    /**
83
     * @inheritdoc
84
     */
85
    protected $allowAnonymous = [
86
    ];
87
88
    // Public Methods
89
    // =========================================================================
90
91
    /**
92
     * Dashboard display
93
     *
94
     * @param string|null $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
95
     * @param bool        $showWelcome
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
96
     *
97
     * @return Response The rendered result
98
     * @throws NotFoundHttpException
99
     * @throws \yii\web\ForbiddenHttpException
100
     */
101
    public function actionDashboard(string $siteHandle = null, bool $showWelcome = false): Response
102
    {
103
        $variables = [];
104
        // Get the site to edit
105
        $siteId = $this->getSiteIdFromHandle($siteHandle);
106
        $pluginName = Seomatic::$settings->pluginName;
107
        $templateTitle = Craft::t('seomatic', 'Dashboard');
108
        // Asset bundle
109
        try {
110
            Seomatic::$view->registerAssetBundle(SeomaticAsset::class);
111
        } catch (InvalidConfigException $e) {
112
            Craft::error($e->getMessage(), __METHOD__);
113
        }
114
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
115
            '@nystudio107/seomatic/assetbundles/seomatic/dist',
116
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

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

116
        /** @scrutinizer ignore-call */ 
117
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
117
        );
118
        // Enabled sites
119
        $this->setMultiSiteVariables($siteHandle, $siteId, $variables);
120
        $variables['controllerHandle'] = 'dashboard';
121
122
        // Basic variables
123
        $variables['fullPageForm'] = false;
124
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
125
        $variables['pluginName'] = Seomatic::$settings->pluginName;
126
        $variables['title'] = $templateTitle;
127
        $variables['docTitle'] = "{$pluginName} - {$templateTitle}";
128
        $siteHandleUri = Craft::$app->isMultiSite ? '/'.$siteHandle : '';
129
        $variables['crumbs'] = [
130
            [
131
                'label' => $pluginName,
132
                'url' => UrlHelper::cpUrl('seomatic'),
133
            ],
134
            [
135
                'label' => $templateTitle,
136
                'url' => UrlHelper::cpUrl('seomatic/dashboard'.$siteHandleUri),
137
            ],
138
        ];
139
        $variables['selectedSubnavItem'] = 'dashboard';
140
        $variables['showWelcome'] = $showWelcome;
141
        // Calulate the setup grades
142
        $variables['contentSetupStats'] = [];
143
        $variables['setupGrades'] = self::SETUP_GRADES;
144
        $numFields = \count(self::SEO_SETUP_FIELDS);
145
        $numGrades = \count(self::SETUP_GRADES);
146
        while ($numGrades--) {
147
            $variables['contentSetupStats'][] = 0;
148
        }
149
        $numGrades = \count(self::SETUP_GRADES);
150
        // Content SEO grades
151
        $variables['metaBundles'] = Seomatic::$plugin->metaBundles->getContentMetaBundlesForSiteId($siteId);
152
        $variables['contentSetupChecklistCutoff'] = floor(count($variables['metaBundles']) / 2);
153
        $variables['contentSetupChecklist'] = [];
154
        Seomatic::$plugin->metaBundles->pruneVestigialMetaBundles($variables['metaBundles']);
155
        /** @var MetaBundle $metaBundle */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
156
        foreach ($variables['metaBundles'] as $metaBundle) {
157
            $stat = 0;
158
            foreach (self::SEO_SETUP_FIELDS as $setupField => $setupLabel) {
159
                $stat += (int)!empty($metaBundle->metaGlobalVars[$setupField]);
160
                $value = $variables['contentSetupChecklist'][$setupField]['value'] ?? 0;
161
                $variables['contentSetupChecklist'][$setupField] = [
162
                    'label' => $setupLabel,
163
                    'value' => $value + (int)!empty($metaBundle->metaGlobalVars[$setupField]),
164
                ];
165
            }
166
            $stat = round($numGrades - (($stat * $numGrades) / $numFields));
167
            if ($stat >= $numGrades) {
168
                $stat = $numGrades - 1;
169
            }
170
            $variables['contentSetupStats'][$stat]++;
171
        }
172
        // Global SEO grades
173
        Seomatic::$previewingMetaContainers = true;
174
        $metaBundle = Seomatic::$plugin->metaBundles->getGlobalMetaBundle((int)$siteId);
175
        Seomatic::$previewingMetaContainers = false;
176
        if ($metaBundle !== null) {
177
            $stat = 0;
178
            $variables['globalSetupChecklist'] = [];
179
            foreach (self::SEO_SETUP_FIELDS as $setupField => $setupLabel) {
180
                $stat += (int)!empty($metaBundle->metaGlobalVars[$setupField]);
181
                $variables['globalSetupChecklist'][$setupField] = [
182
                    'label' => $setupLabel,
183
                    'value' => (int)!empty($metaBundle->metaGlobalVars[$setupField]),
184
                ];
185
            }
186
            $stat = round(($stat / $numFields) * 100);
187
            $variables['globalSetupStat'] = $stat;
188
            // Site Settings grades
189
            $numFields = \count(self::SITE_SETUP_FIELDS) + \count(self::IDENTITY_SETUP_FIELDS);
190
            $stat = 0;
191
            $variables['siteSetupChecklist'] = [];
192
            foreach (self::SITE_SETUP_FIELDS as $setupField => $setupLabel) {
193
                $stat += (int)!empty($metaBundle->metaSiteVars[$setupField]);
194
                $variables['siteSetupChecklist'][$setupField] = [
195
                    'label' => $setupLabel,
196
                    'value' => (int)!empty($metaBundle->metaSiteVars[$setupField]),
197
                ];
198
            }
199
            foreach (self::IDENTITY_SETUP_FIELDS as $setupField => $setupLabel) {
200
                $stat += (int)!empty($metaBundle->metaSiteVars->identity[$setupField]);
201
                $variables['siteSetupChecklist'][$setupField] = [
202
                    'label' => $setupLabel,
203
                    'value' => (int)!empty($metaBundle->metaSiteVars->identity[$setupField]),
204
                ];
205
            }
206
            $stat = round(($stat / $numFields) * 100);
207
            $variables['siteSetupStat'] = $stat;
208
        }
209
210
        // Render the template
211
        return $this->renderTemplate('seomatic/dashboard/index', $variables);
212
    }
213
214
    /**
215
     * Global settings
216
     *
217
     * @param string $subSection
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
218
     * @param string|null $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
219
     * @param null $loadFromSiteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 8 spaces after parameter type; 1 found
Loading history...
Documentation Bug introduced by
Are you sure the doc-type for parameter $loadFromSiteHandle is correct as it would always require null to be passed?
Loading history...
220
     *
221
     * @return Response The rendered result
222
     * @throws NotFoundHttpException
223
     * @throws \yii\web\ForbiddenHttpException
224
     */
225
    public function actionGlobal(string $subSection = 'general', string $siteHandle = null, $loadFromSiteHandle = null): Response
226
    {
227
        $variables = [];
228
        $siteId = $this->getSiteIdFromHandle($siteHandle);
229
230
        $pluginName = Seomatic::$settings->pluginName;
231
        $templateTitle = Craft::t('seomatic', 'Global SEO');
232
        $subSectionTitle = Craft::t('seomatic', ucfirst($subSection));
233
        // Asset bundle
234
        try {
235
            Seomatic::$view->registerAssetBundle(SeomaticAsset::class);
236
        } catch (InvalidConfigException $e) {
237
            Craft::error($e->getMessage(), __METHOD__);
238
        }
239
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
240
            '@nystudio107/seomatic/assetbundles/seomatic/dist',
241
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

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

241
        /** @scrutinizer ignore-call */ 
242
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
242
        );
243
        // Basic variables
244
        $variables['fullPageForm'] = true;
245
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
246
        $variables['pluginName'] = Seomatic::$settings->pluginName;
247
        $variables['title'] = $templateTitle;
248
        $variables['subSectionTitle'] = $subSectionTitle;
249
        $variables['docTitle'] = "{$pluginName} - {$templateTitle} - {$subSectionTitle}";
250
        $siteHandleUri = Craft::$app->isMultiSite ? '/'.$siteHandle : '';
251
        $variables['crumbs'] = [
252
            [
253
                'label' => $pluginName,
254
                'url' => UrlHelper::cpUrl('seomatic'),
255
            ],
256
            [
257
                'label' => $templateTitle,
258
                'url' => UrlHelper::cpUrl('seomatic/global/general'.$siteHandleUri),
259
            ],
260
            [
261
                'label' => $subSectionTitle,
262
                'url' => UrlHelper::cpUrl('seomatic/global/'.$subSection.$siteHandleUri),
263
            ],
264
        ];
265
        $variables['selectedSubnavItem'] = 'global';
266
        // Pass in the pull fields
267
        $this->setGlobalFieldSourceVariables($variables);
268
        // Enabled sites
269
        $this->setMultiSiteVariables($siteHandle, $siteId, $variables);
270
        $variables['controllerHandle'] = 'global'.'/'.$subSection;
271
        $variables['currentSubSection'] = $subSection;
272
        // Meta bundle settings
273
        Seomatic::$previewingMetaContainers = true;
274
        // Get the site to copy the settings from, if any
275
        $variables['loadFromSiteHandle'] = $loadFromSiteHandle;
276
        $loadFromSiteId = $this->getSiteIdFromHandle($loadFromSiteHandle);
277
        $siteIdToLoad = $loadFromSiteHandle === null ? (int)$variables['currentSiteId'] : $loadFromSiteId;
0 ignored issues
show
introduced by
The condition $loadFromSiteHandle === null is always true.
Loading history...
278
        // Load the metabundle
279
        $metaBundle = Seomatic::$plugin->metaBundles->getGlobalMetaBundle($siteIdToLoad);
280
        Seomatic::$previewingMetaContainers = false;
281
        if ($metaBundle !== null) {
282
            $variables['metaGlobalVars'] = clone $metaBundle->metaGlobalVars;
283
            $variables['metaSitemapVars'] = $metaBundle->metaSitemapVars;
284
            $variables['metaBundleSettings'] = $metaBundle->metaBundleSettings;
285
            // Template container settings
286
            $templateContainers = $metaBundle->frontendTemplatesContainer->data;
287
            $variables['robotsTemplate'] = $templateContainers[FrontendTemplates::ROBOTS_TXT_HANDLE];
288
            $variables['humansTemplate'] = $templateContainers[FrontendTemplates::HUMANS_TXT_HANDLE];
289
            // Handle an edge-case where a migration didn't work properly to add ADS_TXT_HANDLE
290
            if (!isset($templateContainers[FrontendTemplates::ADS_TXT_HANDLE])) {
291
                $globalMetaBundle = Seomatic::$plugin->metaBundles->createGlobalMetaBundleForSite($siteId, $metaBundle);
292
                $templateContainers[FrontendTemplates::ADS_TXT_HANDLE] =
0 ignored issues
show
Coding Style introduced by
Multi-line assignments must have the equal sign on the second line
Loading history...
293
                    $globalMetaBundle->frontendTemplatesContainer->data[FrontendTemplates::ADS_TXT_HANDLE];
294
            }
295
            $variables['adsTemplate'] = $templateContainers[FrontendTemplates::ADS_TXT_HANDLE];
296
            // Image selectors
297
            $bundleSettings = $metaBundle->metaBundleSettings;
298
            $variables['elementType'] = Asset::class;
299
            $variables['seoImageElements'] = ImageTransformHelper::assetElementsFromIds(
300
                $bundleSettings->seoImageIds,
301
                $siteId
302
            );
303
            $variables['twitterImageElements'] = ImageTransformHelper::assetElementsFromIds(
304
                $bundleSettings->twitterImageIds,
305
                $siteId
306
            );
307
            $variables['ogImageElements'] = ImageTransformHelper::assetElementsFromIds(
308
                $bundleSettings->ogImageIds,
309
                $siteId
310
            );
311
        }
312
        // Preview the meta containers
313
        Seomatic::$plugin->metaContainers->previewMetaContainers(
314
            MetaBundles::GLOBAL_META_BUNDLE,
315
            (int)$variables['currentSiteId']
316
        );
317
        // Render the template
318
        return $this->renderTemplate('seomatic/settings/global/'.$subSection, $variables);
319
    }
320
321
    /**
322
     * @return Response
323
     * @throws \yii\web\BadRequestHttpException
324
     * @throws \craft\errors\MissingComponentException
325
     */
326
    public function actionSaveGlobal(): Response
327
    {
328
        $this->requirePostRequest();
329
        $request = Craft::$app->getRequest();
330
        $siteId = $request->getParam('siteId');
331
        $globalsSettings = $request->getParam('metaGlobalVars');
332
        $bundleSettings = $request->getParam('metaBundleSettings');
333
        $robotsTemplate = $request->getParam('robotsTemplate');
334
        $humansTemplate = $request->getParam('humansTemplate');
335
        $adsTemplate = $request->getParam('adsTemplate');
336
337
        // Set the element type in the template
338
        $elementName = '';
339
340
        // The site settings for the appropriate meta bundle
341
        Seomatic::$previewingMetaContainers = true;
342
        $metaBundle = Seomatic::$plugin->metaBundles->getGlobalMetaBundle($siteId);
343
        Seomatic::$previewingMetaContainers = false;
344
        if ($metaBundle !== null) {
345
            if (\is_array($globalsSettings) && \is_array($bundleSettings)) {
346
                PullFieldHelper::parseTextSources($elementName, $globalsSettings, $bundleSettings);
347
                PullFieldHelper::parseImageSources($elementName, $globalsSettings, $bundleSettings, $siteId);
348
                if (!empty($bundleSettings['siteType'])) {
349
                    $globalsSettings['mainEntityOfPage'] = SchemaHelper::getSpecificEntityType($bundleSettings);
350
                }
351
                $metaBundle->metaGlobalVars->setAttributes($globalsSettings);
352
                $metaBundle->metaBundleSettings->setAttributes($bundleSettings);
353
            }
354
            $templateContainers = $metaBundle->frontendTemplatesContainer->data;
355
            $robotsContainer = $templateContainers[FrontendTemplates::ROBOTS_TXT_HANDLE];
356
            if ($robotsContainer !== null && \is_array($robotsTemplate)) {
357
                $robotsContainer->setAttributes($robotsTemplate);
358
            }
359
            $humansContainer = $templateContainers[FrontendTemplates::HUMANS_TXT_HANDLE];
360
            if ($humansContainer !== null && \is_array($humansTemplate)) {
361
                $humansContainer->setAttributes($humansTemplate);
362
            }
363
            $adsContainer = $templateContainers[FrontendTemplates::ADS_TXT_HANDLE];
364
            if ($adsContainer !== null && \is_array($adsTemplate)) {
365
                $adsContainer->setAttributes($adsTemplate);
366
            }
367
368
            Seomatic::$plugin->metaBundles->syncBundleWithConfig($metaBundle, true);
369
            Seomatic::$plugin->metaBundles->updateMetaBundle($metaBundle, $siteId);
370
371
            Seomatic::$plugin->clearAllCaches();
372
            Craft::$app->getSession()->setNotice(Craft::t('seomatic', 'SEOmatic global settings saved.'));
373
        }
374
375
        return $this->redirectToPostedUrl();
376
    }
377
378
    /**
379
     * Content settings
380
     *
381
     * @param string|null $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
382
     *
383
     * @return Response The rendered result
384
     * @throws NotFoundHttpException
385
     * @throws \yii\web\ForbiddenHttpException
386
     */
387
    public function actionContent(string $siteHandle = null): Response
388
    {
389
        $variables = [];
390
        // Get the site to edit
391
        $siteId = $this->getSiteIdFromHandle($siteHandle);
392
393
        $pluginName = Seomatic::$settings->pluginName;
394
        $templateTitle = Craft::t('seomatic', 'Content SEO');
395
        // Asset bundle
396
        try {
397
            Seomatic::$view->registerAssetBundle(SeomaticAsset::class);
398
        } catch (InvalidConfigException $e) {
399
            Craft::error($e->getMessage(), __METHOD__);
400
        }
401
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
402
            '@nystudio107/seomatic/assetbundles/seomatic/dist',
403
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

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

403
        /** @scrutinizer ignore-call */ 
404
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
404
        );
405
        // Basic variables
406
        $variables['fullPageForm'] = false;
407
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
408
        $variables['pluginName'] = Seomatic::$settings->pluginName;
409
        $variables['title'] = $templateTitle;
410
        $variables['docTitle'] = "{$pluginName} - {$templateTitle}";
411
        $siteHandleUri = Craft::$app->isMultiSite ? '/'.$siteHandle : '';
412
        $variables['crumbs'] = [
413
            [
414
                'label' => $pluginName,
415
                'url' => UrlHelper::cpUrl('seomatic'),
416
            ],
417
            [
418
                'label' => $templateTitle,
419
                'url' => UrlHelper::cpUrl('seomatic/content'.$siteHandleUri),
420
            ],
421
        ];
422
        $this->setMultiSiteVariables($siteHandle, $siteId, $variables);
423
        $variables['controllerHandle'] = 'content';
424
        $variables['selectedSubnavItem'] = 'content';
425
        $metaBundles = Seomatic::$plugin->metaBundles->getContentMetaBundlesForSiteId($siteId);
426
        Seomatic::$plugin->metaBundles->deleteVestigialMetaBundles($metaBundles);
427
428
        // Render the template
429
        return $this->renderTemplate('seomatic/settings/content/index', $variables);
430
    }
431
432
    /**
433
     * Global settings
434
     *
435
     * @param string $subSection
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
436
     * @param string $sourceBundleType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
437
     * @param string $sourceHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 6 spaces after parameter type; 1 found
Loading history...
438
     * @param string|null $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
439
     * @param int|null $typeId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 4 spaces after parameter type; 1 found
Loading history...
440
     * @param null $loadFromSiteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 8 spaces after parameter type; 1 found
Loading history...
Documentation Bug introduced by
Are you sure the doc-type for parameter $loadFromSiteHandle is correct as it would always require null to be passed?
Loading history...
441
     *
442
     * @return Response The rendered result
443
     * @throws NotFoundHttpException
444
     * @throws \yii\web\ForbiddenHttpException
445
     */
446
    public function actionEditContent(
447
        string $subSection,
448
        string $sourceBundleType,
449
        string $sourceHandle,
450
        string $siteHandle = null,
451
        $typeId = null,
452
        $loadFromSiteHandle = null
453
    ): Response {
454
        $variables = [];
455
        // @TODO: Let people choose an entry/categorygroup/product as the preview
456
        // Get the site to edit
457
        $siteId = $this->getSiteIdFromHandle($siteHandle);
458
        if ($typeId !== null && is_string($typeId)) {
0 ignored issues
show
introduced by
The condition is_string($typeId) is always false.
Loading history...
459
            $typeId = (int)$typeId;
460
        }
461
        // Get the (entry) type menu
462
        $typeMenu = [];
463
        $seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType($sourceBundleType);
464
        if ($seoElement !== null) {
465
            $typeMenu = $seoElement::typeMenuFromHandle($sourceHandle);
466
        }
467
        $variables['typeMenu'] = $typeMenu;
468
        $variables['currentTypeId'] = null;
469
        if (!empty($typeMenu)) {
470
            $currentType = reset($typeMenu);
471
            $variables['currentType'] = $typeMenu[$typeId] ?? $currentType;
472
            $variables['currentTypeId'] = $typeId ?? key($typeMenu);
473
            $typeId = (int)$variables['currentTypeId'];
474
        }
475
        $pluginName = Seomatic::$settings->pluginName;
476
        // Asset bundle
477
        try {
478
            Seomatic::$view->registerAssetBundle(SeomaticAsset::class);
479
        } catch (InvalidConfigException $e) {
480
            Craft::error($e->getMessage(), __METHOD__);
481
        }
482
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
483
            '@nystudio107/seomatic/assetbundles/seomatic/dist',
484
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

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

484
        /** @scrutinizer ignore-call */ 
485
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
485
        );
486
        // Enabled sites
487
        $this->setMultiSiteVariables($siteHandle, $siteId, $variables);
488
        $this->cullDisabledSites($sourceBundleType, $sourceHandle, $variables);
489
        // Meta Bundle settings
490
        Seomatic::$previewingMetaContainers = true;
491
        // Get the site to copy the settings from, if any
492
        $variables['loadFromSiteHandle'] = $loadFromSiteHandle;
493
        $loadFromSiteId = $this->getSiteIdFromHandle($loadFromSiteHandle);
494
        $siteIdToLoad = $loadFromSiteHandle === null ? (int)$variables['currentSiteId'] : $loadFromSiteId;
0 ignored issues
show
introduced by
The condition $loadFromSiteHandle === null is always true.
Loading history...
495
        // Load the metabundle
496
        $metaBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceHandle(
497
            $sourceBundleType,
498
            $sourceHandle,
499
            $siteIdToLoad,
500
            $typeId
501
        );
502
        Seomatic::$previewingMetaContainers = false;
503
        $templateTitle = '';
504
        if ($metaBundle !== null) {
505
            $variables['metaGlobalVars'] = clone $metaBundle->metaGlobalVars;
506
            $variables['metaSitemapVars'] = $metaBundle->metaSitemapVars;
507
            $variables['metaBundleSettings'] = $metaBundle->metaBundleSettings;
508
            $variables['currentSourceHandle'] = $metaBundle->sourceHandle;
509
            $variables['currentSourceBundleType'] = $metaBundle->sourceBundleType;
510
            $templateTitle = $metaBundle->sourceName;
511
        }
512
        // Basic variables
513
        $subSectionTitle = Craft::t('seomatic', ucfirst($subSection));
514
        $variables['fullPageForm'] = true;
515
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
516
        $variables['pluginName'] = Seomatic::$settings->pluginName;
517
        $variables['title'] = $templateTitle;
518
        $variables['subSectionTitle'] = $subSectionTitle;
519
        $variables['docTitle'] = "{$pluginName} - Content SEO - {$templateTitle} - {$subSectionTitle}";
520
        $siteHandleUri = Craft::$app->isMultiSite ? '/'.$siteHandle : '';
521
        $variables['siteHandleUri'] = $siteHandleUri;
522
        $variables['crumbs'] = [
523
            [
524
                'label' => $pluginName,
525
                'url' => UrlHelper::cpUrl('seomatic'),
526
            ],
527
            [
528
                'label' => 'Content SEO',
529
                'url' => UrlHelper::cpUrl('seomatic/content'.$siteHandleUri),
530
            ],
531
            [
532
                'label' => $metaBundle->sourceName.' · '.$subSectionTitle,
533
                'url' => UrlHelper::cpUrl("seomatic/edit-content/${subSection}/${sourceBundleType}/${sourceHandle}"),
534
            ],
535
        ];
536
        $variables['selectedSubnavItem'] = 'content';
537
        $variables['controllerHandle'] = "edit-content/${subSection}/${sourceBundleType}/${sourceHandle}";
538
        // Image selectors
539
        $variables['currentSubSection'] = $subSection;
540
        $bundleSettings = $metaBundle->metaBundleSettings;
541
        $variables['elementType'] = Asset::class;
542
        $variables['seoImageElements'] = ImageTransformHelper::assetElementsFromIds(
543
            $bundleSettings->seoImageIds,
544
            $siteId
545
        );
546
        $variables['twitterImageElements'] = ImageTransformHelper::assetElementsFromIds(
547
            $bundleSettings->twitterImageIds,
548
            $siteId
549
        );
550
        $variables['ogImageElements'] = ImageTransformHelper::assetElementsFromIds(
551
            $bundleSettings->ogImageIds,
552
            $siteId
553
        );
554
        $variables['sourceType'] = $metaBundle->sourceType;
555
        // Pass in the pull fields
556
        $groupName = ucfirst($metaBundle->sourceType);
557
        $this->setContentFieldSourceVariables($sourceBundleType, $sourceHandle, $groupName, $variables);
558
        $uri = $this->uriFromSourceBundle($sourceBundleType, $sourceHandle, $siteId);
559
        // Preview the meta containers
560
        Seomatic::$plugin->metaContainers->previewMetaContainers(
561
            $uri,
562
            (int)$variables['currentSiteId'],
563
            false,
564
            false
565
        );
566
567
        // Render the template
568
        return $this->renderTemplate('seomatic/settings/content/'.$subSection, $variables);
569
    }
570
571
572
    /**
573
     * @return Response
574
     * @throws \yii\web\BadRequestHttpException
575
     * @throws \craft\errors\MissingComponentException
576
     */
577
    public function actionSaveContent(): Response
578
    {
579
        $this->requirePostRequest();
580
        $request = Craft::$app->getRequest();
581
        $sourceBundleType = $request->getParam('sourceBundleType');
582
        $sourceHandle = $request->getParam('sourceHandle');
583
        $siteId = $request->getParam('siteId');
584
        $typeId = $request->getParam('typeId') ?? null;
585
        $globalsSettings = $request->getParam('metaGlobalVars');
586
        $bundleSettings = $request->getParam('metaBundleSettings');
587
        $sitemapSettings = $request->getParam('metaSitemapVars');
588
        // Set the element type in the template
589
        $elementName = '';
590
        $seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType($sourceBundleType);
591
        if ($seoElement !== null) {
592
            $elementName = $seoElement::getElementRefHandle();
593
        }
594
        // The site settings for the appropriate meta bundle
595
        Seomatic::$previewingMetaContainers = true;
596
        $metaBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceHandle(
597
            $sourceBundleType,
598
            $sourceHandle,
599
            $siteId,
600
            $typeId
601
        );
602
        Seomatic::$previewingMetaContainers = false;
603
        if ($metaBundle) {
604
            if (\is_array($globalsSettings) && \is_array($bundleSettings)) {
605
                PullFieldHelper::parseTextSources($elementName, $globalsSettings, $bundleSettings);
606
                PullFieldHelper::parseImageSources($elementName, $globalsSettings, $bundleSettings, $siteId);
607
                if (!empty($bundleSettings['siteType'])) {
608
                    $globalsSettings['mainEntityOfPage'] = SchemaHelper::getSpecificEntityType($bundleSettings);
609
                }
610
                $metaBundle->metaGlobalVars->setAttributes($globalsSettings);
611
                $metaBundle->metaBundleSettings->setAttributes($bundleSettings);
612
            }
613
            if (\is_array($sitemapSettings)) {
614
                $metaBundle->metaSitemapVars->setAttributes($sitemapSettings);
615
            }
616
617
            Seomatic::$plugin->metaBundles->syncBundleWithConfig($metaBundle, true);
618
            $metaBundle->typeId = $typeId;
619
            Seomatic::$plugin->metaBundles->updateMetaBundle($metaBundle, $siteId);
620
621
            Seomatic::$plugin->clearAllCaches();
622
            Craft::$app->getSession()->setNotice(Craft::t('seomatic', 'SEOmatic content settings saved.'));
623
        }
624
625
        return $this->redirectToPostedUrl();
626
    }
627
628
    /**
629
     * Site settings
630
     *
631
     * @param string $subSection
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
632
     * @param string $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
633
     * @param null $loadFromSiteHandle
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $loadFromSiteHandle is correct as it would always require null to be passed?
Loading history...
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
634
     *
635
     * @return Response The rendered result
636
     * @throws NotFoundHttpException
637
     * @throws \yii\web\ForbiddenHttpException
638
     */
639
    public function actionSite(string $subSection = 'identity', string $siteHandle = null, $loadFromSiteHandle = null): Response
640
    {
641
        $variables = [];
642
        // Get the site to edit
643
        $siteId = $this->getSiteIdFromHandle($siteHandle);
644
645
        $pluginName = Seomatic::$settings->pluginName;
646
        $templateTitle = Craft::t('seomatic', 'Site Settings');
647
        $subSectionSuffix = '';
648
        if ($subSection === 'social') {
649
            $subSectionSuffix = ' Media';
650
        }
651
        $subSectionTitle = Craft::t('seomatic', ucfirst($subSection).$subSectionSuffix);
652
        // Asset bundle
653
        try {
654
            Seomatic::$view->registerAssetBundle(SeomaticAsset::class);
655
        } catch (InvalidConfigException $e) {
656
            Craft::error($e->getMessage(), __METHOD__);
657
        }
658
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
659
            '@nystudio107/seomatic/assetbundles/seomatic/dist',
660
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

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

660
        /** @scrutinizer ignore-call */ 
661
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
661
        );
662
        // Basic variables
663
        $variables['fullPageForm'] = true;
664
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
665
        $variables['pluginName'] = Seomatic::$settings->pluginName;
666
        $variables['title'] = $templateTitle;
667
        $variables['subSectionTitle'] = $subSectionTitle;
668
        $variables['docTitle'] = "{$pluginName} - {$templateTitle} - {$subSectionTitle}";
669
        $siteHandleUri = Craft::$app->isMultiSite ? '/'.$siteHandle : '';
670
        $variables['crumbs'] = [
671
            [
672
                'label' => $pluginName,
673
                'url' => UrlHelper::cpUrl('seomatic'),
674
            ],
675
            [
676
                'label' => $templateTitle,
677
                'url' => UrlHelper::cpUrl('seomatic/site/identity'.$siteHandleUri),
678
            ],
679
            [
680
                'label' => $subSectionTitle,
681
                'url' => UrlHelper::cpUrl('seomatic/site/'.$subSection.$siteHandleUri),
682
            ],
683
        ];
684
        $variables['selectedSubnavItem'] = 'site';
685
        $variables['currentSubSection'] = $subSection;
686
687
        // Enabled sites
688
        $this->setMultiSiteVariables($siteHandle, $siteId, $variables);
689
        $variables['controllerHandle'] = 'site'.'/'.$subSection;
690
691
        // The site settings for the appropriate meta bundle
692
        Seomatic::$previewingMetaContainers = true;
693
        // Get the site to copy the settings from, if any
694
        $variables['loadFromSiteHandle'] = $loadFromSiteHandle;
695
        $loadFromSiteId = $this->getSiteIdFromHandle($loadFromSiteHandle);
696
        $siteIdToLoad = $loadFromSiteHandle === null ? (int)$variables['currentSiteId'] : $loadFromSiteId;
0 ignored issues
show
introduced by
The condition $loadFromSiteHandle === null is always true.
Loading history...
697
        // Load the metabundle
698
        $metaBundle = Seomatic::$plugin->metaBundles->getGlobalMetaBundle($siteIdToLoad);
699
        Seomatic::$previewingMetaContainers = false;
700
        if ($metaBundle !== null) {
701
            $variables['site'] = $metaBundle->metaSiteVars;
702
            $variables['identityImageElements'] = ImageTransformHelper::assetElementsFromIds(
703
                $variables['site']->identity->genericImageIds,
704
                $siteId
705
            );
706
            $variables['creatorImageElements'] = ImageTransformHelper::assetElementsFromIds(
707
                $variables['site']->creator->genericImageIds,
708
                $siteId
709
            );
710
        }
711
        $variables['elementType'] = Asset::class;
712
713
        // Render the template
714
        return $this->renderTemplate('seomatic/settings/site/'.$subSection, $variables);
715
    }
716
717
    /**
718
     * @return Response
719
     * @throws \yii\web\BadRequestHttpException
720
     * @throws \craft\errors\MissingComponentException
721
     */
722
    public function actionSaveSite(): Response
723
    {
724
        $this->requirePostRequest();
725
        $request = Craft::$app->getRequest();
726
        $siteId = $request->getParam('siteId');
727
        $siteSettings = $request->getParam('site');
728
729
        // Make sure the twitter handle isn't prefixed with an @
730
        if (!empty($siteSettings['twitterHandle'])) {
731
            $siteSettings['twitterHandle'] = ltrim($siteSettings['twitterHandle'], '@');
732
        }
733
        // Make sure the sameAsLinks are indexed by the handle
734
        if (!empty($siteSettings['sameAsLinks'])) {
735
            $siteSettings['sameAsLinks'] = ArrayHelper::index($siteSettings['sameAsLinks'], 'handle');
736
        }
737
        // The site settings for the appropriate meta bundle
738
        Seomatic::$previewingMetaContainers = true;
739
        $metaBundle = Seomatic::$plugin->metaBundles->getGlobalMetaBundle($siteId);
740
        Seomatic::$previewingMetaContainers = false;
741
        if ($metaBundle) {
742
            if (\is_array($siteSettings)) {
743
                if (!empty($siteSettings['identity'])) {
744
                    $settings = $siteSettings['identity'];
745
                    $this->prepEntitySettings($settings);
746
                    $metaBundle->metaSiteVars->identity->setAttributes($settings);
747
                    $siteSettings['identity'] = $metaBundle->metaSiteVars->identity;
748
                }
749
                if (!empty($siteSettings['creator'])) {
750
                    $settings = $siteSettings['creator'];
751
                    $this->prepEntitySettings($settings);
752
                    $metaBundle->metaSiteVars->creator->setAttributes($settings);
753
                    $siteSettings['creator'] = $metaBundle->metaSiteVars->creator;
754
                }
755
                if (!empty($siteSettings['additionalSitemapUrls'])) {
756
                    $siteSettings['additionalSitemapUrlsDateUpdated'] = new \DateTime;
757
                    Seomatic::$plugin->sitemaps->submitCustomSitemap($siteId);
758
                }
759
                $metaBundle->metaSiteVars->setAttributes($siteSettings);
760
            }
761
            Seomatic::$plugin->metaBundles->syncBundleWithConfig($metaBundle, true);
762
            Seomatic::$plugin->metaBundles->updateMetaBundle($metaBundle, $siteId);
763
764
            Seomatic::$plugin->clearAllCaches();
765
            Craft::$app->getSession()->setNotice(Craft::t('seomatic', 'SEOmatic site settings saved.'));
766
        }
767
768
        return $this->redirectToPostedUrl();
769
    }
770
771
    /**
772
     * Plugin settings
773
     *
774
     * @return Response The rendered result
775
     */
776
    public function actionPlugin(): Response
777
    {
778
        $variables = [];
779
        $pluginName = Seomatic::$settings->pluginName;
780
        $templateTitle = Craft::t('seomatic', 'Plugin Settings');
781
        // Asset bundle
782
        try {
783
            Seomatic::$view->registerAssetBundle(SeomaticAsset::class);
784
        } catch (InvalidConfigException $e) {
785
            Craft::error($e->getMessage(), __METHOD__);
786
        }
787
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
788
            '@nystudio107/seomatic/assetbundles/seomatic/dist',
789
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

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

789
        /** @scrutinizer ignore-call */ 
790
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
790
        );
791
        // Basic variables
792
        $variables['fullPageForm'] = true;
793
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
794
        $variables['pluginName'] = Seomatic::$settings->pluginName;
795
        $variables['title'] = $templateTitle;
796
        $variables['docTitle'] = "{$pluginName} - {$templateTitle}";
797
        $variables['crumbs'] = [
798
            [
799
                'label' => $pluginName,
800
                'url' => UrlHelper::cpUrl('seomatic'),
801
            ],
802
            [
803
                'label' => $templateTitle,
804
                'url' => UrlHelper::cpUrl('seomatic/plugin'),
805
            ],
806
        ];
807
        $variables['selectedSubnavItem'] = 'plugin';
808
        $variables['settings'] = Seomatic::$settings;
809
810
        // Render the template
811
        return $this->renderTemplate('seomatic/settings/plugin/_edit', $variables);
812
    }
813
814
815
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $editedMetaBundle should have a doc-comment as per coding-style.
Loading history...
816
     * Tracking settings
817
     *
818
     * @param string $subSection
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
819
     * @param string $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
820
     * @param null $loadFromSiteHandle
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
Documentation Bug introduced by
Are you sure the doc-type for parameter $loadFromSiteHandle is correct as it would always require null to be passed?
Loading history...
821
     *
822
     * @return Response The rendered result
823
     * @throws NotFoundHttpException
824
     * @throws \yii\web\ForbiddenHttpException
825
     */
826
    public function actionTracking(string $subSection = 'gtag', string $siteHandle = null, $loadFromSiteHandle = null, $editedMetaBundle = null): Response
827
    {
828
        $variables = [];
829
        // Get the site to edit
830
        $siteId = $this->getSiteIdFromHandle($siteHandle);
831
        // Enabled sites
832
        $this->setMultiSiteVariables($siteHandle, $siteId, $variables);
833
        $variables['controllerHandle'] = 'tracking'.'/'.$subSection;
834
        $variables['currentSubSection'] = $subSection;
835
836
        // The script meta containers for the global meta bundle
837
        Seomatic::$previewingMetaContainers = true;
838
        // Get the site to copy the settings from, if any
839
        $variables['loadFromSiteHandle'] = $loadFromSiteHandle;
840
        $loadFromSiteId = $this->getSiteIdFromHandle($loadFromSiteHandle);
841
        $siteIdToLoad = $loadFromSiteHandle === null ? (int)$variables['currentSiteId'] : $loadFromSiteId;
0 ignored issues
show
introduced by
The condition $loadFromSiteHandle === null is always true.
Loading history...
842
        // Load the metabundle
843
        $metaBundle = Seomatic::$plugin->metaBundles->getGlobalMetaBundle($siteIdToLoad);
844
        if ($editedMetaBundle) {
845
            $metaBundle = $editedMetaBundle;
846
        }
847
        Seomatic::$previewingMetaContainers = false;
848
        if ($metaBundle !== null) {
849
            $variables['scripts'] = Seomatic::$plugin->metaBundles->getContainerDataFromBundle(
850
                $metaBundle,
851
                MetaScriptContainer::CONTAINER_TYPE
852
            );
853
        }
854
        // Plugin and section settings
855
        $pluginName = Seomatic::$settings->pluginName;
856
        $templateTitle = Craft::t('seomatic', 'Tracking Scripts');
857
        $subSectionTitle = $variables['scripts'][$subSection]->name;
858
        $subSectionTitle = Craft::t('seomatic', $subSectionTitle);
859
        // Asset bundle
860
        try {
861
            Seomatic::$view->registerAssetBundle(SeomaticAsset::class);
862
        } catch (InvalidConfigException $e) {
863
            Craft::error($e->getMessage(), __METHOD__);
864
        }
865
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(
866
            '@nystudio107/seomatic/assetbundles/seomatic/dist',
867
            true
0 ignored issues
show
Unused Code introduced by
The call to yii\web\AssetManager::getPublishedUrl() has too many arguments starting with true. ( Ignorable by Annotation )

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

867
        /** @scrutinizer ignore-call */ 
868
        $variables['baseAssetsUrl'] = Craft::$app->assetManager->getPublishedUrl(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
868
        );
869
        // Basic variables
870
        $variables['fullPageForm'] = true;
871
        $variables['docsUrl'] = self::DOCUMENTATION_URL;
872
        $variables['pluginName'] = Seomatic::$settings->pluginName;
873
        $variables['title'] = $templateTitle;
874
        $variables['subSectionTitle'] = $subSectionTitle;
875
        $variables['docTitle'] = "{$pluginName} - {$templateTitle} - {$subSectionTitle}";
876
        $siteHandleUri = Craft::$app->isMultiSite ? '/'.$siteHandle : '';
877
        $variables['crumbs'] = [
878
            [
879
                'label' => $pluginName,
880
                'url' => UrlHelper::cpUrl('seomatic'),
881
            ],
882
            [
883
                'label' => $templateTitle,
884
                'url' => UrlHelper::cpUrl('seomatic/tracking'),
885
            ],
886
            [
887
                'label' => $subSectionTitle,
888
                'url' => UrlHelper::cpUrl('seomatic/tracking/'.$subSection.$siteHandleUri),
889
            ],
890
        ];
891
        $variables['selectedSubnavItem'] = 'tracking';
892
893
        // Render the template
894
        return $this->renderTemplate('seomatic/settings/tracking/_edit', $variables);
895
    }
896
897
    /**
898
     * @return Response
899
     * @throws \yii\web\BadRequestHttpException
900
     * @throws \craft\errors\MissingComponentException
901
     */
902
    public function actionSaveTracking()
903
    {
904
        $this->requirePostRequest();
905
        $request = Craft::$app->getRequest();
906
        $siteId = $request->getParam('siteId');
907
        $scriptSettings = $request->getParam('scripts');
908
909
        // The site settings for the appropriate meta bundle
910
        Seomatic::$previewingMetaContainers = true;
911
        $metaBundle = Seomatic::$plugin->metaBundles->getGlobalMetaBundle($siteId);
912
        Seomatic::$previewingMetaContainers = false;
913
        $hasErrors = false;
914
        if ($metaBundle) {
915
            /** @var array $scriptSettings */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
916
            foreach ($scriptSettings as $scriptHandle => $scriptData) {
917
                foreach ($metaBundle->metaContainers as $metaContainer) {
918
                    if ($metaContainer::CONTAINER_TYPE === MetaScriptContainer::CONTAINER_TYPE) {
919
                        $data = $metaContainer->getData($scriptHandle);
920
                        /** @var MetaScript $data */
0 ignored issues
show
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
921
                        if ($data) {
922
                            $error = PluginTemplate::isStringTemplateValid($scriptData['templateString'], []);
923
                            if (!empty($error)) {
924
                                $data->addError('templateString', $error);
925
                                $hasErrors = true;
926
                            }
927
                            $error = PluginTemplate::isStringTemplateValid($scriptData['bodyTemplateString'], []);
928
                            if (!empty($error)) {
929
                                $data->addError('bodyTemplateString', $error);
930
                                $hasErrors = true;
931
                            }
932
                            /** @var array $scriptData */
0 ignored issues
show
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
933
                            foreach ($scriptData as $key => $value) {
934
                                if (\is_array($value)) {
935
                                    foreach ($value as $varsKey => $varsValue) {
936
                                        $data->$key[$varsKey]['value'] = $varsValue;
937
                                    }
938
                                } else {
939
                                    $data->$key = $value;
940
                                }
941
                            }
942
                        }
943
                    }
944
                }
945
            }
946
            if ($hasErrors) {
947
                Craft::$app->getSession()->setError(Craft::t('app', "Couldn't save tracking settings due to a Twig error."));
948
                // Send the redirect back to the template
949
                Craft::$app->getUrlManager()->setRouteParams([
950
                    'editedMetaBundle' => $metaBundle,
951
                ]);
952
953
                return null;
954
            }
955
956
            Seomatic::$plugin->metaBundles->updateMetaBundle($metaBundle, $siteId);
957
958
            Seomatic::$plugin->clearAllCaches();
959
            Craft::$app->getSession()->setNotice(Craft::t('seomatic', 'SEOmatic site settings saved.'));
960
        }
961
962
        return $this->redirectToPostedUrl();
963
    }
964
965
    /**
966
     * Saves a plugin’s settings.
967
     *
968
     * @return Response|null
969
     * @throws NotFoundHttpException if the requested plugin cannot be found
970
     * @throws \yii\web\BadRequestHttpException
971
     * @throws \craft\errors\MissingComponentException
972
     */
973
    public function actionSavePluginSettings()
974
    {
975
        $this->requirePostRequest();
976
        $pluginHandle = Craft::$app->getRequest()->getRequiredBodyParam('pluginHandle');
977
        $settings = Craft::$app->getRequest()->getBodyParam('settings', []);
978
        $plugin = Craft::$app->getPlugins()->getPlugin($pluginHandle);
979
980
        if ($plugin === null) {
981
            throw new NotFoundHttpException('Plugin not found');
982
        }
983
984
        if (!Craft::$app->getPlugins()->savePluginSettings($plugin, $settings)) {
985
            Craft::$app->getSession()->setError(Craft::t('app', "Couldn't save plugin settings."));
986
987
            // Send the plugin back to the template
988
            Craft::$app->getUrlManager()->setRouteParams([
989
                'plugin' => $plugin,
990
            ]);
991
992
            return null;
993
        }
994
995
        Seomatic::$plugin->clearAllCaches();
996
        Craft::$app->getSession()->setNotice(Craft::t('app', 'Plugin settings saved.'));
997
998
        return $this->redirectToPostedUrl();
999
    }
1000
1001
    // Protected Methods
1002
    // =========================================================================
1003
1004
    /**
1005
     * @param array $variables
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1006
     */
1007
    protected function setGlobalFieldSourceVariables(array &$variables)
1008
    {
1009
        $variables['textFieldSources'] = array_merge(
1010
            ['globalsGroup' => ['optgroup' => 'Globals Fields']],
1011
            FieldHelper::fieldsOfTypeFromGlobals(
1012
                FieldHelper::TEXT_FIELD_CLASS_KEY,
1013
                false
1014
            )
1015
        );
1016
        $variables['assetFieldSources'] = array_merge(
1017
            ['globalsGroup' => ['optgroup' => 'Globals Fields']],
1018
            FieldHelper::fieldsOfTypeFromGlobals(
1019
                FieldHelper::ASSET_FIELD_CLASS_KEY,
1020
                false
1021
            )
1022
        );
1023
    }
1024
1025
    /**
1026
     * @param string $sourceBundleType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1027
     * @param string $sourceHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1028
     * @param string $groupName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1029
     * @param array  $variables
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1030
     */
1031
    protected function setContentFieldSourceVariables(
1032
        string $sourceBundleType,
1033
        string $sourceHandle,
1034
        string $groupName,
1035
        array &$variables
1036
    ) {
1037
        $variables['textFieldSources'] = array_merge(
1038
            ['entryGroup' => ['optgroup' => $groupName.' Fields'], 'title' => 'Title'],
1039
            FieldHelper::fieldsOfTypeFromSource(
1040
                $sourceBundleType,
1041
                $sourceHandle,
1042
                FieldHelper::TEXT_FIELD_CLASS_KEY,
1043
                false
1044
            )
1045
        );
1046
        $variables['assetFieldSources'] = array_merge(
1047
            ['entryGroup' => ['optgroup' => $groupName.' Fields']],
1048
            FieldHelper::fieldsOfTypeFromSource(
1049
                $sourceBundleType,
1050
                $sourceHandle,
1051
                FieldHelper::ASSET_FIELD_CLASS_KEY,
1052
                false
1053
            )
1054
        );
1055
        $variables['assetVolumeTextFieldSources'] = array_merge(
1056
            ['entryGroup' => ['optgroup' => 'Asset Volume Fields'], '' => '--', 'title' => 'Title'],
1057
            array_merge(
1058
                FieldHelper::fieldsOfTypeFromAssetVolumes(
1059
                    FieldHelper::TEXT_FIELD_CLASS_KEY,
1060
                    false
1061
                )
1062
            )
1063
        );
1064
        $variables['userFieldSources'] = array_merge(
1065
            ['entryGroup' => ['optgroup' => 'User Fields']],
1066
            FieldHelper::fieldsOfTypeFromUsers(
1067
                FieldHelper::TEXT_FIELD_CLASS_KEY,
1068
                false
1069
            )
1070
        );
1071
    }
1072
1073
    /**
1074
     * @param string   $sourceBundleType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1075
     * @param string   $sourceHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1076
     * @param null|int $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1077
     *
1078
     * @return string
1079
     */
1080
    protected function uriFromSourceBundle(string $sourceBundleType, string $sourceHandle, $siteId): string
1081
    {
1082
        $uri = null;
1083
        // Pick an Element to be used for the preview
1084
        if ($sourceBundleType === MetaBundles::GLOBAL_META_BUNDLE) {
1085
            $uri = MetaBundles::GLOBAL_META_BUNDLE;
1086
        } else {
1087
            $seoElement = Seomatic::$plugin->seoElements->getSeoElementByMetaBundleType($sourceBundleType);
1088
            if ($seoElement !== null) {
1089
                $uri = $seoElement::previewUri($sourceHandle, $siteId);
1090
            }
1091
        }
1092
        // Special-case for the __home__ slug, and default to /
1093
        if (($uri === '__home__') || ($uri === null)) {
1094
            $uri = '/';
1095
        }
1096
1097
        return $uri;
1098
    }
1099
1100
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $element should have a doc-comment as per coding-style.
Loading history...
1101
     * @param string $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1102
     * @param        $siteId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1103
     * @param        $variables
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1104
     *
1105
     * @throws \yii\web\ForbiddenHttpException
1106
     */
1107
    protected function setMultiSiteVariables($siteHandle, &$siteId, array &$variables, $element = null)
0 ignored issues
show
Unused Code introduced by
The parameter $element 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

1107
    protected function setMultiSiteVariables($siteHandle, &$siteId, array &$variables, /** @scrutinizer ignore-unused */ $element = null)

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...
1108
    {
1109
        // Enabled sites
1110
        $sites = Craft::$app->getSites();
1111
        if (Craft::$app->getIsMultiSite()) {
1112
            // Set defaults based on the section settings
1113
            $variables['enabledSiteIds'] = [];
1114
            $variables['siteIds'] = [];
1115
1116
            /** @var Site $site */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
1117
            foreach ($sites->getEditableSiteIds() as $editableSiteId) {
1118
                $variables['enabledSiteIds'][] = $editableSiteId;
1119
                $variables['siteIds'][] = $editableSiteId;
1120
            }
1121
1122
            // Make sure the $siteId they are trying to edit is in our array of editable sites
1123
            if (!\in_array($siteId, $variables['enabledSiteIds'], false)) {
1124
                if (!empty($variables['enabledSiteIds'])) {
1125
                    $siteId = reset($variables['enabledSiteIds']);
1126
                } else {
1127
                    $this->requirePermission('editSite:'.$siteId);
1128
                }
1129
            }
1130
        }
1131
1132
        // Set the currentSiteId and currentSiteHandle
1133
        $variables['currentSiteId'] = empty($siteId) ? Craft::$app->getSites()->currentSite->id : $siteId;
1134
        $variables['currentSiteHandle'] = empty($siteHandle)
1135
            ? Craft::$app->getSites()->currentSite->handle
1136
            : $siteHandle;
1137
1138
        // Page title
1139
        $variables['showSites'] = (
1140
            Craft::$app->getIsMultiSite() &&
1141
            \count($variables['enabledSiteIds'])
1142
        );
1143
1144
        if ($variables['showSites']) {
1145
            $variables['sitesMenuLabel'] = Craft::t(
1146
                'site',
1147
                $sites->getSiteById((int)$variables['currentSiteId'])->name
1148
            );
1149
        } else {
1150
            $variables['sitesMenuLabel'] = '';
1151
        }
1152
    }
1153
1154
    /**
1155
     * Remove any sites for which meta bundles do not exist (they may be
1156
     * disabled for this section)
1157
     *
1158
     * @param string $sourceBundleType
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1159
     * @param string $sourceHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1160
     * @param array  $variables
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1161
     */
1162
    protected function cullDisabledSites(string $sourceBundleType, string $sourceHandle, array &$variables)
1163
    {
1164
        if (isset($variables['enabledSiteIds'])) {
1165
            foreach ($variables['enabledSiteIds'] as $key => $value) {
1166
                $metaBundle = Seomatic::$plugin->metaBundles->getMetaBundleBySourceHandle(
1167
                    $sourceBundleType,
1168
                    $sourceHandle,
1169
                    $value
1170
                );
1171
                if ($metaBundle === null) {
1172
                    unset($variables['enabledSiteIds'][$key]);
1173
                }
1174
            }
1175
        }
1176
    }
1177
1178
    /**
1179
     * Return a siteId from a siteHandle
1180
     *
1181
     * @param string $siteHandle
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
1182
     *
1183
     * @return int|null
1184
     * @throws NotFoundHttpException
1185
     */
1186
    protected function getSiteIdFromHandle($siteHandle)
1187
    {
1188
        // Get the site to edit
1189
        if ($siteHandle !== null) {
0 ignored issues
show
introduced by
The condition $siteHandle !== null is always true.
Loading history...
1190
            $site = Craft::$app->getSites()->getSiteByHandle($siteHandle);
1191
            if (!$site) {
1192
                throw new NotFoundHttpException('Invalid site handle: '.$siteHandle);
1193
            }
1194
            $siteId = $site->id;
1195
        } else {
1196
            $siteId = Craft::$app->getSites()->currentSite->id;
1197
        }
1198
1199
        return $siteId;
1200
    }
1201
1202
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $settings should have a doc-comment as per coding-style.
Loading history...
1203
     * Prep the entity settings for saving to the db
1204
     *
1205
     * @param array &$settings
0 ignored issues
show
Coding Style introduced by
Doc comment for parameter &$settings does not match actual variable name $settings
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
1206
     */
1207
    protected function prepEntitySettings(&$settings)
1208
    {
1209
        DynamicMetaHelper::normalizeTimes($settings['localBusinessOpeningHours']);
1210
        if (!empty($settings['siteType'])) {
1211
            $settings['computedType'] = SchemaHelper::getSpecificEntityType($settings);
1212
        } else {
1213
            $settings['computedType'] = 'WebPage';
1214
        }
1215
        // Empty out the entity image settings to ensure the image gets removed if it no longer exists
1216
        $settings['genericImage'] = '';
1217
        $settings['genericImageWidth'] = '';
1218
        $settings['genericImageHeight'] = '';
1219
        if (!empty($settings['genericImageIds'])) {
1220
            $asset = Craft::$app->getAssets()->getAssetById($settings['genericImageIds'][0]);
1221
            if ($asset !== null) {
1222
                $settings['genericImage'] = $asset->getUrl();
1223
                $settings['genericImageWidth'] = $asset->getWidth();
1224
                $settings['genericImageHeight'] = $asset->getHeight();
1225
            }
1226
        }
1227
    }
1228
}
1229