Skip to content

Commit

Permalink
Improve handling of hreflang and canonical (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
aerni authored Jul 17, 2024
1 parent 6ef3bab commit 2af4adc
Show file tree
Hide file tree
Showing 16 changed files with 508 additions and 291 deletions.
4 changes: 2 additions & 2 deletions lang/en/fields.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@

'seo_canonical_custom' => [
'display' => 'URL',
'instructions' => 'A fully qualified URL starting with https://.',
'default_instructions' => 'A fully qualified URL starting with https://.',
'instructions' => 'A fully qualified and [active URL](https://laravel.com/docs/11.x/validation#rule-active-url).',
'default_instructions' => 'A fully qualified and [active URL](https://laravel.com/docs/11.x/validation#rule-active-url).',
],

'seo_section_indexing' => [
Expand Down
4 changes: 2 additions & 2 deletions resources/fieldsets/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ fields:
import: 'advanced-seo::open_graph'
-
import: 'advanced-seo::twitter'
-
import: 'advanced-seo::canonical_url'
-
import: 'advanced-seo::indexing'
-
import: 'advanced-seo::canonical_url'
-
import: 'advanced-seo::sitemap'
-
Expand Down
7 changes: 7 additions & 0 deletions src/Actions/Indexable.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@
namespace Aerni\AdvancedSeo\Actions;

use Aerni\AdvancedSeo\Facades\Seo;
use Aerni\AdvancedSeo\View\Concerns\EvaluatesIndexability;
use Statamic\Contracts\Entries\Entry;
use Statamic\Contracts\Taxonomies\Taxonomy;
use Statamic\Contracts\Taxonomies\Term;
use Statamic\Facades\Blink;

class Indexable
{
use EvaluatesIndexability;

public static function handle(Entry|Term|Taxonomy $model, ?string $locale = null): bool
{
if (! (new self)->crawlingIsEnabled()) {
return false;
}

$locale = $locale ?? $model->locale();

return Blink::once("{$model->id()}::{$locale}", function () use ($model, $locale) {
Expand Down
78 changes: 39 additions & 39 deletions src/Fields/ContentDefaultsFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ protected function sections(): array
$this->socialImagesGenerator(),
$this->openGraphImage(),
$this->twitterImage(),
$this->canonicalUrl(),
$this->indexing(),
$this->canonicalUrl(),
$this->sitemap(),
$this->jsonLd(),
];
Expand Down Expand Up @@ -283,6 +283,44 @@ protected function twitterImage(): array
];
}

protected function indexing(): array
{
return [
[
'handle' => 'seo_section_indexing',
'field' => [
'type' => 'section',
'display' => $this->trans('seo_section_indexing.display'),
'instructions' => $this->trans('seo_section_indexing.default_instructions'),
],
],
[
'handle' => 'seo_noindex',
'field' => [
'type' => 'toggle',
'display' => $this->trans('seo_noindex.display'),
'instructions' => $this->trans('seo_noindex.default_instructions'),
'default' => Defaults::data('collections')->get('seo_noindex'),
'listable' => 'hidden',
'localizable' => true,
'width' => 50,
],
],
[
'handle' => 'seo_nofollow',
'field' => [
'type' => 'toggle',
'display' => $this->trans('seo_nofollow.display'),
'instructions' => $this->trans('seo_nofollow.default_instructions'),
'default' => Defaults::data('collections')->get('seo_nofollow'),
'listable' => 'hidden',
'localizable' => true,
'width' => 50,
],
],
];
}

protected function canonicalUrl(): array
{
return [
Expand Down Expand Up @@ -347,44 +385,6 @@ protected function canonicalUrl(): array
];
}

protected function indexing(): array
{
return [
[
'handle' => 'seo_section_indexing',
'field' => [
'type' => 'section',
'display' => $this->trans('seo_section_indexing.display'),
'instructions' => $this->trans('seo_section_indexing.default_instructions'),
],
],
[
'handle' => 'seo_noindex',
'field' => [
'type' => 'toggle',
'display' => $this->trans('seo_noindex.display'),
'instructions' => $this->trans('seo_noindex.default_instructions'),
'default' => Defaults::data('collections')->get('seo_noindex'),
'listable' => 'hidden',
'localizable' => true,
'width' => 50,
],
],
[
'handle' => 'seo_nofollow',
'field' => [
'type' => 'toggle',
'display' => $this->trans('seo_nofollow.display'),
'instructions' => $this->trans('seo_nofollow.default_instructions'),
'default' => Defaults::data('collections')->get('seo_nofollow'),
'listable' => 'hidden',
'localizable' => true,
'width' => 50,
],
],
];
}

protected function sitemap(): array
{
return [
Expand Down
99 changes: 54 additions & 45 deletions src/Fields/OnPageSeoFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ protected function sections(): array
$this->socialImagesGenerator(),
$this->openGraphImage(),
$this->twitterImage(),
$this->canonicalUrl(),
$this->indexing(),
$this->canonicalUrl(),
$this->sitemap(),
$this->jsonLd(),
];
Expand Down Expand Up @@ -379,6 +379,50 @@ protected function twitterImage(): array
];
}

protected function indexing(): array
{
return [
[
'handle' => 'seo_section_indexing',
'field' => [
'type' => 'section',
'display' => $this->trans('seo_section_indexing.display'),
'instructions' => $this->trans('seo_section_indexing.instructions'),
],
],
[
'handle' => 'seo_noindex',
'field' => [
'type' => 'seo_source',
'display' => $this->trans('seo_noindex.display'),
'instructions' => $this->trans('seo_noindex.instructions'),
'default' => '@default',
'localizable' => true,
'classes' => 'toggle-fieldtype',
'width' => 50,
'field' => [
'type' => 'toggle',
],
],
],
[
'handle' => 'seo_nofollow',
'field' => [
'type' => 'seo_source',
'display' => $this->trans('seo_nofollow.display'),
'instructions' => $this->trans('seo_nofollow.instructions'),
'default' => '@default',
'localizable' => true,
'classes' => 'toggle-fieldtype',
'width' => 50,
'field' => [
'type' => 'toggle',
],
],
],
];
}

protected function canonicalUrl(): array
{
return [
Expand All @@ -388,6 +432,9 @@ protected function canonicalUrl(): array
'type' => 'section',
'display' => $this->trans('seo_section_canonical_url.display'),
'instructions' => $this->trans('seo_section_canonical_url.instructions'),
'if' => [
'seo_noindex.value' => 'false',
],
],
],
[
Expand All @@ -399,6 +446,9 @@ protected function canonicalUrl(): array
'default' => '@default',
'localizable' => true,
'classes' => 'button_group-fieldtype',
'if' => [
'seo_noindex.value' => 'false',
],
'field' => [
'type' => 'button_group',
'options' => [
Expand All @@ -419,6 +469,7 @@ protected function canonicalUrl(): array
'localizable' => true,
'classes' => 'relationship-fieldtype',
'if' => [
'seo_noindex.value' => 'false',
'seo_canonical_type.value' => 'equals other',
],
'field' => [
Expand All @@ -443,64 +494,22 @@ protected function canonicalUrl(): array
'classes' => 'text-fieldtype',
'antlers' => true,
'if' => [
'seo_noindex.value' => 'false',
'seo_canonical_type.value' => 'equals custom',
],
'field' => [
'type' => 'text',
'input_type' => 'url',
'validate' => [
'required_if:seo_canonical_type,custom',
'active_url',
],
],
],
],
];
}

protected function indexing(): array
{
return [
[
'handle' => 'seo_section_indexing',
'field' => [
'type' => 'section',
'display' => $this->trans('seo_section_indexing.display'),
'instructions' => $this->trans('seo_section_indexing.instructions'),
],
],
[
'handle' => 'seo_noindex',
'field' => [
'type' => 'seo_source',
'display' => $this->trans('seo_noindex.display'),
'instructions' => $this->trans('seo_noindex.instructions'),
'default' => '@default',
'localizable' => true,
'classes' => 'toggle-fieldtype',
'width' => 50,
'field' => [
'type' => 'toggle',
],
],
],
[
'handle' => 'seo_nofollow',
'field' => [
'type' => 'seo_source',
'display' => $this->trans('seo_nofollow.display'),
'instructions' => $this->trans('seo_nofollow.instructions'),
'default' => '@default',
'localizable' => true,
'classes' => 'toggle-fieldtype',
'width' => 50,
'field' => [
'type' => 'toggle',
],
],
],
];
}

protected function sitemap(): array
{
return [
Expand Down
54 changes: 32 additions & 22 deletions src/Sitemap/CollectionSitemapUrl.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use Aerni\AdvancedSeo\Actions\Indexable;
use Aerni\AdvancedSeo\Support\Helpers;
use Illuminate\Support\Collection;
use Statamic\Contracts\Entries\Entry;
use Statamic\Facades\Site;

Expand All @@ -19,22 +18,42 @@ public function loc(): string

public function alternates(): ?array
{
$entries = $this->entries();
if (! Site::multiEnabled()) {
return null;
}

// We only want alternate URLs if there are at least two entries.
if ($entries->count() <= 1) {
if (! Indexable::handle($this->entry)) {
return null;
}

return $entries->map(fn ($entry) => [
'hreflang' => Helpers::parseLocale(Site::get($entry->locale())->locale()),
'href' => $this->absoluteUrl($entry),
])
->put('x-default', [
'hreflang' => 'x-default',
'href' => $this->absoluteUrl($this->entry->origin() ?? $this->entry),
])
->toArray();
$sites = $this->entry->sites();

if ($sites->count() < 2) {
return null;
}

$hreflang = $sites
->map(fn ($locale) => $this->entry->in($locale))
->filter() // A model might not exist in a site. So we need to remove it to prevent calling methods on null
->filter(Indexable::handle(...));

if ($hreflang->count() < 2) {
return null;
}

$hreflang->transform(fn ($model) => [
'href' => $this->absoluteUrl($model),
'hreflang' => Helpers::parseLocale($model->site()->locale()),
]);

$origin = $this->entry->origin() ?? $this->entry;

$xDefault = Indexable::handle($origin) ? $origin : $this->entry;

return $hreflang->push([
'href' => $this->absoluteUrl($xDefault),
'hreflang' => 'x-default',
])->values()->all();
}

public function lastmod(): string
Expand Down Expand Up @@ -65,13 +84,4 @@ public function isCanonicalUrl(): bool
default => false,
};
}

protected function entries(): Collection
{
$root = $this->entry->root();
$descendants = $root->descendants();

return collect([$root->locale() => $root])->merge($descendants)
->filter(fn ($entry) => Indexable::handle($entry));
}
}
Loading

0 comments on commit 2af4adc

Please sign in to comment.