diff --git a/Classes/Controller/AbstractController.php b/Classes/Controller/AbstractController.php
index 7bb3121191c4ea4956ed8dc57c070f43f5de84e0..92a944cd75129a345e6e9ae3f341d7dfdb015c65 100644
--- a/Classes/Controller/AbstractController.php
+++ b/Classes/Controller/AbstractController.php
@@ -27,32 +27,17 @@ namespace SGalinski\SgNews\Controller;
  ***************************************************************/
 
 use RuntimeException;
-use SGalinski\SgNews\Domain\Model\Category;
-use SGalinski\SgNews\Domain\Model\News;
-use SGalinski\SgNews\Service\ImageService;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\Domain\Model\FileReference;
 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
 
 /**
  * Abstract Controller
  */
 abstract class AbstractController extends ActionController {
-	/**
-	 * @var ImageService
-	 */
-	protected $imageService;
-
 	/**
 	 * @var array
 	 */
 	protected $extensionConfiguration = [];
 
-	/**
-	 * @var array
-	 */
-	protected $cachedSingleNews = [];
-
 	/**
 	 * Initializes any action
 	 *
@@ -65,13 +50,6 @@ abstract class AbstractController extends ActionController {
 		parent::initializeAction();
 	}
 
-	/**
-	 * @param ImageService $imageService
-	 */
-	public function injectImageService(ImageService $imageService) {
-		$this->imageService = $imageService;
-	}
-
 	/**
 	 * Error Handler
 	 *
@@ -82,129 +60,6 @@ abstract class AbstractController extends ActionController {
 		throw new RuntimeException($this->getFlattenedValidationErrorMessage());
 	}
 
-	/**
-	 * Returns the metadata of the given news.
-	 *
-	 * @param News $news
-	 * @param Category $category
-	 * @return array
-	 * @throws \InvalidArgumentException
-	 */
-	protected function getMetaDataForNews(News $news, Category $category): array {
-		$newsId = $news->getUid();
-		if (isset($this->cachedSingleNews[$newsId])) {
-			return $this->cachedSingleNews[$newsId];
-		}
-
-		$fileRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\FileRepository::class);
-		$fileObjects = $fileRepository->findByRelation('pages', 'media', $news->getUid());
-
-		$singleNewsImageData = $this->getDataForSingleViewImage($news, $category);
-		$teaserImageData = $this->getDataForTeaserImage($news, $category);
-
-		// Use single news image data for teaser image data, if the teaser imaga data are empty.
-		$teaserIsEmpty = $teaserImageData['teaserImage'] === NULL && $teaserImageData['teaserImageObject'] === NULL;
-		$singleNewsIsEmpty = $singleNewsImageData['image'] === NULL && $singleNewsImageData['imageObject'] === NULL;
-		if ($teaserIsEmpty && !$singleNewsIsEmpty) {
-			$teaserImageData = [
-				'teaserImage' => $singleNewsImageData['image'],
-				'teaserImageObject' => $singleNewsImageData['imageObject'],
-			];
-		}
-
-		$newsRecord = array_merge(
-			[
-				'category' => $category,
-				'news' => $news,
-			],
-			$singleNewsImageData,
-			$teaserImageData,
-			['media' => $fileObjects]
-		);
-
-		$this->cachedSingleNews[$newsId] = $newsRecord;
-
-		return $newsRecord;
-	}
-
-	/**
-	 * Returns the single view image data as an array for the given news and category as fallback.
-	 *
-	 * @param News $news
-	 * @param Category $category
-	 * @return array
-	 * @throws \InvalidArgumentException
-	 */
-	protected function getDataForSingleViewImage(News $news, Category $category): array {
-		/** @var FileReference $singleNewsImage */
-		$singleNewsImage = $singleNewsImageObject = NULL;
-		$singleNewsImages = $news->getTeaser2Image();
-		if (count($singleNewsImages)) {
-			$singleNewsImage = $singleNewsImages->current();
-		} else {
-			$categoryImages = $category->getTeaser2Image();
-			if (count($categoryImages)) {
-				$singleNewsImage = $categoryImages->current();
-			}
-		}
-
-		if ($singleNewsImage) {
-			$singleNewsImageObject = $singleNewsImage;
-			$originalResource = $singleNewsImage->getOriginalResource();
-			if ($originalResource) {
-				$singleNewsImage = $originalResource->getPublicUrl();
-			}
-
-			if ($singleNewsImage) {
-				$singleNewsImage = $GLOBALS['TSFE']->absRefPrefix . $singleNewsImage;
-			}
-		}
-
-		return [
-			'image' => $singleNewsImage,
-			'imageObject' => $singleNewsImageObject,
-		];
-	}
-
-	/**
-	 * Returns the teaser image data as an array for the given news and category as fallback.
-	 *
-	 * @param News $news
-	 * @param Category $category
-	 * @return array
-	 * @throws \InvalidArgumentException
-	 */
-	protected function getDataForTeaserImage(News $news, Category $category): array {
-		/** @var FileReference $teaserImage */
-		$teaserImage = $teaserImageObject = NULL;
-		$teaserImages = $news->getTeaser1Image();
-		if (count($teaserImages)) {
-			$teaserImage = $teaserImages->current();
-		} else {
-			$categoryImages = $category->getTeaser1Image();
-			if (count($categoryImages)) {
-				$teaserImage = $categoryImages->current();
-			}
-		}
-
-		if ($teaserImage) {
-			$teaserImageObject = $teaserImage;
-			$originalResource = $teaserImage->getOriginalResource();
-			if ($originalResource) {
-				$teaserImage = $originalResource->getPublicUrl();
-			}
-
-			if ($teaserImage) {
-				$teaserImage = $GLOBALS['TSFE']->absRefPrefix . $teaserImage;
-			}
-		}
-
-		return [
-			'teaserImage' => $teaserImage,
-			'teaserImageObject' => $teaserImageObject,
-		];
-	}
-
 	/**
 	 * Calculate the pagination offset
 	 *
diff --git a/Classes/Controller/LatestController.php b/Classes/Controller/LatestController.php
index 19b8628a71e5c5ccee01a91bbdbabb48b4272924..d6b07cc6727ea7061fac078a92a0404360b20bfd 100644
--- a/Classes/Controller/LatestController.php
+++ b/Classes/Controller/LatestController.php
@@ -31,6 +31,7 @@ use SGalinski\SgNews\Domain\Model\News;
 use SGalinski\SgNews\Domain\Repository\CategoryRepository;
 use SGalinski\SgNews\Domain\Repository\NewsRepository;
 use SGalinski\SgNews\Domain\Repository\TagRepository;
+use SGalinski\SgNews\Domain\Service\NewsService;
 use SGalinski\SgNews\Service\ConfigurationService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -53,6 +54,11 @@ class LatestController extends AbstractController {
 	 */
 	protected $newsRepository;
 
+	/**
+	 * @var NewsService
+	 */
+	protected $newsService;
+
 	/**
 	 * Renders the news overview
 	 *
@@ -124,7 +130,7 @@ class LatestController extends AbstractController {
 				$categories[$categoryUid] = $category;
 			}
 
-			$newsMetaData[] = $this->getMetaDataForNews($latestNewsEntry, $category);
+			$newsMetaData[] = $this->newsService->getMetaDataForNews($latestNewsEntry, $category);
 			// Make sure, that the amount is the same as the configured limit.
 			if (count($newsMetaData) >= $limit) {
 				break;
@@ -161,4 +167,11 @@ class LatestController extends AbstractController {
 	public function injectTagRepository(TagRepository $tagRepository) {
 		$this->tagRepository = $tagRepository;
 	}
+
+	/**
+	 * @param NewsService $newsService
+	 */
+	public function injectNewsService(NewsService $newsService) {
+		$this->newsService = $newsService;
+	}
 }
diff --git a/Classes/Controller/ListByCategoryController.php b/Classes/Controller/ListByCategoryController.php
index 181e7d572dd2b694bd4c128c3624131092c82181..184c8c555f23a4c4ff3b1b7504a83707d185fb8c 100644
--- a/Classes/Controller/ListByCategoryController.php
+++ b/Classes/Controller/ListByCategoryController.php
@@ -30,6 +30,7 @@ use SGalinski\SgNews\Domain\Model\News;
 use SGalinski\SgNews\Domain\Repository\CategoryRepository;
 use SGalinski\SgNews\Domain\Repository\NewsRepository;
 use SGalinski\SgNews\Domain\Repository\TagRepository;
+use SGalinski\SgNews\Domain\Service\NewsService;
 use SGalinski\SgNews\Service\ConfigurationService;
 use SGalinski\SgNews\Service\HeaderMetaDataService;
 use TYPO3\CMS\Core\Http\ImmediateResponseException;
