Skip to content

Commit 31ffa45

Browse files
AritzPalaciosOrtizjavihgil
authored andcommitted
Canonical Url (#448)
1 parent a8476fa commit 31ffa45

15 files changed

Lines changed: 131 additions & 32 deletions

File tree

cms/contents/page/config.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# this is the page base configuration
22
content:
3-
revision: 2
3+
revision: 3
44
entity_class: 'Softspring\CmsBundle\Entity\Page'
55
default_layout: 'default'
66
version_seo:
@@ -10,6 +10,10 @@ content:
1010
type: translation
1111
metaKeywords:
1212
type: translation
13+
canonicalContent:
14+
type: translatable
15+
type_options:
16+
type: content
1317
indexing:
1418
noIndex:
1519
type: checkbox
@@ -41,7 +45,7 @@ content:
4145
admin_page.form.indexing.sitemapChangefreq.values.weekly: weekly
4246
admin_page.form.indexing.sitemapChangefreq.values.monthly: monthly
4347
admin_page.form.indexing.sitemapChangefreq.values.yearly: yearly
44-
admin_page.form.indexing.sitemapChangefreq.values.never: never
48+
admin_page.form.indexing.sitemapChangefreq.values.never: never
4549
sitemapPriority:
4650
type: number
4751
type_options:

cms/contents/page/seo-migrate.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,14 @@
1313
}
1414
}
1515

16+
// canonicalContent became translatable in revision 3.
17+
// Migrate previous scalar/entity value to a translatable structure.
18+
if ($originVersion < 3 && $targetVersion >= 3 && isset($seo['canonicalContent']) && !is_array($seo['canonicalContent'])) {
19+
$seo['canonicalContent'] = \Softspring\TranslatableBundle\Model\Translation::createFromArray([
20+
'en' => $seo['canonicalContent'],
21+
'_default' => 'en',
22+
]);
23+
}
24+
1625
return $seo;
1726
};

cms/contents/page/translations/sfs_cms_contents.en.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ admin_page:
311311
metaTitle.label: "Title (browser title and meta tags)"
312312
metaDescription.label: "Description (meta tag)"
313313
metaKeywords.label: "Keywords (meta tag)"
314+
canonicalContent.label: "Canonical URL source"
315+
canonicalContent.placeholder: "Use this page as canonical (default)"
316+
canonicalContent.help: "If selected, this page will output a canonical URL pointing to the selected page."
314317

315318
version_form:
316319
note.label: "Note"

cms/contents/page/translations/sfs_cms_contents.es.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ admin_page:
311311
metaTitle.label: "Título (título del navegador y etiquetas meta)"
312312
metaDescription.label: "Descripción (etiqueta meta)"
313313
metaKeywords.label: "Palabras clave (etiqueta meta)"
314+
canonicalContent.label: "Fuente de URL canónica"
315+
canonicalContent.placeholder: "Usar esta página como canónica (por defecto)"
316+
canonicalContent.help: "Si se selecciona, esta página generará la URL canónica apuntando a la página seleccionada."
314317

315318
version_form:
316319
note.label: "Nota"

cms/layouts/default/render.html.twig

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,18 @@
2121
<meta property="og:title" content="{{ version.seo.metaTitle|default|sfs_cms_trans }}">
2222
<meta property="og:description" content="{{ version.seo.metaDescription|default|sfs_cms_trans }}">
2323
<meta property="og:locale" content="{{ app.request.locale }}">
24-
{% for locale, url in sfs_cms_alternate_urls() %}
25-
<link rel="alternate" hreflang="{{ locale }}" href="{{ url }}" />
26-
{% endfor %}
24+
{% set canonical_content = version.seo.canonicalContent|default(null) %}
25+
{% if canonical_content is iterable %}
26+
{% set canonical_content = canonical_content[app.request.locale]|default(null) %}
27+
{% endif %}
28+
{% if canonical_content and canonical_content != version.content %}
29+
<link rel="canonical" href="{{ sfs_cms_url_for_content(canonical_content, app.request.locale) }}" />
30+
{% else %}
31+
<link rel="canonical" href="{{ sfs_cms_url_for_content(version.content, app.request.locale) }}" />
32+
{% for locale, url in sfs_cms_alternate_urls() %}
33+
<link rel="alternate" hreflang="{{ locale }}" href="{{ url }}" />
34+
{% endfor %}
35+
{% endif %}
2736
{% endblock seo %}
2837

2938
{% block body %}
@@ -93,4 +102,4 @@
93102
});
94103
</script>
95104
{% endif %}
96-
{% endblock javascripts %}
105+
{% endblock javascripts %}

src/EntityTransformer/ContentVersionTransformer.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,16 @@ public function untransform(object $entity, ObjectManager $em): void
7777
}
7878

7979
if ($contentVersion->getSeo()) {
80-
$seo = $contentVersion->getSeo();
81-
8280
$config = $this->cmsConfig->getContent($contentVersion->getContent());
83-
$seo = DataMigrator::migrate($config['seo_revision_migration_scripts'], $seo, $config['revision'], $this->cmsConfig);
84-
foreach ($seo as $field => $value) {
85-
$seo[$field] = $this->untransformEntityValues($value, $em);
86-
}
87-
$contentVersion->setSeo($seo);
81+
82+
$contentVersion->_setSeoCallback(function (array $seo) use ($em, $config): array {
83+
$seo = DataMigrator::migrate($config['seo_revision_migration_scripts'], $seo, $config['revision'], $this->cmsConfig);
84+
foreach ($seo as $field => $value) {
85+
$seo[$field] = $this->untransformEntityValues($value, $em);
86+
}
87+
88+
return $seo;
89+
});
8890
}
8991
}
9092

