Commit c671a1c5 authored by Oliver Bartsch's avatar Oliver Bartsch Committed by Benni Mack
Browse files

[FEATURE] Add filter option "Never hit" to Redirects module

The Redirects module is extended for a new filter option
"Never hit". When used, the list is filtered for redirects,
which were never hit before. This is especially handy
for editors managing large sites, while the "automatic
redirect generation on slug change" is enabled.

The redirect demand already features the property
"maxHits", which however was previously only used
for the CLI command and is now also used for the
new filter option.

Resolves: #94489
Releases: master
Change-Id: Ied510109de1c6bfb651ea0b8fdec0cfecbfab43a
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/69823

Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Jochen's avatarJochen <rothjochen@gmail.com>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Jochen's avatarJochen <rothjochen@gmail.com>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 54f68d15
......@@ -29,7 +29,7 @@ class RedirectsModule {
}
private executeSubmit(evt: Event, target: Element): void {
if (target instanceof HTMLSelectElement) {
if (target instanceof HTMLSelectElement || (target instanceof HTMLInputElement && target.type === 'checkbox')) {
target.form.submit();
}
}
......
.. include:: ../../Includes.txt
================================================
Feature: #94489 - Filter for redirects never hit
================================================
See :issue:`94489`
Description
===========
Since :issue:`#89115` TYPO3 is able to automatically create redirects
whenever an editor changes a slug of a page. This is a really handy feature.
However on large sites this could quickly lead to a lot of redirects, which
may will never be used by any website visitor.
To support editors by managing their redirects, a new filter option
:guilabel:`Never hit` has been added to the Redirects modules' filter.
Activating this option therefore filters the list for redirects, which
where never hit before.
.. note::
The filter option will only be available, if the "Redirects hit count"
feature is enabled, see:
:doc:`#83677 <../9.1/Feature-83677-GloballyDisableenableRedirectHitStatistics>`.
Impact
======
A new filter option :guilabel:`Never hit` is available in the Redirects
module, allowing editors to filter for redirects, which were never hit before.
.. index:: Backend, ext:redirects
......@@ -131,7 +131,8 @@ class Demand
$statusCode = (int)($demand['target_statuscode'] ?? 0);
$statusCodes = $statusCode > 0 ? [$statusCode] : [];
$target = $demand['target'] ?? '';
return new self($page, $orderField, $orderDirection, $sourceHosts, $sourcePath, $target, $statusCodes);
$maxHits = (int)($demand['max_hits'] ?? 0);
return new self($page, $orderField, $orderDirection, $sourceHosts, $sourcePath, $target, $statusCodes, $maxHits);
}
public static function fromCommandInput(InputInterface $input): self
......@@ -260,7 +261,9 @@ class Demand
{
return $this->hasSourcePath()
|| $this->hasSourceHosts()
|| $this->hasTarget();
|| $this->hasTarget()
|| $this->hasStatusCodes()
|| $this->hasMaxHits();
}
/**
......@@ -294,6 +297,9 @@ class Demand
if ($this->hasStatusCodes()) {
$parameters['target_statuscode'] = $this->getFirstStatusCode();
}
if ($this->hasMaxHits()) {
$parameters['max_hits'] = $this->getMaxHits();
}
return $parameters;
}
}
......@@ -96,6 +96,16 @@ class RedirectRepository
);
}
if ($demand->hasMaxHits()) {
$queryBuilder->andWhere(
$queryBuilder->expr()->lt('hitcount', $queryBuilder->createNamedParameter($demand->getMaxHits(), \PDO::PARAM_INT))
);
// When max hits is set, exclude records which explicitly disabled the hitcount feature
$queryBuilder->andWhere(
$queryBuilder->expr()->eq('disable_hitcount', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
);
}
if (!empty($constraints)) {
$queryBuilder->where(...$constraints);
}
......
......@@ -51,6 +51,9 @@
<trans-unit id="filter.targetStatusCode" resname="filter.targetStatusCode">
<source>Status Code</source>
</trans-unit>
<trans-unit id="filter.neverHit" resname="filter.neverHit">
<source>Never hit</source>
</trans-unit>
<trans-unit id="filter.sendButton" resname="filter.sendButton">
<source>Filter</source>
</trans-unit>
......
......@@ -196,6 +196,14 @@
</f:for>
</select>
</div>
<f:if condition="{showHitCounter}">
<div class="form-check form-switch">
<label class="form-check-label" for="demand-never-hit">
<f:translate key="LLL:EXT:redirects/Resources/Private/Language/locallang_module_redirect.xlf:filter.neverHit"/>
</label>
<input type="checkbox" class="form-check-input" name="demand[max_hits]" id="demand-never-hit" value="1" data-on-change="submit" {f:if(condition: demand.maxHits, then: 'checked="checked"')}>
</div>
</f:if>
<div class="col">
<input type="submit" value="{f:translate(key: 'LLL:EXT:redirects/Resources/Private/Language/locallang_module_redirect.xlf:filter.sendButton')}" class="btn btn-default" />
<a href="{f:be.uri(route:'site_redirects')}" class="btn btn-link"><f:translate key="LLL:EXT:redirects/Resources/Private/Language/locallang_module_redirect.xlf:filter.resetButton"/></a>
......
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
define(["require","exports","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,t,n){"use strict";return new class{constructor(){const e=document.querySelector('form[data-on-submit="processNavigate"]');null!==e&&(new n("change",this.executeSubmit.bind(this)).delegateTo(document,'[data-on-change="submit"]'),new n("submit",this.processNavigate.bind(this)).bindTo(e))}executeSubmit(e,t){t instanceof HTMLSelectElement&&t.form.submit()}processNavigate(e,t){if(!(t instanceof HTMLFormElement))return;e.preventDefault();const n=t.elements.namedItem("paginator-target-page"),a=parseInt(n.dataset.numberOfPages,10);let s=n.dataset.url,r=parseInt(n.value,10);r>a?r=a:r<1&&(r=1),s=s.replace("987654322",r.toString()),self.location.href=s}}}));
\ No newline at end of file
define(["require","exports","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,t,n){"use strict";return new class{constructor(){const e=document.querySelector('form[data-on-submit="processNavigate"]');null!==e&&(new n("change",this.executeSubmit.bind(this)).delegateTo(document,'[data-on-change="submit"]'),new n("submit",this.processNavigate.bind(this)).bindTo(e))}executeSubmit(e,t){(t instanceof HTMLSelectElement||t instanceof HTMLInputElement&&"checkbox"===t.type)&&t.form.submit()}processNavigate(e,t){if(!(t instanceof HTMLFormElement))return;e.preventDefault();const n=t.elements.namedItem("paginator-target-page"),a=parseInt(n.dataset.numberOfPages,10);let s=n.dataset.url,r=parseInt(n.value,10);r>a?r=a:r<1&&(r=1),s=s.replace("987654322",r.toString()),self.location.href=s}}}));
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment