diff --git a/core-bundle/src/EventListener/DataContainer/AddCanonicalFieldsListener.php b/core-bundle/src/EventListener/DataContainer/AddCanonicalFieldsListener.php
new file mode 100644
index 00000000000..7a3ddf234bc
--- /dev/null
+++ b/core-bundle/src/EventListener/DataContainer/AddCanonicalFieldsListener.php
@@ -0,0 +1,49 @@
+contaoFramework = $contaoFramework;
+ }
+
+ public function __invoke(DataContainer $dc): void
+ {
+ /** @var PageModel $pageModel */
+ $pageModel = $this->contaoFramework->getAdapter(PageModel::class);
+ $page = $pageModel->findWithDetails($dc->id);
+
+ if ('regular' !== $page->type || !$page->enableCanonical) {
+ return;
+ }
+
+ PaletteManipulator::create()
+ ->addField('canonicalLink', 'serpPreview')
+ ->addField('canonicalKeepParams', 'serpPreview')
+ ->applyToPalette('regular', 'tl_page')
+ ;
+ }
+}
diff --git a/core-bundle/src/Resources/config/listener.yml b/core-bundle/src/Resources/config/listener.yml
index 63394218041..b6a81a51837 100644
--- a/core-bundle/src/Resources/config/listener.yml
+++ b/core-bundle/src/Resources/config/listener.yml
@@ -19,6 +19,10 @@ services:
tags:
- { name: kernel.event_listener }
+ Contao\CoreBundle\EventListener\DataContainer\AddCanonicalFieldsListener:
+ arguments:
+ - '@contao.framework'
+
Contao\CoreBundle\EventListener\DataContainer\ContentCompositionListener:
arguments:
- '@contao.framework'
diff --git a/core-bundle/src/Resources/contao/dca/tl_page.php b/core-bundle/src/Resources/contao/dca/tl_page.php
index 3feabb985cc..d6c896e5157 100644
--- a/core-bundle/src/Resources/contao/dca/tl_page.php
+++ b/core-bundle/src/Resources/contao/dca/tl_page.php
@@ -180,8 +180,8 @@
'regular' => '{title_legend},title,alias,type;{meta_legend},pageTitle,robots,description,serpPreview;{protected_legend:hide},protected;{layout_legend:hide},includeLayout;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{expert_legend:hide},cssClass,sitemap,hide,noSearch,guests,requireItem;{tabnav_legend:hide},tabindex,accesskey;{publish_legend},published,start,stop',
'forward' => '{title_legend},title,alias,type;{meta_legend},pageTitle,robots;{redirect_legend},jumpTo,redirect;{protected_legend:hide},protected;{layout_legend:hide},includeLayout;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{expert_legend:hide},cssClass,sitemap,hide,guests;{tabnav_legend:hide},tabindex,accesskey;{publish_legend},published,start,stop',
'redirect' => '{title_legend},title,alias,type;{meta_legend},pageTitle,robots;{redirect_legend},redirect,url,target;{protected_legend:hide},protected;{layout_legend:hide},includeLayout;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{expert_legend:hide},cssClass,sitemap,hide,guests;{tabnav_legend:hide},tabindex,accesskey;{publish_legend},published,start,stop',
- 'root' => '{title_legend},title,alias,type;{meta_legend},pageTitle;{url_legend},dns,useSSL,urlPrefix,urlSuffix,validAliasCharacters,useFolderUrl;{language_legend},language,fallback,disableLanguageRedirect;{global_legend:hide},adminEmail,mailerTransport,dateFormat,timeFormat,datimFormat,staticFiles,staticPlugins;{protected_legend:hide},protected;{layout_legend},includeLayout;{twoFactor_legend:hide},enforceTwoFactor;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{publish_legend},published,start,stop',
- 'rootfallback' => '{title_legend},title,alias,type;{meta_legend},pageTitle;{url_legend},dns,useSSL,urlPrefix,urlSuffix,validAliasCharacters,useFolderUrl;{language_legend},language,fallback,disableLanguageRedirect;{website_legend:hide},favicon,robotsTxt;{global_legend:hide},adminEmail,mailerTransport,dateFormat,timeFormat,datimFormat,staticFiles,staticPlugins;{protected_legend:hide},protected;{layout_legend},includeLayout;{twoFactor_legend:hide},enforceTwoFactor;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{publish_legend},published,start,stop',
+ 'root' => '{title_legend},title,alias,type;{meta_legend},pageTitle,enableCanonical;{url_legend},dns,useSSL,urlPrefix,urlSuffix,validAliasCharacters,useFolderUrl;{language_legend},language,fallback,disableLanguageRedirect;{global_legend:hide},adminEmail,mailerTransport,dateFormat,timeFormat,datimFormat,staticFiles,staticPlugins;{protected_legend:hide},protected;{layout_legend},includeLayout;{twoFactor_legend:hide},enforceTwoFactor;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{publish_legend},published,start,stop',
+ 'rootfallback' => '{title_legend},title,alias,type;{meta_legend},pageTitle,enableCanonical;{url_legend},dns,useSSL,urlPrefix,urlSuffix,validAliasCharacters,useFolderUrl;{language_legend},language,fallback,disableLanguageRedirect;{website_legend:hide},favicon,robotsTxt;{global_legend:hide},adminEmail,mailerTransport,dateFormat,timeFormat,datimFormat,staticFiles,staticPlugins;{protected_legend:hide},protected;{layout_legend},includeLayout;{twoFactor_legend:hide},enforceTwoFactor;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{publish_legend},published,start,stop',
'logout' => '{title_legend},title,alias,type;{forward_legend},jumpTo,redirectBack;{protected_legend:hide},protected;{chmod_legend:hide},includeChmod;{expert_legend:hide},cssClass,sitemap,hide;{tabnav_legend:hide},tabindex,accesskey;{publish_legend},published,start,stop',
'error_401' => '{title_legend},title,alias,type;{meta_legend},pageTitle,robots,description;{forward_legend},autoforward;{layout_legend:hide},includeLayout;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{expert_legend:hide},cssClass;{publish_legend},published,start,stop',
'error_403' => '{title_legend},title,alias,type;{meta_legend},pageTitle,robots,description;{forward_legend},autoforward;{layout_legend:hide},includeLayout;{cache_legend:hide},includeCache;{chmod_legend:hide},includeChmod;{expert_legend:hide},cssClass;{publish_legend},published,start,stop',
@@ -253,6 +253,14 @@
'eval' => array('maxlength'=>255, 'tl_class'=>'w50'),
'sql' => "varchar(255) NOT NULL default ''"
),
+ 'enableCanonical' => array
+ (
+ 'exclude' => true,
+ 'inputType' => 'checkbox',
+ 'default' => true,
+ 'eval' => array('tl_class'=>'w50 m12'),
+ 'sql' => "char(1) NOT NULL default ''"
+ ),
'language' => array
(
'exclude' => true,
@@ -299,6 +307,21 @@ static function ($value)
'eval' => array('url_callback'=>array('tl_page', 'getSerpUrl'), 'title_tag_callback'=>array('tl_page', 'getTitleTag'), 'titleFields'=>array('pageTitle', 'title')),
'sql' => null
),
+ 'canonicalLink' => array
+ (
+ 'exclude' => true,
+ 'search' => true,
+ 'inputType' => 'text',
+ 'eval' => array('rgxp'=>'url', 'decodeEntities'=>true, 'maxlength'=>255, 'dcaPicker'=>true, 'tl_class'=>'w50'),
+ 'sql' => "varchar(255) NOT NULL default ''"
+ ),
+ 'canonicalKeepParams' => array
+ (
+ 'exclude' => true,
+ 'inputType' => 'text',
+ 'eval' => array('decodeEntities'=>true, 'maxlength'=>255, 'tl_class'=>'w50'),
+ 'sql' => "varchar(255) NOT NULL default ''"
+ ),
'redirect' => array
(
'exclude' => true,
diff --git a/core-bundle/src/Resources/contao/languages/en/tl_page.xlf b/core-bundle/src/Resources/contao/languages/en/tl_page.xlf
index 2928729e2c3..70feaa833df 100644
--- a/core-bundle/src/Resources/contao/languages/en/tl_page.xlf
+++ b/core-bundle/src/Resources/contao/languages/en/tl_page.xlf
@@ -26,6 +26,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core-bundle/src/Resources/contao/models/PageModel.php b/core-bundle/src/Resources/contao/models/PageModel.php
index cce68af136f..f529acdbe1b 100644
--- a/core-bundle/src/Resources/contao/models/PageModel.php
+++ b/core-bundle/src/Resources/contao/models/PageModel.php
@@ -84,6 +84,9 @@
* @property string|integer $stop
* @property string|boolean $enforceTwoFactor
* @property string|integer $twoFactorJumpTo
+ * @property string|integer $enableCanonical
+ * @property string $canonicalLink
+ * @property string $canonicalKeepParams
*
* @property array $trail
* @property string $mainAlias
@@ -172,6 +175,9 @@
* @method static PageModel|null findOneByStop($val, array $opt=array())
* @method static PageModel|null findOneByEnforceTwoFactor($val, array $opt=array())
* @method static PageModel|null findOneByTwoFactorJumpTo($val, array $opt=array())
+ * @method static PageModel|null findOneByEnableCanonical($val, array $opt=array())
+ * @method static PageModel|null findOneByCanonicalLink($val, array $opt=array())
+ * @method static PageModel|null findOneByCanonicalKeepParams($val, array $opt=array())
*
* @method static Collection|PageModel[]|PageModel|null findByPid($val, array $opt=array())
* @method static Collection|PageModel[]|PageModel|null findBySorting($val, array $opt=array())
@@ -228,6 +234,9 @@
* @method static Collection|PageModel[]|PageModel|null findByStop($val, array $opt=array())
* @method static Collection|PageModel[]|PageModel|null findByEnforceTwoFactor($val, array $opt=array())
* @method static Collection|PageModel[]|PageModel|null findByTwoFactorJumpTo($val, array $opt=array())
+ * @method static Collection|PageModel[]|PageModel|null findByEnableCanonical($val, array $opt=array())
+ * @method static Collection|PageModel[]|PageModel|null findByCanonicalLink($val, array $opt=array())
+ * @method static Collection|PageModel[]|PageModel|null findByCanonicalKeepParams($val, array $opt=array())
* @method static Collection|PageModel[]|PageModel|null findMultipleByIds($val, array $opt=array())
* @method static Collection|PageModel[]|PageModel|null findBy($col, $val, array $opt=array())
* @method static Collection|PageModel[]|PageModel|null findAll(array $opt=array())
@@ -288,6 +297,9 @@
* @method static integer countByStop($val, array $opt=array())
* @method static integer countByEnforceTwoFactor($val, array $opt=array())
* @method static integer countByTwoFactorJumpTo($val, array $opt=array())
+ * @method static integer countByEnableCanonical($val, array $opt=array())
+ * @method static integer countByCanonicalLink($val, array $opt=array())
+ * @method static integer countByCanonicalKeepParams($val, array $opt=array())
*
* @author Leo Feyer
*/
@@ -1157,6 +1169,7 @@ public function loadDetails()
$this->twoFactorJumpTo = $objParentPage->twoFactorJumpTo;
$this->useFolderUrl = $objParentPage->useFolderUrl;
$this->mailerTransport = $objParentPage->mailerTransport;
+ $this->enableCanonical = $objParentPage->enableCanonical;
$this->useAutoItem = Config::get('useAutoItem');
// Store whether the root page has been published