Helper::extractKeywords()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 3
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * SEOmatic plugin for Craft CMS
4
 *
5
 * A turnkey SEO implementation for Craft CMS that is comprehensive, powerful,
6
 * and flexible
7
 *
8
 * @link      https://nystudio107.com
9
 * @copyright Copyright (c) 2017 nystudio107
10
 */
11
12
namespace nystudio107\seomatic\services;
13
14
use Craft;
15
use craft\base\Component;
16
use craft\elements\Asset;
17
use craft\elements\db\MatrixBlockQuery;
18
use craft\elements\db\TagQuery;
19
use craft\helpers\Template;
20
use craft\web\twig\variables\Paginate;
21
use nystudio107\seomatic\base\InheritableSettingsModel;
22
use nystudio107\seomatic\helpers\DynamicMeta as DynamicMetaHelper;
23
use nystudio107\seomatic\helpers\ImageTransform as ImageTransformHelper;
24
use nystudio107\seomatic\helpers\Schema as SchemaHelper;
25
use nystudio107\seomatic\helpers\Text as TextHelper;
26
use nystudio107\seomatic\helpers\UrlHelper;
27
use nystudio107\seomatic\models\MetaBundle;
28
use nystudio107\seomatic\Seomatic;
29
use Twig\Markup;
30
use yii\base\Exception;
31
use yii\base\InvalidConfigException;
32
33
/**
34
 * Helper functions for SEOmatic
35
 * An instance of the service is available via [[`Seomatic::$plugin->helper`|`seomatic.helper`]]
36
 *
37
 * @author    nystudio107
38
 * @package   Seomatic
39
 * @since     3.0.0
40
 */