src/Form/Type/ContentType.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace Softspring\CmsBundle\Form\Type;
4+
5+
use Doctrine\ORM\EntityManagerInterface;
6+
use Softspring\CmsBundle\Manager\ContentManager;
7+
use Softspring\CmsBundle\Model\ContentInterface;
8+
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
9+
use Symfony\Component\Form\AbstractType;
10+
use Symfony\Component\OptionsResolver\OptionsResolver;
11+
use Symfony\Contracts\Translation\TranslatorInterface;
12+
13+
class ContentType extends AbstractType
14+
{
15+
public function __construct(protected EntityManagerInterface $sfsContentEm, protected ContentManager $contentManager, protected TranslatorInterface $translator)
16+
{
17+
}
18+
19+
public function getParent(): ?string
20+
{
21+
return EntityType::class;
22+
}
23+
24+
public function configureOptions(OptionsResolver $resolver): void
25+
{
26+
$resolver->setDefaults([
27+
'class' => ContentInterface::class,
28+
'em' => $this->sfsContentEm,
29+
'required' => false,
30+
'choice_label' => function (ContentInterface $content) {
31+
return $content->getName();
32+
},
33+
'group_by' => function (ContentInterface $content) {
34+
return $this->translator->trans("{$this->contentManager->getType($content)}.name", [], 'sfs_cms_contents');
35+
},
36+
]);
37+
}
38+
}

src/Helper/RoutingHelper.php

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -91,34 +91,43 @@ public function generatePath($route, ?string $locale = null, $site = null): stri
9191
return $this->generateUrl($route, $locale, $site, UrlGeneratorInterface::ABSOLUTE_PATH);
9292
}
9393

94+
public function generateUrlForContent($content, string $locale, $site = null): string
95+
{
96+
foreach ($content->getRoutes() as $route) {
97+
if ($route->getPathForLocale($locale)) {
98+
return $this->generateUrl($route, $locale, $site);
99+
}
100+
}
101+
102+
return '#';
103+
}
104+
94105
public function generateUrl($route, ?string $locale = null, $site = null, int $referenceType = UrlGeneratorInterface::ABSOLUTE_URL): string
95106
{
96107
if (is_null($route)) {
97108
return '#';
98109
}
99110

100-
if (is_array($route)) {
101-
if (is_null($route['route_name'])) {
102-
return '#';
103-
}
111+
$params = [];
112+
$params['_locale'] = $locale ?: ($this->requestStack->getCurrentRequest()?->getLocale() ?: 'en');
104113

105-
$params = $route['route_params'] ?? [];
114+
if ($site) {
115+
$params['_site'] = $site;
116+
}
106117

107-
$params['_locale'] = $locale ?: ($this->requestStack->getCurrentRequest()?->getLocale() ?: 'en');
118+
$routeName = $route;
108119

109-
if ($site) {
110-
$params['_site'] = $site;
120+
if (is_array($route)) {
121+
if (is_null($route['route_name'])) {
122+
return '#';
111123
}
112124

113-
return $this->router->generate($route['route_name'], $params, $referenceType);
125+
$params = array_merge($params, $route['route_params'] ?? []);
126+
$routeName = $route['route_name'];
114127
} elseif ($route instanceof RouteInterface) {
115-
return $this->router->generate($route->getId(), [], $referenceType);
128+
$routeName = $route->getId();
116129
}
117130

118-
$params = [
119-
'_locale' => $locale ?: ($this->requestStack->getCurrentRequest()?->getLocale() ?: 'en'),
120-
];
121-
122-
return $this->router->generate($route, $params, $referenceType);
131+
return $this->router->generate($routeName, $params, $referenceType);
123132
}
124133
}

src/Model/ContentVersion.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ abstract class ContentVersion implements ContentVersionInterface
1919

2020
protected ?array $seo = null;
2121

22+
protected mixed $_getSeoCallback = null;
23+
24+
protected mixed $_rawSeo = null;
25+
2226
public function getContent(): ?ContentInterface
2327
{
2428
return $this->content;
@@ -52,13 +56,29 @@ public function setLayout(?string $layout): void
5256
$this->layout = $layout;
5357
}
5458

59+
public function _setSeoCallback(callable $getSeoCallback): void
60+
{
61+
$this->_getSeoCallback = $getSeoCallback;
62+
}
63+
5564
public function getSeo(): ?array
5665
{
66+
if ($this->_getSeoCallback) {
67+
$this->_rawSeo = $this->seo;
68+
$this->seo = call_user_func($this->_getSeoCallback, $this->seo);
69+
$this->_getSeoCallback = null;
70+
}
71+
5772
return $this->seo;
5873
}
5974

6075
public function setSeo(?array $seo): void
6176
{
6277
$this->seo = $seo;
6378
}
79+
80+
public function getRawSeo(): ?array
81+
{
82+
return $this->_rawSeo ?? $this->seo;
83+
}
6484
}

src/Routing/UrlGenerator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public function getUrl($routeOrName, ?string $locale = null, $site = null, array
4848
}
4949

5050
if ($route->getContent() && !$route->getContent()->getPublishedVersion()) {
51-
return '#';
51+
return '#not-published';
5252
}
5353

5454
$queryString = [] === $routeParams ? '' : '?'.http_build_query($routeParams);

0 commit comments

Comments
 (0)