Cookie-Einstellungen in Footer aufnehmen

This commit is contained in:
2026-08-27 12:51:02 +02:00
parent da7132d4ce
commit 2179744ddf
13 changed files with 95 additions and 14 deletions
+11 -1
View File
@@ -108,6 +108,16 @@ function app_analytics_head_html(): string
return '<link rel="stylesheet" href="assets/css/privacy-settings.css">' . "\n";
}
function app_analytics_footer_settings_button_html(): string
{
if (app_matomo_configuration() === null) {
return '';
}
return '<button type="button" class="footer-cookie-settings" data-analytics-settings>'
. 'Cookie-Einstellungen</button>';
}
function app_analytics_body_html(): string
{
$configuration = app_matomo_configuration();
@@ -154,7 +164,7 @@ function app_analytics_body_html(): string
</div>
</div>
</section>
<button type="button" class="analytics-consent-settings" id="analytics-consent-settings" hidden>Cookie-Einstellungen</button>
<button type="button" class="analytics-consent-settings" id="analytics-consent-settings" data-analytics-settings hidden>Cookie-Einstellungen</button>
HTML
. "\n<script type=\"application/json\" id=\"analytics-configuration\">{$json}</script>\n"
. '<script src="assets/js/privacy-settings.js" defer></script>' . "\n";
+1
View File
@@ -35,6 +35,7 @@ function app_public_legal_footer(): string
. '<a class="legal-action-link" href="widerrufen.php">Vertrag widerrufen</a>'
. '<a href="preise.php">Preise</a>'
. '<a class="legal-action-link" href="kuendigen.php">Verträge hier kündigen</a>'
. app_analytics_footer_settings_button_html()
. '</footer>';
}
+35
View File
@@ -103,6 +103,41 @@
padding: 0.55rem 0.7rem;
}
.footer-cookie-settings {
appearance: none;
background: transparent;
border: 0;
border-bottom: dotted 1px;
border-radius: 0;
box-shadow: none;
color: inherit !important;
cursor: pointer;
font: inherit;
font-weight: inherit;
height: auto;
letter-spacing: inherit;
line-height: inherit;
margin: 0;
padding: 0;
text-transform: none;
}
.footer-cookie-settings:hover {
background: transparent;
border-bottom-color: transparent;
color: #38761d !important;
}
.footer-cookie-settings:focus-visible {
outline: solid 3px #f0b429;
outline-offset: 3px;
}
.public-footer-links .footer-cookie-settings {
color: #3d4449 !important;
margin: 0 0.5rem;
}
@media screen and (max-width: 736px) {
.analytics-consent {
padding: 1rem;
+10 -7
View File
@@ -3,9 +3,10 @@
var configurationElement = document.getElementById('analytics-configuration');
var banner = document.getElementById('analytics-consent');
var settingsButton = document.getElementById('analytics-consent-settings');
var floatingSettingsButton = document.getElementById('analytics-consent-settings');
var settingsButtons = document.querySelectorAll('[data-analytics-settings]');
if (!configurationElement || !banner || !settingsButton) {
if (!configurationElement || !banner || !floatingSettingsButton) {
return;
}
@@ -148,7 +149,7 @@
function closeBanner() {
banner.hidden = true;
settingsButton.hidden = false;
floatingSettingsButton.hidden = false;
}
function choose(decision) {
@@ -170,21 +171,23 @@
});
});
settingsButton.addEventListener('click', function () {
settingsButtons.forEach(function (button) {
button.addEventListener('click', function () {
banner.hidden = false;
settingsButton.hidden = true;
floatingSettingsButton.hidden = true;
var firstButton = banner.querySelector('[data-analytics-consent="denied"]');
if (firstButton) {
firstButton.focus();
}
});
});
var initialDecision = readDecision();
if (initialDecision === 'granted') {
settingsButton.hidden = false;
floatingSettingsButton.hidden = false;
sendPageView();
} else if (initialDecision === 'denied') {
settingsButton.hidden = false;
floatingSettingsButton.hidden = false;
removeAnalysisCookies();
} else {
banner.hidden = false;
+1
View File
@@ -68,6 +68,7 @@ $result = $token !== ''
<a class="legal-action-link" href="widerrufen.php">Vertrag widerrufen</a>
<a href="preise.php">Preise</a>
<a class="legal-action-link" href="kuendigen.php">Verträge hier kündigen</a>
<?php echo app_analytics_footer_settings_button_html(); ?>
</footer>
<?php echo app_analytics_body_html(); ?>
+1 -1
View File
@@ -133,7 +133,7 @@ if ($saasNavUser !== null) {
<!-- Footer -->
<footer id="footer">
<p class="copyright">&copy; Clemens Creutzburg · Design: <a href="https://html5up.net">HTML5 UP</a> · <a href="impressum.php">Impressum</a> · <a href="agb.php">AGB</a> · <a href="datenschutz.php">Datenschutz</a> · <a href="avv.php">AVV</a> · <a href="widerruf.php">Widerrufsbelehrung</a> · <a href="widerrufen.php">Vertrag widerrufen</a> · <a href="preise.php">Preise</a> · <a href="kuendigen.php"><b>Verträge hier kündigen</b></a></p>
<p class="copyright"><a href="impressum.php">Impressum</a> · <a href="agb.php">AGB</a> · <a href="datenschutz.php">Datenschutz</a> · <a href="avv.php">AVV</a> · <a href="widerruf.php">Widerrufsbelehrung</a> · <a href="widerrufen.php">Vertrag widerrufen</a> · <a href="preise.php">Preise</a> · <a href="kuendigen.php"><b>Verträge hier kündigen</b></a><?php $footerCookieSettings = app_analytics_footer_settings_button_html(); echo $footerCookieSettings !== '' ? ' · ' . $footerCookieSettings : ''; ?></p>
</footer>
+1
View File
@@ -292,6 +292,7 @@ $jsonFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
<a class="legal-action-link" href="widerrufen.php">Vertrag widerrufen</a>
<a href="preise.php">Preise</a>
<a class="legal-action-link" href="kuendigen.php">Verträge hier kündigen</a>
<?php echo app_analytics_footer_settings_button_html(); ?>
</footer>
<?php echo app_analytics_body_html(); ?>
+1
View File
@@ -136,6 +136,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<a class="legal-action-link" href="widerrufen.php">Vertrag widerrufen</a>
<a href="preise.php">Preise</a>
<a class="legal-action-link" href="kuendigen.php">Verträge hier kündigen</a>
<?php echo app_analytics_footer_settings_button_html(); ?>
</footer>
<?php echo app_analytics_body_html(); ?>
+1
View File
@@ -116,6 +116,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<a class="legal-action-link" href="widerrufen.php">Vertrag widerrufen</a>
<a href="preise.php">Preise</a>
<a class="legal-action-link" href="kuendigen.php">Verträge hier kündigen</a>
<?php echo app_analytics_footer_settings_button_html(); ?>
</footer>
<?php echo app_analytics_body_html(); ?>
+1
View File
@@ -111,6 +111,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<a class="legal-action-link" href="widerrufen.php">Vertrag widerrufen</a>
<a href="preise.php">Preise</a>
<a class="legal-action-link" href="kuendigen.php">Verträge hier kündigen</a>
<?php echo app_analytics_footer_settings_button_html(); ?>
</footer>
<?php echo app_analytics_body_html(); ?>
+1
View File
@@ -211,6 +211,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<a class="legal-action-link" href="widerrufen.php">Vertrag widerrufen</a>
<a href="preise.php">Preise</a>
<a class="legal-action-link" href="kuendigen.php">Verträge hier kündigen</a>
<?php echo app_analytics_footer_settings_button_html(); ?>
</footer>
<?php echo app_analytics_body_html(); ?>
+25
View File
@@ -74,6 +74,9 @@ $assert('Matomo selbst ist im HTML nicht vorab eingebunden',
&& !str_contains($body, '"siteId"'));
$assert('Cookie-Einstellungen bleiben nach der Entscheidung erreichbar',
str_contains($body, 'analytics-consent-settings'));
$assert('Footer-Schalter wird bei aktiver Analyse ausgegeben',
str_contains(app_analytics_footer_settings_button_html(), 'data-analytics-settings')
&& str_contains(app_public_legal_footer(), 'Cookie-Einstellungen'));
$assert('Browser nutzt den lokalen First-Party-Endpunkt',
str_contains($body, '"trackingEndpoint":"nutzungsanalyse.php"')
&& str_contains($body, 'assets/js/privacy-settings.js'));
@@ -94,6 +97,9 @@ $assert('Keine Kaffeeliste-Benutzerkennung wird gelesen',
$assert('Widerruf stoppt Tracking und löscht Analyse-Cookies',
str_contains($javascript, 'removeAnalysisCookies()')
&& str_contains($javascript, "name !== visitorCookieName"));
$assert('Alle Cookie-Einstellungs-Schalter öffnen denselben Dialog',
str_contains($javascript, "querySelectorAll('[data-analytics-settings]')")
&& str_contains($javascript, 'settingsButtons.forEach'));
$relay = file_get_contents(APP_ROOT . '/app/analytics-relay.php') ?: '';
$assert('Relay übernimmt keine Client-IP',
@@ -130,6 +136,25 @@ foreach ($publicTemplates as $template) {
$assert('App-Layout bindet Head und Body zentral ein',
str_contains(file_get_contents(APP_ROOT . '/header.php') ?: '', 'app_analytics_head_html')
&& str_contains(file_get_contents(APP_ROOT . '/footer.php') ?: '', 'app_analytics_body_html'));
$appFooter = file_get_contents(APP_ROOT . '/footer.php') ?: '';
$assert('App-Footer enthält Cookie-Einstellungen ohne Copyright- und Designlink',
str_contains($appFooter, 'app_analytics_footer_settings_button_html')
&& !str_contains($appFooter, '&copy; Clemens Creutzburg')
&& !str_contains($appFooter, 'html5up.net'));
foreach ([
'email-verifizieren.php',
'landing.php',
'login.php',
'passwort-vergessen.php',
'passwort-zuruecksetzen.php',
'register.php',
'zwei-faktor.php',
] as $manualFooterTemplate) {
$contents = file_get_contents(APP_ROOT . '/' . $manualFooterTemplate) ?: '';
$assert("{$manualFooterTemplate} bietet Cookie-Einstellungen im Footer an",
str_contains($contents, 'app_analytics_footer_settings_button_html'));
}
$privacy = app_legal_document_text('privacy_notice');
$assert('Aktuelle Datenschutzerklärung beschreibt Matomo und Widerruf',
+1
View File
@@ -112,6 +112,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<a href="datenschutz.php">Datenschutz</a>
<a href="avv.php">AVV</a>
<a href="widerruf.php">Widerrufsbelehrung</a>
<?php echo app_analytics_footer_settings_button_html(); ?>
</footer>
<?php echo app_analytics_body_html(); ?>
</body>