diff --git a/Classes/Command/MigrateNewsCommandController.php b/Classes/Command/MigrateNewsCommandController.php
index 2947e61e87e60cb7755040c7e6ceb404f2e5ecb0..770eba208348d42ab5a9966c891a6f9bc1c512dc 100644
--- a/Classes/Command/MigrateNewsCommandController.php
+++ b/Classes/Command/MigrateNewsCommandController.php
@@ -29,6 +29,7 @@ namespace SGalinski\SgNews\Command;
 use SGalinski\SgNews\Domain\Model\News;
 use SGalinski\SgNews\Domain\Repository\FileReferenceRepository;
 use SGalinski\SgNews\Domain\Repository\NewsRepository;
+use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputArgument;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
@@ -41,7 +42,6 @@ use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Resource\FileInterface;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use Symfony\Component\Console\Command\Command;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 use TYPO3\CMS\Extbase\Persistence\Exception\IllegalObjectTypeException;
 use TYPO3\CMS\Extbase\Persistence\Exception\UnknownObjectException;
@@ -77,12 +77,15 @@ class MigrateNewsCommandController extends Command {
 			->addArgument('categoryPid', InputArgument::REQUIRED, 'The page id of the category page')
 			->addArgument('year', InputArgument::OPTIONAL, 'Only news from that year will be migrated', 2015)
 			->addArgument(
-				'languageMapAsJson', InputArgument::OPTIONAL,
+				'languageMapAsJson',
+				InputArgument::OPTIONAL,
 				'A json, mapping language ids (old => new). this is needed if the sys_language_uids have changed',
 				'{"3":1,"1":0,"2":2,"0":3}'
 			)
 			->addArgument(
-				'categoryMapAsJson', InputArgument::OPTIONAL, 'A json, mapping sys_category ids (old => new).',
+				'categoryMapAsJson',
+				InputArgument::OPTIONAL,
+				'A json, mapping sys_category ids (old => new).',
 				'{"2":17,"3":16,"4":15,"5":14,"6":14,"7":15,"8":16,"9":17}'
 			)
 			->addArgument('pId', InputArgument::OPTIONAL, 'Only news from that pid will be migrated', 52);
@@ -93,7 +96,7 @@ class MigrateNewsCommandController extends Command {
 	 *
 	 * @param InputInterface $input
 	 * @param OutputInterface $output
-	 * @return void
+	 * @return int
 	 * @throws \JsonException
 	 */
 	public function execute(InputInterface $input, OutputInterface $output) {
@@ -121,7 +124,7 @@ class MigrateNewsCommandController extends Command {
 			->where(
 				$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pId, Connection::PARAM_INT))
 			)
-			->execute()->fetchAll();
+			->execute()->fetchAllAssociative();
 		$localDataHandler = GeneralUtility::makeInstance(DataHandler::class);
 		Bootstrap::initializeBackendAuthentication();
 		$localCommandMap = [
@@ -163,20 +166,26 @@ class MigrateNewsCommandController extends Command {
 					$newsPage->setLastUpdated($date);
 					$this->setMatchingTag($row);
 
-					/** @var File $image */
+					/** @var File $file */
 					$file = $this->getMatchingFile($row);
 					if ($file instanceof File) {
 						$teaserImage1 = $fileReferenceRepository->addFileReferenceFromFile(
-							$file, $this->newsPagesMap[$row['uid']],
-							$this->newsPagesMap[$row['uid']], 'pages', 'tx_sgnews_teaser1_image'
+							$file,
+							$this->newsPagesMap[$row['uid']],
+							$this->newsPagesMap[$row['uid']],
+							'pages',
+							'tx_sgnews_teaser1_image'
 						);
 
 						if ($teaserImage1) {
 							$newsPage->addTeaser1Image($teaserImage1);
 
 							$teaserImage2 = $fileReferenceRepository->addFileReferenceFromFile(
-								$file, $this->newsPagesMap[$row['uid']],
-								$this->newsPagesMap[$row['uid']], 'pages', 'tx_sgnews_teaser2_image'
+								$file,
+								$this->newsPagesMap[$row['uid']],
+								$this->newsPagesMap[$row['uid']],
+								'pages',
+								'tx_sgnews_teaser2_image'
 							);
 							$newsPage->addTeaser2Image($teaserImage2);
 						}
@@ -194,12 +203,15 @@ class MigrateNewsCommandController extends Command {
 						->where(
 							$queryBuilder->expr()->andX(
 								$queryBuilder->expr()->eq(
-									'pid', $queryBuilder->createNamedParameter($newPageId, Connection::PARAM_INT)
+									'pid',
+									$queryBuilder->createNamedParameter($newPageId, Connection::PARAM_INT)
 								),
 								$queryBuilder->expr()->eq(
-									'sys_language_uid', $queryBuilder->createNamedParameter(
-									$this->languageMap[(int) $row['sys_language_uid']], \PDO::PARAM_INT
-								)
+									'sys_language_uid',
+									$queryBuilder->createNamedParameter(
+										$this->languageMap[(int) $row['sys_language_uid']],
+										\PDO::PARAM_INT
+									)
 								)
 							)
 						)
@@ -210,6 +222,7 @@ class MigrateNewsCommandController extends Command {
 				$this->updateTranslation($row);
 			}
 		}
+		return Command::SUCCESS;
 	}
 
 	/**
@@ -230,15 +243,17 @@ class MigrateNewsCommandController extends Command {
 			->where(
 				$queryBuilder->expr()->andX(
 					$queryBuilder->expr()->eq(
-						'tablenames', $queryBuilder->createNamedParameter('tx_news_domain_model_news')
+						'tablenames',
+						$queryBuilder->createNamedParameter('tx_news_domain_model_news')
 					),
 					$queryBuilder->expr()->eq('fieldname', $queryBuilder->createNamedParameter('fal_media')),
 					$queryBuilder->expr()->eq(
-						'uid_foreign', $queryBuilder->createNamedParameter($row['uid'], Connection::PARAM_INT)
+						'uid_foreign',
+						$queryBuilder->createNamedParameter($row['uid'], Connection::PARAM_INT)
 					)
 				)
 			)
-			->execute()->fetch();
+			->execute()->fetchAssociative();
 		if (!$fileReferenceResult) {
 			return NULL;
 		}
@@ -251,10 +266,11 @@ class MigrateNewsCommandController extends Command {
 			->from('sys_file_news_migration')
 			->where(
 				$queryBuilder->expr()->eq(
-					'uid', $queryBuilder->createNamedParameter($fileReferenceResult['uid_local'], Connection::PARAM_INT)
+					'uid',
+					$queryBuilder->createNamedParameter($fileReferenceResult['uid_local'], Connection::PARAM_INT)
 				)
 			)
-			->execute()->fetch();
+			->execute()->fetchAssociative();
 		if (!$fileResult) {
 			return NULL;
 		}
@@ -283,10 +299,11 @@ class MigrateNewsCommandController extends Command {
 			->from('sys_category_record_mm_news_migration')
 			->where(
 				$queryBuilder->expr()->eq(
-					'uid_foreign', $queryBuilder->createNamedParameter($row['uid'], Connection::PARAM_INT)
+					'uid_foreign',
+					$queryBuilder->createNamedParameter($row['uid'], Connection::PARAM_INT)
 				)
 			)
-			->execute()->fetchAll();
+			->execute()->fetchAllAssociative();
 		foreach ($mmRows as $mmRow) {
 			$values = [
 				'uid_local' => $this->categoryMap[(int) $mmRow['uid_local']],
@@ -322,7 +339,8 @@ class MigrateNewsCommandController extends Command {
 		if ((int) $this->languageMap[(int) $row['sys_language_uid'] === 0]) {
 			$queryBuilder->where(
 				$queryBuilder->expr()->eq(
-					'uid', $queryBuilder->createNamedParameter($originalContentElement[0], Connection::PARAM_INT)
+					'uid',
+					$queryBuilder->createNamedParameter($originalContentElement[0], Connection::PARAM_INT)
 				)
 			);
 		} else {
@@ -338,9 +356,11 @@ class MigrateNewsCommandController extends Command {
 		if (isset($this->languageMap[(int) $row['sys_language_uid']])) {
 			$queryBuilder->andWhere(
 				$queryBuilder->expr()->eq(
-					'sys_language_uid', $queryBuilder->createNamedParameter(
-					$this->languageMap[(int) $row['sys_language_uid']], Connection::PARAM_INT
-				)
+					'sys_language_uid',
+					$queryBuilder->createNamedParameter(
+						$this->languageMap[(int) $row['sys_language_uid']],
+						Connection::PARAM_INT
+					)
 				)
 			);
 		} else {
@@ -362,10 +382,11 @@ class MigrateNewsCommandController extends Command {
 				->from('pages')
 				->where(
 					$queryBuilder->expr()->eq(
-						'uid', $queryBuilder->createNamedParameter($parentId, Connection::PARAM_INT)
+						'uid',
+						$queryBuilder->createNamedParameter($parentId, Connection::PARAM_INT)
 					)
 				)
-				->execute()->fetch();
+				->execute()->fetchAssociative();
 			if ($result) {
 				$queryBuilder->where(
 					$queryBuilder->expr()->eq(
@@ -390,7 +411,8 @@ class MigrateNewsCommandController extends Command {
 			$queryBuilder->update('pages')
 				->where(
 					$queryBuilder->expr()->eq(
-						'uid', $queryBuilder->createNamedParameter($parentId, Connection::PARAM_INT)
+						'uid',
+						$queryBuilder->createNamedParameter($parentId, Connection::PARAM_INT)
 					)
 				)
 				->set('title', $newTitle, TRUE)
@@ -402,7 +424,8 @@ class MigrateNewsCommandController extends Command {
 			$queryBuilder->update('pages')
 				->where(
 					$queryBuilder->expr()->eq(
-						'l10n_parent', $queryBuilder->createNamedParameter($parentId, Connection::PARAM_INT)
+						'l10n_parent',
+						$queryBuilder->createNamedParameter($parentId, Connection::PARAM_INT)
 					)
 				);
 
@@ -412,9 +435,11 @@ class MigrateNewsCommandController extends Command {
 			) {
 				$queryBuilder->andWhere(
 					$queryBuilder->expr()->eq(
-						'sys_language_uid', $queryBuilder->createNamedParameter(
-						$this->languageMap[(int) $row['sys_language_uid']], Connection::PARAM_INT
-					)
+						'sys_language_uid',
+						$queryBuilder->createNamedParameter(
+							$this->languageMap[(int) $row['sys_language_uid']],
+							Connection::PARAM_INT
+						)
 					)
 				);
 			} else {
diff --git a/Classes/Controller/AbstractController.php b/Classes/Controller/AbstractController.php
index d7fc77278262b39e3bdffa00738268ea33e73c24..92a944cd75129a345e6e9ae3f341d7dfdb015c65 100644
--- a/Classes/Controller/AbstractController.php
+++ b/Classes/Controller/AbstractController.php
@@ -57,7 +57,7 @@ abstract class AbstractController extends ActionController {
 	 * @throws \RuntimeException
 	 */
 	public function errorAction() {
-		throw new RuntimeException(parent::errorAction());
+		throw new RuntimeException($this->getFlattenedValidationErrorMessage());
 	}
 
 	/**
@@ -75,4 +75,15 @@ abstract class AbstractController extends ActionController {
 		}
 		return $offset;
 	}
+
+	/**
+	 * Build Typo3 11 Response
+	 * @param string|NULL $html
+	 * @return \Psr\Http\Message\ResponseInterface
+	 */
+	protected function htmlResponse(string $html = NULL): \Psr\Http\Message\ResponseInterface {
+		return $this->responseFactory->createResponse()
+			->withHeader('Content-Type', 'text/html; charset=utf-8')
+			->withBody($this->streamFactory->createStream($html ?? $this->view->render()));
+	}
 }
diff --git a/Classes/Controller/Ajax/LikeController.php b/Classes/Controller/Ajax/LikeController.php
index d2060167e9b959e03bcbc53d1c55a4e3920b3682..647da0d78b5e366d8a2b12e3df8f032f3f41507e 100644
--- a/Classes/Controller/Ajax/LikeController.php
+++ b/Classes/Controller/Ajax/LikeController.php
@@ -36,7 +36,6 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * @package SGalinski\SgNews\Controller\Ajax
  */
 class LikeController extends AbstractAjaxController {
-
 	/**
 	 * This action increases the tx_sgnews_likes field of a given page ($newsPid) by one
 	 *
@@ -57,9 +56,9 @@ class LikeController extends AbstractAjaxController {
 				)
 				->execute();
 		} catch (\Exception $exception) {
-			$this->returnData(['success' => false]);
+			$this->returnData(['success' => FALSE]);
 		}
 
-		$this->returnData(['success' => true]);
+		$this->returnData(['success' => TRUE]);
 	}
 }
diff --git a/Classes/Controller/BackendController.php b/Classes/Controller/BackendController.php
index 3db08d161509b3d0b0b21df28311baa094ad2bb1..fe347a840d22c01c271fae6b27c483fecca02f8a 100644
--- a/Classes/Controller/BackendController.php
+++ b/Classes/Controller/BackendController.php
@@ -26,14 +26,17 @@ namespace SGalinski\SgNews\Controller;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
+use SGalinski\SgNews\Paginator\QueryBuilderPaginator;
 use SGalinski\SgNews\Utility\BackendNewsUtility;
 use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\Components\DocHeaderComponent;
+use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
+use TYPO3\CMS\Core\Pagination\SimplePagination;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
@@ -43,7 +46,6 @@ use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
  * News Controller
  */
 class BackendController extends ActionController {
-
 	/**
 	 * The uid of the current page
 	 *
@@ -79,6 +81,12 @@ class BackendController extends ActionController {
 	 */
 	private $docHeaderComponent;
 
+
+	/**
+	 * @var ?ModuleTemplate
+	 */
+	protected $moduleTemplate = NULL;
+
 	/**
 	 * Initializes the view before invoking an action method.
 	 *
@@ -100,7 +108,11 @@ class BackendController extends ActionController {
 		$backendUser = $GLOBALS['BE_USER'];
 		$this->pageInfo = BackendUtility::readPageAccess($this->pageUid, $backendUser->getPagePermsClause(1));
 		if ($this->pageInfo) {
-			$this->docHeaderComponent = GeneralUtility::makeInstance(DocHeaderComponent::class);
+			if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+				$this->docHeaderComponent = GeneralUtility::makeInstance(DocHeaderComponent::class);
+			} else {
+				$this->getDocHeaderComponent();
+			}
 			if ($this->pageUid) {
 				$this->rootPageUid = BackendNewsUtility::getRootUidByPageUid($this->pageUid);
 			}
@@ -114,7 +126,8 @@ class BackendController extends ActionController {
 			}
 
 			$this->language = $backendUser->getModuleData(
-				'tools_beuser/index.php/web_SgNewsNews_language', 'ses'
+				'tools_beuser/index.php/web_SgNewsNews_language',
+				'ses'
 			) ?: 0;
 			$languageOptions = BackendNewsUtility::getAvailableLanguages($this->pageUid);
 			$currentLanguageInfo = $languageOptions[$this->language] ?? NULL;
@@ -131,16 +144,15 @@ class BackendController extends ActionController {
 	}
 
 	/**
-	 * @param array $filters
-	 * @throws \InvalidArgumentException
-	 * @throws \UnexpectedValueException
+	 * @param array|null $filters
+	 * @return \Psr\Http\Message\ResponseInterface|null
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
-	public function indexAction(array $filters = NULL) {
+	public function indexAction(array $filters = NULL): ?\Psr\Http\Message\ResponseInterface {
 		$showNewsList = FALSE;
 		if (
 			($this->pageUid && $this->pageUid === $this->rootPageUid) ||
-			(int) $this->pageInfo['doktype'] === BackendNewsUtility::CATEGORY_DOKTYPE
+			(isset($this->pageInfo['doktype']) && (int) $this->pageInfo['doktype'] === BackendNewsUtility::CATEGORY_DOKTYPE)
 		) {
 			/** @var BackendUserAuthentication $backendUser */
 			$backendUser = $GLOBALS['BE_USER'];
@@ -157,7 +169,13 @@ class BackendController extends ActionController {
 				$filters['categories'] = [$this->pageUid];
 			}
 			$tags = BackendNewsUtility::getTagsForPage($this->pageUid, $this->language);
-			$news = BackendNewsUtility::getNewsByFilters($this->rootPageUid, $filters, $this->language);
+			[$news, $newsQueryBuilder] = BackendNewsUtility::getNewsByFilters($this->rootPageUid, $filters, $this->language);
+
+			$paginator = new QueryBuilderPaginator($newsQueryBuilder);
+			$pagination = new SimplePagination($paginator);
+
+			$this->view->assign('paginator', $paginator);
+			$this->view->assign('pagination', $pagination);
 
 			$this->view->assign('tags', $tags);
 			$this->view->assign('news', $news);
@@ -168,6 +186,14 @@ class BackendController extends ActionController {
 			$this->view->assign('alternativePageOptions', $alternativePageOptions);
 		}
 		$this->view->assign('showNewsList', $showNewsList);
+
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			$this->view->assign('V11', FALSE);
+			return NULL;
+		} else {
+			$this->view->assign('V11', TRUE);
+			return $this->createBackendResponse();
+		}
 	}
 
 	/**
@@ -226,7 +252,8 @@ class BackendController extends ActionController {
 				->setTitle($language['title'])
 				->setHref(
 					$uriBuilder->buildUriFromRoute(
-						'web_SgNewsNews', ['id' => $this->pageUid, 'SET' => ['language' => $key]]
+						'web_SgNewsNews',
+						['id' => $this->pageUid, 'SET' => ['language' => $key]]
 					)
 				);
 			if ((int) $this->language === (int) $key) {
@@ -236,4 +263,39 @@ class BackendController extends ActionController {
 		}
 		$this->docHeaderComponent->getMenuRegistry()->addMenu($languageMenu);
 	}
+
+
+	/**
+	 * Use the ModuleTemplateResponse to create a response object for the backend
+	 *
+	 * @return  \Psr\Http\Message\ResponseInterface
+	 */
+	protected function createBackendResponse(): \Psr\Http\Message\ResponseInterface {
+		$this->getModuleTemplate();
+		$this->moduleTemplate->setContent($this->view->render());
+		return $this->htmlResponse($this->moduleTemplate->renderContent());
+	}
+
+	/**
+	 * Since we cannot use constructer Injection, we do have to get one Dynamicly. If we want to use
+	 * our ModuleTemplate, call GetModuleTemplate before, which will init one if there is none for some reason
+	 */
+	protected function getModuleTemplate() {
+		if ($this->moduleTemplate === NULL) {
+			$moduleTemplateFactory = GeneralUtility::makeInstance(
+				\TYPO3\CMS\Backend\Template\ModuleTemplateFactory::class
+			);
+			$this->moduleTemplate = $moduleTemplateFactory->create($this->request);
+		}
+	}
+
+	/**
+	 * Other Helper function, which gets us just the DocHeaderComponent
+	 */
+	protected function getDocHeaderComponent() {
+		if ($this->moduleTemplate === NULL) {
+			$this->getModuleTemplate();
+		}
+		$this->docHeaderComponent = $this->moduleTemplate->getDocHeaderComponent();
+	}
 }
diff --git a/Classes/Controller/LatestController.php b/Classes/Controller/LatestController.php
index e5eb3ea0cdeaa830bdf41fca500797a9a4bf9e68..d6b07cc6727ea7061fac078a92a0404360b20bfd 100644
--- a/Classes/Controller/LatestController.php
+++ b/Classes/Controller/LatestController.php
@@ -64,36 +64,64 @@ class LatestController extends AbstractController {
 	 *
 	 * @param array $newsMetaData
 	 * @param int $offset
-	 * @return void
+	 * @return null|\Psr\Http\Message\ResponseInterface
 	 * @throws \InvalidArgumentException
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
 	 */
-	public function indexAction(array $newsMetaData = [], $offset = 0) {
-		$limit = ((int) $this->settings['limit']);
+	public function indexAction(array $newsMetaData = [], $offset = 0): ?\Psr\Http\Message\ResponseInterface {
+		$limit = 0;
+		if (isset($this->settings['limit'])) {
+			$limit = ((int) $this->settings['limit']);
+		}
 		$limit = ($limit < 1 ? 1 : $limit);
 
 		$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
 		$sortBy = $configurationService->getConfiguration('sortBy', $this->settings);
 
-		$categoryUids = GeneralUtility::intExplode(',', $this->settings['categories'], TRUE);
-		$tagUids = GeneralUtility::intExplode(',', $this->settings['tags'], TRUE);
+		$categoryUids = [];
+		$tagUids = [];
+		if (isset($this->settings['categories'])) {
+			$categoryUids = GeneralUtility::intExplode(',', $this->settings['categories'], TRUE);
+		}
+		if (isset($this->settings['tags'])) {
+			$tagUids = GeneralUtility::intExplode(',', $this->settings['tags'], TRUE);
+		}
 		if ((int) $GLOBALS['TSFE']->page['doktype'] === 117 && !count($categoryUids)) {
 			$categoryUids = [$GLOBALS['TSFE']->id];
 		}
 
-		$startTime = (int) $this->settings['starttime'];
-		$endTime = (int) $this->settings['endtime'];
+		$startTime = 0;
+		$endTime = 0;
+		if (isset($this->settings['starttime'])) {
+			$startTime = (int) $this->settings['starttime'];
+		}
+		if (isset($this->settings['endtime'])) {
+			$endTime = (int) $this->settings['endtime'];
+		}
 		$latestNewsEntries = $this->newsRepository->findLastUpdatedOrHighlightedNewsByCategories(
-			$limit, FALSE, $categoryUids, $offset, TRUE, $sortBy, $tagUids, $startTime, $endTime
+			$limit,
+			FALSE,
+			$categoryUids,
+			$offset,
+			TRUE,
+			$sortBy,
+			$tagUids,
+			$startTime,
+			$endTime
 		);
 
 		$categories = [];
+		$category = NULL;
 		foreach ($latestNewsEntries as $latestNewsEntry) {
 			/** @var News $latestNewsEntry */
 			/** @var Category $category */
 			$categoryUid = $latestNewsEntry->getPid();
-			$category = $categories[$categoryUid];
+
+			if (isset($categories[$categoryUid])) {
+				$category = $categories[$categoryUid];
+			}
+
 			if (!$category) {
 				$category = $this->categoryRepository->findByUid($categoryUid);
 				if (!$category) {
@@ -110,12 +138,18 @@ class LatestController extends AbstractController {
 		}
 
 		$this->view->assign('newsMetaData', $newsMetaData);
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			return NULL;
+		} else {
+			return $this->htmlResponse();
+		}
 	}
 
 	/**
 	 * @param CategoryRepository $categoryRepository
 	 */
-	public function injectCategoryRepository(CategoryRepository $categoryRepository
+	public function injectCategoryRepository(
+		CategoryRepository $categoryRepository
 	) {
 		$this->categoryRepository = $categoryRepository;
 	}
diff --git a/Classes/Controller/ListByCategoryController.php b/Classes/Controller/ListByCategoryController.php
index d4547f514ed26d96f9b0e05c707065975d3db6b4..5dfd1abbc86c4bb0e84e167487a82cb246ea21f8 100644
--- a/Classes/Controller/ListByCategoryController.php
+++ b/Classes/Controller/ListByCategoryController.php
@@ -33,8 +33,8 @@ use SGalinski\SgNews\Domain\Repository\TagRepository;
 use SGalinski\SgNews\Domain\Service\NewsService;
 use SGalinski\SgNews\Service\ConfigurationService;
 use SGalinski\SgNews\Service\HeaderMetaDataService;
-use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Http\ImmediateResponseException;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Frontend\Controller\ErrorController;
 use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
@@ -66,7 +66,8 @@ class ListByCategoryController extends AbstractController {
 	/**
 	 * @param CategoryRepository $categoryRepository
 	 */
-	public function injectCategoryRepository(CategoryRepository $categoryRepository
+	public function injectCategoryRepository(
+		CategoryRepository $categoryRepository
 	) {
 		$this->categoryRepository = $categoryRepository;
 	}
@@ -98,7 +99,9 @@ class ListByCategoryController extends AbstractController {
 	 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
 	 */
 	public function initializeIndexAction() {
-		$currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage'];
+		$currentPageBrowserPage = GeneralUtility::_GP('tx_sgnews_pagebrowser')
+			? (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage']
+			: 0;
 		if ($currentPageBrowserPage > 0) {
 			$this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage);
 		}
@@ -109,17 +112,23 @@ class ListByCategoryController extends AbstractController {
 	 *
 	 * @param array $newsMetaData
 	 * @param int $currentPageBrowserPage
-	 * @return void
+	 * @return null|\Psr\Http\Message\ResponseInterface
 	 * @throws \InvalidArgumentException
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
 	 * @throws ImmediateResponseException
 	 * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException
 	 */
-	public function indexAction(array $newsMetaData = [], int $currentPageBrowserPage = 0) {
+	public function indexAction(array $newsMetaData = [], int $currentPageBrowserPage = 0): ?\Psr\Http\Message\ResponseInterface {
 		$filterByCategories = FALSE;
-		$categoryUids = GeneralUtility::intExplode(',', $this->settings['categories']);
-		$tagUids = GeneralUtility::intExplode(',', $this->settings['tags'], TRUE);
+		$categoryUids = [];
+		$tagUids = [];
+		if (isset($this->settings['categories'])) {
+			$categoryUids = GeneralUtility::intExplode(',', $this->settings['categories'], TRUE);
+		}
+		if (isset($this->settings['tags'])) {
+			$tagUids = GeneralUtility::intExplode(',', $this->settings['tags'], TRUE);
+		}
 
 		HeaderMetaDataService::addPageNumberToCanonical($currentPageBrowserPage);
 
@@ -150,8 +159,14 @@ class ListByCategoryController extends AbstractController {
 			}
 		}
 
-		$startTime = (int) $this->settings['starttime'];
-		$endTime = (int) $this->settings['endtime'];
+		$startTime = 0;
+		$endTime = 0;
+		if (isset($this->settings['starttime'])) {
+			$startTime = (int) $this->settings['starttime'];
+		}
+		if (isset($this->settings['endtime'])) {
+			$endTime = (int) $this->settings['endtime'];
+		}
 		$newsPerPage = (int) $this->settings['newsLimitPerPage'];
 
 		$newsCount = $this->newsRepository->newsCountByCategories($categoryUids, $tagUids, $startTime, $endTime);
@@ -175,29 +190,30 @@ class ListByCategoryController extends AbstractController {
 		$sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings);
 
 		$news = $this->newsRepository->findAllSortedNewsByCategories(
-			$categoryUids, $newsPerPage, $offset, $sortBy, $tagUids, $startTime, $endTime, $sortDirection
+			$categoryUids,
+			$newsPerPage,
+			$offset,
+			$sortBy,
+			$tagUids,
+			$startTime,
+			$endTime,
+			$sortDirection
 		)->toArray();
 
 		foreach ($news as $newsEntry) {
 			/** @var News $newsEntry */
 			$data = $this->newsService->getMetaDataForNews($newsEntry, $categories[$newsEntry->getPid()]);
 			$newsMetaData[] = $data;
-
-			if (!$headerSet) {
-				if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-					if ($data['image']) {
-						HeaderMetaDataService::addOgImageToHeader($data['image']);
-						$headerSet = TRUE;
-					} elseif ($data['teaserImage']) {
-						HeaderMetaDataService::addOgImageToHeader($data['teaserImage']);
-						$headerSet = TRUE;
-					}
-				}
-			}
 		}
 
 		$this->view->assign('numberOfPages', $numberOfPages);
 		$this->view->assign('newsMetaData', $newsMetaData);
 		$this->view->assign('categories', $categories);
+
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			return NULL;
+		} else {
+			return $this->htmlResponse();
+		}
 	}
 }
diff --git a/Classes/Controller/NewsByAuthorController.php b/Classes/Controller/NewsByAuthorController.php
index 217140fc9f465753eee084f7699e37f1d5186e67..1f3db1393ddf42ea209cddfe93c4f85ae27fb094 100644
--- a/Classes/Controller/NewsByAuthorController.php
+++ b/Classes/Controller/NewsByAuthorController.php
@@ -57,18 +57,22 @@ class NewsByAuthorController extends AbstractController {
 	 * Renders the news author list.
 	 *
 	 * @param int $authorId
-	 * @return void
+	 * @return null|\Psr\Http\Message\ResponseInterface
 	 * @throws \InvalidArgumentException
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 * @throws \TYPO3\CMS\Core\Package\Exception
 	 */
-	public function listAction($authorId = 0): void {
+	public function listAction($authorId = 0): ?\Psr\Http\Message\ResponseInterface {
 		if ($authorId) {
 			$newsAuthorsIds[] = $authorId;
 		} else {
 			$newsAuthorsIds = GeneralUtility::intExplode(',', $this->settings['newsAuthors']);
 			if (\count($newsAuthorsIds) <= 0) {
-				return;
+				if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+					return NULL;
+				} else {
+					return $this->htmlResponse();
+				}
 			}
 		}
 
@@ -81,33 +85,34 @@ class NewsByAuthorController extends AbstractController {
 				continue;
 			}
 
-			if (version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-				$headTagService = GeneralUtility::makeInstance(
-					HeadTagService::class,
-					TRUE,
-					$author->getName(),
-					$author->getDescription(),
-					'&tx_sgnews_newsbyauthor[authorId]=' . $author->getUid()
-				);
-				$headTagService->execute();
-			} else {
-				$GLOBALS['TSFE']->page['titlebyextension'] = $author->getName();
-				$GLOBALS['TSFE']->page['description'] = \strip_tags(\substr($author->getDescription(), 0, 200));
-				$GLOBALS['TSFE']->page['extensionArgumentsForCanonicalAndHrefLang'] =
-					'&tx_sgnews_newsbyauthor[authorId]=' . $author->getUid();
-			}
+			$headTagService = GeneralUtility::makeInstance(
+				HeadTagService::class,
+				TRUE,
+				$author->getName(),
+				$author->getDescription(),
+				'&tx_sgnews_newsbyauthor[authorId]=' . $author->getUid()
+			);
+			$headTagService->execute();
 
 			$authors[] = $author;
 		}
 
 		if (\count($authors) <= 0) {
-			return;
+			if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+				return NULL;
+			} else {
+				return $this->htmlResponse();
+			}
 		}
 
 		$newsRepository = $this->objectManager->get(NewsRepository::class);
 		$news = $newsRepository->findAllByNewsAuthor($newsAuthorsIds);
 		if (\count($news) <= 0) {
-			return;
+			if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+				return NULL;
+			} else {
+				return $this->htmlResponse();
+			}
 		}
 
 		$categories = $newsMetaData = [];
@@ -137,5 +142,11 @@ class NewsByAuthorController extends AbstractController {
 
 		$this->view->assign('newsMetaData', $newsMetaData);
 		$this->view->assign('authors', $authors);
+
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			return NULL;
+		} else {
+			return $this->htmlResponse();
+		}
 	}
 }
diff --git a/Classes/Controller/NewsFeedController.php b/Classes/Controller/NewsFeedController.php
index c734588689d49f6ee26cb92193a0e8238d65cf83..c986f508423e839097f9e2bbd55a96eac5c3afb7 100644
--- a/Classes/Controller/NewsFeedController.php
+++ b/Classes/Controller/NewsFeedController.php
@@ -43,16 +43,24 @@ class NewsFeedController extends AbstractController {
 	/**
 	 * Renders the news feed
 	 *
-	 * @return void
+	 * @return null|\Psr\Http\Message\ResponseInterface
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
-	public function indexAction() {
+	public function indexAction(): ?\Psr\Http\Message\ResponseInterface {
 		$categories = GeneralUtility::intExplode(',', $this->settings['showCategories'], TRUE);
 		$tags = GeneralUtility::intExplode(',', $this->settings['showTags'], TRUE);
 		$startTime = (int) $this->settings['starttime'];
 		$endTime = (int) $this->settings['endtime'];
 		$news = $this->newsRepository->findLastUpdatedOrHighlightedNewsByCategories(
-			10, FALSE, $categories, 0, FALSE, 'date', $tags, $startTime, $endTime
+			10,
+			FALSE,
+			$categories,
+			0,
+			FALSE,
+			'date',
+			$tags,
+			$startTime,
+			$endTime
 		);
 
 		$newsCategories = [];
@@ -74,6 +82,12 @@ class NewsFeedController extends AbstractController {
 
 		$this->view->assign('news', $news);
 		$this->view->assign('newsCategories', $newsCategories);
+
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			return NULL;
+		} else {
+			return $this->htmlResponse();
+		}
 	}
 
 	/**
diff --git a/Classes/Controller/OverviewController.php b/Classes/Controller/OverviewController.php
index 93a0d0b702c6e8799ae3b336a15f0bf349cc9eda..5ca9999e7a9eb211065888bfdce07aefea6b2fc9 100644
--- a/Classes/Controller/OverviewController.php
+++ b/Classes/Controller/OverviewController.php
@@ -70,7 +70,8 @@ class OverviewController extends AbstractController {
 	/**
 	 * @param CategoryRepository $categoryRepository
 	 */
-	public function injectCategoryRepository(CategoryRepository $categoryRepository
+	public function injectCategoryRepository(
+		CategoryRepository $categoryRepository
 	) {
 		$this->categoryRepository = $categoryRepository;
 	}
@@ -102,7 +103,7 @@ class OverviewController extends AbstractController {
 	 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
 	 */
 	public function initializeOverviewAction() {
-		$currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage'];
+		$currentPageBrowserPage = (int) (GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage'] ?? 0);
 		if ($currentPageBrowserPage > 0) {
 			$this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage);
 		}
@@ -119,34 +120,45 @@ class OverviewController extends AbstractController {
 	 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
 	 * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
 	 */
-	public function overviewAction(array $newsFilter = [], int $currentPageBrowserPage = 0) {
+	public function overviewAction(array $newsFilter = [], int $currentPageBrowserPage = 0): ?\Psr\Http\Message\ResponseInterface {
 		if ((int) $this->settings['groupBy'] === 0 && (bool) $this->settings['enableFilter'] === FALSE) {
-			$this->forward('overviewWithoutCategories', NULL, NULL, $this->request->getArguments());
+			if (version_compare(
+				\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(),
+				'11.0.0',
+				'<'
+			)) {
+				$this->forward('overviewWithoutCategories', NULL, NULL, $this->request->getArguments());
+			} else {
+				return (new \TYPO3\CMS\Extbase\Http\ForwardResponse(
+					'overviewWithoutCategories'
+				))
+					->withArguments($this->request->getArguments());
+			}
 		}
 
 		// Setup settings
-		$startTime = (int) $this->settings['starttime'];
-		$endTime = (int) $this->settings['endtime'];
-		$newsLimit = (int) $this->settings['newsLimit'];
+		$startTime = (int) ($this->settings['starttime'] ?? 0);
+		$endTime = (int) ($this->settings['endtime'] ?? 0);
+		$newsLimit = (int) ($this->settings['newsLimit'] ?? 0);
 		$offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsLimit);
 		$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
 		$sortBy = $configurationService->getConfiguration('sortBy', $this->settings);
 		$sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings);
 		$this->tagRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]);
 		$this->categoryRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]);
-		$useAllFilters = (bool) $this->settings['enableFilter'];
-		$isCategoryFiltered = $useAllFilters || (int) $this->settings['groupBy'] === 1;
-		$isTagFiltered = $useAllFilters || (int) $this->settings['groupBy'] === 2;
+		$useAllFilters = (bool) ($this->settings['enableFilter'] ?? FALSE);
+		$isCategoryFiltered = $useAllFilters || $this->settings['groupBy'] === 1 ? 1 : 0;
+		$isTagFiltered = $useAllFilters || $this->settings['groupBy'] === 2 ? 1 : 0;
 
 		HeaderMetaDataService::addPageNumberToCanonical($currentPageBrowserPage);
 
 		// Get tag pid
-		$tagPid = (int) $this->settings['tagPid'];
+		$tagPid = (int) ($this->settings['tagPid'] ?? 0);
 		if (!$tagPid) {
 			$tagPid = $GLOBALS['TSFE']->id;
 		}
 
-		if ($this->settings['onlyNewsWithinThisPageSection']) {
+		if ($this->settings['onlyNewsWithinThisPageSection'] ?? FALSE) {
 			$categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id);
 			$tags = $this->tagRepository->findTagsInRootLine($tagPid);
 		} else {
@@ -155,7 +167,7 @@ class OverviewController extends AbstractController {
 		}
 
 		// Apply category restrictions
-		$categoryRestrictions = GeneralUtility::intExplode(',', $this->settings['categoryRestrictions'], TRUE);
+		$categoryRestrictions = GeneralUtility::intExplode(',', $this->settings['categoryRestrictions'] ?? '', TRUE);
 		if (!$isCategoryFiltered) {
 			$categoryRestrictions = [];
 		}
@@ -181,7 +193,7 @@ class OverviewController extends AbstractController {
 		}
 
 		// Apply tag restrictions
-		$tagRestrictions = GeneralUtility::intExplode(',', $this->settings['tagRestrictions'], TRUE);
+		$tagRestrictions = GeneralUtility::intExplode(',', $this->settings['tagRestrictions'] ?? '', TRUE);
 		if (!$isTagFiltered) {
 			$tagRestrictions = [];
 		}
@@ -195,7 +207,7 @@ class OverviewController extends AbstractController {
 
 		// Get category ids or use the one in the filter
 		$categoryIds = [];
-		if ($newsFilter['category']) {
+		if ($newsFilter['category'] ?? FALSE) {
 			$categoryIds = [(int) $newsFilter['category']];
 		} elseif ($isCategoryFiltered) {
 			foreach ($categories as $category) {
@@ -207,7 +219,7 @@ class OverviewController extends AbstractController {
 
 		// Get tag ids or use the one in the filter
 		$tagIds = [];
-		if ($newsFilter['tag']) {
+		if ($newsFilter['tag'] ?? FALSE) {
 			$tagIds = [(int) $newsFilter['tag']];
 		} elseif ($isTagFiltered) {
 			foreach ($tags as $tag) {
@@ -219,7 +231,14 @@ class OverviewController extends AbstractController {
 
 		// Get all news by category and tag ids
 		$news = $this->newsRepository->findAllSortedNewsByCategories(
-			$categoryIds, $newsLimit, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection
+			$categoryIds,
+			$newsLimit,
+			$offset,
+			$sortBy,
+			$tagIds,
+			$startTime,
+			$endTime,
+			$sortDirection
 		);
 
 		// Process news result query based on filters
@@ -229,8 +248,8 @@ class OverviewController extends AbstractController {
 		foreach ($news as $newsEntry) {
 			/** @var News $newsEntry */
 			$newsCategory = $this->categoryRepository->findOriginalLanguageById(
-					$newsEntry->getPid()
-				) ?? $this->categoryRepository->findByUid($newsEntry->getPid());
+				$newsEntry->getPid()
+			) ?? $this->categoryRepository->findByUid($newsEntry->getPid());
 			$newsCategoryId = $newsCategory->getUid();
 			$newsMetaData = $this->newsService->getMetaDataForNews($newsEntry, $newsCategory);
 
@@ -292,8 +311,8 @@ class OverviewController extends AbstractController {
 		}
 
 		// remember selection of the filter values, if any
-		$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
-		$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
+		$selectedTag = $this->tagRepository->findByUid((int) ($newsFilter['tag'] ?? 0));
+		$selectedCategory = $this->categoryRepository->findByUid((int) ($newsFilter['category'] ?? 0));
 		$this->view->assign('selectedCategory', $selectedCategory);
 		$this->view->assign('selectedTag', $selectedTag);
 		$this->view->assign('tags', $tags);
@@ -303,7 +322,7 @@ class OverviewController extends AbstractController {
 		$this->view->assign('allNews', $allNews);
 		$this->setupGridColumns();
 
-		switch ($this->settings['groupBy']) {
+		switch ($this->settings['groupBy'] ?? '') {
 			case 1:
 				$this->view->assign('groupBy', 'category');
 				$this->view->assign('categoryTabs', TRUE);
@@ -315,6 +334,12 @@ class OverviewController extends AbstractController {
 			default:
 				$this->view->assign('groupBy', 'none');
 		}
+
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			return NULL;
+		} else {
+			return $this->htmlResponse();
+		}
 	}
 
 	/**
@@ -334,10 +359,13 @@ class OverviewController extends AbstractController {
 		switch ($columnAmount) {
 			case 4:
 				$columnClasses .= 'col-lg-3 ';
+				// no break
 			case 3:
 				$columnClasses .= 'col-md-4 ';
+				// no break
 			case 2:
 				$columnClasses .= 'col-sm-6 ';
+				// no break
 			default:
 				$columnClasses .= 'col-xs-12';
 		}
@@ -353,13 +381,21 @@ class OverviewController extends AbstractController {
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
 	protected function highlightBestFitNews(array $categoryIds = NULL, array $tagIds = NULL) {
-		$startTime = (int) $this->settings['starttime'];
-		$endTime = (int) $this->settings['endtime'];
+		$startTime = (int) ($this->settings['starttime'] ?? 0);
+		$endTime = (int) ($this->settings['endtime'] ?? 0);
 
 		/** @var News $highlightedNews */
 		$highlightedNews = $this->newsRepository
 			->findLastUpdatedOrHighlightedNewsByCategories(
-				1, FALSE, $categoryIds, 0, FALSE, $this->settings['sortBy'], $tagIds, $startTime, $endTime
+				1,
+				FALSE,
+				$categoryIds,
+				0,
+				FALSE,
+				$this->settings['sortBy'],
+				$tagIds,
+				$startTime,
+				$endTime
 			)->getFirst();
 		if (!$highlightedNews) {
 			return;
@@ -371,14 +407,6 @@ class OverviewController extends AbstractController {
 		if ($category) {
 			$highlightedNewsMetaData = $this->newsService->getMetaDataForNews($highlightedNews, $category);
 		}
-
-		if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-			if ($highlightedNewsMetaData['image']) {
-				HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['image']);
-			} elseif ($highlightedNewsMetaData['teaserImage']) {
-				HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['teaserImage']);
-			}
-		}
 	}
 
 	/**
@@ -406,7 +434,9 @@ class OverviewController extends AbstractController {
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
 	protected function overviewWithoutCategoriesAction(
-		array $newsMetaData = [], array $newsFilter = NULL, int $currentPageBrowserPage = 0
+		array $newsMetaData = [],
+		array $newsFilter = NULL,
+		int $currentPageBrowserPage = 0
 	) {
 		// remember selection of the filter values, if any
 		$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
@@ -484,7 +514,14 @@ class OverviewController extends AbstractController {
 		}
 
 		$news = $this->newsRepository->findAllSortedNewsByCategories(
-			$categoryIds, $newsPerPage, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection
+			$categoryIds,
+			$newsPerPage,
+			$offset,
+			$sortBy,
+			$tagIds,
+			$startTime,
+			$endTime,
+			$sortDirection
 		);
 		foreach ($news as $newsEntry) {
 			/** @var News $newsEntry */
diff --git a/Classes/Controller/SingleViewController.php b/Classes/Controller/SingleViewController.php
index a7d929ff11fc51619c7593d661568217c2a553aa..1031ef76ad11abda4607162f4a01c0b01ae3af30 100644
--- a/Classes/Controller/SingleViewController.php
+++ b/Classes/Controller/SingleViewController.php
@@ -68,44 +68,41 @@ class SingleViewController extends AbstractController {
 	/**
 	 * Renders the news single view
 	 *
-	 * @return void
+	 * @return null|\Psr\Http\Message\ResponseInterface
 	 * @throws \InvalidArgumentException
 	 */
-	public function singleViewAction() {
-		/** @var News $news */
+	public function singleViewAction(): ?\Psr\Http\Message\ResponseInterface {
 		$currentId = (int) $GLOBALS['TSFE']->id;
+		/** @var News $news */
 		$news = $this->newsRepository->findByUid($currentId);
 		if (!$news) {
-			return;
+			if (version_compare(
+				\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(),
+				'11.0.0',
+				'<'
+			)) {
+				return NULL;
+			} else {
+				return $this->htmlResponse();
+			}
 		}
 
 		/** @var Category $newsCategory */
 		$newsCategory = $this->categoryRepository->findByUid($news->getPid());
 		if (!$newsCategory) {
-			return;
+			if (version_compare(
+				\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(),
+				'11.0.0',
+				'<'
+			)) {
+				return NULL;
+			} else {
+				return $this->htmlResponse();
+			}
 		}
 
-//		$similarNewsMetaData = [];
-//		$similarNews = $this->newsRepository->findRandomNews(3, $news);
-//		foreach ($similarNews as $similarNewsEntry) {
-//			/** @var News $similarNewsEntry */
-//			/** @var Category $category */
-//			$category = $this->categoryRepository->findByUid($similarNewsEntry->getPid());
-//			if (!$category) {
-//				continue;
-//			}
-//
-//			$similarNewsMetaData[] = $this->getMetaDataForNews($similarNewsEntry, $category);
-//		}
-
 		$newsMetaData = $this->newsService->getMetaDataForNews($news, $newsCategory);
-		if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-			if ($newsMetaData['image']) {
-				HeaderMetaDataService::addOgImageToHeader($newsMetaData['image']);
-			} elseif ($newsMetaData['teaserImage']) {
-				HeaderMetaDataService::addOgImageToHeader($newsMetaData['teaserImage']);
-			}
-		}
+
 
 		$previousNews = $this->newsRepository->findPreviousNewsEntryFromCurrentNews($news, $this->settings['sortBy'])
 			->getFirst();
@@ -121,12 +118,18 @@ class SingleViewController extends AbstractController {
 				'newsAuthor' => $news->getNewsAuthor(),
 			]
 		);
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			return NULL;
+		} else {
+			return $this->htmlResponse();
+		}
 	}
 
 	/**
 	 * @param CategoryRepository $categoryRepository
 	 */
-	public function injectCategoryRepository(CategoryRepository $categoryRepository
+	public function injectCategoryRepository(
+		CategoryRepository $categoryRepository
 	) {
 		$this->categoryRepository = $categoryRepository;
 	}
diff --git a/Classes/Domain/Model/FileReference.php b/Classes/Domain/Model/FileReference.php
index 63c7c7d9ee19a751613c6db032cc727f422b54bf..9a51b3dee41ed9b0b1930b0ed036d69c8f6719ad 100644
--- a/Classes/Domain/Model/FileReference.php
+++ b/Classes/Domain/Model/FileReference.php
@@ -30,5 +30,4 @@ namespace SGalinski\SgNews\Domain\Model;
  * FileReference
  */
 class FileReference extends \TYPO3\CMS\Extbase\Domain\Model\FileReference {
-
 }
diff --git a/Classes/Domain/Model/Tag.php b/Classes/Domain/Model/Tag.php
index 1dbb808c4adb7dd2a20923b31876db220f4edea3..96a5fd8e73cb2d1ffd0983c652f3b3216ec21ae9 100644
--- a/Classes/Domain/Model/Tag.php
+++ b/Classes/Domain/Model/Tag.php
@@ -31,7 +31,6 @@ use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
  * Tag
  */
 class Tag extends AbstractEntity {
-
 	/**
 	 * @var string
 	 */
diff --git a/Classes/Domain/Repository/AbstractRepository.php b/Classes/Domain/Repository/AbstractRepository.php
index 49ad3c22f70749cf4b18fafb57dafea4b36affca..348f5d4fc313cfc00e5e9c2cce50cfd8a3bc8584 100644
--- a/Classes/Domain/Repository/AbstractRepository.php
+++ b/Classes/Domain/Repository/AbstractRepository.php
@@ -27,6 +27,7 @@ namespace SGalinski\SgNews\Domain\Repository;
  ***************************************************************/
 
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\ApplicationType;
 use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
 use TYPO3\CMS\Extbase\Persistence\QueryInterface;
 use TYPO3\CMS\Extbase\Persistence\Repository;
@@ -43,44 +44,17 @@ abstract class AbstractRepository extends Repository {
 	 * @return void
 	 */
 	public function initializeObject() {
-		/** @var $querySettings Typo3QuerySettings */
+		/** @var Typo3QuerySettings $querySettings  */
 		$querySettings = $this->objectManager->get(Typo3QuerySettings::class);
 		$querySettings->setRespectStoragePage(FALSE);
-		if (TYPO3_MODE === 'BE') {
+		// in Migration wizard it was possible tha $GLOBALS['TYPO3_REQUEST'] was not set
+		// this should not be the case in any other case
+		if (!isset($GLOBALS['TYPO3_REQUEST']) || ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isBackend()) {
 			$querySettings->setIgnoreEnableFields(TRUE);
 		}
 		$this->setDefaultQuerySettings($querySettings);
 	}
 
-	/**
-	 * Method creates a statement string of the enableFields for the given database table.
-	 *
-	 * @param string $table
-	 * @param string $alias
-	 * @param bool $ignoreEnableFields
-	 * @return string
-	 * @throws \InvalidArgumentException
-	 */
-	protected function getEnableFieldsStatement($table, $alias = '', $ignoreEnableFields = FALSE): string {
-		if (TYPO3_MODE === 'FE' && $GLOBALS['TSFE'] instanceof TypoScriptFrontendController) {
-			/** @var PageRepository $pageRepository */
-			$pageRepository = $GLOBALS['TSFE']->sys_page;
-			$statement = $pageRepository->enableFields($table);
-		} else {
-			$statement = BackendUtility::deleteClause($table);
-
-			if (!$ignoreEnableFields) {
-				$statement .= BackendUtility::BEenableFields($table);
-			}
-		}
-
-		if ($alias !== '') {
-			$statement = str_replace($table, $alias, $statement);
-		}
-
-		return $statement;
-	}
-
 	/**
 	 * This count returns the right amount of results, in contrast to $query->execute()->count(), which does not respect
 	 * the language- nor the workspace overlay.
@@ -90,6 +64,6 @@ abstract class AbstractRepository extends Repository {
 	 * @return int
 	 */
 	public function getCount(QueryInterface $query) {
-		return \count($query->execute(true));
+		return \count($query->execute(TRUE));
 	}
 }
diff --git a/Classes/Domain/Repository/AuthorRepository.php b/Classes/Domain/Repository/AuthorRepository.php
index f1ac33f72aec678de1133119d79b55c42dd8d2be..7fd9bb8285e14c7e93bc0dd6dd334ac96fd85989 100644
--- a/Classes/Domain/Repository/AuthorRepository.php
+++ b/Classes/Domain/Repository/AuthorRepository.php
@@ -32,5 +32,4 @@ use SGalinski\SgNews\Domain\Repository\AbstractRepository;
  * Repository for the Author model.
  */
 class AuthorRepository extends AbstractRepository {
-
 }
diff --git a/Classes/Domain/Repository/CategoryRepository.php b/Classes/Domain/Repository/CategoryRepository.php
index 83d5324301f1ee784c1b026803ed1a2619b96b06..6fffcc342b15c13d132b77ba1cea9ea4588c8c5d 100644
--- a/Classes/Domain/Repository/CategoryRepository.php
+++ b/Classes/Domain/Repository/CategoryRepository.php
@@ -37,7 +37,6 @@ use TYPO3\CMS\Extbase\Persistence\QueryInterface;
  * Category Repository
  */
 class CategoryRepository extends AbstractRepository {
-
 	/**
 	 * @var array
 	 */
@@ -61,7 +60,7 @@ class CategoryRepository extends AbstractRepository {
 				$queryBuilder->expr()->eq('translation.uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
 			)
 			->setMaxResults(1)
-			->execute()->fetch();
+			->execute()->fetchAssociative();
 		if ($row && (int) $row['uid'] !== 0) {
 			return current($dataMapper->map($this->objectType, [$row]));
 		}
diff --git a/Classes/Domain/Repository/FileReferenceRepository.php b/Classes/Domain/Repository/FileReferenceRepository.php
index b26ff56edfb84d559a68e8a4f1c3e06694411f37..ac8e9612c3bd9ea888526ba601512099cc449c20 100644
--- a/Classes/Domain/Repository/FileReferenceRepository.php
+++ b/Classes/Domain/Repository/FileReferenceRepository.php
@@ -26,16 +26,15 @@ namespace SGalinski\SgNews\Domain\Repository;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 use SGalinski\SgNews\Domain\Model\FileReference;
+use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * FileReference Repository
  */
 class FileReferenceRepository extends AbstractRepository {
-
 	/**
 	 * Method creates a file reference entry in the database. This step is necessary because the
 	 * extbase can not handle the default TCA for FAL records. Without this method the FAL records will miss
@@ -71,7 +70,7 @@ class FileReferenceRepository extends AbstractRepository {
 	 * extbase can not handle the default TCA for FAL records. Without this method the FAL records will miss
 	 * the uid_foreign, field name and table names.
 	 *
-	 * @param $fileId
+	 * @param int $fileId
 	 * @param array $reference
 	 * @param string $tablename
 	 * @param string $fieldname
diff --git a/Classes/Domain/Repository/NewsRepository.php b/Classes/Domain/Repository/NewsRepository.php
index 7b5f136564ed227a55505911e83fa3e85127a967..9ab663bf11f6bf8d1d1ced9c27cacb8dd2462b97 100644
--- a/Classes/Domain/Repository/NewsRepository.php
+++ b/Classes/Domain/Repository/NewsRepository.php
@@ -86,8 +86,14 @@ class NewsRepository extends AbstractRepository {
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
 	public function findAllSortedNewsByCategories(
-		array $categoryIds = NULL, $limit = 0, $offset = 0, $sortBy = 'date', array $tagIds = NULL,
-		$startTime = 0, $endTime = 0, $sortDirection = 'DESC'
+		array $categoryIds = NULL,
+		$limit = 0,
+		$offset = 0,
+		$sortBy = 'date',
+		array $tagIds = NULL,
+		$startTime = 0,
+		$endTime = 0,
+		$sortDirection = 'DESC'
 	): QueryResultInterface {
 		$query = $this->createQuery();
 
@@ -171,7 +177,10 @@ class NewsRepository extends AbstractRepository {
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
 	public function newsCountByCategories(
-		array $categoryIds = NULL, array $tagIds = NULL, $startTime = 0, $endTime = 0
+		array $categoryIds = NULL,
+		array $tagIds = NULL,
+		$startTime = 0,
+		$endTime = 0
 	): int {
 		$query = $this->createQuery();
 
@@ -231,13 +240,26 @@ class NewsRepository extends AbstractRepository {
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
 	public function findLastUpdatedOrHighlightedNewsByCategories(
-		$limit = 1, $onlyHighlighted = FALSE, array $categoryIds = NULL,
-		$offset = 0, $hideNeverHighlightedNews = FALSE, $sortBy = 'date', array $tagIds = NULL,
-		$startTime = 0, $endTime = 0
+		$limit = 1,
+		$onlyHighlighted = FALSE,
+		array $categoryIds = NULL,
+		$offset = 0,
+		$hideNeverHighlightedNews = FALSE,
+		$sortBy = 'date',
+		array $tagIds = NULL,
+		$startTime = 0,
+		$endTime = 0
 	): QueryResultInterface {
 		return $this->getQueryForLastUpdatedOrHighlightedNewsByCategories(
-			$limit, $onlyHighlighted, $categoryIds, $offset, $hideNeverHighlightedNews, $sortBy, $tagIds,
-			$startTime, $endTime
+			$limit,
+			$onlyHighlighted,
+			$categoryIds,
+			$offset,
+			$hideNeverHighlightedNews,
+			$sortBy,
+			$tagIds,
+			$startTime,
+			$endTime
 		)->execute();
 	}
 
@@ -257,9 +279,15 @@ class NewsRepository extends AbstractRepository {
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
 	protected function getQueryForLastUpdatedOrHighlightedNewsByCategories(
-		$limit = 1, $onlyHighlighted = FALSE, array $categoryIds = NULL,
-		$offset = 0, $hideNeverHighlightedNews = FALSE, $sortBy = 'date', array $tagIds = NULL,
-		$startTime = 0, $endTime = 0
+		$limit = 1,
+		$onlyHighlighted = FALSE,
+		array $categoryIds = NULL,
+		$offset = 0,
+		$hideNeverHighlightedNews = FALSE,
+		$sortBy = 'date',
+		array $tagIds = NULL,
+		$startTime = 0,
+		$endTime = 0
 	): QueryInterface {
 		$query = $this->createQuery();
 		$constraints = NULL;
@@ -498,7 +526,7 @@ class NewsRepository extends AbstractRepository {
 	 */
 	public function findByUidIgnoreEnableFields($uid) {
 		$query = $this->createQuery();
-		/** @var $querySettings \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings */
+		/** @var \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings $querySettings */
 		$querySettings = $query->getQuerySettings();
 		$querySettings->setIgnoreEnableFields(TRUE);
 		$querySettings->setRespectStoragePage(FALSE);
@@ -553,9 +581,9 @@ class NewsRepository extends AbstractRepository {
 
 		// Here we fetch the lastUpdated of the $limit amount of news with older lastUpdated dates
 		$result = $qb->where(
-				$qb->expr()->eq('doktype', $qb->createNamedParameter(News::DOK_TYPE_NEWS, Connection::PARAM_INT)),
-				$qb->expr()->lte('lastUpdated', $news->getLastUpdated()->getTimestamp())
-			)->andWhere(...$constraints)
+			$qb->expr()->eq('doktype', $qb->createNamedParameter(News::DOK_TYPE_NEWS, Connection::PARAM_INT)),
+			$qb->expr()->lte('lastUpdated', $news->getLastUpdated()->getTimestamp())
+		)->andWhere(...$constraints)
 			->orderBy('lastUpdated', 'asc')
 			->execute();
 		$oldest = $result->fetchOne();
diff --git a/Classes/Domain/Service/NewsService.php b/Classes/Domain/Service/NewsService.php
index 7ba3ad6d291e7a412b78cf1b3145c203321c4595..ec24fca72e1d16fcc8048187c3aefc2a801bc8da 100644
--- a/Classes/Domain/Service/NewsService.php
+++ b/Classes/Domain/Service/NewsService.php
@@ -28,10 +28,10 @@ namespace SGalinski\SgNews\Domain\Service;
 
 use SGalinski\SgNews\Domain\Model\Category;
 use SGalinski\SgNews\Domain\Model\News;
+use TYPO3\CMS\Core\Resource\FileRepository;
 use TYPO3\CMS\Core\SingletonInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Domain\Model\FileReference;
-use TYPO3\CMS\Core\Resource\FileRepository;
 
 /**
  * This service takes care of meta data generation for the news objects
diff --git a/Classes/Hooks/EditDocumentController.php b/Classes/Hooks/EditDocumentController.php
deleted file mode 100644
index 34b2ef2dfccbea5b3aa949dd7054dc8af7c2c603..0000000000000000000000000000000000000000
--- a/Classes/Hooks/EditDocumentController.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-
-namespace SGalinski\SgNews\Hooks;
-
-/***************************************************************
- *  Copyright notice
- *
- *  (c) sgalinski Internet Services (https://www.sgalinski.de)
- *  All rights reserved
- *
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
-
-use SGalinski\SgNews\Utility\BackendNewsUtility;
-use TYPO3\CMS\Backend\Controller\EditDocumentController as CoreEditDocumentController;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-
-/**
- * Backend edid form hook
- */
-class EditDocumentController {
-
-	/**
-	 * Sets the default value for the pages author field
-	 * to the name of the logged-in user
-	 *
-	 * @param CoreEditDocumentController $controller
-	 * @return void
-	 */
-	public function preInitAfter($controller) {
-		$tables = ['pages'];
-		if (
-			$GLOBALS['BE_USER']->user['realName'] !== ''
-			&& (isset($controller->editconf[$tables[0]]) || isset($controller->editconf[$tables[1]]))
-		) {
-			$doktype = 0;
-			$userName = $GLOBALS['BE_USER']->user['realName'];
-			$tableName = isset($controller->editconf[$tables[0]]) ? $tables[0] : $tables[1];
-			$command = reset($controller->editconf[$tableName]);
-			$pageUid = key($controller->editconf[$tableName]);
-			if ($command === 'edit') {
-				$pageRow = BackendUtility::getRecord($tableName, (int) $pageUid);
-				if ($pageRow && isset($pageRow['doktype'])) {
-					$doktype = (int) $pageRow['doktype'];
-				}
-			} elseif ($command === 'new' && isset($controller->overrideVals[$tableName]['doktype'])) {
-				$doktype = (int) $controller->overrideVals[$tableName]['doktype'];
-			}
-			if ($doktype === BackendNewsUtility::NEWS_DOKTYPE) {
-				$GLOBALS['BE_USER']->userTS['TCAdefaults.'][$tableName . '.']['author'] = $userName;
-			}
-		}
-	}
-}
diff --git a/Classes/Hooks/PageLayoutController.php b/Classes/Hooks/PageLayoutController.php
index 253737b2c6dfe06c70bfcd236e6ded809e40d4ac..aa63564edb36ede9a51492dc7478b6c1e01beb2e 100644
--- a/Classes/Hooks/PageLayoutController.php
+++ b/Classes/Hooks/PageLayoutController.php
@@ -37,17 +37,15 @@ use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
  * Backend edid form hook
  */
 class PageLayoutController {
-
 	/**
-	 * Sets the default value for the pages author field
-	 * to the name of the logged-in user
+	 * Adds a Button to News-Pages which allows the user to switch to the News module
 	 *
 	 * @param array $parameters
 	 * @param CorePageLayoutController $controller
 	 * @return string
 	 * @throws \InvalidArgumentException
 	 */
-	public function addNewsModuleLink(array $parameters = [], $controller): string {
+	public function addNewsModuleLink(array $parameters = [], CorePageLayoutController $controller = NULL): string {
 		$out = '';
 		$pageRow = BackendUtility::getRecord('pages', $controller->id);
 		$acceptedDoktypes = [BackendNewsUtility::NEWS_DOKTYPE, BackendNewsUtility::CATEGORY_DOKTYPE];
diff --git a/Classes/Hooks/PageLayoutView/PluginRenderer.php b/Classes/Hooks/PageLayoutView/PluginRenderer.php
index 7e94ef789b5461f7baf86b3babbee412bd0fa254..d0bb7e435efd7a06769c48b861cd20ff2b323114 100644
--- a/Classes/Hooks/PageLayoutView/PluginRenderer.php
+++ b/Classes/Hooks/PageLayoutView/PluginRenderer.php
@@ -20,6 +20,7 @@ namespace SGalinski\SgNews\Hooks\PageLayoutView;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
+use SGalinski\SgNews\Preview\PreviewService;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\View\PageLayoutView;
 use TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface;
@@ -34,6 +35,11 @@ use TYPO3\CMS\Fluid\View\StandaloneView;
  * @package SGalinski\SgNews\Hook\PagelayoutView\PluginRenderer
  */
 class PluginRenderer implements PageLayoutViewDrawItemHookInterface {
+	protected PreviewService $previewService;
+
+	public function init() {
+		$this->previewService = GeneralUtility::makeInstance(PreviewService::class);
+	}
 
 	/**
 	 * Preprocesses the preview rendering of an sg_news content element plugin.
@@ -46,34 +52,19 @@ class PluginRenderer implements PageLayoutViewDrawItemHookInterface {
 	 * @noinspection ReferencingObjectsInspection
 	 */
 	public function preProcess(
-		PageLayoutView &$parentObject, &$drawItem, &$headerContent, &$itemContent, array &$row
+		PageLayoutView &$parentObject,
+		&$drawItem,
+		&$headerContent,
+		&$itemContent,
+		array &$row
 	): void {
+		$this->init();
 		switch ($row['list_type']) {
 			case 'sgnews_overview':
 				$drawItem = FALSE;
-
-				$view = $this->createViewWithTemplate('Overview');
-				$view->assign('uid', $row['uid']);
-
 				$this->adaptPluginHeaderContent($headerContent, $row);
 
-				// Get available plugin settings and their values from flexform
-				$pluginConfiguration = GeneralUtility::xml2array(
-					$row['pi_flexform'], 'T3DataStructure'
-				)['data']['main']['lDEF'];
-
-				$templateData = [
-					'groupBy' => $pluginConfiguration['settings.groupBy']['vDEF'],
-					'enableFilter' => $pluginConfiguration['settings.enableFilter']['vDEF'],
-					'newsLimit' => $pluginConfiguration['settings.newsLimit']['vDEF'],
-					'onlyNewsWithinThisPageSection' => $pluginConfiguration['settings.onlyNewsWithinThisPageSection']['vDEF'],
-					'starttime' => $pluginConfiguration['settings.starttime']['vDEF'],
-					'endtime' => $pluginConfiguration['settings.endtime']['vDEF'],
-					'sortBy' => $pluginConfiguration['settings.sortBy']['vDEF'],
-					'sortDirection' => $pluginConfiguration['settings.sortDirection']['vDEF']
-				];
-
-				$view->assign('data', $templateData);
+				$view = $this->previewService->getOverviewView($row);
 
 				$itemContent .= $view->render();
 				break;
@@ -81,32 +72,8 @@ class PluginRenderer implements PageLayoutViewDrawItemHookInterface {
 			case 'sgnews_latest':
 				$drawItem = FALSE;
 
-				$view = $this->createViewWithTemplate('Latest');
-				$view->assign('uid', $row['uid']);
-
 				$this->adaptPluginHeaderContent($headerContent, $row);
-
-				// Get available plugin settings and their values from flexform
-				$pluginConfiguration = GeneralUtility::xml2array(
-					$row['pi_flexform'], 'T3DataStructure'
-				)['data']['main']['lDEF'];
-
-				$categories = $pluginConfiguration['settings.categories']['vDEF'];
-				$tags = $pluginConfiguration['settings.tags']['vDEF'];
-				$templateData = [
-					'limit' => $pluginConfiguration['settings.limit']['vDEF'],
-					'categories' => is_string($categories) ? $this->addFieldContentsToRecordIdList(
-						'pages', $categories
-					) : '',
-					'tags' => is_string($tags) ? $this->addFieldContentsToRecordIdList(
-						'sys_category', $tags
-					) : '',
-					'starttime' => $pluginConfiguration['settings.starttime']['vDEF'],
-					'endtime' => $pluginConfiguration['settings.endtime']['vDEF'],
-					'sortBy' => $pluginConfiguration['settings.sortBy']['vDEF']
-				];
-
-				$view->assign('data', $templateData);
+				$view = $this->previewService->getLatestView($row);
 
 				$itemContent .= $view->render();
 				break;
@@ -114,31 +81,8 @@ class PluginRenderer implements PageLayoutViewDrawItemHookInterface {
 			case 'sgnews_listbycategory':
 				$drawItem = FALSE;
 
-				$view = $this->createViewWithTemplate('ListByCategory');
-				$view->assign('uid', $row['uid']);
-
 				$this->adaptPluginHeaderContent($headerContent, $row);
-
-				// Get available plugin settings and their values from flexform
-				$pluginConfiguration = GeneralUtility::xml2array(
-					$row['pi_flexform'], 'T3DataStructure'
-				)['data']['main']['lDEF'];
-
-				$categories = $pluginConfiguration['settings.categories']['vDEF'];
-				$tags = $pluginConfiguration['settings.tags']['vDEF'];
-				$templateData = [
-					'newsLimitPerPage' => $pluginConfiguration['settings.newsLimitPerPage']['vDEF'],
-					'categories' => is_string($categories) ? $this->addFieldContentsToRecordIdList(
-						'pages', $categories
-					) : '',
-					'tags' => is_string($tags) ? $this->addFieldContentsToRecordIdList('sys_category', $tags) : '',
-					'starttime' => $pluginConfiguration['settings.starttime']['vDEF'],
-					'endtime' => $pluginConfiguration['settings.endtime']['vDEF'],
-					'sortBy' => $pluginConfiguration['settings.sortBy']['vDEF'],
-					'sortDirection' => $pluginConfiguration['settings.sortDirection']['vDEF']
-				];
-
-				$view->assign('data', $templateData);
+				$view = $this->previewService->getListByCategoryView($row);
 
 				$itemContent .= $view->render();
 				break;
@@ -146,37 +90,9 @@ class PluginRenderer implements PageLayoutViewDrawItemHookInterface {
 			case 'sgnews_newsbyauthor':
 				$drawItem = FALSE;
 
-				$view = $this->createViewWithTemplate('NewsByAuthor');
-				$view->assign('uid', $row['uid']);
-
 				$this->adaptPluginHeaderContent($headerContent, $row);
 
-				// Get available plugin settings and their values from flexform
-				$pluginConfiguration = GeneralUtility::xml2array(
-					$row['pi_flexform'], 'T3DataStructure'
-				)['data']['main']['lDEF'];
-
-				$newsAuthors = $pluginConfiguration['settings.newsAuthors']['vDEF'];
-				$templateData = [
-					'showDetails' => $pluginConfiguration['settings.showDetails']['vDEF'],
-					'newsAuthors' => is_string($newsAuthors) ? $this->addFieldContentsToRecordIdList(
-						'tx_sgnews_domain_model_author',$newsAuthors,'name'
-					) : ''
-				];
-
-				// Not using addFieldContentsToRecordIdList to avoid repetitive imploding and exploding.
-				$excludedNewsIds = GeneralUtility::intExplode(
-					',', $pluginConfiguration['settings.excludedNews']['vDEF'], TRUE
-				);
-				$excludedNewsListWithTitles = [];
-				foreach ($excludedNewsIds as $excludedNewsId) {
-					$excludedNewsListWithTitles[] = BackendUtility::getRecord(
-							'pages', $excludedNewsId, 'title'
-						)['title'] . ' [' . $excludedNewsId . ']';
-				}
-				$templateData['excludedNews'] = $excludedNewsListWithTitles;
-
-				$view->assign('data', $templateData);
+				$view = $this->previewService->getNewsByAuthorView($row);
 
 				$itemContent .= $view->render();
 				break;
@@ -186,37 +102,18 @@ class PluginRenderer implements PageLayoutViewDrawItemHookInterface {
 		}
 	}
 
-	/**
-	 * Creates a new StandaloneView object with template and partial rot paths,
-	 * attaches the template with the given name to it and returns it.
-	 *
-	 * @param string $templateName
-	 * @return StandaloneView
-	 */
-	protected
-	function createViewWithTemplate(string $templateName): StandaloneView {
-		$view = GeneralUtility::makeInstance(StandaloneView::class);
-		$view->setTemplateRootPaths(['EXT:sg_news/Resources/Private/Templates/Backend']);
-		$view->setPartialRootPaths(['EXT:sg_news/Resources/Private/Partials/Backend']);
-		if (!str_ends_with($templateName, '.html')) {
-			$templateName .= '.html';
-		}
-		$view->setTemplate($templateName);
-		return $view;
-	}
-
 	/**
 	 * Adapts the given $headerContent.
 	 * To be used in all plugin previews so the Header Contents appear similarly.
 	 *
-	 * @param $headerContent
-	 * @param $row
+	 * @param string $headerContent
+	 * @param array $row
 	 */
-	protected
-	function adaptPluginHeaderContent(&$headerContent, $row): void {
+	protected function adaptPluginHeaderContent(&$headerContent, $row): void {
 		$headerContent = '<h4>' . $this->getPluginNameForHeaderContent(
-				(int) $row['pid'], $row['list_type']
-			) . $headerContent . '</h4>';
+			(int) $row['pid'],
+			$row['list_type']
+		) . $headerContent . '</h4>';
 	}
 
 	/**
@@ -227,39 +124,17 @@ class PluginRenderer implements PageLayoutViewDrawItemHookInterface {
 	 * @param string $listType
 	 * @return string
 	 */
-	protected
-	function getPluginNameForHeaderContent(int $pid, string $listType): string {
+	protected function getPluginNameForHeaderContent(int $pid, string $listType): string {
 		$languageService = GeneralUtility::makeInstance(LanguageService::class);
 
 		$pluginName = $languageService->sL(
 			BackendUtility::getLabelFromItemListMerged(
-				$pid, 'tt_content', 'list_type', $listType
+				$pid,
+				'tt_content',
+				'list_type',
+				$listType
 			)
 		);
 		return '<span class="label label-primary">' . $pluginName . '</span>&nbsp;';
 	}
-
-	/**
-	 * Takes a comma-separated list of record IDs, the corresponding table and optionally the field to look up.
-	 * Returns another comma-space-separated list of the same records with the content of the field added.
-	 * The returned list should look nice enough to be rendered in the backend preview directly.
-	 *
-	 * @param string $table
-	 * @param string $recordIdList
-	 * @param string $field
-	 * @return string
-	 */
-	protected function addFieldContentsToRecordIdList(
-		string $table, string $recordIdList, string $field = 'title'
-	): string {
-		$recordIdsArray = GeneralUtility::intExplode(',', $recordIdList, TRUE);
-		$recordsWithTitlesArray = [];
-
-		foreach ($recordIdsArray as $recordId) {
-			$recordsWithTitlesArray[] = BackendUtility::getRecord(
-					$table, $recordId, $field
-				)[$field] . ' [' . $recordId . ']';
-		}
-		return implode(', ', $recordsWithTitlesArray);
-	}
 }
diff --git a/Classes/Hooks/RealUrlAutoConfiguration.php b/Classes/Hooks/RealUrlAutoConfiguration.php
index f1b77b7960a7868f62c024416f28979a50ade53b..32ac5369318105bc2243bb1ac54642204af67380 100644
--- a/Classes/Hooks/RealUrlAutoConfiguration.php
+++ b/Classes/Hooks/RealUrlAutoConfiguration.php
@@ -37,7 +37,8 @@ class RealUrlAutoConfiguration {
 	 */
 	public function addNewsConfig($params): array {
 		return array_merge_recursive(
-			$params['config'], [
+			$params['config'],
+			[
 				'postVarSets' => [
 					'_DEFAULT' => [
 						'page' => [
diff --git a/Classes/Paginator/QueryBuilderPaginator.php b/Classes/Paginator/QueryBuilderPaginator.php
new file mode 100644
index 0000000000000000000000000000000000000000..405c8a55495e645a6d6b4a040a5264f35bc5cd5d
--- /dev/null
+++ b/Classes/Paginator/QueryBuilderPaginator.php
@@ -0,0 +1,105 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+namespace SGalinski\SgNews\Paginator;
+
+use TYPO3\CMS\Core\Pagination\AbstractPaginator;
+use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
+
+/**
+ * Copied QueryResult Paginator for us to get a raw result returned,
+ * just like the old Controller used to use, also alot of BE ViewHelpers want an array
+ */
+final class QueryBuilderPaginator extends AbstractPaginator {
+	/**
+	 * @var \TYPO3\CMS\Core\Database\Query\QueryBuilder
+	 */
+	private $queryBuilder;
+
+	/**
+	 * @var array
+	 */
+	private $paginatedQueryResult;
+
+	/**
+	 * @var int
+	 */
+	protected int $totalItems = 0;
+
+	public function __construct(
+		\TYPO3\CMS\Core\Database\Query\QueryBuilder $queryBuilder,
+		int $currentPageNumber = 1,
+		int $itemsPerPage = 10
+	) {
+		$this->queryBuilder = $queryBuilder;
+		$this->setCurrentPageNumber($currentPageNumber);
+		$this->setItemsPerPage($itemsPerPage);
+
+		$this->updateInternalState();
+	}
+
+	/**
+	 * @return iterable|QueryResultInterface
+	 */
+	public function getPaginatedItems(): iterable {
+		return $this->paginatedQueryResult;
+	}
+
+	protected function updatePaginatedItems(int $limit, int $offset): void {
+		$this->paginatedQueryResult = $this->queryBuilder
+			->setMaxResults($limit)
+			->setFirstResult($offset)
+			->execute()->fetchAllAssociative();
+	}
+
+	protected function getTotalAmountOfItems(): int {
+		$countBuilder = clone $this->queryBuilder;
+		try {
+			$totalItems = $countBuilder
+				->setMaxResults(99999)
+				->setFirstResult(0)
+				->count('uid')
+				->execute()->fetchOne();
+		} catch (\Exception $e) {
+			$totalItems = $countBuilder
+				->setMaxResults(99999)
+				->setFirstResult(0)
+				->count('p.uid')
+				->execute()->fetchOne();
+		}
+		$this->setTotalItems($totalItems ?: 0);
+		return $totalItems ?: 0;
+	}
+
+	protected function getAmountOfItemsOnCurrentPage(): int {
+		return count($this->paginatedQueryResult);
+	}
+
+	/**
+	 * @return int
+	 */
+	public function getTotalItems(): int {
+		return $this->totalItems;
+	}
+
+	/**
+	 * @param int $totalItems
+	 */
+	public function setTotalItems(int $totalItems): void {
+		$this->totalItems = $totalItems;
+	}
+}
diff --git a/Classes/Preview/PreviewRenderer.php b/Classes/Preview/PreviewRenderer.php
new file mode 100644
index 0000000000000000000000000000000000000000..efbe5c8c1f141b09109a810e5ab73f403ddbcf69
--- /dev/null
+++ b/Classes/Preview/PreviewRenderer.php
@@ -0,0 +1,118 @@
+<?php
+
+/***************************************************************
+ *  Copyright notice
+ *  (c) sgalinski Internet Services (https://www.sgalinski.de)
+ *  All rights reserved
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+namespace SGalinski\SgNews\Preview;
+
+use TYPO3\CMS\Backend\Preview\PreviewRendererInterface;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
+use TYPO3\CMS\Core\Localization\LanguageService;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\View\StandaloneView;
+
+/**
+ *
+ */
+class PreviewRenderer implements PreviewRendererInterface {
+	/**
+	 * @var LanguageService $languageService
+	 */
+	protected LanguageService $languageService;
+
+	protected PreviewService $previewService;
+
+	public function __construct(LanguageService $languageService, PreviewService $previewService) {
+		$this->previewService = $previewService;
+		$this->languageService = $languageService;
+	}
+
+	/**
+	 * Dedicated method for rendering preview header HTML for
+	 * the page module only. Receives $item which is an instance of
+	 * GridColumnItem which has a getter method to return the record.
+	 *
+	 * @param GridColumnItem $item
+	 * @return string
+	 */
+	public function renderPageModulePreviewHeader(GridColumnItem $item): string {
+		$label = BackendUtility::getLabelFromItemListMerged(
+			$item->getRecord()['pid'],
+			'tt_content',
+			'list_type',
+			$item->getRecord()['list_type']
+		);
+		return '<h4><span class="label label-primary">' . $this->languageService->sL($label) . '</span>&nbsp;</h4>';
+	}
+
+	/**
+	 * Dedicated method for rendering preview body HTML for
+	 * the page module only.
+	 *
+	 * @param GridColumnItem $item
+	 * @return string
+	 */
+	public function renderPageModulePreviewContent(GridColumnItem $item): string {
+		$row = $item->getRecord();
+		switch ($row['list_type']) {
+			case 'sgnews_overview':
+				$view = $this->previewService->getOverviewView($row);
+				return $view->render();
+
+			case 'sgnews_latest':
+				$view = $this->previewService->getLatestView($row);
+				return $view->render();
+
+			case 'sgnews_listbycategory':
+				$view = $this->previewService->getListByCategoryView($row);
+				return $view->render();
+
+			case 'sgnews_newsbyauthor':
+				$view = $this->previewService->getNewsByAuthorView($row);
+				return $view->render();
+
+			default:
+				// No need to do anything
+		}
+		return '';
+	}
+
+	/**
+	 * Render a footer for the record to display in page module below
+	 * the body of the item's preview.
+	 *
+	 * @param GridColumnItem $item
+	 * @return string
+	 */
+	public function renderPageModulePreviewFooter(GridColumnItem $item): string {
+		return '';
+	}
+
+	/**
+	 * Dedicated method for wrapping a preview header and body HTML.
+	 *
+	 * @param string $previewHeader
+	 * @param string $previewContent
+	 * @param GridColumnItem $item
+	 * @return string
+	 */
+	public function wrapPageModulePreview(string $previewHeader, string $previewContent, GridColumnItem $item): string {
+		return $previewHeader . $previewContent;
+	}
+}
diff --git a/Classes/Preview/PreviewService.php b/Classes/Preview/PreviewService.php
new file mode 100644
index 0000000000000000000000000000000000000000..8161f2be0b6980a5e0da44d90a5d25f8b80e8493
--- /dev/null
+++ b/Classes/Preview/PreviewService.php
@@ -0,0 +1,250 @@
+<?php
+
+/***************************************************************
+ *  Copyright notice
+ *  (c) sgalinski Internet Services (https://www.sgalinski.de)
+ *  All rights reserved
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+namespace SGalinski\SgNews\Preview;
+
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Fluid\View\StandaloneView;
+
+/**
+ * small helper class, aslong as we use PageLayout hook + Previewrenderer....
+ */
+class PreviewService {
+	public const RETURNTYPE_ARR = 'array';
+
+	/**
+	 * returns a Standalone view for SgNews Overview Plugin
+	 *
+	 * @param array $row
+	 * @return StandaloneView
+	 */
+	public function getOverviewView(array $row): StandaloneView {
+		$view = $this->createViewWithTemplate('Overview');
+		$view->assign('uid', $row['uid']);
+
+		// Get available plugin settings and their values from flexform
+		$pluginConfiguration = GeneralUtility::xml2array(
+			$row['pi_flexform'],
+			'T3DataStructure'
+		)['data']['main']['lDEF'];
+
+		$templateData = [
+			'groupBy' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.groupBy'),
+			'enableFilter' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.enableFilter'),
+			'newsLimit' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.newsLimit'),
+			'onlyNewsWithinThisPageSection' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.onlyNewsWithinThisPageSection'),
+			'starttime' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.starttime'),
+			'endtime' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.endtime'),
+			'sortBy' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.sortBy'),
+			'sortDirection' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.sortDirection'),
+		];
+
+		$view->assign('data', $templateData);
+		return $view;
+	}
+
+	/**
+	 * Returns LatestView for Previews of sg_news
+	 *
+	 * @param array $row
+	 * @return StandaloneView
+	 */
+	public function getLatestView(array $row): StandaloneView {
+		$view = $this->createViewWithTemplate('Latest');
+		$view->assign('uid', $row['uid']);
+
+		// Get available plugin settings and their values from flexform
+		$pluginConfiguration = GeneralUtility::xml2array(
+			$row['pi_flexform'],
+			'T3DataStructure'
+		)['data']['main']['lDEF'];
+
+		$categories = $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.categories');
+		$tags = $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.tags');
+		$templateData = [
+			'limit' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.limit'),
+			'categories' => is_string($categories) ? $this->addFieldContentsToRecordIdList(
+				'pages',
+				$categories
+			) : '',
+			'tags' => is_string($tags) ? $this->addFieldContentsToRecordIdList(
+				'sys_category',
+				$tags
+			) : '',
+			'starttime' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.starttime'),
+			'endtime' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.endtime'),
+			'sortBy' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.sortBy'),
+		];
+
+		$view->assign('data', $templateData);
+		return $view;
+	}
+
+	/**
+	 * Returns ListByCategory View for Previews of sg_news
+	 *
+	 * @param array $row
+	 * @return StandaloneView
+	 */
+	public function getListByCategoryView(array $row): StandaloneView {
+		$view = $this->createViewWithTemplate('ListByCategory');
+		$view->assign('uid', $row['uid']);
+
+
+		// Get available plugin settings and their values from flexform
+		$pluginConfiguration = GeneralUtility::xml2array(
+			$row['pi_flexform'],
+			'T3DataStructure'
+		)['data']['main']['lDEF'];
+
+		$categories = $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.categories');
+		$tags = $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.tags');
+		$templateData = [
+			'newsLimitPerPage' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.newsLimitPerPage'),
+			'categories' => is_string($categories) ? $this->addFieldContentsToRecordIdList(
+				'pages',
+				$categories
+			) : '',
+			'tags' => is_string($tags) ? $this->addFieldContentsToRecordIdList(
+				'sys_category',
+				$tags
+			) : '',
+
+			'starttime' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.starttime'),
+			'endtime' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.endtime'),
+			'sortBy' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.sortBy'),
+			'sortDirection' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.sortDirection')
+		];
+
+		$view->assign('data', $templateData);
+		return $view;
+	}
+
+	/**
+	 * Returns News by author View for Previews of sg_news
+	 *
+	 * @param array $row
+	 * @return StandaloneView
+	 */
+	public function getNewsByAuthorView(array $row): StandaloneView {
+		$view = $this->createViewWithTemplate('NewsByAuthor');
+		$view->assign('uid', $row['uid']);
+
+		// Get available plugin settings and their values from flexform
+		$pluginConfiguration = GeneralUtility::xml2array(
+			$row['pi_flexform'],
+			'T3DataStructure'
+		)['data']['main']['lDEF'];
+
+		$newsAuthors = $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.newsAuthors');
+		$templateData = [
+			'showDetails' => $this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.showDetails'),
+			'newsAuthors' => is_string($newsAuthors) ? $this->addFieldContentsToRecordIdList(
+				'tx_sgnews_domain_model_author',
+				$newsAuthors,
+				'name'
+			) : ''
+		];
+
+		// Not using addFieldContentsToRecordIdList to avoid repetitive imploding and exploding.
+		$excludedNewsIds = GeneralUtility::intExplode(
+			',',
+			$this->passVDefOnKeyToTemplate($pluginConfiguration, 'settings.excludedNews'),
+			TRUE
+		);
+		$excludedNewsListWithTitles = [];
+		foreach ($excludedNewsIds as $excludedNewsId) {
+			$excludedNewsListWithTitles[] = BackendUtility::getRecord(
+				'pages',
+				$excludedNewsId,
+				'title'
+			)['title'] . ' [' . $excludedNewsId . ']';
+		}
+		$templateData['excludedNews'] = $excludedNewsListWithTitles;
+
+		$view->assign('data', $templateData);
+		return $view;
+	}
+
+	/**
+	 * @param array $conf
+	 * @param string $key
+	 * @param string $returnType
+	 * @return array|mixed|string
+	 */
+	private function passVDefOnKeyToTemplate(array $conf, string $key, string $returnType = '') {
+		if (isset($conf[$key])) {
+			return $conf[$key]['vDEF'];
+		}
+
+		// check if we got a possible returntype:
+		if ($returnType === self::RETURNTYPE_ARR) {
+			return [];
+		}
+
+		return '';
+	}
+
+	/**
+	 * Creates a new StandaloneView object with template and partial root paths,
+	 * attaches the template with the given name to it and returns it.
+	 *
+	 * @param string $templateName
+	 * @return StandaloneView
+	 */
+	protected function createViewWithTemplate(string $templateName): StandaloneView {
+		$view = GeneralUtility::makeInstance(StandaloneView::class);
+		$view->setTemplateRootPaths(['EXT:sg_news/Resources/Private/Templates/Backend']);
+		$view->setPartialRootPaths(['EXT:sg_news/Resources/Private/Partials/Backend']);
+		if (!str_ends_with($templateName, '.html')) {
+			$templateName .= '.html';
+		}
+		$view->setTemplate($templateName);
+		return $view;
+	}
+
+	/**
+	 * Takes a comma-separated list of record IDs, the corresponding table and optionally the field to look up.
+	 * Returns another comma-space-separated list of the same records with the content of the field added.
+	 * The returned list should look nice enough to be rendered in the backend preview directly.
+	 *
+	 * @param string $table
+	 * @param string $recordIdList
+	 * @param string $field
+	 * @return string
+	 */
+	protected function addFieldContentsToRecordIdList(
+		string $table,
+		string $recordIdList,
+		string $field = 'title'
+	): string {
+		$recordIdsArray = GeneralUtility::intExplode(',', $recordIdList, TRUE);
+		$recordsWithTitlesArray = [];
+
+		foreach ($recordIdsArray as $recordId) {
+			$recordsWithTitlesArray[] = BackendUtility::getRecord(
+				$table,
+				$recordId,
+				$field
+			)[$field] . ' [' . $recordId . ']';
+		}
+		return implode(', ', $recordsWithTitlesArray);
+	}
+}
diff --git a/Classes/Service/ConfigurationService.php b/Classes/Service/ConfigurationService.php
index 4ee488f46b88b3388009592d9128ddf413d3125c..e2cdd4683ba7ebc560bc6f83ab5cbb2ffd9df269 100644
--- a/Classes/Service/ConfigurationService.php
+++ b/Classes/Service/ConfigurationService.php
@@ -36,7 +36,6 @@ use TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException;
  * This service provides helper function for dealing with plugin configuration
  */
 class ConfigurationService implements SingletonInterface {
-
 	/**
 	 * @var array
 	 */
diff --git a/Classes/Service/HeaderMetaDataService.php b/Classes/Service/HeaderMetaDataService.php
index aa686892aa0dd5eda059acb9dfb9e2429c1aba5a..f3c4e52bca8940334bdb657a155b6a0d7dc9eb64 100644
--- a/Classes/Service/HeaderMetaDataService.php
+++ b/Classes/Service/HeaderMetaDataService.php
@@ -44,11 +44,23 @@ class HeaderMetaDataService {
 	 * @return void
 	 */
 	public static function addOgImageToHeader($path): void {
-		/** @var $typoScriptController TypoScriptFrontendController */
+		/** @var TypoScriptFrontendController $typoScriptController */
 		$typoScriptController = $GLOBALS['TSFE'];
 		$typoScriptController->page['og_image_path_by_extension'] = $path;
 	}
 
+	/**
+	 * Sets the data for the og:image meta data header tag.
+	 *
+	 * @param FileReference $file
+	 * @return void
+	 */
+	public static function addOgImageObjectToHeader($file): void {
+		/** @var TypoScriptFrontendController $typoScriptController */
+		$typoScriptController = $GLOBALS['TSFE'];
+		$typoScriptController->page['og_image_path_by_extension'] = $file;
+	}
+
 	/**
 	 * Adds the page number to the canonical
 	 *
@@ -61,18 +73,13 @@ class HeaderMetaDataService {
 			return;
 		}
 
-		if (version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-			$headTagService = GeneralUtility::makeInstance(
-				HeadTagService::class,
-				FALSE,
-				'',
-				'',
-				'&tx_sgnews_pagebrowser[currentPage]=' . $currentPage
-			);
-			$headTagService->execute();
-		} else {
-			$GLOBALS['TSFE']->page['extensionArgumentsForCanonicalAndHrefLang'] =
-				'&tx_sgnews_pagebrowser[currentPage]=' . $currentPage;
-		}
+		$headTagService = GeneralUtility::makeInstance(
+			HeadTagService::class,
+			FALSE,
+			'',
+			'',
+			'&tx_sgnews_pagebrowser[currentPage]=' . $currentPage
+		);
+		$headTagService->execute();
 	}
 }
diff --git a/Classes/Service/ImageService.php b/Classes/Service/ImageService.php
index 67aa6736192b1e92ee796fb9e65c29e019043ca0..0438bb314fed6558d4385ec3d1e477a5b24a9717 100644
--- a/Classes/Service/ImageService.php
+++ b/Classes/Service/ImageService.php
@@ -61,7 +61,10 @@ class ImageService implements SingletonInterface {
 	 * @throws \InvalidArgumentException
 	 */
 	public function cropFirstMediaImage(
-		FileReference $image, array $coordinates, $path = 'typo3temp/sg_news/', $prefix = ''
+		FileReference $image,
+		array $coordinates,
+		$path = 'typo3temp/sg_news/',
+		$prefix = ''
 	): string {
 		$originalResource = $image->getOriginalResource();
 		$extension = strtolower($originalResource->getExtension());
diff --git a/Classes/TCA/TcaProvider.php b/Classes/TCA/TcaProvider.php
index c0ace7acee23cbd3f5eccfe44d7652ab4a88a3de..6594390e175eb86cb00e73a3aef592a15e86c889 100644
--- a/Classes/TCA/TcaProvider.php
+++ b/Classes/TCA/TcaProvider.php
@@ -35,7 +35,6 @@ use TYPO3\CMS\Extbase\Object\ObjectManager;
  * This class contains methods for usage within the TCA forms.
  */
 class TcaProvider implements SingletonInterface {
-
 	/**
 	 * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
 	 */
@@ -79,13 +78,13 @@ class TcaProvider implements SingletonInterface {
 					->where(
 						$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($pagesIdentity, \PDO::PARAM_INT))
 					)
-					->execute()->fetch();
+					->execute()->fetchAssociative();
 
 				$workspaceOriginalId = (int) $row['t3ver_oid'];
 				if ($workspaceOriginalId > 0) {
 					$row = $queryBuilder->where(
-							$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($workspaceOriginalId, \PDO::PARAM_INT))
-						)->execute()->fetch();
+						$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($workspaceOriginalId, \PDO::PARAM_INT))
+					)->execute()->fetchAssociative();
 				}
 
 				// only articles
diff --git a/Classes/Updates/MigrateSchedulerTasks.php b/Classes/Updates/MigrateSchedulerTasks.php
index b7af223e9e09c4d4b1dbcb770aad118f23eda876..00381f8e2658c2e6b5ae22b5bffbb255041c4b5a 100644
--- a/Classes/Updates/MigrateSchedulerTasks.php
+++ b/Classes/Updates/MigrateSchedulerTasks.php
@@ -41,7 +41,7 @@ class MigrateSchedulerTasks implements UpgradeWizardInterface {
 	/**
 	 * Identifier of the upgrade
 	 */
-	const IDENTIFIER = 'tx_sgnews_migrateschedulertasks';
+	public const IDENTIFIER = 'tx_sgnews_migrateschedulertasks';
 
 	/**
 	 * @inheritDoc
@@ -75,11 +75,11 @@ class MigrateSchedulerTasks implements UpgradeWizardInterface {
 			->from('tx_scheduler_task')
 			->where(
 				$queryBuilder->expr()->eq('disable', 0)
-			)->execute()->fetchAll();
+			)->execute()->fetchAllAssociative();
 		foreach ($tasks as $_task) {
 			$task = unserialize($_task['serialized_task_object'], [\__PHP_Incomplete_Class::class]);
 			$taskVars = $this->cleanArrayKeys((array)$task);
-			$identifier = $taskVars['*commandIdentifier'];
+			$identifier = $taskVars['*commandIdentifier'] ?? '';
 			if (
 				$identifier === 'sg_news:migratenews:runmigratenews'
 			) {
@@ -131,11 +131,11 @@ class MigrateSchedulerTasks implements UpgradeWizardInterface {
 			->from('tx_scheduler_task')
 			->where(
 				$queryBuilder->expr()->eq('disable', 0)
-			)->execute()->fetchAll();
+			)->execute()->fetchAllAssociative();
 		foreach ($tasks as $_task) {
 			$task = unserialize($_task['serialized_task_object'], [\__PHP_Incomplete_Class::class]);
 			$taskVars = $this->cleanArrayKeys((array)$task);
-			$identifier = $taskVars['*commandIdentifier'];
+			$identifier = $taskVars['*commandIdentifier'] ?? '';
 			if (
 				$identifier === 'sg_news:migratenews:runmigratenews'
 			) {
@@ -153,7 +153,7 @@ class MigrateSchedulerTasks implements UpgradeWizardInterface {
 	 */
 	protected function cleanArrayKeys(array $array) {
 		$newArray = [];
-		foreach($array as $key => $value) {
+		foreach ($array as $key => $value) {
 			$newArray[str_replace("\0", '', $key)] = $value;
 		}
 		return $newArray;
diff --git a/Classes/Updates/UpdateAuthors.php b/Classes/Updates/UpdateAuthors.php
index eb56fa715436765a2e45b831a0edc1f0f1a7b655..f87a04db977da9150056f55a3d2cf51b7e9608bc 100644
--- a/Classes/Updates/UpdateAuthors.php
+++ b/Classes/Updates/UpdateAuthors.php
@@ -41,7 +41,7 @@ class UpdateAuthors implements UpgradeWizardInterface {
 	/**
 	 * The wizard identifier
 	 */
-	const IDENTIFIER = 'tx_sgnews_update_authors';
+	public const IDENTIFIER = 'tx_sgnews_update_authors';
 
 	/**
 	 * Retrieves the next site root in the page hierarchy from the current page
@@ -86,6 +86,8 @@ class UpdateAuthors implements UpgradeWizardInterface {
 
 	/**
 	 * @return bool
+	 * @throws \Doctrine\DBAL\DBALException
+	 * @throws \Doctrine\DBAL\Driver\Exception
 	 */
 	public function executeUpdate(): bool {
 		$newsQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
@@ -98,7 +100,7 @@ class UpdateAuthors implements UpgradeWizardInterface {
 					$newsQueryBuilder->expr()->neq('author', $newsQueryBuilder->quote(''))
 				)
 			)
-			->execute()->fetchAll();
+			->execute()->fetchAllAssociative();
 		if (count($newsEntries) <= 0) {
 			return TRUE;
 		}
@@ -122,7 +124,7 @@ class UpdateAuthors implements UpgradeWizardInterface {
 					)
 				)
 				->setMaxResults(1)
-				->execute()->fetchAll();
+				->execute()->fetchAllAssociative();
 			if (!$author) {
 				$authorQueryBuilder->insert('tx_sgnews_domain_model_author')
 					->values([
diff --git a/Classes/UserFunction/AddAdditionalMailRecipients.php b/Classes/UserFunction/AddAdditionalMailRecipients.php
index 08d4644fa28e998289454620c85f50d792ae036d..dd1d5bf8c0a58c09b75095c786365a3a4eacc114 100644
--- a/Classes/UserFunction/AddAdditionalMailRecipients.php
+++ b/Classes/UserFunction/AddAdditionalMailRecipients.php
@@ -38,7 +38,7 @@ class AddAdditionalMailRecipients implements SingletonInterface {
 	/**
 	 * @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
 	 */
-	public $cObj;
+	protected $cObj;
 
 	/**
 	 * Adds the news authors to the additional mail recipients.
@@ -69,4 +69,8 @@ class AddAdditionalMailRecipients implements SingletonInterface {
 
 		return $authorEmail;
 	}
+
+	public function setContentObjectRenderer(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $cObj): void {
+		$this->cObj = $cObj;
+	}
 }
diff --git a/Classes/Utility/BackendNewsUtility.php b/Classes/Utility/BackendNewsUtility.php
index 4cb2354ff3afcc609df0fd6a15987630a4ff7ad9..47de86a49364d0ed542aa1190092b94803a4156d 100644
--- a/Classes/Utility/BackendNewsUtility.php
+++ b/Classes/Utility/BackendNewsUtility.php
@@ -50,16 +50,15 @@ use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
  * Class Utility
  */
 class BackendNewsUtility {
-
 	/**
 	 * @var int The category page doktype
 	 */
-	const CATEGORY_DOKTYPE = 117;
+	public const CATEGORY_DOKTYPE = 117;
 
 	/**
 	 * @var int The news page doktype
 	 */
-	const NEWS_DOKTYPE = 116;
+	public const NEWS_DOKTYPE = 116;
 
 	/**
 	 * Retrieves the next site root in the page hierarchy from the current page
@@ -92,7 +91,12 @@ class BackendNewsUtility {
 		$andWhere = ' AND sys_language_uid IN (0,-1)';
 		/** @var array $rootOptionRows */
 		$rootOptionRows = self::getRecordsByField(
-			'pages', 'is_siteroot', 1, $andWhere, '', 'sorting'
+			'pages',
+			'is_siteroot',
+			1,
+			$andWhere,
+			'',
+			'sorting'
 		);
 		if ($rootOptionRows) {
 			foreach ($rootOptionRows as $row) {
@@ -106,7 +110,8 @@ class BackendNewsUtility {
 				foreach ($categories as $categoryUid => $categoryTitle) {
 					if ((int) $pageInfo['uid'] !== $categoryUid) {
 						$categoryPageInfo = BackendUtility::readPageAccess(
-							$categoryUid, $GLOBALS['BE_USER']->getPagePermsClause(1)
+							$categoryUid,
+							$GLOBALS['BE_USER']->getPagePermsClause(1)
 						);
 						if ($categoryPageInfo) {
 							$options[] = self::getOptionPageInfo($categoryPageInfo);
@@ -154,7 +159,10 @@ class BackendNewsUtility {
 		// get all pageids below the given siteroot
 		$queryGenerator = GeneralUtility::makeInstance(QueryGenerator::class);
 		$childPids = $queryGenerator->getTreeList(
-			$siteRootUid, PHP_INT_MAX, 0, $GLOBALS['BE_USER']->getPagePermsClause(1)
+			$siteRootUid,
+			PHP_INT_MAX,
+			0,
+			$GLOBALS['BE_USER']->getPagePermsClause(1)
 		);
 
 		$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
@@ -167,11 +175,12 @@ class BackendNewsUtility {
 					$queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter(explode(',', $childPids), Connection::PARAM_INT_ARRAY))
 				)
 			)
-			->execute()->fetchAll();
+			->execute()->fetchAllAssociative();
 		$categories = [];
 		foreach ($result as $page) {
 			$categoryPageInfo = BackendUtility::readPageAccess(
-				(int) $page['uid'], $GLOBALS['BE_USER']->getPagePermsClause(1)
+				(int) $page['uid'],
+				$GLOBALS['BE_USER']->getPagePermsClause(1)
 			);
 			if ($categoryPageInfo) {
 				$categories[(int) $page['uid']] = $page['title'];
@@ -207,11 +216,14 @@ class BackendNewsUtility {
 		$querySettings = $query->getQuerySettings();
 		$querySettings->setLanguageUid($languageUid);
 		$querySettings->setLanguageOverlayMode(TRUE);
-		$querySettings->setLanguageMode('content_fallback');
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			$querySettings->setLanguageMode('content_fallback');
+		}
+
 		$query->setQuerySettings($querySettings);
 		if ($pageUid) {
 			$rootline = BackendUtility::BEgetRootLine($pageUid, '', TRUE);
-			$pageTS = BackendUtility::getPagesTSconfig($pageUid, $rootline);
+			$pageTS = BackendUtility::getPagesTSconfig($pageUid);
 
 			$tagsPid = 0;
 			if (isset($pageTS['TCEFORM.']['pages.']['tx_sgnews_tags.']['PAGE_TSCONFIG_ID'])) {
@@ -262,7 +274,9 @@ class BackendNewsUtility {
 		$querySettings = $query->getQuerySettings();
 		$querySettings->setLanguageUid($languageUid);
 		$querySettings->setLanguageOverlayMode(TRUE);
-		$querySettings->setLanguageMode('content_fallback');
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			$querySettings->setLanguageMode('content_fallback');
+		}
 		$query->setQuerySettings($querySettings);
 		if ($newsItemUid) {
 			$query->matching($query->equals('uid', $newsItemUid));
@@ -293,7 +307,7 @@ class BackendNewsUtility {
 	 * @return array
 	 * @throws \InvalidArgumentException
 	 */
-	public static function getNewsByFilters($rootPageUid = 0, array $filters = [], $languageUid = 0): array {
+	public static function getNewsByFilters($rootPageUid = 0, array $filters = [], $languageUid = 0, $limit = 0): array {
 		$out = [];
 		$rootPageUid = (int) $rootPageUid;
 		$languageUid = (int) $languageUid;
@@ -312,7 +326,8 @@ class BackendNewsUtility {
 			$filterCategories = $filters['categories'];
 			foreach ($filterCategories as $categoryUid) {
 				$categoryPageInfo = BackendUtility::readPageAccess(
-					(int) $categoryUid, $GLOBALS['BE_USER']->getPagePermsClause(1)
+					(int) $categoryUid,
+					$GLOBALS['BE_USER']->getPagePermsClause(1)
 				);
 				if ($categoryPageInfo) {
 					$categories[] = (int) $categoryUid;
@@ -328,9 +343,14 @@ class BackendNewsUtility {
 		$allowedUids = [];
 		foreach ($categories as $categoryUid) {
 			$allowedUidsTemp = GeneralUtility::intExplode(
-				',', $queryGenerator->getTreeList(
-				$categoryUid, 1, 0, $GLOBALS['BE_USER']->getPagePermsClause(1)
-			), TRUE
+				',',
+				$queryGenerator->getTreeList(
+					$categoryUid,
+					1,
+					0,
+					$GLOBALS['BE_USER']->getPagePermsClause(1)
+				),
+				TRUE
 			);
 			$allowedUids = array_unique(array_merge($allowedUids, $allowedUidsTemp));
 		}
@@ -343,13 +363,20 @@ class BackendNewsUtility {
 		$deletedRestriction = GeneralUtility::makeInstance(DeletedRestriction::class);
 		$queryBuilder = $connectionPool->getQueryBuilderForTable('pages');
 		$queryBuilder->getRestrictions()->removeAll()->add($deletedRestriction);
-		$queryBuilder->select('p.uid',
-				'p.pid',
-				'p.hidden',
-				'p.sorting',
-				'p.doktype',
-				'p.title'
-			)->from('pages', 'p')
+		$queryBuilder->select(
+			'p.uid',
+			'p.pid',
+			'p.hidden',
+			'p.sorting',
+			'p.doktype',
+			'p.nav_hide',
+			'p.t3ver_state',
+			'p.starttime',
+			'p.endtime',
+			'p.fe_group',
+			'p.l10n_parent',
+			'p.title'
+		)->from('pages', 'p')
 			->where(
 				$queryBuilder->expr()->andX(
 					$queryBuilder->expr()->in('p.uid', $queryBuilder->createNamedParameter($allowedUids, Connection::PARAM_INT_ARRAY)),
@@ -359,7 +386,10 @@ class BackendNewsUtility {
 			->groupBy('p.uid')
 			->orderBy('p.sorting');
 		if ($languageUid) {
-			$queryBuilder->leftJoin('p', 'pages', 'translation',
+			$queryBuilder->leftJoin(
+				'p',
+				'pages',
+				'translation',
 				$queryBuilder->expr()->andX(
 					$queryBuilder->expr()->eq('translation.l10n_parent', 'p.uid'),
 					$queryBuilder->expr()->eq('translation.sys_language_uid', $queryBuilder->createNamedParameter($languageUid, \PDO::PARAM_INT))
@@ -368,7 +398,10 @@ class BackendNewsUtility {
 		}
 
 		if (isset($filters['tags']) && is_array($filters['tags']) && count($filters['tags'])) {
-			$queryBuilder->innerJoin('p', 'sys_category_record_mm', 'tag',
+			$queryBuilder->innerJoin(
+				'p',
+				'sys_category_record_mm',
+				'tag',
 				$queryBuilder->expr()->andX(
 					$queryBuilder->expr()->eq('tag.tablenames', $queryBuilder->createNamedParameter('pages')),
 					$queryBuilder->expr()->eq('tag.fieldname', $queryBuilder->createNamedParameter('tx_sgnews_tags')),
@@ -400,7 +433,7 @@ class BackendNewsUtility {
 						$authorQueryBuilder->expr()->like('author.name', $authorSearchParameter),
 						$authorQueryBuilder->expr()->like('author.email', $authorSearchParameter)
 					)
-				)->execute()->fetchAll();
+				)->execute()->fetchAllAssociative();
 
 			if (count($authors) > 0) {
 				foreach (array_column($authors, 'uid') as $authorUid) {
@@ -414,8 +447,11 @@ class BackendNewsUtility {
 				)
 			);
 		}
+		if ($limit > 0) {
+			$queryBuilder->setMaxResults($limit);
+		}
 
-		return $queryBuilder->execute()->fetchAll();
+		return [$queryBuilder->execute()->fetchAllAssociative(), $queryBuilder];
 	}
 
 	/**
@@ -429,7 +465,7 @@ class BackendNewsUtility {
 		$pageUid = (int) $pageUid;
 		$rootline = BackendUtility::BEgetRootLine($pageUid, '', TRUE);
 		$defaultLanguage = LocalizationUtility::translate('backend.language.default', 'SgNews');
-		$pageTS = BackendUtility::getPagesTSconfig($pageUid, $rootline);
+		$pageTS = BackendUtility::getPagesTSconfig($pageUid);
 		if (isset($pageTS['mod.']['SHARED.']['defaultLanguageLabel'])) {
 			$defaultLanguage = $pageTS['mod.']['SHARED.']['defaultLanguageLabel'] . ' (' . $defaultLanguage . ')';
 		}
@@ -446,7 +482,7 @@ class BackendNewsUtility {
 		$languageRows = $queryBuilder->select('uid', 'title', 'flag')
 			->from('sys_language')
 			->orderBy('sorting')
-			->execute()->fetchAll();
+			->execute()->fetchAllAssociative();
 		if ($languageRows) {
 			/** @var BackendUserAuthentication $backendUser */
 			$backendUser = $GLOBALS['BE_USER'];
@@ -479,12 +515,19 @@ class BackendNewsUtility {
 	 * @return mixed Multidimensional array with selected records (if any is selected)
 	 */
 	public static function getRecordsByField(
-		$theTable, $theField, $theValue, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '',
+		$theTable,
+		$theField,
+		$theValue,
+		$whereClause = '',
+		$groupBy = '',
+		$orderBy = '',
+		$limit = '',
 		$useDeleteClause = TRUE
 	) {
 		if (is_array($GLOBALS['TCA'][$theTable])) {
 			$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($theTable);
-			$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));;
+			$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
+			;
 			if ($useDeleteClause) {
 				$queryBuilder->getRestrictions()
 					->add(GeneralUtility::makeInstance(DeletedRestriction::class));
@@ -508,7 +551,7 @@ class BackendNewsUtility {
 			// order by
 			if ($orderBy !== '') {
 				foreach (QueryHelper::parseOrderBy($orderBy) as $orderPair) {
-					list($fieldName, $order) = $orderPair;
+					[$fieldName, $order] = $orderPair;
 					$queryBuilder->addOrderBy($fieldName, $order);
 				}
 			}
@@ -524,7 +567,7 @@ class BackendNewsUtility {
 				}
 			}
 
-			return $queryBuilder->execute()->fetchAll();
+			return $queryBuilder->execute()->fetchAllAssociative();
 		}
 
 		return NULL;
diff --git a/Classes/ViewHelpers/AbstractViewHelper.php b/Classes/ViewHelpers/AbstractViewHelper.php
index 87cb14a7473934b6d3414e683dd487ae198d2c70..740f8f26da8241cd413f59437c516d78ca202a13 100644
--- a/Classes/ViewHelpers/AbstractViewHelper.php
+++ b/Classes/ViewHelpers/AbstractViewHelper.php
@@ -32,7 +32,6 @@ use TYPO3\CMS\Fluid\ViewHelpers\Be\AbstractBackendViewHelper;
  * Abstract view helper
  */
 class AbstractViewHelper extends AbstractBackendViewHelper {
-
 	/**
 	 * @var boolean
 	 */
diff --git a/Classes/ViewHelpers/Backend/ControlViewHelper.php b/Classes/ViewHelpers/Backend/ControlViewHelper.php
index 9ec52630991bc5cd0841d9dcf47903d301c01cc7..807864ce1102c69dd4f97161143bf749f80dc035 100644
--- a/Classes/ViewHelpers/Backend/ControlViewHelper.php
+++ b/Classes/ViewHelpers/Backend/ControlViewHelper.php
@@ -39,7 +39,6 @@ use TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList;
  * Class ControlViewHelper
  **/
 class ControlViewHelper extends AbstractViewHelper {
-
 	/**
 	 * Initialize the ViewHelper arguments
 	 */
@@ -66,9 +65,22 @@ class ControlViewHelper extends AbstractViewHelper {
 		}
 
 		$databaseRecordList = GeneralUtility::makeInstance(DatabaseRecordList::class);
+		if ($table === 'pages') {
+			if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+				$databaseRecordList->searchlevels = 1;
+			} else {
+				// searchLevels is Init with 0 and can only be set by using ->start
+				$databaseRecordList->start($row['uid'], $table, 0, '', 1, 1);
+			}
+		}
+
 		$backendUser = $GLOBALS['BE_USER'];
 		$pageInfo = BackendUtility::readPageAccess($row['pid'], $backendUser->getPagePermsClause(1));
-		$databaseRecordList->calcPerms = $GLOBALS['BE_USER']->calcPerms($pageInfo);
+		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
+			$databaseRecordList->calcPerms = $GLOBALS['BE_USER']->calcPerms($pageInfo);
+		} else {
+			$databaseRecordList->calcPerms = new \TYPO3\CMS\Core\Type\Bitmask\Permission($GLOBALS['BE_USER']->calcPerms($pageInfo));
+		}
 		$pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
 		$pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/AjaxDataHandler');
 		$pageRenderer->addInlineLanguageLabelFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf');
@@ -76,9 +88,7 @@ class ControlViewHelper extends AbstractViewHelper {
 		$languageService->includeLLFile('EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf');
 
 		$databaseRecordList->currentTable = $sortingData;
-		if ($table === 'pages') {
-			$databaseRecordList->searchLevels = 1;
-		}
+
 
 		$out = $databaseRecordList->makeControl($table, $row);
 		if ($table === 'pages') {
diff --git a/Classes/ViewHelpers/Backend/IconViewHelper.php b/Classes/ViewHelpers/Backend/IconViewHelper.php
index 5788ca4d81acf229368e7c31b2566c411188b021..981acef8eca1db5ebbcd56aeaca3de07ed76a840 100644
--- a/Classes/ViewHelpers/Backend/IconViewHelper.php
+++ b/Classes/ViewHelpers/Backend/IconViewHelper.php
@@ -35,7 +35,6 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * Class IconViewHelper
  **/
 class IconViewHelper extends AbstractViewHelper {
-
 	/**
 	 * Initialize the ViewHelper arguments
 	 */
@@ -58,13 +57,13 @@ class IconViewHelper extends AbstractViewHelper {
 		$size = trim($this->arguments['size']);
 		$overlayId = $this->arguments['overlayId'];
 		switch ($size) {
-			case 'small' :
+			case 'small':
 				$size = Icon::SIZE_SMALL;
 				break;
-			case 'large' :
+			case 'large':
 				$size = Icon::SIZE_LARGE;
 				break;
-			default :
+			default:
 				$size = Icon::SIZE_DEFAULT;
 				break;
 		}
diff --git a/Classes/ViewHelpers/Backend/Link/NewRecordViewHelper.php b/Classes/ViewHelpers/Backend/Link/NewRecordViewHelper.php
index 6fce666ac733b9091d855fbfb781ee0d8ff3678e..a496db6999c9771a5fd883cfca32663b54a6388b 100644
--- a/Classes/ViewHelpers/Backend/Link/NewRecordViewHelper.php
+++ b/Classes/ViewHelpers/Backend/Link/NewRecordViewHelper.php
@@ -78,45 +78,42 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
  *
  *    <be:link.newRecord table="a_table" returnUrl="{f:be.uri(route: 'web_MyextensionList')}" pid="17">
  */
-class NewRecordViewHelper extends AbstractTagBasedViewHelper
-{
-    /**
-     * @var string
-     */
-    protected $tagName = 'a';
+class NewRecordViewHelper extends AbstractTagBasedViewHelper {
+	/**
+	 * @var string
+	 */
+	protected $tagName = 'a';
 
-    public function initializeArguments()
-    {
-        parent::initializeArguments();
-        $this->registerUniversalTagAttributes();
-        $this->registerArgument('uid', 'int', 'uid < 0 will insert the record after the given uid', false);
-        $this->registerArgument('pid', 'int', 'the page id where the record will be created', false);
-        $this->registerArgument('table', 'string', 'target database table', true);
-		$this->registerArgument('type', 'string', 'The type of the news', true);
-        $this->registerArgument('returnUrl', 'string', 'return to this URL after closing the edit dialog', false, '');
-    }
+	public function initializeArguments() {
+		parent::initializeArguments();
+		$this->registerUniversalTagAttributes();
+		$this->registerArgument('uid', 'int', 'uid < 0 will insert the record after the given uid', FALSE);
+		$this->registerArgument('pid', 'int', 'the page id where the record will be created', FALSE);
+		$this->registerArgument('table', 'string', 'target database table', TRUE);
+		$this->registerArgument('type', 'string', 'The type of the news', TRUE);
+		$this->registerArgument('returnUrl', 'string', 'return to this URL after closing the edit dialog', FALSE, '');
+	}
 
-    /**
-     * @return string
-     * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
-     */
-    public function render(): string
-    {
-        if ($this->arguments['uid'] && $this->arguments['pid']) {
-            throw new \InvalidArgumentException('Can\'t handle both uid and pid for new records', 1526129969);
-        }
-        if (isset($this->arguments['uid']) && $this->arguments['uid'] >= 0) {
-            throw new \InvalidArgumentException('Uid must be negative integer, ' . $this->arguments['uid'] . ' given', 1526134901);
-        }
+	/**
+	 * @return string
+	 * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
+	 */
+	public function render(): string {
+		if ($this->arguments['uid'] && $this->arguments['pid']) {
+			throw new \InvalidArgumentException('Can\'t handle both uid and pid for new records', 1526129969);
+		}
+		if (isset($this->arguments['uid']) && $this->arguments['uid'] >= 0) {
+			throw new \InvalidArgumentException('Uid must be negative integer, ' . $this->arguments['uid'] . ' given', 1526134901);
+		}
 
-        if (empty($this->arguments['returnUrl'])) {
-            $this->arguments['returnUrl'] = GeneralUtility::getIndpEnv('REQUEST_URI');
-        }
+		if (empty($this->arguments['returnUrl'])) {
+			$this->arguments['returnUrl'] = GeneralUtility::getIndpEnv('REQUEST_URI');
+		}
 
-        $params = [
-            'edit' => [$this->arguments['table'] => [$this->arguments['uid'] ?? $this->arguments['pid'] ?? 0 => 'new']],
-            'returnUrl' => $this->arguments['returnUrl']
-        ];
+		$params = [
+			'edit' => [$this->arguments['table'] => [$this->arguments['uid'] ?? $this->arguments['pid'] ?? 0 => 'new']],
+			'returnUrl' => $this->arguments['returnUrl']
+		];
 		if ($this->arguments['table'] === 'pages' && in_array($this->arguments['type'], ['news', 'category'], TRUE)) {
 			$params['overrideVals'] = [
 				'pages' => [
@@ -125,11 +122,11 @@ class NewRecordViewHelper extends AbstractTagBasedViewHelper
 			];
 		}
 
-        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
-        $uri = (string)$uriBuilder->buildUriFromRoute('record_edit', $params);
-        $this->tag->addAttribute('href', $uri);
-        $this->tag->setContent($this->renderChildren());
-        $this->tag->forceClosingTag(true);
-        return $this->tag->render();
-    }
+		$uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
+		$uri = (string)$uriBuilder->buildUriFromRoute('record_edit', $params);
+		$this->tag->addAttribute('href', $uri);
+		$this->tag->setContent($this->renderChildren());
+		$this->tag->forceClosingTag(TRUE);
+		return $this->tag->render();
+	}
 }
diff --git a/Classes/ViewHelpers/Backend/NewsItemTagsViewHelper.php b/Classes/ViewHelpers/Backend/NewsItemTagsViewHelper.php
index ebaa2980d917bcea4fd960c176381ac16a32fb95..d8ba9a15d3c44eeb6c551290bcc50d5874f7eaa2 100644
--- a/Classes/ViewHelpers/Backend/NewsItemTagsViewHelper.php
+++ b/Classes/ViewHelpers/Backend/NewsItemTagsViewHelper.php
@@ -33,7 +33,6 @@ use SGalinski\SgNews\ViewHelpers\AbstractViewHelper;
  * Class EditOnClickViewHelper
  **/
 class NewsItemTagsViewHelper extends AbstractViewHelper {
-
 	/**
 	 * Initialize the ViewHelper arguments
 	 */
diff --git a/Classes/ViewHelpers/Backend/RecordIconViewHelper.php b/Classes/ViewHelpers/Backend/RecordIconViewHelper.php
index 20f18b705713daa8d7002da845edd6eb01f511f3..d7d6be0a2cc21d60eb3958283a0354fc49ba4588 100644
--- a/Classes/ViewHelpers/Backend/RecordIconViewHelper.php
+++ b/Classes/ViewHelpers/Backend/RecordIconViewHelper.php
@@ -36,7 +36,6 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * Class IconViewHelper
  **/
 class RecordIconViewHelper extends AbstractViewHelper {
-
 	/**
 	 * Initialize the ViewHelper arguments
 	 */
diff --git a/Classes/ViewHelpers/Backend/TranslationLinksViewHelper.php b/Classes/ViewHelpers/Backend/TranslationLinksViewHelper.php
index 56e190c67ee06cc7e394718159f450b8792bd630..c7f08571b077d168cc9210ada42847da4dd140af 100644
--- a/Classes/ViewHelpers/Backend/TranslationLinksViewHelper.php
+++ b/Classes/ViewHelpers/Backend/TranslationLinksViewHelper.php
@@ -40,7 +40,6 @@ use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
  * Class EditOnClickViewHelper
  **/
 class TranslationLinksViewHelper extends AbstractViewHelper {
-
 	/**
 	 * Register the ViewHelp0er arguments
 	 */
@@ -115,13 +114,14 @@ class TranslationLinksViewHelper extends AbstractViewHelper {
 							'returnUrl' => (string) $returnUrl
 						]);
 
-					$out .= ' <a href="' . $link . '" title="'. $language['title'] . ' [' . $editLabel . ']" >'
+					$out .= ' <a href="' . $link . '" title="' . $language['title'] . ' [' . $editLabel . ']" >'
 						. $iconFactory->getIcon($language['flag'], Icon::SIZE_SMALL)->render()
 						. '</a>';
 				} else {
 					$out .= ' <a href="'
 						. BackendUtility::getLinkToDataHandlerAction(
-							sprintf($translationParameters, $languageUid), $returnUrl
+							sprintf($translationParameters, $languageUid),
+							$returnUrl
 						)
 						. '" title="' . $language['title'] . ' [' . $newLabel . ']" >'
 						. $iconFactory->getIcon(
diff --git a/Classes/ViewHelpers/Backend/Widget/Controller/PaginateController.php b/Classes/ViewHelpers/Backend/Widget/Controller/PaginateController.php
deleted file mode 100644
index 3b1f2ea17ce7fd1b4656de6f6ed279dcd29bdd47..0000000000000000000000000000000000000000
--- a/Classes/ViewHelpers/Backend/Widget/Controller/PaginateController.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-
-namespace SGalinski\SgNews\ViewHelpers\Backend\Widget\Controller;
-
-/***************************************************************
- *  Copyright notice
- *
- *  (c) sgalinski Internet Services (https://www.sgalinski.de)
- *
- *  All rights reserved
- *
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
-
-use TYPO3\CMS\Extbase\Persistence\Generic\Query;
-use TYPO3\CMS\Fluid\ViewHelpers\Be\Widget\Controller\PaginateController as FluidPaginateController;
-
-/**
- * Class PaginateController
- */
-class PaginateController extends FluidPaginateController {
-
-	/**
-	 * @var mixed
-	 */
-	protected $objects;
-
-	/**
-	 * Renders the paginator
-	 *
-	 * @param int $currentPage
-	 * @return void
-	 * @throws \InvalidArgumentException
-	 */
-	public function indexAction($currentPage = 1) {
-		// set current page
-		$this->currentPage = (int) $currentPage;
-		if ($this->currentPage < 1) {
-			$this->currentPage = 1;
-		}
-		if ($this->currentPage > $this->numberOfPages) {
-			// set $modifiedObjects to NULL if the page does not exist
-			$modifiedObjects = NULL;
-		} else {
-			// modify query
-			$this->itemsPerPage = (int) $this->configuration['itemsPerPage'];
-			$this->offset = $this->itemsPerPage * ($this->currentPage - 1);
-			if (is_array($this->objects)) {
-				$modifiedObjects = [];
-				for ($index = $this->offset; $index < $this->offset + $this->itemsPerPage; $index++) {
-					if (isset($this->objects[$index])) {
-						$modifiedObjects[] = $this->objects[$index];
-					} else {
-						break;
-					}
-				}
-			} else {
-				/** @var Query $query */
-				$query = $this->objects->getQuery();
-				$query->setLimit($this->itemsPerPage);
-				if ($this->currentPage > 1) {
-					$query->setOffset($this->offset);
-				}
-				$modifiedObjects = $query->execute();
-			}
-		}
-		$this->view->assign(
-			'contentArguments', [
-				$this->widgetConfiguration['as'] => $modifiedObjects
-			]
-		);
-		$this->view->assign('configuration', $this->configuration);
-		$this->view->assign('pagination', $this->buildPagination());
-	}
-
-	/**
-	 * Returns an array with the keys "pages", "current", "numberOfPages",
-	 * "nextPage" & "previousPage"
-	 *
-	 * @return array
-	 */
-	protected function buildPagination(): array {
-		$pagination = parent::buildPagination();
-		$pagination['totalObjects'] = count($this->objects);
-		return $pagination;
-	}
-}
diff --git a/Classes/ViewHelpers/Backend/Widget/PaginateViewHelper.php b/Classes/ViewHelpers/Backend/Widget/PaginateViewHelper.php
deleted file mode 100644
index 644806b9d8baa9ed11e7c0288846750fd119d2c6..0000000000000000000000000000000000000000
--- a/Classes/ViewHelpers/Backend/Widget/PaginateViewHelper.php
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-
-namespace SGalinski\SgNews\ViewHelpers\Backend\Widget;
-
-/***************************************************************
- *  Copyright notice
- *
- *  (c) sgalinski Internet Services (https://www.sgalinski.de)
- *
- *  All rights reserved
- *
- *  This script is part of the TYPO3 project. The TYPO3 project is
- *  free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  The GNU General Public License can be found at
- *  http://www.gnu.org/copyleft/gpl.html.
- *
- *  This script is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  This copyright notice MUST APPEAR in all copies of the script!
- ***************************************************************/
-use SGalinski\SgNews\ViewHelpers\Backend\Widget\Controller\PaginateController;
-use TYPO3\CMS\Fluid\Core\Widget\AbstractWidgetViewHelper;
-
-/**
- * Class PaginateViewHelper
- */
-class PaginateViewHelper extends AbstractWidgetViewHelper {
-	/**
-	 * @var PaginateController
-	 */
-	protected $controller;
-
-	/**
-	 * Initializes the controller
-	 *
-	 * @param PaginateController $controller
-	 */
-	public function injectPaginateController(PaginateController $controller) {
-		$this->controller = $controller;
-	}
-
-	/**
-	 * Initialize the ViewHelper arguments
-	 */
-	public function initializeArguments() {
-		parent::initializeArguments();
-		$this->registerArgument('objects', 'mixed', 'The objects to paginate', TRUE);
-		$this->registerArgument('as', 'string', 'The name of the variable inside the pagination', TRUE);
-		$this->registerArgument(
-			'configuration',
-			'array',
-			'The configuration of the pagination',
-			FALSE,
-			[
-				'itemsPerPage' => 10,
-				'insertAbove' => FALSE,
-				'insertBelow' => TRUE,
-				'recordsLabel' => ''
-			]
-		);
-	}
-
-	/**
-	 * Renders the paginator
-	 *
-	 * @return string
-	 * @throws \TYPO3\CMS\Fluid\Core\Widget\Exception\MissingControllerException
-	 */
-	public function render(): string {
-		return $this->initiateSubRequest();
-	}
-}
diff --git a/Classes/ViewHelpers/GetReadingTimeViewHelper.php b/Classes/ViewHelpers/GetReadingTimeViewHelper.php
index eb601920b7563f7c97099834374ab3c6279a9cfd..bb11302bc3557ee17cbc4d8735465de03dd08411 100644
--- a/Classes/ViewHelpers/GetReadingTimeViewHelper.php
+++ b/Classes/ViewHelpers/GetReadingTimeViewHelper.php
@@ -36,7 +36,6 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
  * <sg:getReadingTime content="" />
  */
 class GetReadingTimeViewHelper extends AbstractViewHelper {
-
 	/**
 	 * Register the ViewHelper arguments
 	 */
diff --git a/Classes/ViewHelpers/RelatedViewHelper.php b/Classes/ViewHelpers/RelatedViewHelper.php
index 69b8e781d353728940d593b4788c082e934de247..3be86fcc2b3790134b21996350e11ae802a970ce 100644
--- a/Classes/ViewHelpers/RelatedViewHelper.php
+++ b/Classes/ViewHelpers/RelatedViewHelper.php
@@ -19,7 +19,7 @@ class RelatedViewHelper extends AbstractViewHelper {
 	/**
 	 * @var bool
 	 */
-	protected $escapeOutput = false;
+	protected $escapeOutput = FALSE;
 
 	/**
 	 * Initialize the view helper arguments
@@ -45,7 +45,8 @@ class RelatedViewHelper extends AbstractViewHelper {
 			TRUE
 		);
 		$this->registerArgument(
-			'iteration', 'string',
+			'iteration',
+			'string',
 			'The name of the variable to store iteration information (index, cycle, isFirst, isLast, isEven, isOdd)'
 		);
 		$this->registerArgument(
@@ -68,7 +69,9 @@ class RelatedViewHelper extends AbstractViewHelper {
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
 	public static function renderStatic(
-		array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext
+		array $arguments,
+		\Closure $renderChildrenClosure,
+		RenderingContextInterface $renderingContext
 	) {
 		$newsService = GeneralUtility::makeInstance(NewsService::class);
 		$categoryRepository = GeneralUtility::makeInstance(CategoryRepository::class);
diff --git a/Classes/ViewHelpers/RenderAuthorNewsViewHelper.php b/Classes/ViewHelpers/RenderAuthorNewsViewHelper.php
index 8a6bccd56ec0fd1d6fa516bc6cb36fcee265f244..07643323d37017d2c595025cdfd6a130a5e584d9 100644
--- a/Classes/ViewHelpers/RenderAuthorNewsViewHelper.php
+++ b/Classes/ViewHelpers/RenderAuthorNewsViewHelper.php
@@ -61,7 +61,7 @@ class RenderAuthorNewsViewHelper extends AbstractViewHelper {
 	/**
 	 * Initialize arguments.
 	 *
-	 * @throws \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
+	 * @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception
 	 * @return void
 	 * @throws \TYPO3Fluid\Fluid\Core\ViewHelper\Exception
 	 */
diff --git a/Classes/Xclass/PageRenderer.php b/Classes/Xclass/PageRenderer.php
index 2a26a5b62c792ac2239ee778b14980b2eb76865d..84583eb353686619902f1de1ab07f5415045b5f2 100755
--- a/Classes/Xclass/PageRenderer.php
+++ b/Classes/Xclass/PageRenderer.php
@@ -58,7 +58,9 @@ class PageRenderer extends \TYPO3\CMS\Core\Page\PageRenderer {
 		if (is_array($this->headerDataRegex)) {
 			foreach ($this->headerDataRegex as $regex) {
 				$this->headerData = preg_replace(
-					'/' . $regex['pattern'] . '/is', $regex['replacement'], $this->headerData
+					'/' . $regex['pattern'] . '/is',
+					$regex['replacement'],
+					$this->headerData
 				);
 			}
 		}
@@ -72,7 +74,9 @@ class PageRenderer extends \TYPO3\CMS\Core\Page\PageRenderer {
 	 * @param string $substituteHash
 	 * @return string
 	 */
-	public function renderJavaScriptAndCssForProcessingOfUncachedContentObjects($cachedPageContent, $substituteHash
+	public function renderJavaScriptAndCssForProcessingOfUncachedContentObjects(
+		$cachedPageContent,
+		$substituteHash
 	): string {
 		$this->executeHeaderRegularExpressions();
 		return parent::renderJavaScriptAndCssForProcessingOfUncachedContentObjects($cachedPageContent, $substituteHash);
diff --git a/Configuration/Commands.php b/Configuration/Commands.php
deleted file mode 100644
index 813f2eed18af07382c22a5a6c20bad8a1c1a2ecd..0000000000000000000000000000000000000000
--- a/Configuration/Commands.php
+++ /dev/null
@@ -1,6 +0,0 @@
-<?php
-return [
-	'sg_news:migrateNews' => [
-		'class' => \SGalinski\SgNews\Command\MigrateNewsCommandController::class
-	]
-];
diff --git a/Configuration/Extbase/Persistence/Classes.php b/Configuration/Extbase/Persistence/Classes.php
index bd14047d646e2916741aab1b5792740200bbc634..8513d90f04b09ad8247980b88ed4fcf15c2cb14b 100644
--- a/Configuration/Extbase/Persistence/Classes.php
+++ b/Configuration/Extbase/Persistence/Classes.php
@@ -1,4 +1,5 @@
 <?php
+
 declare(strict_types=1);
 
 // if you need to change this, keep in mind the changes need to be done in
diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml
index 9afc78e3bafed7f16ff66441ba06742b01bbbb21..3c0cb4eb296d3f3af857a2d25f8cf085b274211c 100644
--- a/Configuration/Services.yaml
+++ b/Configuration/Services.yaml
@@ -1,8 +1,17 @@
 services:
-    _defaults:
-        autowire: true
-        autoconfigure: true
-        public: true
+  _defaults:
+      autowire: true
+      autoconfigure: true
+      public: false
 
-    SGalinski\SgNews\:
-        resource: '../Classes/*'
+  SGalinski\SgNews\:
+      resource: '../Classes/*'
+
+  SGalinski\SgNews\Preview\PreviewRenderer:
+    public: true
+
+# Commands
+  SGalinski\SgNews\Command\MigrateNewsCommandController:
+    tags:
+      - name: 'console.command'
+        command: 'sg_news:migrateNews'
diff --git a/Configuration/TCA/Overrides/pages.php b/Configuration/TCA/Overrides/pages.php
index 89fe28395137c140dcd5645668a8ae94ba8d72f2..d67c9e9cb2bbf2654233b55cb2677642943263c5 100644
--- a/Configuration/TCA/Overrides/pages.php
+++ b/Configuration/TCA/Overrides/pages.php
@@ -1,5 +1,6 @@
 <?php
 
+defined('TYPO3') or die();
 /**
  *
  * Copyright notice
@@ -56,121 +57,68 @@ foreach (
 	];
 }
 
-if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-	$GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility::NEWS_DOKTYPE] = [
-		'showitem' => '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
-			--palette--;;standard,
-			--palette--;;titleDescriptionAndHighlightFlag,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.editorial;editorialWithNewsAuthor,
-			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,
-				--palette--;;robots,
-				--palette--;;canonical,
-				--palette--;;sitemap,
-		--div--;LLL:EXT:seo/Resources/Private/Language/locallang_tca.xlf:pages.tabs.socialmedia,
-			--palette--;;opengraph,
-			--palette--;;twittercards,
-		--div--;' . $localLangDbPath . 'pages.tabs.images,
-			tx_sgnews_teaser2_image, tx_sgnews_teaser1_image,
-			--palette--;;media,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.metadata,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.abstract;abstract,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.appearance,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.layout;layout,
-		--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.visibility;visibility,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.access;access,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.behaviour,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.caching;caching,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.miscellaneous;miscellaneous,
-		--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
-			--palette--;;language
-		'
-	];
-} else {
-	$GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility::NEWS_DOKTYPE] = [
-		'showitem' => '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
-			--palette--;;standard,
-			--palette--;;titleDescriptionAndHighlightFlag,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.editorial;editorialWithNewsAuthor,
-			tx_sgnews_content_from_another_page, tx_sgnews_related_news, tx_sgnews_tags,
-		--div--;' . $localLangDbPath . 'pages.tabs.images,
-			tx_sgnews_teaser2_image, tx_sgnews_teaser1_image,
-			--palette--;;media,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.metadata,
-			tx_projectbase_devnullrobots_flags,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.abstract;abstract,
-			tx_projectbase_seo_titletag,tx_projectbase_seo_canonicaltag,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.appearance,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.layout;layout,
-		--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.visibility;visibility,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.access;access,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.behaviour,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.caching;caching,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.miscellaneous;miscellaneous,
-		--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
-			--palette--;;language
-		'
-	];
-}
-if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-	$GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility::CATEGORY_DOKTYPE] = [
-		'showitem' => '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
-			--palette--;;standard,
-			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,
-				--palette--;;robots,
-				--palette--;;canonical,
-				--palette--;;sitemap,
-		--div--;LLL:EXT:seo/Resources/Private/Language/locallang_tca.xlf:pages.tabs.socialmedia,
-			--palette--;;opengraph,
-			--palette--;;twittercards,
-		--div--;' . $localLangDbPath . 'pages.tabs.images,
-			tx_sgnews_teaser2_image, tx_sgnews_teaser1_image,
-			--palette--;;media,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.metadata,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.abstract;abstract,
-			seo_title,canonical_link, ' . (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('yoast_seo') || \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('seo') ? '':'description,') . '
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.appearance,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.layout;layout,
-		--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.visibility;visibility,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.access;access,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.behaviour,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.caching;caching,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.miscellaneous;miscellaneous,
-		--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
-			--palette--;;language
-		'
-	];
-} else {
-	$GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility::CATEGORY_DOKTYPE] = [
-		'showitem' => '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
-			--palette--;;standard,
-			title, slug, tx_projectbase_path_segment, tx_projectbase_excludefromsluggeneration, tx_realurl_pathsegment, tx_realurl_exclude,
-		--div--;' . $localLangDbPath . 'pages.tabs.images,
-			tx_sgnews_teaser2_image, tx_sgnews_teaser1_image,
-			--palette--;;media,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.metadata,
-			tx_projectbase_devnullrobots_flags,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.abstract;abstract,
-			tx_projectbase_seo_titletag,tx_projectbase_seo_canonicaltag, ' . (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('yoast_seo') || \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('seo') ? '':'description,') . '
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.appearance,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.layout;layout,
-		--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.visibility;visibility,
-			--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.access;access,
-		--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.behaviour,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.caching;caching,
-			--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.miscellaneous;miscellaneous,
-		--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
-			--palette--;;language
-		'
-	];
-}
+$GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility::NEWS_DOKTYPE] = [
+	'showitem' => '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
+		--palette--;;standard,
+		--palette--;;titleDescriptionAndHighlightFlag,
+		--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.editorial;editorialWithNewsAuthor,
+		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,
+			--palette--;;robots,
+			--palette--;;canonical,
+			--palette--;;sitemap,
+	--div--;LLL:EXT:seo/Resources/Private/Language/locallang_tca.xlf:pages.tabs.socialmedia,
+		--palette--;;opengraph,
+		--palette--;;twittercards,
+	--div--;' . $localLangDbPath . 'pages.tabs.images,
+		tx_sgnews_teaser2_image, tx_sgnews_teaser1_image,
+		--palette--;;media,
+	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.metadata,
+		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.abstract;abstract,
+	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.appearance,
+		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.layout;layout,
+	--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
+		--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.visibility;visibility,
+		--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.access;access,
+	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.behaviour,
+		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.caching;caching,
+		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.miscellaneous;miscellaneous,
+	--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
+		--palette--;;language
+	'
+];
+
+$GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility::CATEGORY_DOKTYPE] = [
+	'showitem' => '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general,
+		--palette--;;standard,
+		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,
+			--palette--;;robots,
+			--palette--;;canonical,
+			--palette--;;sitemap,
+	--div--;LLL:EXT:seo/Resources/Private/Language/locallang_tca.xlf:pages.tabs.socialmedia,
+		--palette--;;opengraph,
+		--palette--;;twittercards,
+	--div--;' . $localLangDbPath . 'pages.tabs.images,
+		tx_sgnews_teaser2_image, tx_sgnews_teaser1_image,
+		--palette--;;media,
+	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.metadata,
+		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.abstract;abstract,
+		seo_title,canonical_link, ' . (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('yoast_seo') || \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('seo') ? '' : 'description,') . '
+	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.appearance,
+		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.layout;layout,
+	--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access,
+		--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.visibility;visibility,
+		--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:pages.palettes.access;access,
+	--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.tabs.behaviour,
+		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.caching;caching,
+		--palette--;LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.palettes.miscellaneous;miscellaneous,
+	--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,
+		--palette--;;language
+	'
+];
 
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns(
 	'pages',
@@ -178,11 +126,7 @@ if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExten
 		'tx_sgnews_teaser1_image' => [
 			'exclude' => TRUE,
 			'label' => $localLangDbPath . 'pages.tx_sgnews_teaser1_image',
-			'description' => (version_compare(
-				\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionVersion('sg_seo'),
-				'5.0.0',
-				'>=')
-			) ? 'LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:teaser_description' : null,
+			'description' => 'LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:teaser_description',
 			'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
 				'tx_sgnews_teaser1_image',
 				[
@@ -190,32 +134,32 @@ if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExten
 					'foreign_types' => [
 						'0' => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						]
 					],
@@ -232,11 +176,7 @@ if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExten
 		'tx_sgnews_teaser2_image' => [
 			'exclude' => TRUE,
 			'label' => $localLangDbPath . 'pages.tx_sgnews_teaser2_image',
-			'description' => (version_compare(
-				\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionVersion('sg_seo'),
-				'5.0.0',
-				'>=')
-			) ? 'LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:teaser_description' : null,
+			'description' => 'LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:teaser_description',
 			'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
 				'tx_sgnews_teaser2_image',
 				[
@@ -244,32 +184,32 @@ if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExten
 					'foreign_types' => [
 						'0' => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_TEXT => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_AUDIO => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_VIDEO => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						],
 						\TYPO3\CMS\Core\Resource\File::FILETYPE_APPLICATION => [
 							'showitem' => '
-						--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
+						--palette--;LLL:EXT:core/Resources/Private/Language/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
 						--palette--;;filePalette'
 						]
 					],
@@ -460,7 +400,7 @@ if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExten
 $GLOBALS['TCA']['pages']['palettes']['titleDescriptionAndHighlightFlag'] = [
 	'showitem' => 'subtitle;' . $localLangDbPath . 'pages.subtitle.inPalette,
 	--linebreak--, title,
-	' . (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('yoast_seo') || \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('seo') ? '':'--linebreak--, description,') . '
+	' . (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('yoast_seo') || \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('seo') ? '' : '--linebreak--, description,') . '
 	--linebreak--, slug,
 	--linebreak--, tx_projectbase_path_segment, tx_projectbase_excludefromsluggeneration,
 	--linebreak--, tx_realurl_pathsegment, tx_realurl_exclude,
@@ -478,64 +418,38 @@ $GLOBALS['TCA']['pages']['palettes']['editorialWithNewsAuthor'] = [
 ];
 
 foreach ($GLOBALS['TCA']['pages']['columns'] as $languageExcludeField => $_) {
-	if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-		$fieldNames = [
-			'doktype',
-			'title',
-			'subtitle',
-			'description',
-			'slug',
-			'tx_projectbase_path_segment',
-			'tx_projectbase_excludefromsluggeneration',
-			'tx_sgnews_location',
-			'tx_sgnews_teaser1_image',
-			'tx_sgnews_teaser2_image',
-			'tx_sgnews_tags',
-			'abstract',
-			'seo_title',
-			'canonical_link',
-			'hidden',
-			'sys_language_uid',
-			'tx_languagevisibility_visibility',
-			'lastUpdated',
-			'tx_sgnews_date_end',
-			'tx_sgnews_highlighted',
-			'tx_sgnews_never_highlighted',
-			'tx_sgnews_comments_enable',
-			'og_title',
-			'og_description',
-			'og_image',
-			'twitter_title',
-			'twitter_description',
-			'twitter_image',
-			'twitter_card'
-		];
-	} else {
-		$fieldNames = [
-			'doktype',
-			'title',
-			'subtitle',
-			'description',
-			'slug',
-			'tx_projectbase_path_segment',
-			'tx_projectbase_excludefromsluggeneration',
-			'tx_sgnews_location',
-			'tx_sgnews_teaser1_image',
-			'tx_sgnews_teaser2_image',
-			'tx_sgnews_tags',
-			'abstract',
-			'tx_projectbase_seo_titletag',
-			'tx_projectbase_seo_canonicaltag',
-			'hidden',
-			'sys_language_uid',
-			'tx_languagevisibility_visibility',
-			'lastUpdated',
-			'tx_sgnews_date_end',
-			'tx_sgnews_highlighted',
-			'tx_sgnews_never_highlighted',
-			'tx_sgnews_comments_enable'
-		];
-	}
+	$fieldNames = [
+		'doktype',
+		'title',
+		'subtitle',
+		'description',
+		'slug',
+		'tx_projectbase_path_segment',
+		'tx_projectbase_excludefromsluggeneration',
+		'tx_sgnews_location',
+		'tx_sgnews_teaser1_image',
+		'tx_sgnews_teaser2_image',
+		'tx_sgnews_tags',
+		'abstract',
+		'seo_title',
+		'canonical_link',
+		'hidden',
+		'sys_language_uid',
+		'tx_languagevisibility_visibility',
+		'lastUpdated',
+		'tx_sgnews_date_end',
+		'tx_sgnews_highlighted',
+		'tx_sgnews_never_highlighted',
+		'tx_sgnews_comments_enable',
+		'og_title',
+		'og_description',
+		'og_image',
+		'twitter_title',
+		'twitter_description',
+		'twitter_image',
+		'twitter_card'
+	];
+
 	if (!in_array($languageExcludeField, $fieldNames)) {
 		$GLOBALS['TCA']['pages']['types'][\SGalinski\SgNews\Utility\BackendNewsUtility::NEWS_DOKTYPE]['columnsOverrides'][$languageExcludeField]['l10n_mode'] = 'exclude';
 	}
diff --git a/Configuration/TCA/Overrides/sys_template.php b/Configuration/TCA/Overrides/sys_template.php
index 866956e45ad81c53aa88d3ddb71febc934353263..e68202faf0645ab8f8451d2ea11fad57c5b2c41b 100644
--- a/Configuration/TCA/Overrides/sys_template.php
+++ b/Configuration/TCA/Overrides/sys_template.php
@@ -1,4 +1,6 @@
 <?php
+
+defined('TYPO3') or die();
 /**
  *
  * Copyright notice
@@ -25,5 +27,7 @@
  */
 
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile(
-	'sg_news', 'Configuration/TypoScript/Frontend', 'News System'
+	'sg_news',
+	'Configuration/TypoScript/Frontend',
+	'News System'
 );
diff --git a/Configuration/TCA/Overrides/tt_content.php b/Configuration/TCA/Overrides/tt_content.php
index 849be5b17a03744908929d18d717026c6c856c38..eb86f04f405069b444799b7d5d054a0ffe3743ce 100644
--- a/Configuration/TCA/Overrides/tt_content.php
+++ b/Configuration/TCA/Overrides/tt_content.php
@@ -1,4 +1,6 @@
 <?php
+
+defined('TYPO3') or die();
 /**
  *
  * Copyright notice
@@ -58,20 +60,29 @@ $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist']['sgnews_n
 // Flex form assignment
 $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['sgnews_overview'] = 'pi_flexform';
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
-	'sgnews_overview', 'FILE:EXT:sg_news/Configuration/FlexForms/Overview.xml'
+	'sgnews_overview',
+	'FILE:EXT:sg_news/Configuration/FlexForms/Overview.xml'
 );
 
 $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['sgnews_listbycategory'] = 'pi_flexform';
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
-	'sgnews_listbycategory', 'FILE:EXT:sg_news/Configuration/FlexForms/ListByCategory.xml'
+	'sgnews_listbycategory',
+	'FILE:EXT:sg_news/Configuration/FlexForms/ListByCategory.xml'
 );
 
 $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['sgnews_latest'] = 'pi_flexform';
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
-	'sgnews_latest', 'FILE:EXT:sg_news/Configuration/FlexForms/Latest.xml'
+	'sgnews_latest',
+	'FILE:EXT:sg_news/Configuration/FlexForms/Latest.xml'
 );
 
 $GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['sgnews_newsbyauthor'] = 'pi_flexform';
 \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
-	'sgnews_newsbyauthor', 'FILE:EXT:sg_news/Configuration/FlexForms/NewsByAuthor.xml'
+	'sgnews_newsbyauthor',
+	'FILE:EXT:sg_news/Configuration/FlexForms/NewsByAuthor.xml'
 );
+
+$GLOBALS['TCA']['tt_content']['types']['list']['previewRenderer']['sgnews_overview'] = \SGalinski\SgNews\Preview\PreviewRenderer::class;
+$GLOBALS['TCA']['tt_content']['types']['list']['previewRenderer']['sgnews_listbycategory'] = \SGalinski\SgNews\Preview\PreviewRenderer::class;
+$GLOBALS['TCA']['tt_content']['types']['list']['previewRenderer']['sgnews_latest'] = \SGalinski\SgNews\Preview\PreviewRenderer::class;
+$GLOBALS['TCA']['tt_content']['types']['list']['previewRenderer']['sgnews_newsbyauthor'] = \SGalinski\SgNews\Preview\PreviewRenderer::class;
diff --git a/Configuration/TCA/tx_sgnews_domain_model_author.php b/Configuration/TCA/tx_sgnews_domain_model_author.php
index 779d63e3e171a46ba7a99acbc3bfe4add5880e7a..173e05f2a70d1a8a3df3c9edaf24cc7e3cd2f498 100644
--- a/Configuration/TCA/tx_sgnews_domain_model_author.php
+++ b/Configuration/TCA/tx_sgnews_domain_model_author.php
@@ -34,7 +34,6 @@ $configuration = [
 		'crdate' => 'crdate',
 		'cruser_id' => 'cruser_id',
 		'searchFields' => 'name, email, description, website',
-		'dividers2tabs' => TRUE,
 		'delete' => 'deleted',
 		'enablecolumns' => [
 			'disabled' => 'hidden',
@@ -48,7 +47,7 @@ $configuration = [
 	'interface' => [],
 	'types' => [
 		'1' => [
-			'showitem' => 'hidden;;1, --palette--;;authorInfos, path_segment, description'
+			'showitem' => 'hidden,--palette--;;1,--palette--;;authorInfos,path_segment,description'
 		],
 	],
 	'palettes' => [
@@ -164,7 +163,8 @@ $configuration = [
 			'l10n_mode' => 'exclude',
 			'label' => 'LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:tx_sgnews_domain_model_author.image',
 			'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
-				'files', [
+				'files',
+				[
 					'appearance' => [
 						'useSortable' => TRUE,
 					],
@@ -192,8 +192,5 @@ $configuration = [
 		],
 	]
 ];
-if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '10.3.0', '<')) {
-	$configuration['interface']['showRecordFieldList'] = 'sys_language_uid, l10n_parent, l10n_diffsource, hidden, crdate, name, email, description, website, image, path_segment';
-}
 
 return $configuration;
diff --git a/Configuration/TypoScript/Common/setup.typoscript b/Configuration/TypoScript/Common/setup.typoscript
index 1223a9805550ed76981e5ea357b34c112095d4f1..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644
--- a/Configuration/TypoScript/Common/setup.typoscript
+++ b/Configuration/TypoScript/Common/setup.typoscript
@@ -1,50 +0,0 @@
-config.tx_extbase {
-	persistence {
-		classes {
-			# @deprecated This configuration does not work in TYPO3 10 at all, you need to also change
-			# Configuration/Extbase/Persistence/Classes.php
-			SGalinski\SgNews\Domain\Model\News {
-				mapping {
-					tableName = pages
-					recordType = 116
-					columns {
-						tx_sgnews_highlighted.mapOnProperty = highlighted
-						tx_sgnews_never_highlighted.mapOnProperty = neverHighlighted
-						tx_sgnews_related_news.mapOnProperty = relatedNews
-						tx_sgnews_news_author.mapOnProperty = newsAuthor
-						lastUpdated.mapOnProperty = lastUpdated
-						crdate.mapOnProperty = creationDate
-						tx_sgnews_teaser1_image.mapOnProperty = teaser1Image
-						tx_sgnews_teaser2_image.mapOnProperty = teaser2Image
-						tx_sgnews_tags.mapOnProperty = tags
-						tx_sgnews_likes.mapOnProperty = likes
-						tx_sgnews_content_from_another_page.mapOnProperty = contentFromAnotherPage
-						tx_sgnews_location.mapOnProperty = location
-						tx_sgnews_date_end.mapOnProperty = dateEnd
-					}
-				}
-			}
-			SGalinski\SgNews\Domain\Model\Category {
-				mapping {
-					tableName = pages
-					recordType = 117
-					columns {
-						tx_sgnews_teaser1_image.mapOnProperty = teaser1Image
-						tx_sgnews_teaser2_image.mapOnProperty = teaser2Image
-					}
-				}
-			}
-			SGalinski\SgNews\Domain\Model\Tag {
-				mapping {
-					tableName = sys_category
-				}
-			}
-
-			SGalinski\SgNews\Domain\Model\FileReference {
-				mapping {
-					tableName = sys_file_reference
-				}
-			}
-		}
-	}
-}
diff --git a/Configuration/TypoScript/Frontend/constants.typoscript b/Configuration/TypoScript/Frontend/constants.typoscript
index 58f8138af09e551c7aec4fbb1efd6f6b9db7ca00..056a6f06563356824bebc02b2bd764d182a6d6d9 100644
--- a/Configuration/TypoScript/Frontend/constants.typoscript
+++ b/Configuration/TypoScript/Frontend/constants.typoscript
@@ -21,6 +21,6 @@ plugin.tx_sgnews {
 		sortDirection = DESC
 
 		# This enables the output of related news in regards to the news category or tags
-		enableAutomaticRelatedNews = 0
+		enableAutomaticRelatedNews = 1
 	}
 }
diff --git a/README.md b/README.md
index 09323fcaa0349055ac13b4b94239da470a30c5ef..6e56e2faff35e87a5ac42e23a5015799929e5b20 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Repository: https://gitlab.sgalinski.de/typo3/sg_news
 
 Please report bugs here: https://gitlab.sgalinski.de/typo3/sg_news
 
-TYPO3 version: >=9.5
+TYPO3 version: >=10.4
 
 ## About
 
diff --git a/Resources/Private/Layouts/Backend.html b/Resources/Private/Layouts/Backend.html
index 11777dd28bf8a4a54fe506d87525c293a6f8f951..73ae87a2fdbf1b53bcc8580a0fa8225f38b2ffe5 100644
--- a/Resources/Private/Layouts/Backend.html
+++ b/Resources/Private/Layouts/Backend.html
@@ -1,52 +1,68 @@
 {namespace core = TYPO3\CMS\Core\ViewHelpers}
 {namespace sg=SGalinski\SgNews\ViewHelpers}
 
-<f:be.container
-	includeRequireJsModules="{
-		0: 'TYPO3/CMS/Backend/ContextMenu',
-		1: 'TYPO3/CMS/Backend/Tooltip',
-		2: 'TYPO3/CMS/SgNews/Backend'}">
-	<div class="module" data-module-id="" data-module-name="">
-		<div class="module-docheader t3js-module-docheader">
-			<div class="module-docheader-bar module-docheader-bar-navigation t3js-module-docheader-bar t3js-module-docheader-bar-navigation">
-				<div class="module-docheader-bar-column-left">
-					<f:for each="{docHeader.menus}" as="menu">
-						<f:be.menus.actionMenu additionalAttributes="{name: menu.identifier}">
-							<f:for each="{menu.menuItems}" as="menuItem">
-								<option value="{menuItem.href}" {f:if(condition: '{menuItem.active}', then: 'selected="selected"')}>{menuItem.title}</option>
+<f:if condition="{V11}">
+	<f:then>
+		<f:be.pageRenderer	includeRequireJsModules="{
+				0: 'TYPO3/CMS/Backend/ContextMenu',
+				1: 'TYPO3/CMS/Backend/Tooltip',
+				2: 'TYPO3/CMS/SgNews/Backend'}"
+		/>
+
+		<h1>
+			<f:render section="headline" />
+		</h1>
+		<f:render section="content" />
+	</f:then>
+	<f:else>
+		<f:be.container
+			includeRequireJsModules="{
+				0: 'TYPO3/CMS/Backend/ContextMenu',
+				1: 'TYPO3/CMS/Backend/Tooltip',
+				2: 'TYPO3/CMS/SgNews/Backend'}">
+			<div class="module" data-module-id="" data-module-name="">
+				<div class="module-docheader t3js-module-docheader">
+					<div class="module-docheader-bar module-docheader-bar-navigation t3js-module-docheader-bar t3js-module-docheader-bar-navigation">
+						<div class="module-docheader-bar-column-left">
+							<f:for each="{docHeader.menus}" as="menu">
+								<f:be.menus.actionMenu additionalAttributes="{name: menu.identifier}">
+									<f:for each="{menu.menuItems}" as="menuItem">
+										<option value="{menuItem.href}" {f:if(condition: '{menuItem.active}', then: 'selected="selected"')}>{menuItem.title}</option>
+									</f:for>
+								</f:be.menus.actionMenu>
 							</f:for>
-						</f:be.menus.actionMenu>
-					</f:for>
-				</div>
-				<div class="module-docheader-bar-column-right">
-					<span class="typo3-docheader-pagePath">
-						<f:if condition="{typo3Version} < 9000000">
-							<f:then>
-								<f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw>
-							</f:then>
-							<f:else>
-								<f:translate key="LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw>
-							</f:else>
-						</f:if>
-					</span>
-					<f:format.raw>{docHeader.metaInformation.recordInformation}</f:format.raw>
+						</div>
+						<div class="module-docheader-bar-column-right">
+							<span class="typo3-docheader-pagePath">
+								<f:if condition="{typo3Version} < 9000000">
+									<f:then>
+										<f:translate key="LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw>
+									</f:then>
+									<f:else>
+										<f:translate key="LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.path" />: <f:format.raw>{docHeader.metaInformation.path}</f:format.raw>
+									</f:else>
+								</f:if>
+							</span>
+							<f:format.raw>{docHeader.metaInformation.recordInformation}</f:format.raw>
+						</div>
+					</div>
+					<div class="module-docheader-bar module-docheader-bar-buttons t3js-module-docheader-bar t3js-module-docheader-bar-buttons">
+						<div class="module-docheader-bar-column-left">
+						</div>
+						<div class="module-docheader-bar-column-right">
+							<f:render partial="ButtonBar" arguments="{buttons:docHeader.buttons.right}" />
+						</div>
+					</div>
 				</div>
 			</div>
-			<div class="module-docheader-bar module-docheader-bar-buttons t3js-module-docheader-bar t3js-module-docheader-bar-buttons">
-				<div class="module-docheader-bar-column-left">
-				</div>
-				<div class="module-docheader-bar-column-right">
-					<f:render partial="ButtonBar" arguments="{buttons:docHeader.buttons.right}" />
+			<div id="typo3-docbody">
+				<div id="typo3-inner-docbody">
+					<h1>
+						<f:render section="headline" />
+					</h1>
+					<f:render section="content" />
 				</div>
 			</div>
-		</div>
-	</div>
-	<div id="typo3-docbody">
-		<div id="typo3-inner-docbody">
-			<h1>
-				<f:render section="headline" />
-			</h1>
-			<f:render section="content" />
-		</div>
-	</div>
-</f:be.container>
+		</f:be.container>
+	</f:else>
+</f:if>
diff --git a/Resources/Private/Partials/Backend/Filter.html b/Resources/Private/Partials/Backend/Filter.html
index 256ca3dcdc31e4799c53d90940fde5b4943317cd..2837aa7324fee73005c5405bff29574dde43e189 100644
--- a/Resources/Private/Partials/Backend/Filter.html
+++ b/Resources/Private/Partials/Backend/Filter.html
@@ -1,7 +1,7 @@
 <f:form action="index" controller="Backend" method="post" objectName="filters" object="{filters}">
 	<div class="row">
 		<f:if condition="{showCategoryFilter}">
-			<div class="col-xs-4">
+			<div class="col-sm-4">
 				<div class="form-group">
 					<label for="filter-categories">
 						<f:translate key="backend.filters.categories" />
@@ -11,7 +11,7 @@
 				</div>
 			</div>
 		</f:if>
-		<div class="col-xs-{f:if(condition: showCategoryFilter, then: '4', else: '6')}">
+		<div class="col-sm-{f:if(condition: showCategoryFilter, then: '4', else: '6')}">
 			<div class="form-group">
 				<label for="filter-tags">
 					<f:translate key="backend.filters.tags" />
@@ -20,16 +20,16 @@
 				<small><f:format.raw><f:translate key="backend.filters.tags.description" /></f:format.raw></small>
 			</div>
 		</div>
-		<div class="col-xs-{f:if(condition: showCategoryFilter, then: '4', else: '6')}">
+		<div class="col-sm-{f:if(condition: showCategoryFilter, then: '4', else: '6')}">
 			<div class="form-group">
 				<label for="filter-search"><f:translate key="backend.filters.search" /></label>
 				<f:form.textfield class="form-control" property="search" id="filter-search" />
 			</div>
-			<div class="media">
+			<div class="media-buttons">
 				<div class="pull-right divider">
 					<f:form.button class="btn btn-success form-control" type="submit"><f:translate key="backend.filter" /></f:form.button>
 				</div>
-				<div class="pull-right divider">
+				<div class="pull-right divider" style="margin-right: 15px">
 					<f:form.button id="filter-reset-btn" class="btn btn-danger form-control" type="reset"><f:translate key="backend.filter.reset" /></f:form.button>
 				</div>
 			</div>
diff --git a/Resources/Private/Partials/Backend/Pagination.html b/Resources/Private/Partials/Backend/Pagination.html
new file mode 100644
index 0000000000000000000000000000000000000000..242dff918ccb9d5ff8faae1bf0644db8e67a23b0
--- /dev/null
+++ b/Resources/Private/Partials/Backend/Pagination.html
@@ -0,0 +1,103 @@
+{namespace core=TYPO3\CMS\Core\ViewHelpers}
+{namespace sg=SGalinski\SgMail\ViewHelpers}
+
+<nav class="pagination-wrap">
+	<ul class="pagination pagination-block">
+		<f:if condition="{pagination.previousPageNumber} && {pagination.previousPageNumber} >= {pagination.firstPageNumber}">
+			<f:then>
+				<li class="page-item">
+					<a href="{f:uri.action(action:actionName, arguments:{currentPage: 1})}" title="{f:translate(key:'widget.pagination.first')}" class="page-link">
+						<core:icon identifier="actions-view-paging-first" />
+					</a>
+				</li>
+				<li class="page-item">
+					<a href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.previousPageNumber})}" title="{f:translate(key:'widget.pagination.previous')}" class="page-link">
+						<core:icon identifier="actions-view-paging-previous" />
+					</a>
+				</li>
+			</f:then>
+			<f:else>
+				<li class="page-item disabled">
+					<span class="page-link">
+						<core:icon identifier="actions-view-paging-first" />
+					</span>
+				</li>
+				<li class="page-item disabled">
+					<span class="page-link">
+						<core:icon identifier="actions-view-paging-previous" />
+					</span>
+				</li>
+			</f:else>
+		</f:if>
+		<li class="page-item">
+			<span class="page-link">
+				<f:if condition="{recordsLabel}">
+					<f:then>
+						{recordsLabel}
+					</f:then>
+					<f:else>
+						<f:translate key="widget.pagination.records" />
+					</f:else>
+				</f:if>
+				{pagination.startRecordNumber} - {pagination.endRecordNumber} / {paginator.totalItems}
+			</span>
+		</li>
+		<li class="page-item">
+			<span class="page-link">
+				<f:translate key="widget.pagination.page" />
+				<form id="paginator-form-{position}" onsubmit="goToPage{position}(this); return false;" style="display:inline;">
+				<script type="text/javascript">
+					function goToPage{position}(formObject) {
+						var page = formObject.elements['paginator-target-page'].value;
+						var url = '{f:uri.action(action:actionName, arguments:{currentPage: 987654321}) -> f:format.raw()}';
+
+						if (page > {pagination.lastPageNumber}) {
+							page = {pagination.lastPageNumber};
+						}
+						else
+						if (page < 1) {
+							page = 1;
+						}
+						url = url.replace('987654321', page);
+						self.location.href = url;
+					}
+				</script>
+				<f:form.textfield id="paginator-{position}" name="paginator-target-page" additionalAttributes="{min: '1'}" class="form-control input-sm paginator-input" size="5" value="{currentPage}" type="number" />
+				</form>
+
+				/ {pagination.lastPageNumber}
+			</span>
+		</li>
+		<f:if condition="{pagination.nextPageNumber} && {pagination.nextPageNumber} <= {pagination.lastPageNumber}">
+			<f:then>
+				<li class="page-item">
+					<a class="page-link" href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.nextPageNumber})}" title="{f:translate(key:'widget.pagination.next')}">
+						<core:icon identifier="actions-view-paging-next" />
+					</a>
+				</li>
+				<li class="page-item">
+					<a class="page-link" href="{f:uri.action(action:actionName, arguments:{currentPage: pagination.lastPageNumber})}" title="{f:translate(key:'widget.pagination.last')}">
+						<core:icon identifier="actions-view-paging-last" />
+					</a>
+				</li>
+			</f:then>
+			<f:else>
+				<li class="page-item disabled">
+					<span class="page-link">
+						<core:icon identifier="actions-view-paging-next" />
+					</span>
+				</li>
+				<li class="page-item disabled">
+					<span class="page-link">
+						<core:icon identifier="actions-view-paging-last" />
+					</span>
+				</li>
+			</f:else>
+		</f:if>
+		<li class="page-item">
+			<a class="page-link" href="{f:uri.action(action:actionName, arguments:{currentPage: currentPage})}" title="{f:translate(key:'widget.pagination.refresh')}">
+				<core:icon identifier="actions-refresh" />
+			</a>
+		</li>
+	</ul>
+</nav>
diff --git a/Resources/Private/Templates/Backend/Index.html b/Resources/Private/Templates/Backend/Index.html
index 164b931cd4f72f930dde5780cecb47611254e9f0..e511a05940a4939154947b45746d86df1e3f19af 100644
--- a/Resources/Private/Templates/Backend/Index.html
+++ b/Resources/Private/Templates/Backend/Index.html
@@ -45,55 +45,54 @@
 				<div class="panel panel-default recordlist">
 					<div class="table-fit">
 						<table data-table="pages" class="table table-striped table-hover">
-							<sg:backend.widget.paginate objects="{news}" as="paginatedNews" configuration="{insertAbove: 1, itemsPerPage: 20}">
-								<tbody>
-									<f:for each="{paginatedNews}" as="singleNews">
-										<tr data-uid="{singleNews.uid}">
-											<td nowrap="nowrap" class="col-icon">
-												<f:format.raw>
-													<sg:backend.recordIcon table="pages" row="{singleNews}" />
-												</f:format.raw>
-											</td>
-											<td nowrap="nowrap">
-												<f:alias map="{newsItemTags: '{sg:backend.newsItemTags(uid: singleNews.uid, languageUid: language)}'}">
-													<f:if condition="{singleNews.translation_uid}">
-														<f:then>
-															<be:link.editRecord uid="{singleNews.translation_uid}" table="pages">
-																<span>
-																	<f:if condition="{singleNews.translation_title}">
-																		<f:then>
-																			{singleNews.translation_title}
-																		</f:then>
-																		<f:else>
-																			{singleNews.title}
-																		</f:else>
-																	</f:if>
-																	<f:if condition="{newsItemTags}">({newsItemTags})</f:if>
-																</span>
-															</be:link.editRecord>
-														</f:then>
-														<f:else>
-															<be:link.editRecord uid="{singleNews.uid}" table="pages">
-																<span>
-																	{singleNews.title}
-																	<f:if condition="{newsItemTags}">({newsItemTags})</f:if>
-																</span>
-															</be:link.editRecord>
-														</f:else>
-													</f:if>
-												</f:alias>
-												<br />
-												<sg:backend.translationLinks pageUid="{pageUid}" table="pages" uid="{singleNews.uid}" />
-											</td>
-											<td nowrap="nowrap" class="col-control">
-												<f:format.raw>
-													<sg:backend.control table="pages" row="{singleNews}" />
-												</f:format.raw>
-											</td>
-										</tr>
-									</f:for>
-								</tbody>
-							</sg:backend.widget.paginate>
+							<f:render partial="Backend/Pagination" arguments="{pagination: pagination, paginator: paginator, actionName: 'index', currentPage: currentPage}"/>
+							<tbody>
+								<f:for each="{paginator.paginatedItems}" as="singleNews">
+									<tr data-uid="{singleNews.uid}">
+										<td nowrap="nowrap" class="col-icon">
+											<f:format.raw>
+												<sg:backend.recordIcon table="pages" row="{singleNews}" />
+											</f:format.raw>
+										</td>
+										<td nowrap="nowrap">
+											<f:alias map="{newsItemTags: '{sg:backend.newsItemTags(uid: singleNews.uid, languageUid: language)}'}">
+												<f:if condition="{singleNews.translation_uid}">
+													<f:then>
+														<be:link.editRecord uid="{singleNews.translation_uid}" table="pages">
+															<span>
+																<f:if condition="{singleNews.translation_title}">
+																	<f:then>
+																		{singleNews.translation_title}
+																	</f:then>
+																	<f:else>
+																		{singleNews.title}
+																	</f:else>
+																</f:if>
+																<f:if condition="{newsItemTags}">({newsItemTags})</f:if>
+															</span>
+														</be:link.editRecord>
+													</f:then>
+													<f:else>
+														<be:link.editRecord uid="{singleNews.uid}" table="pages">
+															<span>
+																{singleNews.title}
+																<f:if condition="{newsItemTags}">({newsItemTags})</f:if>
+															</span>
+														</be:link.editRecord>
+													</f:else>
+												</f:if>
+											</f:alias>
+											<br />
+											<sg:backend.translationLinks pageUid="{pageUid}" table="pages" uid="{singleNews.uid}" />
+										</td>
+										<td nowrap="nowrap" class="col-control">
+											<f:format.raw>
+												<sg:backend.control table="pages" row="{singleNews}" />
+											</f:format.raw>
+										</td>
+									</tr>
+								</f:for>
+							</tbody>
 						</table>
 					</div>
 				</div>
diff --git a/Resources/Public/Icons/Extension.png b/Resources/Public/Icons/Extension.png
new file mode 100644
index 0000000000000000000000000000000000000000..67fda8fec210ccf660363ff30c10f19513b4bfb2
Binary files /dev/null and b/Resources/Public/Icons/Extension.png differ
diff --git a/Resources/Public/JavaScript/Backend.js b/Resources/Public/JavaScript/Backend.js
index 8a23a1f3793986483424c1a028a0decb234f66ec..37d69d2f0250f0a433d9ad8287a8a492aeda49d5 100644
--- a/Resources/Public/JavaScript/Backend.js
+++ b/Resources/Public/JavaScript/Backend.js
@@ -39,8 +39,10 @@ define([
 				this.form.submit();
 			});
 			$('.sg-news_pageswitch').on('click', function(event) {
-				event.preventDefault();
-				SgNewsModule.goTo('web_SgNewsNews', event.target.dataset.page, event.target.dataset.path);
+				if(Viewport.NavigationContainer.PageTree !== undefined) {
+					event.preventDefault();
+					SgNewsModule.goTo('web_SgNewsNews', event.target.dataset.page, event.target.dataset.path);
+				}
 			});
 		},
 
diff --git a/Upgrade.md b/Upgrade.md
index 140b41e2afea0854efbd877c96159f33c16d1ad2..eaa76f6b7b65f214d046ae1d4cdc7636182942c9 100644
--- a/Upgrade.md
+++ b/Upgrade.md
@@ -1,3 +1,10 @@
+# Upgrade from ```9.x.x``` to ```10.x.x```
+
+- Dropped TYPO3 9 support
+- Dropped php 7.3 support
+- Dropped sg_seo < 6.0 support
+- enableAutomaticRelatedNews defaults now to 1 instead of 0
+
 ## Upgrade from ```9.5.x``` to ```9.6.x```
 
 - Filters are now visible when using the option ```settings.enableFilter``` in the **Overview** plugin.
diff --git a/composer.json b/composer.json
index 9b0413761978d7f07744c337b58191d616448db0..e8c2b0590cee23d9a49b8e1483db420282777ae8 100644
--- a/composer.json
+++ b/composer.json
@@ -16,7 +16,8 @@
         }
     ],
     "require": {
-        "typo3/cms-core": "^9.5.0 || ^10.4.0"
+        "typo3/cms-core": "^10.4.0 || ^11.5.0",
+        "sgalinski/sg-seo": ">=6.0.0"
     },
     "suggest": {
         "sgalinski/sg-ajax": "Required for the like feature",
diff --git a/ext_emconf.php b/ext_emconf.php
index 45ec25ffa3886211f7878a53fa1e94afccc4649a..7e98f8f9620800ab974e18f607fe07700cf8ac16 100644
--- a/ext_emconf.php
+++ b/ext_emconf.php
@@ -22,13 +22,13 @@ $EM_CONF['sg_news'] = [
 	'version' => '9.8.6',
 	'constraints' => [
 		'depends' => [
-			'typo3' => '9.5.0-10.4.99',
-			'php' => '7.3.0-7.4.99',
+			'typo3' => '10.4.0-11.5.99',
+			'php' => '7.4.0-8.1.99',
 		],
 		'conflicts' => [],
 		'suggests' => [
-			'sg_comments' => '5.0.0',
-			'sg_ajax' => '3.0.0'
+			'sg_comments' => '6.0.0',
+			'sg_ajax' => '4.0.0'
 		],
 	],
 	'suggests' => [],
diff --git a/ext_localconf.php b/ext_localconf.php
index 050de5bb24d54bb615a436ea248bdc11858932f4..eea75eda0d6ef416d213abfd9c9dfcd306acc84a 100644
--- a/ext_localconf.php
+++ b/ext_localconf.php
@@ -1,4 +1,6 @@
 <?php
+
+defined('TYPO3') or die();
 /**
  *
  * Copyright notice
@@ -33,86 +35,75 @@ call_user_func(
 
 		// plugin configurations
 		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-			'SGalinski.sg_news',
+			'SgNews',
 			'Overview',
-			['Overview' => 'overview',],
-			['Overview' => 'overview',]
+			[\SGalinski\SgNews\Controller\OverviewController::class => 'overview', ],
+			[\SGalinski\SgNews\Controller\OverviewController::class => 'overview', ]
 		);
 
 		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-			'SGalinski.sg_news',
+			'SgNews',
 			'ListByCategory',
-			['ListByCategory' => 'index',],
-			['ListByCategory' => '',]
+			[\SGalinski\SgNews\Controller\ListByCategoryController::class => 'index', ],
+			[\SGalinski\SgNews\Controller\ListByCategoryController::class => '', ]
 		);
 
 		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-			'SGalinski.sg_news',
+			'SgNews',
 			'SingleView',
-			['SingleView' => 'singleView',],
-			['SingleView' => '',]
+			[\SGalinski\SgNews\Controller\SingleViewController::class => 'singleView', ],
+			[\SGalinski\SgNews\Controller\SingleViewController::class => '', ]
 		);
 
 		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-			'SGalinski.sg_news',
+			'SgNews',
 			'NewsFeed',
-			['NewsFeed' => 'index',],
-			['NewsFeed' => '',]
+			[\SGalinski\SgNews\Controller\NewsFeedController::class => 'index', ],
+			[\SGalinski\SgNews\Controller\NewsFeedController::class => '', ]
 		);
 
 		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-			'SGalinski.sg_news',
+			'SgNews',
 			'Latest',
-			['Latest' => 'index',],
-			['Latest' => '',]
+			[\SGalinski\SgNews\Controller\LatestController::class => 'index', ],
+			[\SGalinski\SgNews\Controller\LatestController::class => '', ]
 		);
 
 		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-			'SGalinski.sg_news',
+			'SgNews',
 			'ListByCategory',
-			['ListByCategory' => 'index',],
-			['ListByCategory' => '',]
+			[\SGalinski\SgNews\Controller\ListByCategoryController::class => 'index', ],
+			[\SGalinski\SgNews\Controller\ListByCategoryController::class => '', ]
 		);
 
 		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
-			'SGalinski.sg_news',
+			'SgNews',
 			'NewsByAuthor',
-			['NewsByAuthor' => 'list',],
-			['NewsByAuthor' => '',]
+			[\SGalinski\SgNews\Controller\NewsByAuthorController::class => 'list', ],
+			[\SGalinski\SgNews\Controller\NewsByAuthorController::class => '', ]
 		);
 
 		if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('sg_ajax')) {
 			\SGalinski\SgAjax\Service\AjaxRegistration::configureAjaxFrontendPlugin(
 				'sg_news',
 				[
-					'Ajax\Like' => 'addLike',
+					\SGalinski\SgNews\Controller\Ajax\LikeController::class => 'addLike',
 				]
 			);
 		}
 
 		// hook registration
 		$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] =
-			'SGalinski\SgNews\TCA\TcaProvider';
+			\SGalinski\SgNews\TCA\TcaProvider::class;
 		$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem']['sg_news']
 			= \SGalinski\SgNews\Hooks\PageLayoutView\PluginRenderer::class;
 
 		// Xclasses
-		$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects']['TYPO3\CMS\Core\Page\PageRenderer'] =
-			['className' => 'SGalinski\SgNews\Xclass\PageRenderer'];
-
-		/** @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher */
-		$signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
-			\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class
-		);
-
-		$signalSlotDispatcher->connect(
-			\TYPO3\CMS\Backend\Controller\EditDocumentController::class,
-			'preInitAfter',
-			\SGalinski\SgNews\Hooks\EditDocumentController::class,
-			'preInitAfter'
-		);
+		$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Core\Page\PageRenderer::class] =
+			['className' => \SGalinski\SgNews\Xclass\PageRenderer::class];
 
-		if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'])) {
+		# Hook to add the "go to News Module Button
+		if (!isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'])) {
 			$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'] = [];
 		}
 		$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'][] =
diff --git a/ext_tables.php b/ext_tables.php
index acb4c72e9b86ef2d85bc4f94e9f24ab3c0d703a1..bdd99ffb4c5bee55e04fb0e6f06174bbbe510cf8 100644
--- a/ext_tables.php
+++ b/ext_tables.php
@@ -1,4 +1,6 @@
 <?php
+
+defined('TYPO3') or die();
 /**
  *
  * Copyright notice
@@ -30,23 +32,21 @@ call_user_func(
 			'tx_sgnews_domain_model_author'
 		);
 
-		if (TYPO3_MODE === 'BE') {
-			$navigationComponentId = 'TYPO3/CMS/Backend/PageTree/PageTreeElement';
-			\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
-				'SGalinski.sg_news',
-				'web',
-				'News',
-				'',
-				[
-					'Backend' => 'index',
-				],
-				[
-					'access' => 'user,group',
-					'icon' => 'EXT:sg_news/Resources/Public/Icons/module-sgnews.svg',
-					'labels' => 'LLL:EXT:sg_news/Resources/Private/Language/locallang.xlf',
-					'navigationComponentId' => $navigationComponentId
-				]
-			);
-		}
+		$navigationComponentId = 'TYPO3/CMS/Backend/PageTree/PageTreeElement';
+		\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerModule(
+			'SgNews',
+			'web',
+			'News',
+			'',
+			[
+				\SGalinski\SgNews\Controller\BackendController::class => 'index',
+			],
+			[
+				'access' => 'user,group',
+				'icon' => 'EXT:sg_news/Resources/Public/Icons/module-sgnews.svg',
+				'labels' => 'LLL:EXT:sg_news/Resources/Private/Language/locallang.xlf',
+				'navigationComponentId' => $navigationComponentId
+			]
+		);
 	}
 );