diff --git a/Classes/Controller/SingleViewController.php b/Classes/Controller/SingleViewController.php index 1031ef76ad11abda4607162f4a01c0b01ae3af30..620d479d58d34852b5efc4ee5934e06e6df5500e 100644 --- a/Classes/Controller/SingleViewController.php +++ b/Classes/Controller/SingleViewController.php @@ -1,7 +1,4 @@ <?php - -namespace SGalinski\SgNews\Controller; - /*************************************************************** * Copyright notice * @@ -26,15 +23,15 @@ namespace SGalinski\SgNews\Controller; * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +namespace SGalinski\SgNews\Controller; + use SGalinski\SgNews\Domain\Model\Category; use SGalinski\SgNews\Domain\Model\News; use SGalinski\SgNews\Domain\Repository\CategoryRepository; use SGalinski\SgNews\Domain\Repository\NewsRepository; use SGalinski\SgNews\Domain\Repository\TagRepository; use SGalinski\SgNews\Domain\Service\NewsService; -use SGalinski\SgNews\Service\HeaderMetaDataService; use TYPO3\CMS\Core\Charset\CharsetConverter; -use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; /** * Controller that handles the news single view page @@ -82,9 +79,9 @@ class SingleViewController extends AbstractController { '<' )) { return NULL; - } else { - return $this->htmlResponse(); } + + return $this->htmlResponse(); } /** @var Category $newsCategory */ @@ -96,9 +93,9 @@ class SingleViewController extends AbstractController { '<' )) { return NULL; - } else { - return $this->htmlResponse(); } + + return $this->htmlResponse(); } $newsMetaData = $this->newsService->getMetaDataForNews($news, $newsCategory); @@ -120,9 +117,9 @@ class SingleViewController extends AbstractController { ); if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) { return NULL; - } else { - return $this->htmlResponse(); } + + return $this->htmlResponse(); } /** diff --git a/Classes/Domain/Service/NewsService.php b/Classes/Domain/Service/NewsService.php index cf7a3dab15ed9706297c4e89a94e62c774775f3a..7795775e49aa699bc94cbea34805395cf3a21c21 100644 --- a/Classes/Domain/Service/NewsService.php +++ b/Classes/Domain/Service/NewsService.php @@ -1,7 +1,4 @@ <?php - -namespace SGalinski\SgNews\Domain\Service; - /*************************************************************** * Copyright notice * @@ -26,11 +23,16 @@ namespace SGalinski\SgNews\Domain\Service; * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +namespace SGalinski\SgNews\Domain\Service; + use SGalinski\SgNews\Domain\Model\Category; use SGalinski\SgNews\Domain\Model\News; use SGalinski\SgNews\Domain\Repository\NewsRepository; use TYPO3\CMS\Core\Resource\FileRepository; +use TYPO3\CMS\Core\Database\Connection; +use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\SingletonInterface; +use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Domain\Model\FileReference; @@ -75,6 +77,24 @@ class NewsService implements SingletonInterface { ]; } + // If sg_seo is loaded, add the jsonld schema data from the field if filled + $customSchemaJson = ''; + if (ExtensionManagementUtility::isLoaded('sg_seo')) { + $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) + ->getQueryBuilderForTable('pages'); + $schemaJson = $queryBuilder->select('tx_sgseo_schemajson') + ->from('pages') + ->where( + $queryBuilder->expr()->eq( + 'uid', + $queryBuilder->createNamedParameter($newsId, Connection::PARAM_INT) + ) + )->execute()->fetchOne(); + if (!empty($schemaJson)) { + $customSchemaJson = $schemaJson; + } + } + // Overwrite the number of likes with the one from the default news entry and add possible likes from translated // entries to fix broken data in older instances. $newsRepository = GeneralUtility::makeInstance(NewsRepository::class); @@ -88,7 +108,8 @@ class NewsService implements SingletonInterface { ], $singleNewsImageData, $teaserImageData, - ['media' => $fileObjects] + ['media' => $fileObjects], + ['customSchemaJson' => $customSchemaJson] ); $this->cachedSingleNews[$newsId] = $newsRecord; diff --git a/Configuration/TCA/Overrides/pages.php b/Configuration/TCA/Overrides/pages.php index dff98d1b411a8d02e42408be2006333c7bdafe95..17bf55d49966575eb4f39adf07c86a6e0a6592da 100644 --- a/Configuration/TCA/Overrides/pages.php +++ b/Configuration/TCA/Overrides/pages.php @@ -1,6 +1,5 @@ <?php -defined('TYPO3') or die(); /** * * Copyright notice @@ -26,6 +25,8 @@ defined('TYPO3') or die(); * This copyright notice MUST APPEAR in all copies of the script! */ +defined('TYPO3') or die(); + $localLangDbPath = 'LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:'; $localLangBackendPath = 'LLL:EXT:sg_news/Resources/Private/Language/locallang_backend.xlf:'; foreach ( @@ -65,6 +66,7 @@ $GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility:: tx_sgnews_content_from_another_page, tx_sgnews_related_news, tx_sgnews_tags, --div--;LLL:EXT:seo/Resources/Private/Language/locallang_tca.xlf:pages.tabs.seo, --palette--;;seo, + ' . (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('sg_seo') ? 'tx_sgseo_schemajson,' : '') . ' --palette--;;robots, --palette--;;canonical, --palette--;;sitemap, @@ -95,6 +97,7 @@ $GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility:: title, slug, tx_projectbase_path_segment, tx_projectbase_excludefromsluggeneration, tx_realurl_pathsegment, tx_realurl_exclude, --div--;LLL:EXT:seo/Resources/Private/Language/locallang_tca.xlf:pages.tabs.seo, --palette--;;seo, + ' . (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('sg_seo') ? 'tx_sgseo_schemajson,' : '') . ' --palette--;;robots, --palette--;;canonical, --palette--;;sitemap, diff --git a/Resources/Private/Partials/SingleViewSchema.html b/Resources/Private/Partials/SingleViewSchema.html index 55435e60903409e4e6ad192288e210e5be8318c1..55400386cd0acc24809842dd8b687c1e57e4303d 100644 --- a/Resources/Private/Partials/SingleViewSchema.html +++ b/Resources/Private/Partials/SingleViewSchema.html @@ -1,29 +1,40 @@ <f:alias map="{leftBrace: '{', rightBrace: '}'}"> - <script type="application/ld+json"> - {leftBrace} - "@context": "http://schema.org/", - "@type": "NewsArticle", - "mainEntityOfPage": {leftBrace} - "@type": "WebPage", - "@id": "<f:uri.page absolute="TRUE"/>" - {rightBrace}, - "author": "{newsMetaData.news.author}", - "publisher": {leftBrace} - "@type": "Organization"{f:if(condition: settings.publisher, then:',')} - <f:if condition="{settings.publisher}">"name": "{settings.publisher}"{f:if(condition: settings.publisherLogo, then:',')}</f:if> - <f:if condition="{settings.publisherLogo}">"logo": {leftBrace} - "@type": "ImageObject", - "url": "{settings.publisherLogo}" - {rightBrace}</f:if> - {rightBrace}, - <f:if condition="{newsMetaData.imageObject}"> - "image": "<f:uri.image absolute="TRUE" image="{newsMetaData.imageObject}" />", - </f:if> - "headline": "{newsMetaData.news.navTitle}", - "description": "{newsMetaData.news.description}", - "dateCreated": "<f:format.date format="Y-m-d">{newsMetaData.news.creationDate}</f:format.date>", - "datePublished": "<f:format.date format="Y-m-d">{newsMetaData.news.creationDate}</f:format.date>", - "dateModified": "<f:format.date format="Y-m-d">{newsMetaData.news.lastUpdated}</f:format.date>" - {rightBrace} - </script> + <script type="application/ld+json"> + {leftBrace} + <f:if condition="{newsMetaData.customSchemaJson}"> + <f:then> + <f:format.raw>{newsMetaData.customSchemaJson}</f:format.raw> + </f:then> + <f:else> + <f:render section="default" arguments="{_all}"/> + </f:else> + </f:if> + {rightBrace} + </script> </f:alias> + +<f:section name="default"> +"@context": "http://schema.org/", +"@type": "NewsArticle", +"mainEntityOfPage": {leftBrace} + "@type": "WebPage", + "@id": "<f:uri.page absolute="TRUE"/>" +{rightBrace}, +"author": "{newsMetaData.news.author}", +"publisher": {leftBrace} + "@type": "Organization"{f:if(condition: settings.publisher, then:',')} + <f:if condition="{settings.publisher}">"name": "{settings.publisher}"{f:if(condition: settings.publisherLogo, then:',')}</f:if> + <f:if condition="{settings.publisherLogo}">"logo": {leftBrace} + "@type": "ImageObject", + "url": "{settings.publisherLogo}" + {rightBrace}</f:if> +{rightBrace}, +<f:if condition="{newsMetaData.imageObject}"> +"image": "<f:uri.image absolute="TRUE" image="{newsMetaData.imageObject}" />", +</f:if> +"headline": "{newsMetaData.news.navTitle}", +"description": "{newsMetaData.news.description}", +"dateCreated": "<f:format.date format="Y-m-d">{newsMetaData.news.creationDate}</f:format.date>", +"datePublished": "<f:format.date format="Y-m-d">{newsMetaData.news.creationDate}</f:format.date>", +"dateModified": "<f:format.date format="Y-m-d">{newsMetaData.news.lastUpdated}</f:format.date>" +</f:section> diff --git a/composer.json b/composer.json index 25c141d75d326b566b45a2707dde23b6117bb112..cad7b3871a48bcdf53e5ef71725772a07551d1b9 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,8 @@ }, "suggest": { "sgalinski/sg-ajax": "Required for the like feature", - "sgalinski/sg-comments": "Flexible comments system" + "sgalinski/sg-comments": "Flexible comments system", + "sgalinski/sg-seo": "For additional SEO features" }, "replace": { "sgalinski/sg_news": "self.version" diff --git a/ext_emconf.php b/ext_emconf.php index a308df0b4ffa888798204ff397a1ad47b5840ae7..52eec3deb14d202fea7fbb2be7a3a7b57306483e 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -28,7 +28,8 @@ $EM_CONF['sg_news'] = [ 'conflicts' => [], 'suggests' => [ 'sg_comments' => '6.0.0', - 'sg_ajax' => '4.0.0' + 'sg_ajax' => '4.0.0', + 'sg_seo' => '' ], ], 'suggests' => [],