41
class Helper extends Component
42
{
43
    // Constants
44
    // =========================================================================
45
46
    public const TWITTER_TRANSFORM_MAP = [
47
        'summary' => 'twitter-summary',
48
        'summary_large_image' => 'twitter-large',
49
        'app' => 'twitter-large',
50
        'player' => 'twitter-large',
51
    ];
52
53
    // Public Methods
54
    // =========================================================================
55
56
    /**
57
     * Return a base URL to the $path, removing any language segments that may
58
     * be present, for files like robots.txt that must be served from the root
59
     *
60
     * @param $path
61
     * @return string
62
     * @throws Exception
63
     */
64
    public static function baseSiteUrl($path): string
65
    {
66
        $baseUrl = UrlHelper::hostInfo(UrlHelper::siteUrl($path));
67
68
        return rtrim($baseUrl, '/') . '/' . ltrim($path, '/');
69
    }
70
71
    /**
72
     * Sanitize user input by decoding any HTML Entities, URL decoding the text,
73
     * then removing any newlines, stripping tags, stripping Twig tags, and changing
74
     * single {}'s into ()'s
75
     *
76
     * @param $str
77
     * @return string
78
     */
79
    public static function sanitizeUserInput($str): string
80
    {
81
        return TextHelper::sanitizeUserInput($str);
82
    }
83
84
    /**
85
     * Return the appropriate Twitter Transform based on the current $metaGlobalVars->twitterCard
86
     *
87
     * @return string
88
     */
89
    public static function twitterTransform(): string
90
    {
91
        $transform = 'twitter-summary';
92
        $metaGlobalVars = Seomatic::$plugin->metaContainers->metaGlobalVars;
93
        if ($metaGlobalVars) {
94
            $transform = self::TWITTER_TRANSFORM_MAP[$metaGlobalVars->twitterCard] ?? $transform;
95
        }
96
97
        return $transform;
98
    }
99
100
    /**
101
     * Return the proper content for the `query-input` JSON-LD property
102
     *
103
     * @return string
104
     */
105
    public static function siteLinksQueryInput(): string
106
    {
107
        $result = '';
108
109
        $metaSiteVars = Seomatic::$plugin->metaContainers->metaSiteVars;
110
        if ($metaSiteVars && !empty($metaSiteVars->siteLinksQueryInput)) {
111
            $result = 'required name=' . $metaSiteVars->siteLinksQueryInput;
112
        }
113
114
        return $result;
115
    }
116
117
    /**
118
     * Return whether this is a preview request of any kind
119
     *
120
     * @return bool
121
     */
122
    public static function isPreview(): bool
123
    {
124
        $request = Craft::$app->getRequest();
125
        $isPreview = $request->getIsPreview();
126
        $isLivePreview = $request->getIsLivePreview();
127
128
        return ($isPreview || $isLivePreview);
129
    }
130
131
    /**
132
     * Return the Same As Links info as an array or null
133
     *
134
     * @param string $handle
135
     * @return array|null
136
     */
137
    public static function sameAsByHandle(string $handle)
138
    {
139
        $result = null;
140
141
        $sameAs = Seomatic::$plugin->metaContainers->metaSiteVars->sameAsLinks;
142
        if (!empty($sameAs) && !empty($handle)) {
143
            foreach ($sameAs as $sameAsInfo) {
144
                if (!empty($sameAsInfo) && is_array($sameAsInfo) && !empty($sameAsInfo['handle'])) {
145
                    if ($sameAsInfo['handle'] === $handle) {
146
                        return $sameAsInfo;
147
                    }
148
                }
149
            }
150
        }
151
152
        return $result;
153
    }
154
155
    /**
156
     * Return the canonical URL for the request, with the query string stripped
157
     *
158
     * @return string
159
     */
160
    public static function safeCanonicalUrl(): string
161
    {
162
        $url = '';
0 ignored issues
show
Unused Code introduced by
The assignment to $url is dead and can be removed.
Loading history...
163
        try {
164
            $url = Craft::$app->getRequest()->getPathInfo();
165
        } catch (InvalidConfigException $e) {
166
            Craft::error($e->getMessage(), __METHOD__);
167
        }
168
169
        return DynamicMetaHelper::sanitizeUrl(UrlHelper::absoluteUrlWithProtocol($url));
170
    }
171
172
    /**
173
     * Return the site URL for a given URL. This gives SEOmatic a chance to override it
174
     *
175
     * @param string $path
176
     * @param array|string|null $params
177
     * @param string|null $scheme
178
     * @param int|null $siteId
179
     * @return string
180
     * @throws Exception if|null $siteId is invalid
181
     */
182
    public static function siteUrl(string $path = '', $params = null, string $scheme = null, int $siteId = null): string
183
    {
184
        return UrlHelper::siteUrl($path, $params, $scheme, $siteId);
185
    }
186
187
    /**
188
     * Paginate based on the passed in Paginate variable as returned from the
189
     * Twig {% paginate %} tag:
190
     * https://docs.craftcms.com/v3/templating/tags/paginate.html#the-pageInfo-variable
191
     *
192
     * @param Paginate $pageInfo
193
     */
194
    public static function paginate(Paginate $pageInfo)
195
    {
196
        DynamicMetaHelper::paginate($pageInfo);
197
    }
198
199
    /**
200
     * Truncates the string to a given length. If $substring is provided, and
201
     * truncating occurs, the string is further truncated so that the substring
202
     * may be appended without exceeding the desired length.
203
     *
204
     * @param string $string The string to truncate
205
     * @param int $length Desired length of the truncated string
206
     * @param string $substring The substring to append if it can fit
207
     *
208
     * @return string with the resulting $str after truncating
209
     */
210
    public static function truncate($string, $length, $substring = '…'): string
211
    {
212
        return TextHelper::truncate($string, $length, $substring);
213
    }
214
215
    /**
216
     * Truncates the string to a given length, while ensuring that it does not
217
     * split words. If $substring is provided, and truncating occurs, the
218
     * string is further truncated so that the substring may be appended without
219
     * exceeding the desired length.
220
     *
221
     * @param string $string The string to truncate
222
     * @param int $length Desired length of the truncated string
223
     * @param string $substring The substring to append if it can fit
224
     *
225
     * @return string with the resulting $str after truncating
226
     */
227
    public static function truncateOnWord($string, $length, $substring = '…'): string
228
    {
229
        return TextHelper::truncateOnWord($string, $length, $substring);
230
    }
231
232
    /**
233
     * Return a list of localized URLs that are in the current site's group
234
     * The current URI is used if $uri is null. Similarly, the current site is
235
     * used if $siteId is null.
236
     * The resulting array of arrays has `id`, `language`, `ogLanguage`,
237
     * `hreflangLanguage`, and `url` as keys.
238
     *
239
     * @param string|null $uri
240
     * @param int|null $siteId
241
     *
242
     * @return array
243
     */
244
    public static function getLocalizedUrls(string $uri = null, int $siteId = null): array
245
    {
246
        return DynamicMetaHelper::getLocalizedUrls($uri, $siteId);
247
    }
248
249
    /**
250
     * Allow setting the X-Robots-Tag and Link headers on static files as per:
251
     * https://moz.com/blog/how-to-advanced-relcanonical-http-headers
252
     *
253
     * @param        $url
254
     * @param string $robots
255
     * @param string $canonical
256
     * @param bool $inline
257
     *
258
     * @return Markup
259
     * @throws Exception
260
     */
261
    public static function seoFileLink($url, $robots = '', $canonical = '', $inline = true): Markup
262
    {
263
        // Get the file name
264
        $path = parse_url($url, PHP_URL_PATH);
265
        $fileName = pathinfo($path, PATHINFO_BASENAME);
266
        // Set some defaults
267
        $robots = empty($robots) ? 'all' : $robots;
268
        $canonical = empty($canonical) ? $url : $canonical;
269
        $inlineStr = $inline === true ? '1' : '0';
270
        // Compose the base64 encoded URL
271
        $seoFileLink = 'seomatic/seo-file-link/'
272
            . base64_encode($url)
273
            . '/'
274
            . base64_encode($robots)
275
            . '/'
276
            . base64_encode($canonical)
277
            . '/'
278
            . $inlineStr
279
            . '/'
280
            . $fileName;
0 ignored issues
show
Bug introduced by
Are you sure $fileName of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

280
            . /** @scrutinizer ignore-type */ $fileName;
Loading history...
281
282
        return Template::raw(UrlHelper::siteUrl($seoFileLink));
283
    }
284
285
    /**
286
     * Load the appropriate meta containers for the given $uri and optional
287
     * $siteId
288
     *
289
     * @param string $uri
290
     * @param int|null $siteId
291
     */
292
    public static function loadMetadataForUri(string $uri = '', int $siteId = null)
293
    {
294
        Seomatic::$plugin->metaContainers->loadMetaContainers($uri, $siteId);
295
    }
296
297
    /**
298
     * Get the URL to the $siteId's sitemap index
299
     *
300
     * @param int|null $siteId
301
     *
302
     * @return string
303
     */
304
    public static function sitemapIndexForSiteId(int $siteId = null): string
305
    {
306
        return Seomatic::$plugin->sitemaps->sitemapIndexUrlForSiteId($siteId);
307
    }
308
309
    /**
310
     * Return a sitemap for each site in the same site group
311
     *
312
     * @return string
313
     */
314
    public static function sitemapIndex(): string
315
    {
316
        return Seomatic::$plugin->sitemaps->sitemapIndex();
317
    }
318
319
    /**
320
     * Return a sitemap for each site in the same site group
321
     *
322
     * @return string
323
     * @deprecated use sitemapIndex() instead
324
     */
325
    public static function siteGroupSitemaps(): string
326
    {
327
        return Seomatic::$plugin->sitemaps->sitemapIndex();
328
    }
329
330
    /**
331
     * @param string $sourceType
332
     * @param string $sourceHandle
333
     * @param int|null $siteId
334
     *
335
     * @return string
336
     */
337
    public static function sitemapUrlForBundle(string $sourceType, string $sourceHandle, int $siteId = null, int $page = 0): string
338
    {
339
        return Seomatic::$plugin->sitemaps->sitemapUrlForBundle($sourceType, $sourceHandle, $siteId, $page);
340
    }
341
342
    /**
343
     * Extract plain old text from a field
344
     *
345
     * @param $field
346
     *
347
     * @return string
348
     */
349
    public static function extractTextFromField($field = null): string
350
    {
351
        return TextHelper::extractTextFromField($field);
352
    }
353
354
    /**
355
     * Extract concatenated text from all of the tags in the $tagElement and
356
     * return as a comma-delimited string
357
     *
358
     * @param TagQuery $tagQuery
359
     *
360
     * @return string
361
     */
362
    public static function extractTextFromTags($tagQuery = null): string
363
    {
364
        return TextHelper::extractTextFromTags($tagQuery);
365
    }
366
367
    /**
368
     * Extract text from all of the blocks in a matrix field, concatenating it
369
     * together.
370
     *
371
     * @param MatrixBlockQuery $matrixQuery
372
     * @param string $fieldHandle
373
     *
374
     * @return string
375
     */
376
    public static function extractTextFromMatrix($matrixQuery = null, $fieldHandle = ''): string
377
    {
378
        return TextHelper::extractTextFromMatrix($matrixQuery, $fieldHandle);
379
    }
380
381
    /**
382
     * Return the most important keywords extracted from the text as a comma-
383
     * delimited string
384
     *
385
     * @param string $text
386
     * @param int $limit
387
     * @param bool $useStopWords
388
     *
389
     * @return string
390
     */
391
    public static function extractKeywords($text = '', $limit = 15, $useStopWords = true): string
392
    {
393
        return TextHelper::extractKeywords($text, $limit, $useStopWords);
394
    }
395
396
    /**
397
     * Extract a summary consisting of the 3 most important sentences from the
398
     * text
399
     *
400
     * @param string $text
401
     * @param bool $useStopWords
402
     *
403
     * @return string
404
     */
405
    public static function extractSummary($text = '', $useStopWords = true): string
406
    {
407
        return TextHelper::extractSummary($text, $useStopWords);
408
    }
409
410
    /**
411
     * Return a period-delimited schema.org path from the $settings
412
     *
413
     * @param $settings
414
     *
415
     * @return string
416
     */
417
    public static function getEntityPath($settings): string
418
    {
419
        return SchemaHelper::getEntityPath($settings);
420
    }
421
422
    /**
423
     * Return a flattened, indented menu of the given $path
424
     *
425
     * @param string $path
426
     *
427
     * @return array
428
     */
429
    public static function getTypeMenu($path): array
430
    {
431
        return SchemaHelper::getTypeMenu($path);
432
    }
433
434
    /**
435
     * Return a single menu of schemas starting at $path
436
     *
437
     * @param string $path
438
     *
439
     * @return array
440
     */
441
    public static function getSingleTypeMenu($path): array
442
    {
443
        return SchemaHelper::getSingleTypeMenu($path);
444
    }
445
446
    /**
447
     * Transform the $asset for social media sites in $transformName and
448
     * optional $siteId
449
     *
450
     * @param int|Asset $asset the Asset or Asset ID
451
     * @param string $transformName the name of the transform to apply
452
     * @param int|null $siteId
453
     * @param string $transformMode
454
     *
455
     * @return string URL to the transformed image
456
     */
457
    public function socialTransform($asset, $transformName = '', $siteId = null, $transformMode = null): string
458
    {
459
        return ImageTransformHelper::socialTransform($asset, $transformName, $siteId, $transformMode);
460
    }
461
462
    /**
463
     * Get the width of the transformed social image for $transformName and
464
     * optional $siteId
465
     *
466
     * @param int|Asset $asset the Asset or Asset ID
467
     * @param string $transformName the name of the transform to apply
468
     * @param int|null $siteId
469
     * @param string $transformMode
470
     *
471
     * @return string URL to the transformed image
472
     */
473
    public function socialTransformWidth(
474
        $asset,
475
        $transformName = '',
476
        $siteId = null,
477
        $transformMode = null,
478
    ): string {
479
        return ImageTransformHelper::socialTransformWidth($asset, $transformName, $siteId, $transformMode);
480
    }
481
482
    /**
483
     * Get the height of the transformed social image for $transformName and
484
     * optional $siteId
485
     *
486
     * @param int|Asset $asset the Asset or Asset ID
487
     * @param string $transformName the name of the transform to apply
488
     * @param int|null $siteId
489
     * @param string $transformMode
490
     *
491
     * @return string URL to the transformed image
492
     */
493
    public function socialTransformHeight(
494
        $asset,
495
        $transformName = '',
496
        $siteId = null,
497
        $transformMode = null,
498
    ): string {
499
        return ImageTransformHelper::socialTransformHeight($asset, $transformName, $siteId, $transformMode);
500
    }
501
502
    /**
503
     * Return whether we are running Craft 3.1 or later
504
     *
505
     * @return bool
506
     */
507
    public function craft31(): bool
508
    {
509
        return true;
510
    }
511
512
    /**
513
     * Return whether we are running Craft 3.2 or later
514
     *
515
     * @return bool
516
     */
517
    public function craft32(): bool
518
    {
519
        return true;
520
    }
521
522
    /**
523
     * Return whether we are running Craft 3.3 or later
524
     *
525
     * @return bool
526
     */
527
    public function craft33(): bool
528
    {
529
        return true;
530
    }
531
532
    /**
533
     * Given a list of meta bundles in order of descending distance, return the bundle that has inheritable value.
534
     *
535
     * @param array $inheritedValues
536
     * @param string $settingName
537
     * @param string $collectionName The name off the collection to search
538
     * @return MetaBundle|null
539
     * @since 3.4.0
540
     */
541
    public function findInheritableBundle(array $inheritedValues, string $settingName, string $collectionName = "metaGlobalVars")
542
    {
543
        if (in_array($collectionName, ['metaGlobalVars', 'metaSitemapVars'], true)) {
544
            foreach ($inheritedValues as $bundle) {
545
                /** @var $bundle MetaBundle */
546
                if (isset($bundle->{$collectionName}[$settingName])) {
547
                    if (is_bool($bundle->{$collectionName}[$settingName]) || !empty($bundle->{$collectionName}[$settingName])) {
548
                        return $bundle;
549
                    }
550
                }
551
            }
552
        }
553
554
        return null;
555
    }
556
557
    /**
558
     * Return true if a setting is inherited.
559
     *
560
     * @param InheritableSettingsModel $settingCollection
561
     * @param $settingName
562
     * @return bool
563
     * @since 3.4.0
564
     */
565
    public function isInherited(InheritableSettingsModel $settingCollection, $settingName)
566
    {
567
        $explicitInherit = array_key_exists($settingName, (array)$settingCollection->inherited);
568
        $explicitOverride = array_key_exists($settingName, (array)$settingCollection->overrides);
569
570
        if ($explicitInherit || $explicitOverride) {
571
            return $explicitInherit && !$explicitOverride;
572
        }
573
574
        return empty($settingCollection->{$settingName});
575
    }
576
}
577