@@ -57,6 +58,11 @@ class ListByCategoryController extends AbstractController {
 	 */
 	protected $newsRepository;
 
+	/**
+	 * @var NewsService
+	 */
+	protected $newsService;
+
 	/**
 	 * @param CategoryRepository $categoryRepository
 	 */
@@ -80,6 +86,13 @@ class ListByCategoryController extends AbstractController {
 		$this->tagRepository = $tagRepository;
 	}
 
+	/**
+	 * @param NewsService $newsService
+	 */
+	public function injectNewsService(NewsService $newsService) {
+		$this->newsService = $newsService;
+	}
+
 	/**
 	 * Initialize the indexAction to set the currentPageBrowserPage parameter
 	 *
@@ -186,7 +199,7 @@ class ListByCategoryController extends AbstractController {
 
 		foreach ($news as $newsEntry) {
 			/** @var News $newsEntry */
-			$data = $this->getMetaDataForNews($newsEntry, $categories[$newsEntry->getPid()]);
+			$data = $this->newsService->getMetaDataForNews($newsEntry, $categories[$newsEntry->getPid()]);
 			$newsMetaData[] = $data;
 
 			if (!$headerSet) {
diff --git a/Classes/Controller/NewsByAuthorController.php b/Classes/Controller/NewsByAuthorController.php
index 7321064d68354b1d6750a5a989b5a299e45d471b..2e391648eda30c5046b4f3eb19d875916fbffa92 100644
--- a/Classes/Controller/NewsByAuthorController.php
+++ b/Classes/Controller/NewsByAuthorController.php
@@ -32,6 +32,7 @@ use SGalinski\SgNews\Domain\Model\News;
 use SGalinski\SgNews\Domain\Repository\AuthorRepository;
 use SGalinski\SgNews\Domain\Repository\CategoryRepository;
 use SGalinski\SgNews\Domain\Repository\NewsRepository;
+use SGalinski\SgNews\Domain\Service\NewsService;
 use SGalinski\SgSeo\Service\HeadTagService;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -40,6 +41,18 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * News Author List Controller
  */
 class NewsByAuthorController extends AbstractController {
+	/**
+	 * @var NewsService
+	 */
+	protected $newsService;
+
+	/**
+	 * @param NewsService $newsService
+	 */
+	public function injectNewsService(NewsService $newsService) {
+		$this->newsService = $newsService;
+	}
+
 	/**
 	 * Renders the news author list.
 	 *
@@ -130,7 +143,7 @@ class NewsByAuthorController extends AbstractController {
 					$categories[$categoryId] = $category;
 				}
 
-				$newsMetaData[] = $this->getMetaDataForNews($newsEntry, $categories[$categoryId]);
+				$newsMetaData[] = $this->newsService->getMetaDataForNews($newsEntry, $categories[$categoryId]);
 			}
 		}
 
diff --git a/Classes/Controller/OverviewController.php b/Classes/Controller/OverviewController.php
index a5c802b2573cc6f6b2b2db2e099ffe9a3ebec314..5b002811c71f32d22e80395f42762c173c3515bd 100644
--- a/Classes/Controller/OverviewController.php
+++ b/Classes/Controller/OverviewController.php
@@ -28,16 +28,15 @@ namespace SGalinski\SgNews\Controller;
 
 use SGalinski\SgNews\Domain\Model\Category;
 use SGalinski\SgNews\Domain\Model\News;
-use SGalinski\SgNews\Domain\Model\Tag;
 use SGalinski\SgNews\Domain\Repository\CategoryRepository;
 use SGalinski\SgNews\Domain\Repository\NewsRepository;
 use SGalinski\SgNews\Domain\Repository\TagRepository;
+use SGalinski\SgNews\Domain\Service\NewsService;
 use SGalinski\SgNews\Service\ConfigurationService;
 use SGalinski\SgNews\Service\HeaderMetaDataService;
 use TYPO3\CMS\Core\Http\ImmediateResponseException;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Extbase\Persistence\Generic\Query;
 use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
 use TYPO3\CMS\Extbase\Persistence\QueryInterface;
 use TYPO3\CMS\Frontend\Controller\ErrorController;
@@ -62,11 +61,15 @@ class OverviewController extends AbstractController {
 	 */
 	protected $newsRepository;
 
+	/**
+	 * @var NewsService
+	 */
+	protected $newsService;
+
 	/**
 	 * @param CategoryRepository $categoryRepository
 	 */
-	public function injectCategoryRepository(
-		CategoryRepository $categoryRepository
+	public function injectCategoryRepository(CategoryRepository $categoryRepository
 	) {
 		$this->categoryRepository = $categoryRepository;
 	}
@@ -85,15 +88,20 @@ class OverviewController extends AbstractController {
 		$this->tagRepository = $tagRepository;
 	}
 
+	/**
+	 * @param NewsService $newsService
+	 */
+	public function injectNewsService(NewsService $newsService) {
+		$this->newsService = $newsService;
+	}
+
 	/**
 	 * Initialize the overviewAction to set the currentPageBrowserPage parameter
 	 *
 	 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidArgumentNameException
 	 */
 	public function initializeOverviewAction() {
-		$currentPageBrowserPage = GeneralUtility::_GP('tx_sgnews_pagebrowser') ? (int) GeneralUtility::_GP(
-			'tx_sgnews_pagebrowser'
-		)['currentPage'] : 0;
+		$currentPageBrowserPage = (int) GeneralUtility::_GP('tx_sgnews_pagebrowser')['currentPage'];
 		if ($currentPageBrowserPage > 0) {
 			$this->request->setArgument('currentPageBrowserPage', $currentPageBrowserPage);
 		}
@@ -104,288 +112,171 @@ class OverviewController extends AbstractController {
 	 *
 	 * @param array $newsFilter
 	 * @param int $currentPageBrowserPage
+	 * @return void
 	 * @throws \InvalidArgumentException
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 * @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
 	 * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
 	 */
-	public function overviewAction(array $newsFilter = [], int $currentPageBrowserPage = 0
-	): ?\Psr\Http\Message\ResponseInterface {
-		switch ((int) $this->settings['groupBy']) {
-			case 1:
-				$this->overviewWithCategories([], [], $newsFilter, $currentPageBrowserPage);
-				break;
-			case 2:
-				$this->overviewWithTags([], [], $newsFilter, $currentPageBrowserPage);
-				break;
-			default:
-				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'
-					))->withControllerName('Record')
-						->withExtensionName('Extension')
-						->withArguments($this->request->getArguments());
-				}
-				break;
-		}
-
-		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
-			return NULL;
-		} else {
-			return $this->htmlResponse();
-		}
-	}
-
-	/**
-	 * Highlights the best fitting news in the metadata of the page
-	 *
-	 * @param array|null $categoryIds
-	 * @param array|null $tagIds
-	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
-	 */
-	protected function highlightBestFitNews(array $categoryIds = NULL, array $tagIds = NULL) {
-		$startTime = 0;
-		if (isset($this->settings['starttime'])) {
-			$startTime = (int) $this->settings['starttime'];
+	public function overviewAction(array $newsFilter = [], int $currentPageBrowserPage = 0) {
+		if ((int) $this->settings['groupBy'] === 0 && (bool) $this->settings['enableFilter'] === FALSE) {
+			$this->forward('overviewWithoutCategories', NULL, NULL, $this->request->getArguments());
 		}
 
-		$endTime = 0;
-		if (isset($this->settings['endtime'])) {
-			$endTime = (int) $this->settings['endtime'];
-		}
-
-		/** @var News $highlightedNews */
-		$highlightedNews = $this->newsRepository
-			->findLastUpdatedOrHighlightedNewsByCategories(
-				1,
-				FALSE,
-				$categoryIds,
-				0,
-				FALSE,
-				$this->settings['sortBy'],
-				$tagIds,
-				$startTime,
-				$endTime
-			)->getFirst();
-		if (!$highlightedNews) {
-			return;
-		}
-
-		/** @var Category $category */
-		$category = $this->categoryRepository->findByUid($highlightedNews->getPid());
-		$highlightedNewsMetaData = NULL;
-		if ($category) {
-			$highlightedNewsMetaData = $this->getMetaDataForNews($highlightedNews, $category);
-		}
+		// Setup settings
+		$startTime = (int) $this->settings['starttime'];
+		$endTime = (int) $this->settings['endtime'];
+		$newsLimit = (int) $this->settings['newsLimit'];
+		$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;
 
-		if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
-			if (isset($highlightedNewsMetaData['imageObject'])) {
-				HeaderMetaDataService::addOgImageObjectToHeader(
-					$highlightedNewsMetaData['imageObject']
-						? $highlightedNewsMetaData['imageObject']->getOriginalResource()
-						: NULL
-				);
-			} elseif (isset($highlightedNewsMetaData['teaserImageObject'])) {
-				HeaderMetaDataService::addOgImageObjectToHeader(
-					$highlightedNewsMetaData['teaserImageObject']
-						? $highlightedNewsMetaData['teaserImageObject']->getOriginalResource()
-						: NULL
-				);
-			}
+		// Get tag pid
+		$tagPid = (int) $this->settings['tagPid'];
+		if (!$tagPid) {
+			$tagPid = $GLOBALS['TSFE']->id;
 		}
-	}
-
-	/**
-	 * Renders the news overview grouped by categories
-	 *
-	 * @param array $newsByCategory
-	 * @param array $allNews
-	 * @param array $newsFilter
-	 * @param int $currentPageBrowserPage
-	 * @return void
-	 * @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
-	 */
-	protected function overviewWithCategories(
-		array $newsByCategory = [],
-		array $allNews = [],
-		array $newsFilter = [],
-		int $currentPageBrowserPage = 0
-	) {
-		$newsLimitPerCategory = (int) $this->settings['newsLimit'];
-		$this->categoryRepository->setDefaultOrderings(['sorting' => Query::ORDER_ASCENDING]);
-
-		$offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsLimitPerCategory);
 
 		if ($this->settings['onlyNewsWithinThisPageSection']) {
 			$categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id);
+			$tags = $this->tagRepository->findTagsInRootLine($tagPid);
 		} else {
+			$tags = $this->tagRepository->findAll()->toArray();
 			$categories = $this->categoryRepository->findAll()->toArray();
 		}
 
-		if (count($categories) <= 0) {
-			return;
+		// Apply category restrictions
+		$categoryRestrictions = GeneralUtility::intExplode(',', $this->settings['categoryRestrictions'], TRUE);
+		if (!$isCategoryFiltered) {
+			$categoryRestrictions = [];
 		}
+		if (count($categoryRestrictions) > 0) {
+			foreach ($categories as $key => $category) {
+				$categoryId = $category->getUid();
 
-		if (isset($this->settings['categoryRestrictions'])) {
-			$categoryRestrictions = GeneralUtility::intExplode(',', $this->settings['categoryRestrictions'], TRUE);
-			if (count($categoryRestrictions) > 0) {
-				foreach ($categories as $key => $category) {
-					$categoryId = $category->getUid();
-
-					// older version compatibility with selection of categories in translations and so on
-					$categoryIdTranslated = $categoryId;
-					if ($category->_getProperty('_languageUid') > 0) {
-						$originalLangCategory = $this->categoryRepository->findOriginalLanguageById($categoryId);
-						if ($originalLangCategory) {
-							$categoryIdTranslated = $originalLangCategory->getUid();
-						}
+				// older version compatibility with selection of categories in translations and so on
+				$categoryIdTranslated = $categoryId;
+				if ($category->_getProperty('_languageUid') > 0) {
+					$originalLangCategory = $this->categoryRepository->findOriginalLanguageById($categoryId);
+					if ($originalLangCategory) {
+						$categoryIdTranslated = $originalLangCategory->getUid();
 					}
+				}
 
-					if (!in_array($categoryId, $categoryRestrictions, TRUE) &&
-						!in_array($categoryIdTranslated, $categoryRestrictions, TRUE)
-					) {
-						unset($categories[$key]);
-					}
+				if (!in_array($categoryId, $categoryRestrictions, TRUE) &&
+					!in_array($categoryIdTranslated, $categoryRestrictions, TRUE)
+				) {
+					unset($categories[$key]);
 				}
 			}
 		}
 
-		if (count($categories) <= 0) {
-			return;
-		}
-
-		$startTime = 0;
-		if (isset($this->settings['starttime'])) {
-			$startTime = (int) $this->settings['starttime'];
-		}
-
-		$endTime = 0;
-		if (isset($this->settings['endtime'])) {
-			$endTime = (int) $this->settings['endtime'];
+		// Apply tag restrictions
+		$tagRestrictions = GeneralUtility::intExplode(',', $this->settings['tagRestrictions'], TRUE);
+		if (!$isTagFiltered) {
+			$tagRestrictions = [];
 		}
-
-		$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
-		$sortBy = $configurationService->getConfiguration('sortBy', $this->settings);
-		$sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings);
-
-		$categoryIds = [];
-		$categoriesById = [];
-		$newsMetaData = [];
-		foreach ($categories as $category) {
-			/** @var Category $category */
-			$categoryId = $category->getUid();
-			$categoryIdsForSelect = [$categoryId];
-			$categoryIds[] = $category->getUid();
-			$categoriesById[$categoryId] = $category;
-			if ($category->_getProperty('_languageUid') > 0) {
-				$originalLangCategory = $this->categoryRepository->findOriginalLanguageById($category->getUid());
-				if ($originalLangCategory) {
-					$originalLangCategoryId = $originalLangCategory->getUid();
-					$categoryIdsForSelect[] = $originalLangCategoryId;
-					$categoryIds[] = $originalLangCategoryId;
-					$categoriesById[$originalLangCategoryId] = $originalLangCategory;
-				}
-			}
-
-			$tagIds = NULL;
-			if (isset($newsFilter['tag']) && $newsFilter['tag']) {
-				$tagIds = [(int) $newsFilter['tag']];
-			}
-			foreach ($categoryIdsForSelect as $categoryIdsForSelectId) {
-				$news = $this->newsRepository->findAllSortedNewsByCategories(
-					[$categoryIdsForSelectId],
-					$newsLimitPerCategory,
-					$offset,
-					$sortBy,
-					$tagIds,
-					$startTime,
-					$endTime,
-					$sortDirection
-				);
-
-				$newsMetaData[$categoryIdsForSelectId] = [];
-				foreach ($news as $newsEntry) {
-					/** @var News $newsEntry */
-					$category = $categoriesById[$categoryIdsForSelectId];
-					if (!$category) {
-						// Category isn't visible.
-						continue;
-					}
-
-					$data = $this->getMetaDataForNews($newsEntry, $category);
-					$newsMetaData[$categoryIdsForSelectId][] = $data;
+		if (count($tagRestrictions) > 0) {
+			foreach ($tags as $key => $tag) {
+				if (!in_array($tag->getUid(), $tagRestrictions, TRUE)) {
+					unset($tags[$key]);
 				}
 			}
 		}
 
-		$maxNewsPerCategory = 0;
-		foreach ($categoriesById as $categoryId => $category) {
-			if (!isset($newsMetaData[$categoryId]) || count($newsMetaData[$categoryId]) <= 0) {
-				// Hide empty categories.
-				continue;
-			}
-
-			/** @var Category $category */
-			if (isset($newsByCategory[$categoryId])) {
-				/** @var Category $category */
-				$newsByCategory[$categoryId]['newsMetaData'] =
-					array_merge($newsByCategory[$categoryId]['newsMetaData'], $newsMetaData[$categoryId], $newsFilter);
-			} else {
-				$newsByCategory[$categoryId] = [
-					'record' => $category,
-					'recordId' => $categoryId,
-					'recordType' => 'category',
-					'newsMetaData' => $newsMetaData[$categoryId],
-					'newsCount' => count($newsMetaData[$categoryId])
-				];
+		// Get category ids or use the one in the filter
+		$categoryIds = [];
+		if ($newsFilter['category']) {
+			$categoryIds = [(int) $newsFilter['category']];
+		} elseif ($isCategoryFiltered) {
+			foreach ($categories as $category) {
+				$categoryIds[] = $category->getUid();
 			}
-
-			$maxNewsPerCategory = \max($maxNewsPerCategory, \count($newsByCategory[$categoryId]['newsMetaData']));
+		} else {
+			$categoryIds = NULL;
 		}
 
-		$tagIds = NULL;
-		if (isset($newsFilter['tag']) && $newsFilter['tag']) {
+		// Get tag ids or use the one in the filter
+		$tagIds = [];
+		if ($newsFilter['tag']) {
 			$tagIds = [(int) $newsFilter['tag']];
+		} elseif ($isTagFiltered) {
+			foreach ($tags as $tag) {
+				$tagIds[] = $tag->getUid();
+			}
+		} else {
+			$tagIds = NULL;
 		}
-		if ($newsFilter['category']) {
-			$categoryIds = [(int) $newsFilter['category']];
-		}
+
+		// Get all news by category and tag ids
 		$news = $this->newsRepository->findAllSortedNewsByCategories(
-			$categoryIds,
-			$newsLimitPerCategory,
-			$offset,
-			$sortBy,
-			$tagIds,
-			$startTime,
-			$endTime,
-			$sortDirection
+			$categoryIds, $newsLimit, $offset, $sortBy, $tagIds, $startTime, $endTime, $sortDirection
 		);
 
+		// Process news result query based on filters
+		$allNews = [];
+		$newsItems = [];
+		$areCategoriesCreated = FALSE;
 		foreach ($news as $newsEntry) {
 			/** @var News $newsEntry */
-			$categoryId = $newsEntry->getPid();
-			$category = $categoriesById[$categoryId];
-			if (!$category) {
-				// Category isn't visible.
-				continue;
+			$newsCategory = $this->categoryRepository->findOriginalLanguageById(
+					$newsEntry->getPid()
+				) ?? $this->categoryRepository->findByUid($newsEntry->getPid());
+			$newsCategoryId = $newsCategory->getUid();
+			$newsMetaData = $this->newsService->getMetaDataForNews($newsEntry, $newsCategory);
+
+			if ((int) $this->settings['groupBy'] === 1) {
+				if (!$areCategoriesCreated) {
+					// Add all required categories
+					foreach ($categories as $category) {
+						/** @var Category $category */
+						$newsItems[$category->getUid()] = [
+							'record' => $category,
+							'recordId' => $category->getUid(),
+							'recordType' => 'category',
+							'newsMetaData' => [],
+							'newsCount' => 0
+						];
+					}
+					$areCategoriesCreated = TRUE;
+				}
+
+				$newsItems[$newsCategoryId]['newsMetaData'][] = $newsMetaData;
+				$newsItems[$newsCategoryId]['newsCount'] += 1;
+			} else {
+				foreach ($tags as $tag) {
+					$tagId = $tag->getUid();
+					if (!isset($newsItems[$tagId])) {
+						$newsItems[$tagId] = [
+							'record' => $tag,
+							'recordId' => $tagId,
+							'recordType' => 'tag',
+							'newsMetaData' => [],
+							'newsCount' => 0
+						];
+					}
+
+					if ($newsEntry->getTags()->contains($tag)) {
+						$newsItems[$tagId]['newsMetaData'][] = $newsMetaData;
+						$newsItems[$tagId]['newsCount'] += 1;
+					}
+				}
 			}
 
-			$data = $this->getMetaDataForNews($newsEntry, $category);
-			$allNews[] = $data;
+			$allNews[] = $newsMetaData;
 		}
 
-		$this->highlightBestFitNews($categoryIds);
+		$this->highlightBestFitNews($categoryIds, $tagIds);
 
+		// Check to achieve less Ajax calls.
 		$newsCount = $this->newsRepository->newsCountByCategories($categoryIds, $tagIds, $startTime, $endTime);
-		$numberOfPages = (int) ($newsLimitPerCategory <= 0 ? 0 : ceil($newsCount / $newsLimitPerCategory));
+		$numberOfPages = (int) ($newsLimit <= 0 ? 0 : ceil($newsCount / $newsLimit));
 		if ($numberOfPages !== 0 && $currentPageBrowserPage >= $numberOfPages) {
 			/** @var ErrorController $errorController */
 			$errorController = GeneralUtility::makeInstance(ErrorController::class);
@@ -397,214 +288,94 @@ class OverviewController extends AbstractController {
 			throw new ImmediateResponseException($response);
 		}
 
-		// find all tags
-		$tagPid = $GLOBALS['TSFE']->id;
-		if ($this->settings['onlyNewsWithinThisPageSection']) {
-			$tags = $this->tagRepository->findTagsInRootLine($tagPid);
-		} else {
-			$tags = $this->tagRepository->findAll()->toArray();
-		}
-
 		// remember selection of the filter values, if any
-		$selectedTag = NULL;
-		if (isset($newsFilter['tag'])) {
-			$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
-		}
-		$selectedCategory = NULL;
-		if(isset($newsFilter['category'])) {
-			$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
-		}
+		$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
+		$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
 		$this->view->assign('selectedCategory', $selectedCategory);
 		$this->view->assign('selectedTag', $selectedTag);
 		$this->view->assign('tags', $tags);
 		$this->view->assign('categories', $categories);
 		$this->view->assign('numberOfPages', $numberOfPages);
-		$this->view->assign('newsItems', $newsByCategory);
-		$this->view->assign('groupBy', 'category');
+		$this->view->assign('newsItems', $newsItems);
 		$this->view->assign('allNews', $allNews);
-		$this->view->assign('categoryTabs', TRUE);
+		$this->setupGridColumns();
+
+		switch ($this->settings['groupBy']) {
+			case 1:
+				$this->view->assign('groupBy', 'category');
+				$this->view->assign('categoryTabs', TRUE);
+				break;
+			case 2:
+				$this->view->assign('groupBy', 'tag');
+				$this->view->assign('tagTabs', TRUE);
+				break;
+			default:
+				$this->view->assign('groupBy', 'none');
+		}
 	}
 
 	/**
-	 * Renders the news overview grouped by tags
+	 * Assign the grid column classes to the frontend
 	 *
-	 * @param array $newsByTag
-	 * @param array $allNews
-	 * @param array $newsFilter
-	 * @param int $currentPageBrowserPage
 	 * @return void
-	 * @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
 	 */
-	protected function overviewWithTags(
-		array $newsByTag = [],
-		array $allNews = [],
-		array $newsFilter = [],
-		int $currentPageBrowserPage = 0
-	) {
-		$startTime = (int) $this->settings['starttime'];
-		$endTime = (int) $this->settings['endtime'];
-		$newsLimitPerTag = (int) $this->settings['newsLimit'];
-		$offset = $this->calculatePaginationOffset($currentPageBrowserPage, $newsLimitPerTag);
-		$tagPid = (int) $this->settings['tagPid'];
-		if (!$tagPid) {
-			$tagPid = $GLOBALS['TSFE']->id;
+	protected function setupGridColumns(): void {
+		if (!isset($this->settings['gridColumns'])) {
+			$this->view->assign('gridColumnClasses', 'col-md-4 col-sm-6 col-xs-12');
+			return;
 		}
 
-		$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
-		$sortBy = $configurationService->getConfiguration('sortBy', $this->settings);
-		$sortDirection = $configurationService->getConfiguration('sortDirection', $this->settings);
+		$columnAmount = (int) $this->settings['gridColumns'];
+		$columnClasses = '';
 
-		$categoryIds = NULL;
-		if ($newsFilter['category']) {
-			$categoryIds = [(int) $newsFilter['category']];
-		}
-
-		$this->tagRepository->setDefaultOrderings(['sorting' => QueryInterface::ORDER_ASCENDING]);
-		if ($this->settings['onlyNewsWithinThisPageSection']) {
-			$tags = $this->tagRepository->findTagsInRootLine($tagPid);
-		} else {
-			$tags = $this->tagRepository->findAll()->toArray();
+		switch ($columnAmount) {
+			case 4:
+				$columnClasses .= 'col-lg-3 ';
+			case 3:
+				$columnClasses .= 'col-md-4 ';
+			case 2:
+				$columnClasses .= 'col-sm-6 ';
+			default:
+				$columnClasses .= 'col-xs-12';
 		}
 
-		$tagRestrictions = GeneralUtility::intExplode(',', $this->settings['tagRestrictions'], TRUE);
-		if (count($tagRestrictions) > 0) {
-			foreach ($tags as $key => $tag) {
-				if (!in_array($tag->getUid(), $tagRestrictions, TRUE)) {
-					unset($tags[$key]);
-				}
-			}
-		}
+		$this->view->assign('gridColumnClasses', $columnClasses);
+	}
 
-		// Get news by tag id
-		$tagIds = [];
-		$tagsById = [];
-		$categoriesById = [];
-		$newsMetaData = [];
-		foreach ($tags as $tag) {
-			/** @var Tag $tag */
-			$tagId = $tag->getUid();
-			$tagIds[] = $tagId;
-			$tagsById[$tagId] = $tag;
-
-			$news = $this->newsRepository->findAllSortedNewsByCategories(
-				$categoryIds,
-				$newsLimitPerTag,
-				$offset,
-				$sortBy,
-				[$tagId],
-				$startTime,
-				$endTime,
-				$sortDirection
-			);
-			$newsMetaData[$tagId] = [];
-			foreach ($news as $newsEntry) {
-				/** @var News $newsEntry */
-				$categoryId = $newsEntry->getPid();
-				if (!isset($categoriesById[$categoryId])) {
-					$categoriesById[$categoryId] = $this->categoryRepository->findByUid($categoryId);
-				}
-				$category = $categoriesById[$categoryId];
-				if (!$category) {
-					// Category isn't visible.
-					continue;
-				}
+	/**
+	 * Highlights the best fitting news in the metadata of the page
+	 *
+	 * @param array|null $categoryIds
+	 * @param array|null $tagIds
+	 * @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'];
 
-				$newsMetaData[$tagId][] = $this->getMetaDataForNews($newsEntry, $category);
-			}
+		/** @var News $highlightedNews */
+		$highlightedNews = $this->newsRepository
+			->findLastUpdatedOrHighlightedNewsByCategories(
+				1, FALSE, $categoryIds, 0, FALSE, $this->settings['sortBy'], $tagIds, $startTime, $endTime
+			)->getFirst();
+		if (!$highlightedNews) {
+			return;
 		}
 
-		// Process news by tag id
-		$maxNewsPerTag = 0;
-		foreach ($tagsById as $tagId => $tag) {
-			if (\count($newsMetaData[$tagId]) <= 0) {
-				// Hide empty tags.
-				continue;
-			}
-
-			if (isset($newsByTag[$tagId])) {
-				$newsByTag[$tagId]['newsMetaData'] =
-					\array_merge($newsByTag[$tagId]['newsMetaData'], $newsMetaData[$tagId]);
-			} else {
-				$newsByTag[$tagId] = [
-					'record' => $tag,
-					'recordId' => $tagId,
-					'recordType' => 'tag',
-					'newsMetaData' => $newsMetaData[$tagId],
-					'newsCount' => \count($newsMetaData[$tagId])
-				];
-			}
-
-			$maxNewsPerTag = \max($maxNewsPerTag, \count($newsByTag[$tagId]['newsMetaData']));
+		/** @var Category $category */
+		$category = $this->categoryRepository->findByUid($highlightedNews->getPid());
+		$highlightedNewsMetaData = NULL;
+		if ($category) {
+			$highlightedNewsMetaData = $this->newsService->getMetaDataForNews($highlightedNews, $category);
 		}
 
-		// Get all news by tags.
-		if ($newsFilter['tag']) {
-			$tagIds = [(int) $newsFilter['tag']];
-		}
-		$news = $this->newsRepository->findAllSortedNewsByCategories(
-			$categoryIds,
-			$newsLimitPerTag,
-			$offset,
-			$sortBy,
-			$tagIds,
-			$startTime,
-			$endTime,
-			$sortDirection
-		);
-		foreach ($news as $newsEntry) {
-			/** @var News $newsEntry */
-			$categoryId = $newsEntry->getPid();
-			if (!isset($categoriesById[$categoryId])) {
-				$categoriesById[$categoryId] = $this->categoryRepository->findByUid($categoryId);
-			}
-			/** @var Category $category */
-			$category = $categoriesById[$categoryId];
-			if (!$category) {
-				// Category isn't visible.
-				continue;
+		if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
+			if ($highlightedNewsMetaData['image']) {
+				HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['image']);
+			} elseif ($highlightedNewsMetaData['teaserImage']) {
+				HeaderMetaDataService::addOgImageToHeader($highlightedNewsMetaData['teaserImage']);
 			}
-
-			$allNews[] = $this->getMetaDataForNews($newsEntry, $category);
-		}
-
-		$this->highlightBestFitNews([], $tagIds);
-
-		// Check to achieve less Ajax calls.
-		$newsCount = $this->newsRepository->newsCountByCategories([], $tagIds, $startTime, $endTime);
-		$numberOfPages = (int) ($newsLimitPerTag <= 0 ? 0 : ceil($newsCount / $newsLimitPerTag));
-		if ($numberOfPages !== 0 && $currentPageBrowserPage >= $numberOfPages) {
-			/** @var ErrorController $errorController */
-			$errorController = GeneralUtility::makeInstance(ErrorController::class);
-			$response = $errorController->pageNotFoundAction(
-				$GLOBALS['TYPO3_REQUEST'],
-				'The requested page does not exist',
-				['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
-			);
-			throw new ImmediateResponseException($response);
-		}
-
-		if ($this->settings['onlyNewsWithinThisPageSection']) {
-			$categories = $this->categoryRepository->findCategoriesInRootLine($GLOBALS['TSFE']->id);
-		} else {
-			$categories = $this->categoryRepository->findAll()->toArray();
 		}
-
-		// remember selection of the filter values, if any
-		$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
-		$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
-		$this->view->assign('selectedCategory', $selectedCategory);
-		$this->view->assign('selectedTag', $selectedTag);
-		$this->view->assign('tags', $tags);
-		$this->view->assign('categories', $categories);
-		$this->view->assign('numberOfPages', $numberOfPages);
-		$this->view->assign('newsItems', $newsByTag);
-		$this->view->assign('groupBy', 'tag');
-		$this->view->assign('allNews', $allNews);
-		$this->view->assign('tagTabs', TRUE);
 	}
 
 	/**
@@ -625,17 +396,15 @@ class OverviewController extends AbstractController {
 	 * @param array $newsMetaData
 	 * @param array|null $newsFilter
 	 * @param int $currentPageBrowserPage
-	 * @return null|\Psr\Http\Message\ResponseInterface
+	 * @return void
 	 * @throws ImmediateResponseException
 	 * @throws \TYPO3\CMS\Core\Error\Http\PageNotFoundException
 	 * @throws \TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException
 	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
 	 */
 	protected function overviewWithoutCategoriesAction(
-		array $newsMetaData = [],
-		array $newsFilter = NULL,
-		int $currentPageBrowserPage = 0
-	): ?\Psr\Http\Message\ResponseInterface {
+		array $newsMetaData = [], array $newsFilter = NULL, int $currentPageBrowserPage = 0
+	) {
 		// remember selection of the filter values, if any
 		$selectedTag = $this->tagRepository->findByUid((int) $newsFilter['tag']);
 		$selectedCategory = $this->categoryRepository->findByUid((int) $newsFilter['category']);
@@ -696,13 +465,7 @@ class OverviewController extends AbstractController {
 		}
 
 		if ($newsCount <= 0) {
-			if (version_compare(
-				\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<'
-			)) {
-				return NULL;
-			} else {
-				return $this->htmlResponse();
-			}
+			return;
 		}
 
 		// filter by category and tag if selected in the filter
@@ -716,18 +479,11 @@ 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 */
-			$data = $this->getMetaDataForNews($newsEntry, $categoriesById[$newsEntry->getPid()]);
+			$data = $this->newsService->getMetaDataForNews($newsEntry, $categoriesById[$newsEntry->getPid()]);
 			$newsMetaData[] = $data;
 		}
 
@@ -756,11 +512,7 @@ class OverviewController extends AbstractController {
 		$this->view->assign('categories', $categories);
 		$this->view->assign('numberOfPages', $numberOfPages);
 		$this->view->assign('newsMetaData', $newsMetaData);
-		if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '11.0.0', '<')) {
-			return NULL;
-		} else {
-			return $this->htmlResponse();
-		}
+		$this->setupGridColumns();
 	}
 
 	/**
diff --git a/Classes/Controller/SingleViewController.php b/Classes/Controller/SingleViewController.php
index d65d6834ca0bf6415d9fe02926f51136abf35bff..d05abdf9b1cb7fd764fff8f7ea0725c701b56a72 100644
--- a/Classes/Controller/SingleViewController.php
+++ b/Classes/Controller/SingleViewController.php
@@ -31,6 +31,7 @@ use SGalinski\SgNews\Domain\Model\News;
 use SGalinski\SgNews\Domain\Repository\CategoryRepository;
 use SGalinski\SgNews\Domain\Repository\NewsRepository;
 use SGalinski\SgNews\Domain\Repository\TagRepository;
+use SGalinski\SgNews\Domain\Service\NewsService;
 use SGalinski\SgNews\Service\HeaderMetaDataService;
 use TYPO3\CMS\Core\Charset\CharsetConverter;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
@@ -59,6 +60,11 @@ class SingleViewController extends AbstractController {
 	 */
 	protected $characterSetConverter;
 
+	/**
+	 * @var NewsService
+	 */
+	protected $newsService;
+
 	/**
 	 * Renders the news single view
 	 *
@@ -91,7 +97,7 @@ class SingleViewController extends AbstractController {
 			}
 		}
 
-		$newsMetaData = $this->getMetaDataForNews($news, $newsCategory);
+		$newsMetaData = $this->newsService->getMetaDataForNews($news, $newsCategory);
 		if (!version_compare(ExtensionManagementUtility::getExtensionVersion('sg_seo'), '5.0.0', '>=')) {
 			if (isset($newsMetaData['imageObject'])) {
 				HeaderMetaDataService::addOgImageObjectToHeader(
@@ -158,4 +164,11 @@ class SingleViewController extends AbstractController {
 	public function injectTagRepository(TagRepository $tagRepository) {
 		$this->tagRepository = $tagRepository;
 	}
+
+	/**
+	 * @param NewsService $newsService
+	 */
+	public function injectNewsService(NewsService $newsService) {
+		$this->newsService = $newsService;
+	}
 }
diff --git a/Classes/Domain/Model/News.php b/Classes/Domain/Model/News.php
index f6e06c12d0c02c5a76e2658b1778f2fedc2b8c35..d042f4b004717147ad9e35f700652254dc8786b1 100644
--- a/Classes/Domain/Model/News.php
+++ b/Classes/Domain/Model/News.php
@@ -97,14 +97,19 @@ class News extends CategoryAndNews {
 	 */
 	protected $contentFromAnotherPage = 0;
 
+	/**
+	 * @var bool
+	 */
+	protected $enableComments = TRUE;
+
 	/**
 	 * Constructor
 	 */
 	public function __construct() {
 		parent::__construct();
-		$this->relatedNews = new ObjectStorage();
 		$this->tags = new ObjectStorage();
 		$this->newsAuthor = new ObjectStorage();
+		$this->relatedNews = new ObjectStorage();
 	}
 
 	/**
@@ -383,4 +388,18 @@ class News extends CategoryAndNews {
 	public function setContentFromAnotherPage(int $contentFromAnotherPage): void {
 		$this->contentFromAnotherPage = $contentFromAnotherPage;
 	}
+
+	/**
+	 * @return bool
+	 */
+	public function getEnableComments(): bool {
+		return $this->enableComments;
+	}
+
+	/**
+	 * @param bool $enableComments
+	 */
+	public function setEnableComments(bool $enableComments): void {
+		$this->enableComments = $enableComments;
+	}
 }
diff --git a/Classes/Domain/Repository/NewsRepository.php b/Classes/Domain/Repository/NewsRepository.php
index d7c474bdc9b0e6c6d6273b1c3df282a7b3f71fb7..216bd862376f686dd833c08e4de5d1bfd77f47b3 100644
--- a/Classes/Domain/Repository/NewsRepository.php
+++ b/Classes/Domain/Repository/NewsRepository.php
@@ -26,8 +26,10 @@ namespace SGalinski\SgNews\Domain\Repository;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
-use SGalinski\SgNews\Domain\Model\Author;
 use SGalinski\SgNews\Domain\Model\News;
+use TYPO3\CMS\Core\Database\Connection;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
 use TYPO3\CMS\Extbase\Persistence\QueryInterface;
 use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
@@ -533,4 +535,102 @@ class NewsRepository extends AbstractRepository {
 		$query->matching($query->equals('uid', $uid));
 		return $query->execute()->getFirst();
 	}
+
+	/**
+	 * This method finds news related by Tag or Category to the given news record
+	 *
+	 * @param News $news The news to find related news to
+	 * @param int $limit Limit the amount of related news
+	 * @return QueryResultInterface
+	 * @throws \Doctrine\DBAL\Driver\Exception
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
+	 */
+	public function findRelated(News $news, int $limit = 0): QueryResultInterface {
+		$connection = $this->getConnection();
+		$qb = $connection->createQueryBuilder();
+		// We need to build the constraint for the tags/categories
+		$constraints = [];
+		$tags = $news->getTags();
+		if ($tags->count() > 0) {
+			$qb->leftJoin('pages', 'sys_category_record_mm', 'tags', 'pages.uid=tags.uid_foreign');
+			$tagConstraints = [];
+			foreach ($tags as $tag) {
+				$tagConstraints[] = $qb->expr()->eq('tags.uid_local', $tag->getUid());
+			}
+			$constraints[] = $qb->expr()->eq('tags.tablenames', $qb->createNamedParameter('pages'));
+			$constraints[] = $qb->expr()->eq('tags.fieldname', $qb->createNamedParameter('tx_sgnews_tags'));
+			$constraints[] = $qb->expr()->orX(...$tagConstraints);
+		} else {
+			$constraints[] = $qb->expr()->eq('pid', $news->getPid());
+		}
+
+		if ($limit > 0) {
+			$qb->setMaxResults($limit);
+		}
+
+		// here we fetch the lastUpdated of the $limit amount of news with newer lastUpdated dates
+		$result = $qb->select('lastUpdated')
+			->from('pages', 'pages')
+			->where(
+				$qb->expr()->eq('doktype', $qb->createNamedParameter(News::DOK_TYPE_NEWS, Connection::PARAM_INT)),
+				$qb->expr()->gte('lastUpdated', $news->getLastUpdated()->getTimestamp())
+			)->andWhere(...$constraints)
+			->orderBy('lastUpdated', 'desc')
+			->execute();
+		$newest = $result->fetchOne();
+
+		// 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)
+			->orderBy('lastUpdated', 'asc')
+			->execute();
+		$oldest = $result->fetchOne();
+
+		$query = $this->createQuery();
+		$query->getQuerySettings()->setRespectStoragePage(FALSE);
+		$query->setOrderings([
+			'lastUpdated' => QueryInterface::ORDER_DESCENDING
+		]);
+		$constraints = [
+			$query->logicalNot(
+				$query->equals('uid', $news->getUid())
+			)
+		];
+		if ($newest) {
+			$constraints[] = $query->lessThanOrEqual('lastUpdated', $newest);
+		}
+		if ($oldest) {
+			$constraints[] = $query->greaterThanOrEqual('lastUpdated', $oldest);
+		}
+
+		// Now we fetch the $limit amount of news via extbase query and limit them to the newest and oldest date
+		// remember, we fetched the oldest and newest date from the $limit amount of news newer and older then
+		// the given news. If we limit the result of the following query to $limit, we get $limit amount of news
+		// "around" the given news, where newer news are preferred due to the ordering.
+		$tags = $news->getTags();
+		if ($tags->count() > 0) {
+			$tagConstraints = [];
+			foreach ($tags as $tag) {
+				$tagConstraints[] = $query->contains('tags', $tag);
+			}
+
+			$constraints[] = $query->logicalOr($tagConstraints);
+		} else {
+			$constraints[] = $query->equals('pid', $news->getPid());
+		}
+
+		$query->matching($query->logicalAnd($constraints));
+		if ($limit > 0) {
+			$query->setLimit($limit);
+		}
+
+		return $query->execute();
+	}
+
+	protected function getConnection(): Connection {
+		return GeneralUtility::makeInstance(ConnectionPool::class)
+			->getConnectionForTable('pages');
+	}
 }
diff --git a/Classes/Domain/Service/NewsService.php b/Classes/Domain/Service/NewsService.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ba3ad6d291e7a412b78cf1b3145c203321c4595
--- /dev/null
+++ b/Classes/Domain/Service/NewsService.php
@@ -0,0 +1,167 @@
+<?php
+
+namespace SGalinski\SgNews\Domain\Service;
+
+/***************************************************************
+ *  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\Domain\Model\Category;
+use SGalinski\SgNews\Domain\Model\News;
+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
+ */
+class NewsService implements SingletonInterface {
+	/**
+	 * @var array
+	 */
+	protected $cachedSingleNews = [];
+
+	/**
+	 * Returns the metadata of the given news.
+	 *
+	 * @param News $news
+	 * @param Category $category
+	 * @return array
+	 * @throws \InvalidArgumentException
+	 */
+	public function getMetaDataForNews(News $news, Category $category): array {
+		$newsId = $news->getUid();
+		if (isset($this->cachedSingleNews[$newsId])) {
+			return $this->cachedSingleNews[$newsId];
+		}
+
+		$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
+		$fileObjects = $fileRepository->findByRelation('pages', 'media', $news->getUid());
+
+		$singleNewsImageData = $this->getDataForSingleViewImage($news, $category);
+		$teaserImageData = $this->getDataForTeaserImage($news, $category);
+
+		// Use single news image data for teaser image data, if the teaser imaga data are empty.
+		$teaserIsEmpty = $teaserImageData['teaserImage'] === NULL && $teaserImageData['teaserImageObject'] === NULL;
+		$singleNewsIsEmpty = $singleNewsImageData['image'] === NULL && $singleNewsImageData['imageObject'] === NULL;
+		if ($teaserIsEmpty && !$singleNewsIsEmpty) {
+			$teaserImageData = [
+				'teaserImage' => $singleNewsImageData['image'],
+				'teaserImageObject' => $singleNewsImageData['imageObject'],
+			];
+		}
+
+		$newsRecord = array_merge(
+			[
+				'category' => $category,
+				'news' => $news,
+			],
+			$singleNewsImageData,
+			$teaserImageData,
+			['media' => $fileObjects]
+		);
+
+		$this->cachedSingleNews[$newsId] = $newsRecord;
+
+		return $newsRecord;
+	}
+
+	/**
+	 * Returns the single view image data as an array for the given news and category as fallback.
+	 *
+	 * @param News $news
+	 * @param Category $category
+	 * @return array
+	 * @throws \InvalidArgumentException
+	 */
+	public function getDataForSingleViewImage(News $news, Category $category): array {
+		/** @var FileReference $singleNewsImage */
+		$singleNewsImage = $singleNewsImageObject = NULL;
+		$singleNewsImages = $news->getTeaser2Image();
+		if (count($singleNewsImages)) {
+			$singleNewsImage = $singleNewsImages->current();
+		} else {
+			$categoryImages = $category->getTeaser2Image();
+			if (count($categoryImages)) {
+				$singleNewsImage = $categoryImages->current();
+			}
+		}
+
+		if ($singleNewsImage) {
+			$singleNewsImageObject = $singleNewsImage;
+			$originalResource = $singleNewsImage->getOriginalResource();
+			if ($originalResource) {
+				$singleNewsImage = $originalResource->getPublicUrl();
+			}
+
+			if ($singleNewsImage) {
+				$singleNewsImage = $GLOBALS['TSFE']->absRefPrefix . $singleNewsImage;
+			}
+		}
+
+		return [
+			'image' => $singleNewsImage,
+			'imageObject' => $singleNewsImageObject,
+		];
+	}
+
+	/**
+	 * Returns the teaser image data as an array for the given news and category as fallback.
+	 *
+	 * @param News $news
+	 * @param Category $category
+	 * @return array
+	 * @throws \InvalidArgumentException
+	 */
+	public function getDataForTeaserImage(News $news, Category $category): array {
+		/** @var FileReference $teaserImage */
+		$teaserImage = $teaserImageObject = NULL;
+		$teaserImages = $news->getTeaser1Image();
+		if (count($teaserImages)) {
+			$teaserImage = $teaserImages->current();
+		} else {
+			$categoryImages = $category->getTeaser1Image();
+			if (count($categoryImages)) {
+				$teaserImage = $categoryImages->current();
+			}
+		}
+
+		if ($teaserImage) {
+			$teaserImageObject = $teaserImage;
+			$originalResource = $teaserImage->getOriginalResource();
+			if ($originalResource) {
+				$teaserImage = $originalResource->getPublicUrl();
+			}
+
+			if ($teaserImage) {
+				$teaserImage = $GLOBALS['TSFE']->absRefPrefix . $teaserImage;
+			}
+		}
+
+		return [
+			'teaserImage' => $teaserImage,
+			'teaserImageObject' => $teaserImageObject,
+		];
+	}
+}
diff --git a/Classes/ViewHelpers/RelatedViewHelper.php b/Classes/ViewHelpers/RelatedViewHelper.php
new file mode 100644
index 0000000000000000000000000000000000000000..69b8e781d353728940d593b4788c082e934de247
--- /dev/null
+++ b/Classes/ViewHelpers/RelatedViewHelper.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace SGalinski\SgNews\ViewHelpers;
+
+use SGalinski\SgNews\Domain\Repository\CategoryRepository;
+use SGalinski\SgNews\Domain\Repository\NewsRepository;
+use SGalinski\SgNews\Domain\Service\NewsService;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
+
+/**
+ * Renders related news based on the current news
+ */
+class RelatedViewHelper extends AbstractViewHelper {
+	use CompileWithRenderStatic;
+
+	/**
+	 * @var bool
+	 */
+	protected $escapeOutput = false;
+
+	/**
+	 * Initialize the view helper arguments
+	 */
+	public function initializeArguments() {
+		$this->registerArgument(
+			'news',
+			'SGalinski\SgNews\Domain\Model\News',
+			'The news record from which to find related news',
+			TRUE
+		);
+		$this->registerArgument(
+			'limit',
+			'int',
+			'Limit the amount of related news to display',
+			FALSE,
+			5
+		);
+		$this->registerArgument(
+			'as',
+			'string',
+			'The name of the iteration variable',
+			TRUE
+		);
+		$this->registerArgument(
+			'iteration', 'string',
+			'The name of the variable to store iteration information (index, cycle, isFirst, isLast, isEven, isOdd)'
+		);
+		$this->registerArgument(
+			'relatedNews',
+			ObjectStorage::class,
+			'An optional list of related news to take instead of finding some via the news repository',
+			FALSE,
+			NULL
+		);
+	}
+
+	/**
+	 * It works like the for-ViewHelper by running through the child content and adding the related news records to it
+	 *
+	 * @param array $arguments
+	 * @param \Closure $renderChildrenClosure
+	 * @param RenderingContextInterface $renderingContext
+	 * @return string
+	 * @throws \Doctrine\DBAL\Driver\Exception
+	 * @throws \TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException
+	 */
+	public static function renderStatic(
+		array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext
+	) {
+		$newsService = GeneralUtility::makeInstance(NewsService::class);
+		$categoryRepository = GeneralUtility::makeInstance(CategoryRepository::class);
+		$templateVariableContainer = $renderingContext->getVariableProvider();
+		$news = $arguments['news'];
+		$newsRepository = GeneralUtility::makeInstance(NewsRepository::class);
+		if ($arguments['relatedNews']) {
+			$related = $arguments['relatedNews'];
+		} else {
+			$related = $newsRepository->findRelated($news, (int) $arguments['limit']);
+		}
+
+		if (isset($arguments['iteration'])) {
+			$iterationData = [
+				'index' => 0,
+				'cycle' => 1,
+				'total' => $related->count()
+			];
+		}
+
+		$output = '';
+		$categories = [];
+		foreach ($related as $relatedNews) {
+			if (!isset($categories[$relatedNews->getPid()])) {
+				$categories[$relatedNews->getPid()] = $categoryRepository->findByUid($relatedNews->getPid());
+			}
+
+			$newsMetaData = $newsService->getMetaDataForNews($relatedNews, $categories[$relatedNews->getPid()]);
+			$templateVariableContainer->add($arguments['as'], $newsMetaData);
+			if (isset($iterationData)) {
+				$iterationData['isFirst'] = $iterationData['cycle'] === 1;
+				$iterationData['isLast'] = $iterationData['cycle'] === $iterationData['total'];
+				$iterationData['isEven'] = $iterationData['cycle'] % 2 === 0;
+				$iterationData['isOdd'] = !$iterationData['isEven'];
+				$templateVariableContainer->add($arguments['iteration'], $iterationData);
+				$iterationData['index']++;
+				$iterationData['cycle']++;
+			}
+
+			$output .= $renderChildrenClosure();
+			$templateVariableContainer->remove($arguments['as']);
+			if (isset($arguments['iteration'])) {
+				$templateVariableContainer->remove($arguments['iteration']);
+			}
+		}
+
+		return $output;
+	}
+}
diff --git a/Configuration/Extbase/Persistence/Classes.php b/Configuration/Extbase/Persistence/Classes.php
index cadba116249d6ee6fbed375b6fbdf39900b19986..8513d90f04b09ad8247980b88ed4fcf15c2cb14b 100644
--- a/Configuration/Extbase/Persistence/Classes.php
+++ b/Configuration/Extbase/Persistence/Classes.php
@@ -47,6 +47,9 @@ return [
 			],
 			'dateEnd' => [
 				'fieldName' => 'tx_sgnews_date_end'
+			],
+			'enableComments' => [
+				'fieldName' => 'tx_sgnews_comments_enable'
 			]
 		]
 	],
diff --git a/Configuration/FlexForms/Overview.xml b/Configuration/FlexForms/Overview.xml
index 3825dd256d5b310f69bfbeceb8fabfa9cf9b3fa3..10b59fda4f6bbbac6dcaddcc5f0e878460b3b5f2 100644
--- a/Configuration/FlexForms/Overview.xml
+++ b/Configuration/FlexForms/Overview.xml
@@ -13,6 +13,7 @@
 					<settings.groupBy>
 						<TCEforms>
 							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.groupBy</label>
+							<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.groupBy.description</description>
 							<onChange>reload</onChange>
 							<config>
 								<type>select</type>
@@ -36,11 +37,28 @@
 						</TCEforms>
 					</settings.groupBy>
 
+					<settings.enableFilter>
+						<TCEforms>
+							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.enableFilter</label>
+							<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.enableFilter.description</description>
+							<onChange>reload</onChange>
+							<config>
+								<type>check</type>
+								<default>0</default>
+							</config>
+						</TCEforms>
+					</settings.enableFilter>
+
 					<settings.categoryRestrictions>
 						<TCEforms>
 							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryRestrictions</label>
 							<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryRestrictions.description</description>
-							<displayCond>FIELD:settings.groupBy:=:1</displayCond>
+							<displayCond>
+								<or>
+									<value1>FIELD:settings.groupBy:=:1</value1>
+									<value2>FIELD:settings.enableFilter:=:1</value2>
+								</or>
+							</displayCond>
 							<config>
 								<type>select</type>
 								<renderType>selectMultipleSideBySide</renderType>
@@ -57,7 +75,12 @@
 						<TCEforms>
 							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.tags</label>
 							<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.tags.description</description>
-							<displayCond>FIELD:settings.groupBy:=:2</displayCond>
+							<displayCond>
+								<or>
+									<value1>FIELD:settings.groupBy:=:2</value1>
+									<value2>FIELD:settings.enableFilter:=:1</value2>
+								</or>
+							</displayCond>
 							<config>
 								<type>select</type>
 								<renderType>selectTree</renderType>
@@ -77,16 +100,6 @@
 						</TCEforms>
 					</settings.tagRestrictions>
 
-					<settings.enableFilter>
-						<TCEforms>
-							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.enableFilter</label>
-							<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.enableFilter.description</description>
-							<config>
-								<type>check</type>
-								<default>0</default>
-							</config>
-						</TCEforms>
-					</settings.enableFilter>
 					<settings.categoryLabel>
 						<TCEforms>
 							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.categoryLabel</label>
@@ -98,11 +111,20 @@
 					<settings.tagLabel>
 						<TCEforms>
 							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.tagLabel</label>
+							<description>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.tagLabel.description</description>
 							<config>
 								<type>input</type>
 							</config>
 						</TCEforms>
 					</settings.tagLabel>
+					<settings.allLabel>
+						<TCEforms>
+							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.allLabel</label>
+							<config>
+								<type>input</type>
+							</config>
+						</TCEforms>
+					</settings.allLabel>
 					<settings.newsLimit>
 						<TCEforms>
 							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.overview.flexForm.newsLimit</label>
@@ -192,6 +214,53 @@
 							</config>
 						</TCEforms>
 					</settings.sortDirection>
+					<settings.layout>
+						<TCEforms>
+							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.layout</label>
+							<config>
+								<type>select</type>
+								<renderType>selectSingle</renderType>
+								<items>
+									<numIndex index="0">
+										<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.layout.1</numIndex>
+										<numIndex index="1">1</numIndex>
+									</numIndex>
+									<numIndex index="1">
+										<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.layout.2</numIndex>
+										<numIndex index="1">2</numIndex>
+									</numIndex>
+								</items>
+							</config>
+						</TCEforms>
+					</settings.layout>
+					<settings.gridColumns>
+						<TCEforms>
+							<label>LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns</label>
+							<config>
+								<type>select</type>
+								<renderType>selectSingle</renderType>
+								<default>3</default>
+								<items>
+									<numIndex index="0">
+										<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns.1</numIndex>
+										<numIndex index="1">1</numIndex>
+									</numIndex>
+									<numIndex index="1">
+										<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns.2</numIndex>
+										<numIndex index="1">2</numIndex>
+									</numIndex>
+									<numIndex index="2">
+										<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns.3</numIndex>
+										<numIndex index="1">3</numIndex>
+									</numIndex>
+									<numIndex index="3">
+										<numIndex index="0">LLL:EXT:sg_news/Resources/Private/Language/locallang_db.xlf:plugin.flexForm.gridColumns.4</numIndex>
+										<numIndex index="1">4</numIndex>
+									</numIndex>
+								</items>
+							</config>
+						</TCEforms>
+					</settings.gridColumns>
 				</el>
 			</ROOT>
 		</main>
diff --git a/Configuration/TCA/Overrides/pages.php b/Configuration/TCA/Overrides/pages.php
index 5a0f60d4c0a0138971216c3faaa831a5ba2ffad1..db490478170880bde2bba8c6b11230074f1f67ac 100644
--- a/Configuration/TCA/Overrides/pages.php
+++ b/Configuration/TCA/Overrides/pages.php
@@ -449,6 +449,14 @@ if (version_compare(\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExten
 					'allowLanguageSynchronization' => TRUE
 				]
 			]
+		],
+		'tx_sgnews_comments_enable' => [
+			'exclude' => TRUE,
+			'label' => $localLangDbPath . 'pages.tx_sgnews_comments_enable',
+			'config' => [
+				'type' => 'check',
+				'default' => 1
+			]
 		]
 	]
 );
@@ -460,7 +468,8 @@ $GLOBALS['TCA']['pages']['palettes']['titleDescriptionAndHighlightFlag'] = [
 	--linebreak--, slug,
 	--linebreak--, tx_projectbase_path_segment, tx_projectbase_excludefromsluggeneration,
 	--linebreak--, tx_realurl_pathsegment, tx_realurl_exclude,
-	--linebreak--, tx_sgnews_highlighted, tx_sgnews_never_highlighted',
+	--linebreak--, tx_sgnews_highlighted, tx_sgnews_never_highlighted,
+	--linebreak--, tx_sgnews_comments_enable',
 	'canNotCollapse' => 1,
 ];
 
@@ -496,6 +505,7 @@ foreach ($GLOBALS['TCA']['pages']['columns'] as $languageExcludeField => $_) {
 			'tx_sgnews_date_end',
 			'tx_sgnews_highlighted',
 			'tx_sgnews_never_highlighted',
+			'tx_sgnews_comments_enable',
 			'og_title',
 			'og_description',
 			'og_image',
@@ -527,6 +537,7 @@ foreach ($GLOBALS['TCA']['pages']['columns'] as $languageExcludeField => $_) {
 			'tx_sgnews_date_end',
 			'tx_sgnews_highlighted',
 			'tx_sgnews_never_highlighted',
+			'tx_sgnews_comments_enable'
 		];
 	}
 	if (!in_array($languageExcludeField, $fieldNames)) {
diff --git a/Configuration/TypoScript/Frontend/constants.typoscript b/Configuration/TypoScript/Frontend/constants.typoscript
index 34a9c4da599228c1cc1b6f3069b7b9a49eab04db..58f8138af09e551c7aec4fbb1efd6f6b9db7ca00 100644
--- a/Configuration/TypoScript/Frontend/constants.typoscript
+++ b/Configuration/TypoScript/Frontend/constants.typoscript
@@ -19,5 +19,8 @@ plugin.tx_sgnews {
 
 		# sort direction (DESC / ASC)
 		sortDirection = DESC
+
+		# This enables the output of related news in regards to the news category or tags
+		enableAutomaticRelatedNews = 0
 	}
 }
diff --git a/Configuration/TypoScript/Frontend/setup.typoscript b/Configuration/TypoScript/Frontend/setup.typoscript
index 9a52fd4ef64e299d3c2fd12ce028ac75c9ebbf6a..fb32038793c9f09240980a30d131cdea7f83f512 100644
--- a/Configuration/TypoScript/Frontend/setup.typoscript
+++ b/Configuration/TypoScript/Frontend/setup.typoscript
@@ -109,6 +109,9 @@ plugin.tx_sgnews {
 
 		# The logo value for the structured data implementation (see single view template)
 		publisherLogo =
+
+		# This enables the output of related news in regards to the news category or tags
+		enableAutomaticRelatedNews = {$plugin.tx_sgnews.settings.enableAutomaticRelatedNews}
 	}
 
 	features {
diff --git a/Resources/Private/Language/de.locallang_db.xlf b/Resources/Private/Language/de.locallang_db.xlf
index a2d5f49d314880b118eca77799f3d33e8e92dcdc..10d21c38c025ad2e9731b8d48b500ae8578ab2b9 100644
--- a/Resources/Private/Language/de.locallang_db.xlf
+++ b/Resources/Private/Language/de.locallang_db.xlf
@@ -81,6 +81,10 @@
 				<source><![CDATA[Use Image Cropping]]></source>
 				<target><![CDATA[Bild-Cropping aktivieren]]></target>
 			</trans-unit>
+			<trans-unit id="pages.tx_sgnews_comments_enable" approved="yes">
+				<source><![CDATA[Enable comments on this page]]></source>
+				<target><![CDATA[Kommentare auf dieser Seite aktivieren]]></target>
+			</trans-unit>
 			<trans-unit id="plugin.flexForm" approved="yes">
 				<source><![CDATA[Settings]]></source>
 				<target><![CDATA[Einstellungen]]></target>
@@ -109,6 +113,26 @@
 				<source><![CDATA[News which are excluded from the list]]></source>
 				<target><![CDATA[News, welche nicht in der Liste dargestellt werden]]></target>
 			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns" approved="yes">
+				<source><![CDATA[Columns]]></source>
+				<target><![CDATA[Anzahl der Spalten]]></target>
+			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns.1" approved="yes">
+				<source><![CDATA[1 Column]]></source>
+				<target><![CDATA[1 Spalte]]></target>
+			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns.2" approved="yes">
+				<source><![CDATA[2 Columns]]></source>
+				<target><![CDATA[2 Spalten]]></target>
+			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns.3" approved="yes">
+				<source><![CDATA[3 Columns]]></source>
+				<target><![CDATA[3 Spalten]]></target>
+			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns.4" approved="yes">
+				<source><![CDATA[4 Columns]]></source>
+				<target><![CDATA[4 Spalten]]></target>
+			</trans-unit>
 			<trans-unit id="plugin.flexForm.layout" approved="yes">
 				<source><![CDATA[Layout]]></source>
 				<target><![CDATA[Layout]]></target>
@@ -189,6 +213,14 @@
 				<source><![CDATA[Categories]]></source>
 				<target><![CDATA[Kategorien]]></target>
 			</trans-unit>
+			<trans-unit id="plugin.overview.flexForm.allLabel" approved="yes">
+				<source><![CDATA[Override all label]]></source>
+				<target><![CDATA[Alle-Label überschreiben]]></target>
+			</trans-unit>
+			<trans-unit id="plugin.overview.flexForm.allLabel.description" approved="yes">
+				<source><![CDATA[Will be used when filtering by all criteria is disabled.]]></source>
+				<target><![CDATA[Wird nur bei nicht aktivierten Filtern von allen Kriterien verwendet.]]></target>
+			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.categoryLabel" approved="yes">
 				<source><![CDATA[Override category label]]></source>
 				<target><![CDATA[Kategorie-Label überschreiben]]></target>
@@ -220,16 +252,20 @@ If none are selected, all categories will be available in the frontend.]]></sour
 Wenn keine ausgewählt werden, sind alle Kategorien im Frontend verfügbar.]]></target>
 			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.enableFilter" approved="yes">
-				<source><![CDATA[Enable filtering by all criteria.]]></source>
-				<target><![CDATA[Ermögliche das Filtern mit allen Krierien.]]></target>
+				<source><![CDATA[Show all filters]]></source>
+				<target><![CDATA[Zeige alle Filter an]]></target>
 			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.enableFilter.description" approved="yes">
 				<source><![CDATA[Filters will be rendered as select boxes and tabs will be hidden.]]></source>
 				<target><![CDATA[Filter werden als Dropdown-Box angezeigt und die Tabs ausgeblendet.]]></target>
 			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.groupBy" approved="yes">
-				<source><![CDATA[Group news pages in tabs by]]></source>
-				<target><![CDATA[News-Seiten nach folgendem Kriterium in Tabs gruppieren]]></target>
+				<source><![CDATA[Group news pages by]]></source>
+				<target><![CDATA[News-Seiten nach folgendem Kriterium gruppieren]]></target>
+			</trans-unit>
+			<trans-unit id="plugin.overview.flexForm.groupBy.description" approved="yes">
+				<source><![CDATA[News pages will be grouped in tabs.]]></source>
+				<target><![CDATA[News-Seiten werden in Tabs gruppiert.]]></target>
 			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.groupBy.I.0" approved="yes">
 				<source><![CDATA[No grouping]]></source>
diff --git a/Resources/Private/Language/locallang_db.xlf b/Resources/Private/Language/locallang_db.xlf
index cc259e90a064d8df03944dd502232d342da356e6..4d42520c1b82b563b95e9ebf859d6c61489b0978 100644
--- a/Resources/Private/Language/locallang_db.xlf
+++ b/Resources/Private/Language/locallang_db.xlf
@@ -63,6 +63,9 @@
 			<trans-unit id="pages.tx_sgnews_use_image_crop">
 				<source><![CDATA[Use Image Cropping]]></source>
 			</trans-unit>
+			<trans-unit id="pages.tx_sgnews_comments_enable">
+				<source><![CDATA[Enable comments on this page]]></source>
+			</trans-unit>
 			<trans-unit id="plugin.flexForm">
 				<source><![CDATA[Settings]]></source>
 			</trans-unit>
@@ -84,6 +87,21 @@
 			<trans-unit id="plugin.flexForm.excludedNews">
 				<source><![CDATA[News which are excluded from the list]]></source>
 			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns">
+				<source><![CDATA[Columns]]></source>
+			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns.1">
+				<source><![CDATA[1 Column]]></source>
+			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns.2">
+				<source><![CDATA[2 Columns]]></source>
+			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns.3">
+				<source><![CDATA[3 Columns]]></source>
+			</trans-unit>
+			<trans-unit id="plugin.flexForm.gridColumns.4">
+				<source><![CDATA[4 Columns]]></source>
+			</trans-unit>
 			<trans-unit id="plugin.flexForm.layout">
 				<source><![CDATA[Layout]]></source>
 			</trans-unit>
@@ -156,6 +174,12 @@
 			<trans-unit id="plugin.overview.flexForm.categoryRestrictions">
 				<source><![CDATA[Category Selection]]></source>
 			</trans-unit>
+			<trans-unit id="plugin.overview.flexForm.allLabel">
+				<source><![CDATA[Override all label]]></source>
+			</trans-unit>
+			<trans-unit id="plugin.overview.flexForm.allLabel.description">
+				<source><![CDATA[Will be used when filtering by all criteria is disabled.]]></source>
+			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.categoryLabel">
 				<source><![CDATA[Override category label]]></source>
 			</trans-unit>
@@ -167,13 +191,16 @@
 If none are selected, all categories will be available in the frontend.]]></source>
 			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.enableFilter">
-				<source><![CDATA[Enable filtering by all criteria.]]></source>
+				<source><![CDATA[Show all filters]]></source>
 			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.enableFilter.description">
 				<source><![CDATA[Filters will be rendered as select boxes and tabs will be hidden.]]></source>
 			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.groupBy">
-				<source><![CDATA[Group news pages in tabs by]]></source>
+				<source><![CDATA[Group news pages by]]></source>
+			</trans-unit>
+			<trans-unit id="plugin.overview.flexForm.groupBy.description">
+				<source><![CDATA[News pages will be grouped in tabs.]]></source>
 			</trans-unit>
 			<trans-unit id="plugin.overview.flexForm.groupBy.I.0">
 				<source><![CDATA[No grouping]]></source>
diff --git a/Resources/Private/Partials/TeaserRelated.html b/Resources/Private/Partials/TeaserRelated.html
new file mode 100644
index 0000000000000000000000000000000000000000..2360faca6abc939c58cd947f821469b07d090b7b
--- /dev/null
+++ b/Resources/Private/Partials/TeaserRelated.html
@@ -0,0 +1,36 @@
+{namespace sg=SGalinski\SgNews\ViewHelpers}
+
+<f:comment>
+	<!--
+	Usage Example:
+
+	<f:render partial="Teaser" arguments="{
+		newsMetaData: newsMetaData,
+		headerTag: '<h3>',
+		closingHeaderTag: '</h3>',
+		showCategory: 1
+	}" />
+
+	newsMetaData -> news element
+	headerTag -> hierarchy type of the header tag
+	showCategory -> defines if the category may be shown
+
+	Use <f:debug>{_all}</f:debug> to see all parameters and fields.
+	-->
+</f:comment>
+
+<f:link.page pageUid="{news.uid}" class="tx-sgnews-teaser">
+	<f:if condition="{news.teaser1Image}">
+		<f:for each="{news.teaser1Image}" as="teaserImage">
+			<div class="tx-sgnews-teaser-image tx-sgnews-teaser-image-stretched"
+				 style="background-image: url({f:uri.image(image: teaserImage)});"></div>
+		</f:for>
+	</f:if>
+	<div class="tx-sgnews-teaser-inner">
+		<div class="tx-sgnews-teaser-title">
+			{headerTag -> f:format.raw()}
+			{news.subtitleWithFallbackToTitle}
+			{closingHeaderTag -> f:format.raw()}
+		</div>
+	</div>
+</f:link.page>
diff --git a/Resources/Private/Templates/Overview/Overview.html b/Resources/Private/Templates/Overview/Overview.html
index 6735798bce05105076c454a3543a11d0c6e626cc..1538104f9f84b4923c4178dc4b71ea434922ad66 100644
--- a/Resources/Private/Templates/Overview/Overview.html
+++ b/Resources/Private/Templates/Overview/Overview.html
@@ -18,7 +18,14 @@
 			<div class="tx-sgnews-categories m-tabs" data-more-label="Mehr">
 				<div class="m-tabs__tablist" role="tablist">
 					<button class="m-tabs__tab" role="tab" aria-controls="news-category-0" id="tab-news-0" aria-selected="true">
-						<f:translate key="frontend.overview.allTabLabel" />
+						<f:if condition="{settings.allLabel}">
+							<f:then>
+								{settings.allLabel}
+							</f:then>
+							<f:else>
+								<f:translate key="frontend.overview.allTabLabel" />
+							</f:else>
+						</f:if>
 					</button>
 					<f:for each="{newsItems}" as="dataItems" iteration="iterator">
 						<button class="m-tabs__tab" role="tab" aria-controls="news-category-{iterator.index + 1}" id="tab-news-{iterator.index + 1}" aria-selected="false">
@@ -51,7 +58,7 @@
 							<ul class="tx-sgnews-list tx-sgnews-list-{dataItems.record.uid} row" data-record="{dataItems.record.uid}">
 								<f:for each="{dataItems.newsMetaData}" as="newsMetaDataEntry">
 									<f:if condition="{newsMetaDataEntry.news}">
-										<li class="col-md-4 col-sm-6 col-xs-12">
+										<li class="{gridColumnClasses}">
 											<f:render partial="Teaser" arguments="{
 											newsMetaData: newsMetaDataEntry,
 											headerTag: '<h2>',
@@ -85,7 +92,7 @@
 <f:section name="content">
 	<ul class="tx-sgnews-list tx-sgnews-list-0 row" data-record="0">
 		<f:for each="{allNews}" as="newsMetaDataEntry">
-			<li class="col-md-4 col-sm-6 col-xs-12">
+			<li class="{gridColumnClasses}">
 				<f:render partial="Teaser" arguments="{
 								newsMetaData: newsMetaDataEntry,
 								headerTag: '<h2>',
diff --git a/Resources/Private/Templates/Overview/OverviewWithoutCategories.html b/Resources/Private/Templates/Overview/OverviewWithoutCategories.html
index e41b2fc4b9b96bd21054ebb41c371f2b1bd5e5b7..f1839f91f8ac6ff3ec81ff96df463c8bd3b3d5c1 100644
--- a/Resources/Private/Templates/Overview/OverviewWithoutCategories.html
+++ b/Resources/Private/Templates/Overview/OverviewWithoutCategories.html
@@ -18,7 +18,7 @@
 			<f:then>
 				<ul class="tx-sgnews-list tx-sgnews-list-0 row" data-record="0">
 					<f:for each="{newsMetaData}" as="newsMetaDataEntry">
-						<li class="col-md-4 col-sm-6 col-xs-12">
+						<li class="{gridColumnClasses}">
 							<f:render partial="Teaser" arguments="{
 											newsMetaData: newsMetaDataEntry,
 											headerTag: '<h2>',
diff --git a/Resources/Private/Templates/SingleView/SingleView.html b/Resources/Private/Templates/SingleView/SingleView.html
index e41e216fb8066430e905713e216397888239bf95..bbbb26abdbc10e04953aebdaedf7bfccd65ae54a 100644
--- a/Resources/Private/Templates/SingleView/SingleView.html
+++ b/Resources/Private/Templates/SingleView/SingleView.html
@@ -1,4 +1,4 @@
-<f:layout name="Default" />
+<f:layout name="Default"/>
 
 {namespace base=SGalinski\ProjectBase\ViewHelpers}
 {namespace sg=SGalinski\SgNews\ViewHelpers}
@@ -10,14 +10,15 @@
 
 		<div class="intro-section">
 			<section class="dark-bg">
-				<div class="tx-sgnews-single-header {f:if(condition: newsMetaData.imageObject, then: 'tx-sgnews-single-header-image')}">
+				<div
+					class="tx-sgnews-single-header {f:if(condition: newsMetaData.imageObject, then: 'tx-sgnews-single-header-image')}">
 					<f:if condition="{newsMetaData.imageObject}">
 						<div class="tx-sgnews-single-image">
 							<picture>
 								<source media="(max-width: 1200px)"
-									srcset="{f:uri.image(src: newsMetaData.imageObject.uid, treatIdAsReference: '1', width: '1200c', height: '403c', cropVariant: 'small')}">
+										srcset="{f:uri.image(src: newsMetaData.imageObject.uid, treatIdAsReference: '1', width: '1200c', height: '403c', cropVariant: 'small')}">
 								<f:image image="{newsMetaData.imageObject}" alt="" width="1845c"
-									height="619c" loading="lazy"/>
+										 height="619c" loading="lazy"/>
 							</picture>
 						</div>
 					</f:if>
@@ -30,11 +31,15 @@
 								<div class="tx-sgnews-teaser-meta">
 									<f:if condition="{authorCount}">
 										<span class="author">
-											<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="#FFF" d="M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z" /></svg>
+											<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path
+												fill="#FFF"
+												d="M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z"/></svg>
 										</span>
 
-										<f:for each="{newsMetaData.news.newsAuthor}" as="newsAuthor" iteration="iterator">
-											<f:alias map="{divider: '{f:if(condition: \'{iterator.cycle} < {authorCount}\', then: \',\')}'}">
+										<f:for each="{newsMetaData.news.newsAuthor}" as="newsAuthor"
+											   iteration="iterator">
+											<f:alias
+												map="{divider: '{f:if(condition: \'{iterator.cycle} < {authorCount}\', then: \',\')}'}">
 												<a class="tx-sgnews-teaser-meta-author" href="#author{newsAuthor.uid}">
 													<f:if condition="{newsAuthor.name}">
 														{newsAuthor.name}{divider}
@@ -46,26 +51,32 @@
 
 									<f:if condition="{newsMetaData.news.location}">
 										<span class="location">
-											<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path fill="#FFF" d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z" /></svg>
+											<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path
+												fill="#FFF"
+												d="M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0z"/></svg>
 											{newsMetaData.news.location}
 										</span>
 									</f:if>
 
 									<span class="date">
-										<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#FFF" d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm57.1 350.1L224.9 294c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h48c6.6 0 12 5.4 12 12v137.7l63.5 46.2c5.4 3.9 6.5 11.4 2.6 16.8l-28.2 38.8c-3.9 5.3-11.4 6.5-16.8 2.6z" /></svg>
+										<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#FFF"
+																											d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm57.1 350.1L224.9 294c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h48c6.6 0 12 5.4 12 12v137.7l63.5 46.2c5.4 3.9 6.5 11.4 2.6 16.8l-28.2 38.8c-3.9 5.3-11.4 6.5-16.8 2.6z"/></svg>
 										<f:format.date format="{f:translate(key:'frontend.dateformat')}">{newsMetaData.news.lastUpdated}</f:format.date>
 									</span>
 
 									<span class="category">
-										<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#FFF" d="M0 252.118V48C0 21.49 21.49 0 48 0h204.118a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882L293.823 497.941c-18.745 18.745-49.137 18.745-67.882 0L14.059 286.059A48 48 0 0 1 0 252.118zM112 64c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z" /></svg>
+										<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#FFF"
+																											d="M0 252.118V48C0 21.49 21.49 0 48 0h204.118a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882L293.823 497.941c-18.745 18.745-49.137 18.745-67.882 0L14.059 286.059A48 48 0 0 1 0 252.118zM112 64c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z"/></svg>
 										<a href="{f:uri.page(pageUid: '{newsMetaData.category.uid}')}">
 											{newsMetaData.category.subtitleWithFallbackToTitle}
 										</a>
 									</span>
 									<f:if condition="{newsMetaData.news.tags}">
-										<br />
+										<br/>
 										<span class="tags">
-											<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path fill="#FFF" d="M497.941 225.941L286.059 14.059A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v204.118a48 48 0 0 0 14.059 33.941l211.882 211.882c18.744 18.745 49.136 18.746 67.882 0l204.118-204.118c18.745-18.745 18.745-49.137 0-67.882zM112 160c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm513.941 133.823L421.823 497.941c-18.745 18.745-49.137 18.745-67.882 0l-.36-.36L527.64 323.522c16.999-16.999 26.36-39.6 26.36-63.64s-9.362-46.641-26.36-63.64L331.397 0h48.721a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882z" /></svg>
+											<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path
+												fill="#FFF"
+												d="M497.941 225.941L286.059 14.059A48 48 0 0 0 252.118 0H48C21.49 0 0 21.49 0 48v204.118a48 48 0 0 0 14.059 33.941l211.882 211.882c18.744 18.745 49.136 18.746 67.882 0l204.118-204.118c18.745-18.745 18.745-49.137 0-67.882zM112 160c-26.51 0-48-21.49-48-48s21.49-48 48-48 48 21.49 48 48-21.49 48-48 48zm513.941 133.823L421.823 497.941c-18.745 18.745-49.137 18.745-67.882 0l-.36-.36L527.64 323.522c16.999-16.999 26.36-39.6 26.36-63.64s-9.362-46.641-26.36-63.64L331.397 0h48.721a48 48 0 0 1 33.941 14.059l211.882 211.882c18.745 18.745 18.745 49.137 0 67.882z"/></svg>
 											<f:for each="{newsMetaData.news.tags}" as="tag" iteration="it">
 												{tag.title}<f:if condition="{it.isLast}"><f:else>, </f:else></f:if>
 											</f:for>
@@ -77,20 +88,22 @@
 					</div>
 				</div>
 			</section>
-
 		</div>
+
 		<section class="content">
 			<div class="container">
 				<div class="tx-sgnews-single">
-					<div class="tx-sgnews-single-container">
-						<f:alias map="{content: '{f:cObject(typoscriptObjectPath: \'{f:if(condition: \\\'{newsMetaData.news.contentFromAnotherPage}\\\', then: \\\'lib.contentFromAnotherPage\\\', else: \\\'lib.mainContent\\\')}\')}'}">
+					<ul class="tx-sgnews-single-container">
+						<f:alias
+							map="{content: '{f:cObject(typoscriptObjectPath: \'{f:if(condition: \\\'{newsMetaData.news.contentFromAnotherPage}\\\', then: \\\'lib.contentFromAnotherPage\\\', else: \\\'lib.mainContent\\\')}\')}'}">
 							<div class="tx-sgnews-single-content">
 								<p>
-									<a href="#comments">{f:cObject(typoscriptObjectPath: "lib.sgCommentsGetCountWithLabel")}</a>
+									<a href="#comments">{f:cObject(typoscriptObjectPath:
+										"lib.sgCommentsGetCountWithLabel")}</a>
 									<span>//</span>
-									<f:translate key="frontend.singleview.readingTime" />
+									<f:translate key="frontend.singleview.readingTime"/>
 									<strong>
-										<sg:getReadingTime content="{content}" />
+										<sg:getReadingTime content="{content}"/>
 									</strong>
 								</p>
 
@@ -100,7 +113,7 @@
 
 						<f:if condition="{newsMetaData.news.newsAuthor -> f:count()}">
 							<h2>
-								<f:translate key="frontend.singleview.authors" />
+								<f:translate key="frontend.singleview.authors"/>
 							</h2>
 
 							<hr>
@@ -108,7 +121,8 @@
 							<f:for each="{newsMetaData.news.newsAuthor}" as="newsAuthor" iteration="iterator">
 								<div id="author{newsAuthor.uid}" class="tx-sgnews-author">
 									<f:if condition="{newsAuthor.image}">
-										<f:image class="tx-sgnews-author-image" image="{newsAuthor.image}" width="150c" height="150px" />
+										<f:image class="tx-sgnews-author-image" image="{newsAuthor.image}" width="150c"
+												 height="150px"/>
 									</f:if>
 
 									<div class="tx-sgnews-author-information">
@@ -122,7 +136,8 @@
 											<div class="tx-sgnews-author-information-bar">
 												<f:if condition="{newsAuthor.email}">
 													<div class="tx-sgnews-author-information-email">
-														<span class="glyphicon glyphicon-envelope" aria-hidden="true"></span>
+														<span class="glyphicon glyphicon-envelope"
+															  aria-hidden="true"></span>
 														<f:link.email email="{newsAuthor.email}" target="_blank">
 															{newsAuthor.email}
 														</f:link.email>
@@ -131,7 +146,8 @@
 
 												<f:if condition="{newsAuthor.website}">
 													<div class="tx-sgnews-author-information-website">
-														<span class="glyphicon glyphicon-home" aria-hidden="true"></span>
+														<span class="glyphicon glyphicon-home"
+															  aria-hidden="true"></span>
 														<f:link.external uri="{newsAuthor.website}" target="_blank">
 															{newsAuthor.website}
 														</f:link.external>
@@ -149,8 +165,10 @@
 										<f:if condition="{settings.authorNewsPid}">
 											<div class="tx-sgnews-author-information-articles">
 												<span class="glyphicon glyphicon-tag" aria-hidden="true"></span>
-												<f:link.action pageUid="{settings.authorNewsPid}" pluginName="NewsByAuthor" controller="NewsByAuthor" action="list" arguments="{authorId: newsAuthor.uid}">
-													<f:translate key="frontend.singleview.authorsAdditionalArticles" />
+												<f:link.action pageUid="{settings.authorNewsPid}"
+															   pluginName="NewsByAuthor" controller="NewsByAuthor"
+															   action="list" arguments="{authorId: newsAuthor.uid}">
+													<f:translate key="frontend.singleview.authorsAdditionalArticles"/>
 												</f:link.action>
 											</div>
 										</f:if>
@@ -165,35 +183,67 @@
 
 						<hr>
 						<div class="tx-sgnews-meta-bar">
-							<base:sharer />
+							<base:sharer/>
 							<div class="tx-sgnews-likes" id="tx-sgnews-likes" data-uid="{newsMetaData.news.uid}">
-								<button class="tx-sgnews-like-buton btn btn-sm btn-info" data-ajaxurl="{sgajax:uri.ajax(extensionName: 'SgNews', controller: 'Ajax\Like', action: 'addLike', format: 'json')}">
+								<button class="tx-sgnews-like-buton btn btn-sm btn-info"
+										data-ajaxurl="{sgajax:uri.ajax(extensionName: 'SgNews', controller: 'Ajax\Like', action: 'addLike', format: 'json')}">
 								<span class="tx-sgnews-number-of-likes">
 									<span class="badge"><i class="fa fa-star-o" aria-hidden="true"></i>
 										<span class="tx-sgnews-number-of-likes-value">{newsMetaData.news.likes}</span>
 									</span>
 								</span>
-									<f:translate key="frontend.singleview.likeButton" />
+									<f:translate key="frontend.singleview.likeButton"/>
 								</button>
 							</div>
 						</div>
 
 						<f:if condition="{newsMetaData.news.relatedNews}">
-							<div class="tx-sgnews-single-related">
-								<h3>
-									<f:translate key="frontend.singleview.relatedArticles" />
-								</h3>
-
-								<ul>
-									<f:for each="{newsMetaData.news.relatedNews}" as="relatedNewsEntry">
-										<li>
-											<a href="{f:uri.page(pageUid: '{relatedNewsEntry.uid}')}">
-												{relatedNewsEntry.subtitleWithFallbackToTitle}
-											</a>
-										</li>
-									</f:for>
-								</ul>
-							</div>
+							<f:then>
+								<div class="tx-sgnews-single-related tx-sgnews-categories">
+									<h3>
+										<f:translate key="frontend.singleview.relatedArticles"/>
+									</h3>
+									<ul class="tx-sgnews-list tx-sgnews-overview row">
+										<sg:related news="{newsMetaData.news}"
+													relatedNews="{newsMetaData.news.relatedNews}"
+													as="relatedNewsEntry">
+											<li class="col-md-4 col-sm-6 col-xs-12">
+												<f:render partial="Teaser" arguments="{
+													newsMetaData: relatedNewsEntry,
+													headerTag: '<h2>',
+													closingHeaderTag: '</h2>',
+													showCategory: '1'
+												}" />
+											</li>
+										</sg:related>
+									</ul>
+								</div>
+							</f:then>
+							<f:else>
+								<f:if condition="{settings.enableAutomaticRelatedNews}">
+									<sg:related news="{newsMetaData.news}" iteration="iterator" limit="3" as="relatedNewsEntry">
+										<f:if condition="{iterator.isFirst}">
+											<div class="tx-sgnews-single-related tx-sgnews-categories">
+												<h3>
+													<f:translate key="frontend.singleview.relatedArticles"/>
+												</h3>
+												<ul class="tx-sgnews-list tx-sgnews-overview row">
+										</f:if>
+													<li class="col-md-4 col-sm-6 col-xs-12">
+														<f:render partial="Teaser" arguments="{
+															newsMetaData: relatedNewsEntry,
+															headerTag: '<h2>',
+															closingHeaderTag: '</h2>',
+															showCategory: '1'
+														}" />
+													</li>
+										<f:if condition="{iterator.isLast}">
+												</ul>
+											</div>
+										</f:if>
+									</sg:related>
+								</f:if>
+							</f:else>
 						</f:if>
 					</div>
 				</div>
@@ -206,16 +256,24 @@
 					<f:if condition="{previousNews} || {nextNews}">
 						<div class="tx-sgnews-single-footer-browser">
 							<f:if condition="{previousNews}">
-								<a href="{f:uri.page(pageUid: '{previousNews.uid}')}" class="btn btn-md btn-info tx-sgnews-footer-browser-previous">
-									<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#FFF" d="M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zM142.1 273l135.5 135.5c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L226.9 256l101.6-101.6c9.4-9.4 9.4-24.6 0-33.9l-17-17c-9.4-9.4-24.6-9.4-33.9 0L142.1 239c-9.4 9.4-9.4 24.6 0 34z" /></svg>
-									<f:translate key="frontend.singleview.previousArticle" />
+								<a href="{f:uri.page(pageUid: '{previousNews.uid}')}"
+								   class="btn btn-md btn-info tx-sgnews-footer-browser-previous">
+									<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
+										<path fill="#FFF"
+											  d="M256 504C119 504 8 393 8 256S119 8 256 8s248 111 248 248-111 248-248 248zM142.1 273l135.5 135.5c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L226.9 256l101.6-101.6c9.4-9.4 9.4-24.6 0-33.9l-17-17c-9.4-9.4-24.6-9.4-33.9 0L142.1 239c-9.4 9.4-9.4 24.6 0 34z"/>
+									</svg>
+									<f:translate key="frontend.singleview.previousArticle"/>
 								</a>
 							</f:if>
 
 							<f:if condition="{nextNews}">
-								<a href="{f:uri.page(pageUid: '{nextNews.uid}')}" class="btn btn-md btn-info tx-sgnews-footer-browser-next">
-									<f:translate key="frontend.singleview.nextArticle" />
-									<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#FFF" d="M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zm113.9 231L234.4 103.5c-9.4-9.4-24.6-9.4-33.9 0l-17 17c-9.4 9.4-9.4 24.6 0 33.9L285.1 256 183.5 357.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L369.9 273c9.4-9.4 9.4-24.6 0-34z" /></svg>
+								<a href="{f:uri.page(pageUid: '{nextNews.uid}')}"
+								   class="btn btn-md btn-info tx-sgnews-footer-browser-next">
+									<f:translate key="frontend.singleview.nextArticle"/>
+									<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
+										<path fill="#FFF"
+											  d="M256 8c137 0 248 111 248 248S393 504 256 504 8 393 8 256 119 8 256 8zm113.9 231L234.4 103.5c-9.4-9.4-24.6-9.4-33.9 0l-17 17c-9.4 9.4-9.4 24.6 0 33.9L285.1 256 183.5 357.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L369.9 273c9.4-9.4 9.4-24.6 0-34z"/>
+									</svg>
 								</a>
 							</f:if>
 						</div>
@@ -224,14 +282,16 @@
 			</div>
 		</section>
 
-		<section class="content">
-			<div class="container">
-				<div class="tx-sgnews-single-comments">
-					<div id="comments" class="tx-sgnews-comments-inner">
-						<f:cObject typoscriptObjectPath="lib.sgCommentsIndex" />
+		<f:if condition="{newsMetaData.news.enableComments}">
+			<section class="content">
+				<div class="container">
+					<div class="tx-sgnews-single-comments">
+						<div id="comments" class="tx-sgnews-comments-inner">
+							<f:cObject typoscriptObjectPath="lib.sgCommentsIndex"/>
+						</div>
 					</div>
 				</div>
-			</div>
-		</section>
+			</section>
+		</f:if>
 	</f:alias>
 </f:section>
diff --git a/Resources/Public/Sass/_sg-news.scss b/Resources/Public/Sass/_sg-news.scss
index f90f33c0dffaa070dc7bd6e43c1e650f57b1ac71..63843a397acbc4a3091e0e2d072b42f4c2105843 100644
--- a/Resources/Public/Sass/_sg-news.scss
+++ b/Resources/Public/Sass/_sg-news.scss
@@ -1,11 +1,5 @@
 @import "layout-content";
 
-// sg_news SingleView pages have two intro-sections,
-// so we need to remove the duplicate white space created by the first one
-.intro-section + .main-content .tx-sgnews {
-	margin-top: $margin-base-vertical * -2;
-}
-
 // reduce the gap between the .dark-bg and the comment section
 .tx-sgnews .content.dark-bg + .content {
 	margin-top: $margin-base-vertical * -1;
diff --git a/composer.json b/composer.json
index be7a715926154138e4c318990a6f41f42738279c..8ced56d988cfe6df39a70134a45783213c2a8151 100644
--- a/composer.json
+++ b/composer.json
@@ -6,7 +6,7 @@
     "license": [
         "GPL-2.0-or-later"
     ],
-    "version": "9.6.3",
+    "version": "9.8.3",
     "support": {
     },
     "repositories": [
diff --git a/ext_emconf.php b/ext_emconf.php
index c50566f6a4cd7035a8942ba88313927dce7fe4b1..c02387d4a7ad7e4f0874a0f223a30748f9d8d46c 100644
--- a/ext_emconf.php
+++ b/ext_emconf.php
@@ -19,7 +19,7 @@ $EM_CONF['sg_news'] = [
 	'modify_tables' => '',
 	'clearCacheOnLoad' => 0,
 	'lockType' => '',
-	'version' => '9.6.3',
+	'version' => '9.8.3',
 	'constraints' => [
 		'depends' => [
 			'typo3' => '10.4.0-11.5.99',
diff --git a/ext_tables.sql b/ext_tables.sql
index cf5da4c80990185b37ed49d6cb7afb4664e7e346..82c2a724a4ac75c867450c6e421a505080acd1cf 100644
--- a/ext_tables.sql
+++ b/ext_tables.sql
@@ -10,6 +10,7 @@ CREATE TABLE pages (
 	tx_sgnews_location mediumtext,
   	tx_sgnews_date_end  int(10) unsigned DEFAULT '0' NOT NULL,
 	tx_sgnews_content_from_another_page int(11) unsigned DEFAULT '0' NOT NULL,
+	tx_sgnews_comments_enable tinyint(4) unsigned DEFAULT '1' NOT NULL,
 	KEY news_author (tx_sgnews_news_author)
 );