diff --git a/Classes/Controller/TreeController.php b/Classes/Controller/TreeController.php
index 0c7a8e0..b48ffe2 100644
--- a/Classes/Controller/TreeController.php
+++ b/Classes/Controller/TreeController.php
@@ -20,10 +20,14 @@ public function filterDataAction(ServerRequestInterface $request): ResponseInter
$rootElement['name'] = sprintf('❌ %s', $this->getLanguageService()->sL('LLL:EXT:pagetreefilter/Resources/Private/Language/locallang.xlf:filter_error'));
$elements = [$rootElement];
} else {
- if (PageTreeRepository::$filteredPageUids !== []) {
- foreach($elements as $key => $element) {
- if (in_array($element['identifier'], PageTreeRepository::$filteredPageUids)) {
+ foreach ($elements as $key => $element) {
+ foreach (PageTreeRepository::$resultSets as $resultSet) {
+ if (in_array($element['identifier'], $resultSet['pageUids'])) {
+ if (isset($resultSet['description'])) {
+ $elements[$key]['tip'] .= sprintf(', %s', $resultSet['description']);
+ }
$elements[$key]['class'] = 'pagetreefilter-highlighted';
+ $elements[$key]['backgroundColor'] = $resultSet['backgroundColor'] ?? '#0078e6';
}
}
}
diff --git a/Classes/Controller/WizardController.php b/Classes/Controller/WizardController.php
index 8a9a203..51419cc 100644
--- a/Classes/Controller/WizardController.php
+++ b/Classes/Controller/WizardController.php
@@ -51,6 +51,8 @@ public function getWizards(): array
$wizards = $this->appendRecords($wizards);
$wizards = $this->appendPageTypes($wizards);
$wizards = $this->appendUnknownContentTypes($wizards);
+ $wizards = $this->appendExtended($wizards);
+
return $wizards;
}
@@ -241,6 +243,26 @@ protected function appendUnknownContentTypes(array $wizards): array
return $wizards;
}
+ protected function appendExtended($wizards)
+ {
+ $customWizardItems = ConfigurationUtility::getCustomWizardItems();
+ if ($customWizardItems !== []) {
+ $wizards['filters']['header'] =
+ $this->getLanguageService()->sL('LLL:EXT:pagetreefilter/Resources/Private/Language/locallang.xlf:wizard_tab_extended_filters');
+
+ foreach ($customWizardItems as $identifier => $wizardItem) {
+ $wizards['filters_' . $identifier] = [
+ 'title' => $this->getLanguageService()->sL($wizardItem['title']),
+ 'description' => $this->getLanguageService()->sL($wizardItem['description'] ?? ''),
+ 'iconIdentifier' => $wizardItem['iconIdentifier'] ?? 'actions-filter',
+ 'filter' => $wizardItem['filter']
+ ];
+ }
+ }
+
+ return $wizards;
+ }
+
protected function areRecordsInTable($tableName): bool
{
/** @var QueryBuilder $queryBuilder */
diff --git a/Classes/Domain/Repository/PageTreeRepository.php b/Classes/Domain/Repository/PageTreeRepository.php
index 03368a1..dd07573 100644
--- a/Classes/Domain/Repository/PageTreeRepository.php
+++ b/Classes/Domain/Repository/PageTreeRepository.php
@@ -13,7 +13,7 @@
class PageTreeRepository extends \TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository
{
- public static $filteredPageUids = [];
+ public static $resultSets = [];
public static $filterErrorneous = false;
@@ -21,7 +21,8 @@ class PageTreeRepository extends \TYPO3\CMS\Backend\Tree\Repository\PageTreeRepo
protected $filterConstraints = [];
- // @todo: Use predefined list from core. Where is it?
+ protected $extendedFiltersThatShouldBeApplied = [];
+
protected const ALLOWED_TABLE_FIELDS = [
'tt_content:CType',
'tt_content:list_type',
@@ -35,19 +36,52 @@ public function fetchFilteredTree(string $searchFilter, array $allowedMountPoint
{
if (ConfigurationUtility::isWizardEnabled()) {
$newSearchFilter = $this->extractConstraints($searchFilter);
+ $searchFilter = $newSearchFilter;
+ $pages = [];
+
if ($this->filterTable) {
$this->validate();
if (!self::$filterErrorneous) {
- self::$filteredPageUids = $this->getFilteredPageUids();
+ $pages = $this->getFilteredPageUids();
+ self::$resultSets['default'] = [
+ 'pageUids' => $pages
+ ];
+ }
+ }
- if (self::$filteredPageUids !== []) {
- $additionalWhereClause = sprintf('%s AND uid IN (%s)', $additionalWhereClause,
- implode(',', self::$filteredPageUids));
- $searchFilter = $newSearchFilter;
+ $extendedFilters = ConfigurationUtility::getExtendedFilters();
+ if ($this->extendedFiltersThatShouldBeApplied !== [] && $extendedFilters !== []) {
+ foreach($this->extendedFiltersThatShouldBeApplied as $extendedFilter) {
+ if (isset($extendedFilters[$extendedFilter])) {
+ $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+ ->getQueryBuilderForTable($extendedFilters[$extendedFilter]['select.']['table']);
+ $filteredPages = $queryBuilder
+ ->select($extendedFilters[$extendedFilter]['select.']['field'])
+ ->from($extendedFilters[$extendedFilter]['select.']['table'])
+ ->andWhere($extendedFilters[$extendedFilter]['select.']['where'])
+ ->execute()
+ ->fetchFirstColumn();
+
+ self::$resultSets[$extendedFilter] = array_merge(
+ $extendedFilters[$extendedFilter],
+ [
+ 'pageUids' => $filteredPages
+ ]
+ );
+
+ foreach ($filteredPages as $filteredPage) {
+ $pages[] = $filteredPage;
+ }
}
}
}
+
+
+ if ($pages !== []) {
+ $additionalWhereClause = sprintf('%s AND uid IN (%s)', $additionalWhereClause,
+ implode(',', array_unique($pages)));
+ }
}
return parent::fetchFilteredTree($searchFilter, $allowedMountPointPageIds, $additionalWhereClause);
@@ -117,6 +151,9 @@ protected function extractConstraints(string $searchFilter): string
case 'table':
$this->filterTable = $filter[1];
break;
+ case 'filter':
+ $this->extendedFiltersThatShouldBeApplied[] = $filter[1];
+ break;
default:
$this->filterConstraints[] = [
'field' => $filter[0],
@@ -140,7 +177,7 @@ protected function validate()
if (!$backendUser->isAdmin() && !$backendUser->check('tables_select', $this->filterTable)) {
self::$filterErrorneous = true;
}
- $connection = $connection = GeneralUtility::makeInstance(ConnectionPool::class)
+ $connection = GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable($this->filterTable);
foreach($this->filterConstraints as $constraint) {
if (!isset($GLOBALS['TCA'][$this->filterTable]['columns'][$constraint['field']])) {
diff --git a/Classes/Utility/ConfigurationUtility.php b/Classes/Utility/ConfigurationUtility.php
index 53b15ce..d3a4b58 100644
--- a/Classes/Utility/ConfigurationUtility.php
+++ b/Classes/Utility/ConfigurationUtility.php
@@ -39,6 +39,28 @@ public static function getPageId()
return GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('pagetreefilter', 'pageId');
}
+ public static function getExtendedFilters(): array
+ {
+ $backendUser = self::getBackendUser();
+ $filters = $backendUser->getTSConfig()['tx_pagetreefilter.']['filters.'] ?? [];
+ foreach ($filters as $name => $configuration) {
+ $filters[rtrim($name, '.')] = $configuration;
+ unset($filters[$name]);
+ }
+ return $filters;
+ }
+
+ public static function getCustomWizardItems(): array
+ {
+ $backendUser = self::getBackendUser();
+ $wizardItems = $backendUser->getTSConfig()['tx_pagetreefilter.']['wizardItems.'] ?? [];
+ foreach ($wizardItems as $name => $configuration) {
+ $wizardItems[rtrim($name, '.')] = $configuration;
+ unset($wizardItems[$name]);
+ }
+ return $wizardItems;
+ }
+
protected static function getBackendUser(): ?BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
diff --git a/Configuration/TsConfig/Examples/Seo.tsconfig b/Configuration/TsConfig/Examples/Seo.tsconfig
new file mode 100644
index 0000000..52fc931
--- /dev/null
+++ b/Configuration/TsConfig/Examples/Seo.tsconfig
@@ -0,0 +1,40 @@
+tx_pagetreefilter {
+ filters {
+ indexingEnabled {
+ description = Page will be indexed by search engines
+ select {
+ field = uid
+ table = pages
+ where = no_index=0 AND doktype < 199
+ }
+ backgroundColor = green
+ }
+ indexingDisabled {
+ description = Page will be not be indexed by search engines
+ select {
+ field = uid
+ table = pages
+ where = no_index=1 AND doktype < 199
+ }
+ backgroundColor = grey
+ }
+ noMetaDescription {
+ description = Page has no meta description, so the description in search engine results might be inaccurate
+ select {
+ field = uid
+ table = pages
+ where = no_index=0 AND doktype < 199 AND (description='' OR description IS NULL)
+ }
+ backgroundColor = red
+ }
+ }
+
+ wizardItems {
+ seoStatus {
+ title = SEO Status
+ description = Show pages with SEO issues
+ iconIdentifier = content-elements-searchform
+ filter = filter=indexingEnabled filter=indexingDisabled filter=noMetaDescription
+ }
+ }
+}
\ No newline at end of file
diff --git a/Configuration/TsConfig/Examples/SolrIndexQueue.tsconfig b/Configuration/TsConfig/Examples/SolrIndexQueue.tsconfig
new file mode 100644
index 0000000..6f9f5f0
--- /dev/null
+++ b/Configuration/TsConfig/Examples/SolrIndexQueue.tsconfig
@@ -0,0 +1,75 @@
+tx_pagetreefilter {
+ filters {
+ indexedInSolr {
+ # The description is visible when you hover over the page icon
+ description = Indexed in Solr
+
+ select {
+ field = item_uid
+ table = tx_solr_indexqueue_item
+ where = indexing_configuration = 'pages' AND indexed > changed AND errors = ''
+ }
+
+ # A CSS background color for pages matching the query
+ backgroundColor = darkgreen
+ }
+ solrIndexingErrors {
+ description = Has indexing error
+ select {
+ field = item_uid
+ table = tx_solr_indexqueue_item
+ where = indexing_configuration = 'pages' AND errors != ''
+ }
+ backgroundColor = red
+ }
+ solrNeedsIndexing {
+ description = Needs (re)indexing
+ select {
+ field = item_uid
+ table = tx_solr_indexqueue_item
+ where = indexing_configuration = 'pages' AND indexed = 0 AND errors = ''
+ }
+ backgroundColor = lightgreen
+ }
+ solrNotInQueue {
+ description = Not in Index Queue
+ select {
+ field = uid
+ table = pages
+ where = sys_language_uid = 0 AND uid NOT IN (SELECT item_uid FROM tx_solr_indexqueue_item)
+ }
+ backgroundColor = orange
+ }
+ solrNoSearch {
+ description = Indexing disabled
+ select {
+ field = uid
+ table = pages
+ where = no_search = 1
+ }
+ backgroundColor = lightgrey
+ }
+ solrNoSearchSubEntries {
+ description = Indexing disabled for sub entries
+ select {
+ field = uid
+ table = pages
+ where = no_search_sub_entries = 1
+ }
+ backgroundColor = #4b4b4b
+ }
+ }
+
+ wizardItems {
+ solrIndexQueueStatus {
+ title = Solr Index Queue Status
+ description = Show pages that are indexed, not in the queue or have errors
+
+ # Overview of icons in TYPO3: https://typo3.github.io/TYPO3.Icons/
+ iconIdentifier = content-elements-searchform
+
+ # Multiple filters can be combined. The order matters for overlapping queries with different background colors
+ filter = filter=indexedInSolr filter=solrIndexingErrors filter=solrNeedsIndexing filter=solrNotInQueue filter=solrNoSearch filter=solrNoSearchSubEntries
+ }
+ }
+}
\ No newline at end of file
diff --git a/Resources/Private/Language/de.locallang.xlf b/Resources/Private/Language/de.locallang.xlf
index b5edbff..88d16a8 100644
--- a/Resources/Private/Language/de.locallang.xlf
+++ b/Resources/Private/Language/de.locallang.xlf
@@ -15,6 +15,10 @@
Datensätze
+
+
+ Erweiterte Filter
+
Nichts gefunden. Wahrscheinlich ist die Seiten-Id falsch konfiguriert.
diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf
index 07385a0..b8183a1 100644
--- a/Resources/Private/Language/locallang.xlf
+++ b/Resources/Private/Language/locallang.xlf
@@ -12,6 +12,9 @@
+
+
+
diff --git a/Resources/Public/Css/Backend/pagetreefilter.css b/Resources/Public/Css/Backend/pagetreefilter.css
index 0138425..2a5be44 100644
--- a/Resources/Public/Css/Backend/pagetreefilter.css
+++ b/Resources/Public/Css/Backend/pagetreefilter.css
@@ -1,13 +1,12 @@
.pagetreefilter-highlighted {
- fill: #0078e6 !important;
- fill-opacity: 0.1;
+ fill-opacity: 0.3;
stroke-width: 1px;
stroke: #d7d7d7;
}
.pagetreefilter-highlighted.node-over,
.pagetreefilter-highlighted.node-selected {
- fill-opacity: 0.3;
+ fill-opacity: 0.6;
}
.pagetreefilter-wizard .modal-body {