diff --git a/.prettierrc.json b/.prettierrc.json
index a39e4f3..86fa54a 100644
--- a/.prettierrc.json
+++ b/.prettierrc.json
@@ -1,3 +1,4 @@
{
- "phpVersion": "7.2"
+ "phpVersion": "7.2",
+ "tabWidth": 2
}
diff --git a/Classes/DataSource/GroupsDataSource.php b/Classes/DataSource/GroupsDataSource.php
index 0883460..1bc8a60 100644
--- a/Classes/DataSource/GroupsDataSource.php
+++ b/Classes/DataSource/GroupsDataSource.php
@@ -11,23 +11,27 @@ class GroupsDataSource extends AbstractDataSource
/**
* @var string
*/
- protected static $identifier = 'sandstorm-cookiepunch-groups';
+ protected static $identifier = 'sandstorm-cookiepunch-services';
/**
- * @Flow\InjectConfiguration(package="Sandstorm.CookiePunch", path="groups")
+ * @Flow\InjectConfiguration(package="Sandstorm.CookiePunch", path="consent.services")
*/
- protected $groups;
+ protected $services;
public function getData(NodeInterface $node = null, array $arguments = [])
{
$CookiePunchConfig = new CookiePunchConfig();
$options = [];
- foreach ($this->groups as $name => $group) {
- $label = isset($group["title"])
- ? $CookiePunchConfig->translate($group["title"])
- : $name;
- $options[$name] = ['label' => $label];
+
+ if(isset($this->services) && sizeof(array_keys($this->services)) > 0) {
+ foreach ($this->services as $name => $service) {
+ $label = isset($service["title"])
+ ? $CookiePunchConfig->translate($service["title"])
+ : $name;
+ $options[$name] = ['label' => $label];
+ }
}
+
return $options;
}
}
diff --git a/Classes/Eel/Helper/CookiePunch.php b/Classes/Eel/Helper/CookiePunch.php
index 9faa0e7..d6b02b2 100644
--- a/Classes/Eel/Helper/CookiePunch.php
+++ b/Classes/Eel/Helper/CookiePunch.php
@@ -5,39 +5,19 @@
use Neos\Flow\Annotations as Flow;
use Neos\Eel\ProtectedContextAwareInterface;
use phpDocumentor\Reflection\Types\Boolean;
-use Sandstorm\CookiePunch\ConsentConfigImplementation;
use Sandstorm\CookiePunch\TagHelper;
class CookiePunch implements ProtectedContextAwareInterface
{
- const SETTINGS_BLOCK = "block";
-
- const SETTINGS_GROUP = "group";
- const SETTINGS_OPTIONS = "options";
- const SETTINGS_BLOCK_ALL = "block";
-
- const SETTINGS_BLOCK_PATTERNS = "patterns";
- const DEFAULT_GROUP = "default";
-
- /**
- * @Flow\InjectConfiguration(package="Sandstorm.CookiePunch", path="groups")
- */
- protected $groups;
-
/**
- * @Flow\InjectConfiguration(package="Sandstorm.CookiePunch", path="elements.patterns")
+ * @Flow\InjectConfiguration(package="Sandstorm.CookiePunch", path="services")
*/
- protected $patterns;
+ protected $services;
/**
- * @Flow\InjectConfiguration(package="Sandstorm.CookiePunch", path="elements.block")
+ * @Flow\InjectConfiguration(package="Sandstorm.CookiePunch", path="blocking.tagPatterns")
*/
- protected $block;
-
- /**
- * @Flow\InjectConfiguration(package="Sandstorm.CookiePunch", path="elements.group")
- */
- protected $defaultGroup;
+ protected $tagPatterns;
public function neverBlockIframes(string $markup): string
{
@@ -64,80 +44,91 @@ public function neverBlockScripts(string $markup): string
public function blockIframes(
string $markup,
bool $enabled = true,
- string $groupOverride = null
+ string $serviceNameOverride = null
): string {
if (!$enabled) {
return $markup;
}
return $this->replaceTags("iframe", $markup, function (
- $tag,
- $blockConfig
- ) use ($groupOverride) {
+ $tagMarkup,
+ $serviceName
+ ) use ($serviceNameOverride) {
// IMPORTANT: keep the order here or update all tests!
- $tag = TagHelper::tagRenameAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagRenameAttribute(
+ $tagMarkup,
TagHelper::SRC,
TagHelper::DATA_SRC
);
- $tag = $this->addDataNameAttribute(
- $tag,
- $blockConfig,
- $groupOverride
- );
- $tag = TagHelper::tagAddAttribute($tag, "style", "display: none;");
- $tag = $this->addDataOptionsAttribute($tag, $blockConfig);
- return $tag;
+ $dataNameAttribute = $serviceNameOverride
+ ? $serviceNameOverride
+ : $serviceName;
+
+ if (
+ !TagHelper::tagHasAttribute($tagMarkup, TagHelper::DATA_NAME) &&
+ $dataNameAttribute
+ ) {
+ $tagMarkup = TagHelper::tagAddAttribute(
+ $tagMarkup,
+ TagHelper::DATA_NAME,
+ $dataNameAttribute
+ );
+ }
+
+ return $tagMarkup;
});
}
/**
- * @param string $markup
+ * @param string $contentMarkup
* @return string
*/
public function blockScripts(
- string $markup,
+ string $contentMarkup,
bool $enabled = true,
- string $groupOverride = null
+ string $serviceNameOverride = null
): string {
if (!$enabled) {
- return $markup;
+ return $contentMarkup;
}
- return $this->replaceTags("script", $markup, function (
- $tag,
- $blockConfig
- ) use ($groupOverride) {
+ return $this->replaceTags("script", $contentMarkup, function (
+ $tagMarkup,
+ $serviceName
+ ) use ($serviceNameOverride) {
// #########################################################################
// IMPORTANT: keep the order in the following section or update all tests!
// #########################################################################
- $tag = TagHelper::tagRenameAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagRenameAttribute(
+ $tagMarkup,
TagHelper::SRC,
TagHelper::DATA_SRC
);
- $hasType = TagHelper::tagHasAttribute($tag, TagHelper::TYPE);
+ $hasType = TagHelper::tagHasAttribute($tagMarkup, TagHelper::TYPE);
- $typeAttributeValue = TagHelper::tagGetAttributeValue($tag, "type");
+ $typeAttributeValue = TagHelper::tagGetAttributeValue(
+ $tagMarkup,
+ "type"
+ );
- if(!$typeAttributeValue) {
+ if (!$typeAttributeValue) {
// We want to be least invasive and try to reuse the type attribute value
// if none is present we use fallback.
$typeAttributeValue = TagHelper::TYPE_JAVASCRIPT;
}
- if (TagHelper::tagHasAttribute($tag, TagHelper::DATA_SRC)) {
+ if (TagHelper::tagHasAttribute($tagMarkup, TagHelper::DATA_SRC)) {
if ($hasType) {
- $tag = TagHelper::tagRenameAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagRenameAttribute(
+ $tagMarkup,
TagHelper::TYPE,
TagHelper::DATA_TYPE
);
- $tag = TagHelper::tagAddAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagAddAttribute(
+ $tagMarkup,
TagHelper::TYPE,
TagHelper::TYPE_TEXT_PLAIN
);
@@ -145,8 +136,8 @@ public function blockScripts(
// IMPORTANT: we need to add data-type="text/javascript" here to prevent Klaro from
// not correctly recovering the correct value.
// we add type="text/javascript" which later will be turned into an data attribute
- $tag = TagHelper::tagAddAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagAddAttribute(
+ $tagMarkup,
TagHelper::DATA_TYPE,
$typeAttributeValue
);
@@ -154,40 +145,66 @@ public function blockScripts(
} else {
// nor src so we have to "break" the tag by setting the type
if ($hasType) {
- $tag = TagHelper::tagRenameAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagRenameAttribute(
+ $tagMarkup,
TagHelper::TYPE,
TagHelper::DATA_TYPE
);
- $tag = TagHelper::tagAddAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagAddAttribute(
+ $tagMarkup,
TagHelper::TYPE,
TagHelper::TYPE_TEXT_PLAIN
);
} else {
- $tag = TagHelper::tagAddAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagAddAttribute(
+ $tagMarkup,
TagHelper::TYPE,
TagHelper::TYPE_TEXT_PLAIN
);
- $tag = TagHelper::tagAddAttribute(
- $tag,
+ $tagMarkup = TagHelper::tagAddAttribute(
+ $tagMarkup,
TagHelper::DATA_TYPE,
$typeAttributeValue
);
}
}
- $tag = $this->addDataNameAttribute(
- $tag,
- $blockConfig,
- $groupOverride
- );
- $tag = $this->addDataOptionsAttribute($tag, $blockConfig);
- return $tag;
+ $dataNameAttribute = $serviceNameOverride
+ ? $serviceNameOverride
+ : $serviceName;
+
+ if (
+ !TagHelper::tagHasAttribute($tagMarkup, TagHelper::DATA_NAME) &&
+ $dataNameAttribute
+ ) {
+ $tagMarkup = TagHelper::tagAddAttribute(
+ $tagMarkup,
+ TagHelper::DATA_NAME,
+ $dataNameAttribute
+ );
+ }
+
+ return $tagMarkup;
});
}
+ /**
+ * @param string | null $markup
+ * @param string $service
+ * @return string
+ */
+ public function addContextualConsent(
+ string $service,
+ ?string $markup,
+ ?bool $isEnabled
+ ) {
+ if ($isEnabled) {
+ return "
" . $markup . "
";
+ } else {
+ return $markup;
+ }
+ }
+
private function addNeverBlockAttribute(string $tag): string
{
if (!TagHelper::tagHasAttribute($tag, TagHelper::DATA_NEVER_BLOCK)) {
@@ -199,44 +216,6 @@ private function addNeverBlockAttribute(string $tag): string
return $tag;
}
- private function addDataNameAttribute(
- string $tag,
- array $blockConfig,
- string $groupOverride = null
- ): string {
- if (!TagHelper::tagHasAttribute($tag, TagHelper::DATA_NAME)) {
- $value = $groupOverride
- ? $groupOverride
- : $blockConfig[self::SETTINGS_GROUP];
- return TagHelper::tagAddAttribute(
- $tag,
- TagHelper::DATA_NAME,
- $value
- );
- }
- return $tag;
- }
-
- private function addDataOptionsAttribute(
- string $tag,
- array $blockConfig
- ): string {
- if (isset($blockConfig[self::SETTINGS_OPTIONS])) {
- $encodedOptions = htmlspecialchars(
- json_encode($blockConfig[self::SETTINGS_OPTIONS]),
- ENT_QUOTES,
- 'UTF-8'
- );
- return TagHelper::tagAddAttribute(
- $tag,
- TagHelper::DATA_OPTIONS,
- $encodedOptions
- );
- }
-
- return $tag;
- }
-
/**
* @param string $haystack
* @param string $needle
@@ -247,131 +226,141 @@ private function tagContains(string $haystack, string $needle): bool
return !!strpos($haystack, $needle) !== false;
}
- /**
- * @param string $tag
- * @return array
- */
- private function getBlockConfig(string $tag): array
- {
- if (!$this->patterns) {
- return $this->buildBlockConfigForPatternConfig();
- }
-
- foreach ($this->patterns as $pattern => $config) {
- if ($this->tagContains($tag, $pattern)) {
- return $this->buildBlockConfigForPatternConfig($config);
- }
- }
- return $this->buildBlockConfigForPatternConfig();
- }
-
- /**
- * @param array|null $config
- * @return array
- */
- private function buildBlockConfigForPatternConfig(
- array $config = null
- ): array {
- $fallbackBlocked = isset($this->block) ? $this->block : false;
- $fallbackGroup = isset($this->defaultGroup)
- ? $this->defaultGroup
- : self::DEFAULT_GROUP;
-
- // no config early return
- if (!$config) {
- return [
- self::SETTINGS_BLOCK => $fallbackBlocked,
- self::SETTINGS_GROUP => $fallbackGroup,
- ];
- }
-
- $blocked = isset($config[self::SETTINGS_BLOCK])
- ? $config[self::SETTINGS_BLOCK]
- : $fallbackBlocked;
- $group = isset($config[self::SETTINGS_GROUP])
- ? $config[self::SETTINGS_GROUP]
- : $fallbackGroup;
- $options = isset($config[self::SETTINGS_OPTIONS])
- ? $config[self::SETTINGS_OPTIONS]
- : null;
-
- return [
- self::SETTINGS_BLOCK => $blocked,
- self::SETTINGS_GROUP => $group,
- self::SETTINGS_OPTIONS => $options,
- ];
- }
-
/**
* @param string $tagName
- * @param string $text
+ * @param string $contentMarkup
* @param callable $hitCallback
* @return string
*/
private function replaceTags(
string $tagName,
- string $text,
+ string $contentMarkup,
callable $hitCallback
): string {
$regex = '/<' . $tagName . '.*?>/';
+ // STAGE 1:
+ //
+ // Before making changes to a tag we do some check first
+ // and decide if we need to apply more logic.
+ // This is basically a collection of early return before using the
+ // callback which will the replace the tags.
+ //
+ // IMPORTANT: here we do not change a tag. We only check if we need to proceed
return preg_replace_callback(
$regex,
- function ($hits) use ($hitCallback) {
- $tag = $hits[0];
+ function ($hits) use ($hitCallback, $tagName) {
+ $tagMarkup = $hits[0];
// EARLY RETURN - NO CALLBACK
if (!$hitCallback) {
- return $tag;
+ return $tagMarkup;
}
// EARLY RETURN - NEVER BLOCK
$neverBlock = $this->tagContains(
- $tag,
+ $tagMarkup,
TagHelper::DATA_NEVER_BLOCK
);
+
if ($neverBlock) {
- return $tag;
+ return $tagMarkup;
}
// EARLY RETURN - SPECIAL MIME TYPE
$mimeType = TagHelper::tagGetAttributeValue(
- $tag,
+ $tagMarkup,
TagHelper::TYPE
);
- if($mimeType === TagHelper::TYPE_TEXT_PLAIN || $mimeType === TagHelper::TYPE_APPLICATION_JSON_LD) return $tag;
+ if (
+ $mimeType === TagHelper::TYPE_TEXT_PLAIN ||
+ $mimeType === TagHelper::TYPE_APPLICATION_JSON_LD
+ ) {
+ return $tagMarkup;
+ }
// EARLY RETURN - HAS BLOCKING ATTRIBUTES
// if a part of the markup was already processed
+ // We do not check if TagHelper::DATA_NAME is present, because we might want the editor
+ // to choose a group, e.g. in the inspector and still block tags.
$hasBlockingAttributes =
- TagHelper::tagHasAttribute($tag, TagHelper::DATA_SRC) ||
TagHelper::tagHasAttribute(
- $tag,
+ $tagMarkup,
+ TagHelper::DATA_SRC
+ ) ||
+ TagHelper::tagHasAttribute(
+ $tagMarkup,
TagHelper::DATA_TYPE
);
- // We do not check if TagHelper::DATA_NAME is present, because we might want the editor
- // to choose a group, e.g. in the inspector and still block tags.
- if ($hasBlockingAttributes) return $tag;
- $blockConfig = $this->getBlockConfig($tag);
+ if ($hasBlockingAttributes) {
+ return $tagMarkup;
+ }
+
+ // Blocking based on patterns from the config
+ // tagName can be iframe or script
+
+ // default is always true but can change depending on the next stage
+ $block = true;
+ $serviceName = null;
+
+ $tagPatterns = isset($this->tagPatterns[$tagName])
+ ? $this->tagPatterns[$tagName]
+ : [];
+
+ if (isset($tagPatterns["*"])) {
+ $patternConfig = $tagPatterns["*"];
+ if (isset($patternConfig["block"])) {
+ $block = $patternConfig["block"];
+ }
+ if (isset($patternConfig["service"])) {
+ $block = true;
+ // We also pass the corresponding service name to the next stage
+ $serviceName = $patternConfig["service"];
+ }
+ }
- if ($blockConfig[self::SETTINGS_BLOCK]) {
- return call_user_func($hitCallback, $tag, $blockConfig);
+ foreach ($tagPatterns as $pattern => $patternConfig) {
+ if ($pattern === "*") {
+ continue;
+ }
+ if ($this->tagContains($tagMarkup, $pattern)) {
+ if (isset($patternConfig["block"])) {
+ $block = $patternConfig["block"];
+ }
+
+ if (isset($patternConfig["service"])) {
+ // if we habe a relating consent service the elment will always be blocked
+ // as it will be controlled by the consent itself
+ $block = true;
+
+ // We also pass the corresponding service name to the next stage
+ $serviceName = $patternConfig["service"];
+ }
+ }
+ }
+
+ if ($block) {
+ return call_user_func(
+ $hitCallback,
+ $tagMarkup,
+ $serviceName
+ );
} else {
- return $tag;
+ return $tagMarkup;
}
},
- $text
+ $contentMarkup
);
}
- private function validateGroup(string $name = null)
+ private function validateService(string $name = null)
{
- if ($name && !isset($this->groups[$name])) {
+ if ($name && !isset($this->services[$name])) {
throw new \InvalidArgumentException(
- 'The group "' .
+ 'The service "' .
$name .
- '" could not be found in your config. Expected config for "Sandstorm.CookiePunch.groups.' .
+ '" could not be found in your config. Expected config for "Sandstorm.CookiePunch.services.' .
$name .
'"',
1596469884
diff --git a/Classes/Eel/Helper/CookiePunchConfig.php b/Classes/Eel/Helper/CookiePunchConfig.php
index 1112132..621b5e5 100644
--- a/Classes/Eel/Helper/CookiePunchConfig.php
+++ b/Classes/Eel/Helper/CookiePunchConfig.php
@@ -10,13 +10,17 @@
class CookiePunchConfig implements ProtectedContextAwareInterface
{
- public function translate(string $path): string
+ public function translate($path): ?string
{
- $settingsValue = (new ConfigurationHelper())->setting($path);
- if ($settingsValue) {
- return (new TranslationHelper())->translate($settingsValue);
+ if ($path) {
+ $settingsValue = (new ConfigurationHelper())->setting($path);
+ if ($settingsValue) {
+ return (new TranslationHelper())->translate($settingsValue);
+ } else {
+ return (new TranslationHelper())->translate($path);
+ }
} else {
- return (new TranslationHelper())->translate($path);
+ return null;
}
}
diff --git a/Classes/FusionObjects/ConfigImplementation.php b/Classes/FusionObjects/ConfigImplementation.php
deleted file mode 100644
index 80152b6..0000000
--- a/Classes/FusionObjects/ConfigImplementation.php
+++ /dev/null
@@ -1,137 +0,0 @@
- $groupConfig) {
- $translations[$name] = $this->buildAppTranslation($groupConfig);
- array_push($apps, $this->buildAppConfig($name, $groupConfig));
- }
- if ($purposes && sizeof($purposes)) {
- $translations["purposes"] = $purposes;
- }
- }
-
- $config = [
- "acceptAll" => isset($dataStructure[self::CONSENT_CONFIG]["acceptAll"])
- ? $dataStructure[self::CONSENT_CONFIG]["acceptAll"]
- : true,
- "apps" => $apps,
- "cookieDomain" => isset(
- $dataStructure[self::CONSENT_CONFIG]["cookieDomain"]
- )
- ? $dataStructure[self::CONSENT_CONFIG]["cookieDomain"]
- : null,
- "cookieExpiresAfterDays" => isset(
- $dataStructure[self::CONSENT_CONFIG]["cookieExpiresAfterDays"]
- )
- ? $dataStructure[self::CONSENT_CONFIG]["cookieExpiresAfterDays"]
- : 120,
- "cookieName" => isset($dataStructure[self::CONSENT_CONFIG]["cookieName"])
- ? $dataStructure[self::CONSENT_CONFIG]["cookieName"]
- : "cookie_punch",
- "default" => isset($dataStructure[self::CONSENT_CONFIG]["default"])
- ? $dataStructure[self::CONSENT_CONFIG]["default"]
- : false,
-
- "handleConsentOptions" => isset($dataStructure["handleConsentOptions"])
- ? $dataStructure["handleConsentOptions"]
- : [],
- "hideDeclineAll" => isset(
- $dataStructure[self::CONSENT_CONFIG]["hideDeclineAll"]
- )
- ? $dataStructure[self::CONSENT_CONFIG]["hideDeclineAll"]
- : false,
- "mustConsent" => isset(
- $dataStructure[self::CONSENT_CONFIG]["mustConsent"]
- )
- ? $dataStructure[self::CONSENT_CONFIG]["mustConsent"]
- : true,
- "privacyPolicy" => isset(
-
- $dataStructure[self::CONSENT_CONFIG]["privacyPolicyUrl"]
- )
- ? $dataStructure[self::CONSENT_CONFIG]["privacyPolicyUrl"]
- : "/privacy",
- "storageMethod" =>
- isset($dataStructure[self::CONSENT_CONFIG]["storageMethod"]) &&
- ($dataStructure[self::CONSENT_CONFIG]["storageMethod"] === "cookie" ||
- $dataStructure[self::CONSENT_CONFIG]["storageMethod"] === "localStorage")
- ? $dataStructure[self::CONSENT_CONFIG]["storageMethod"]
- : "cookie",
- "translations" => $translations,
- ];
-
- return $config;
- }
-
- private function buildAppConfig(string $name, array $groupConfig): array {
- $result = [
- "name" => $name,
- "title" => isset($groupConfig["title"])
- ? $groupConfig["title"]
- : $name,
- "purposes" =>
- isset($groupConfig["purposes"]) &&
- is_array($groupConfig["purposes"])
- ? $groupConfig["purposes"]
- : [],
- "cookies" =>
- isset($groupConfig[self::CONSENT_CONFIG]["cookies"]) &&
- is_array($groupConfig[self::CONSENT_CONFIG]["cookies"])
- ? $groupConfig[self::CONSENT_CONFIG]["cookies"]
- : [],
- ];
-
- if (isset($groupConfig[self::CONSENT_CONFIG]["default"])) {
- $result["default"] = $groupConfig[self::CONSENT_CONFIG]["default"];
- }
-
- if (isset($groupConfig[self::CONSENT_CONFIG]["required"])) {
- $result["required"] =
- $groupConfig[self::CONSENT_CONFIG]["required"];
- }
-
- return $result;
- }
-
- private function buildAppTranslation(array $groupConfig): array {
- $result = [];
- if (isset($groupConfig["title"])) {
- $result["title"] = $groupConfig["title"];
- }
- if (isset($groupConfig["description"])) {
- $result["description"] = $groupConfig["description"];
- }
- return $result;
- }
-}
diff --git a/Classes/TagHelper.php b/Classes/TagHelper.php
index 94adca5..e87b31c 100644
--- a/Classes/TagHelper.php
+++ b/Classes/TagHelper.php
@@ -77,11 +77,13 @@ function ($hits) use ($newName) {
* @param string $name
* @return string
*/
- static function tagGetAttributeValue(
- string $tag,
- string $name
- ): ?string {
- preg_match(self::buildMatchAttributeNameWithAnyValueReqex($name), $tag, $matches);
+ static function tagGetAttributeValue(string $tag, string $name): ?string
+ {
+ preg_match(
+ self::buildMatchAttributeNameWithAnyValueReqex($name),
+ $tag,
+ $matches
+ );
return isset($matches['value']) ? $matches['value'] : null;
}
diff --git a/Configuration/NodeTypes.Mixin.ConsentGroup.yaml b/Configuration/NodeTypes.Mixin.ConsentServices.yaml
similarity index 61%
rename from Configuration/NodeTypes.Mixin.ConsentGroup.yaml
rename to Configuration/NodeTypes.Mixin.ConsentServices.yaml
index 66d9077..873d7d2 100644
--- a/Configuration/NodeTypes.Mixin.ConsentGroup.yaml
+++ b/Configuration/NodeTypes.Mixin.ConsentServices.yaml
@@ -1,10 +1,10 @@
-"Sandstorm.CookiePunch:Mixin.ConsentGroup":
+"Sandstorm.CookiePunch:Mixin.ConsentServices":
abstract: true
properties:
- consentGroup:
+ consentServices:
type: string
ui:
- label: "Groups"
+ label: "Cookie Consent Services"
reloadIfChanged: true
inspector:
group: "html"
@@ -12,4 +12,4 @@
editor: Neos.Neos/Inspector/Editors/SelectBoxEditor
editorOptions:
placeholder: Choose
- dataSourceIdentifier: sandstorm-cookiepunch-groups
+ dataSourceIdentifier: sandstorm-cookiepunch-services
diff --git a/Configuration/Settings.Translations.yaml b/Configuration/Settings.Translations.yaml
index 9e10972..094d343 100644
--- a/Configuration/Settings.Translations.yaml
+++ b/Configuration/Settings.Translations.yaml
@@ -7,36 +7,53 @@
Sandstorm:
CookiePunch:
translations:
+ acceptAll: Sandstorm.CookiePunch:Klaro:acceptAll
+ acceptSelected: Sandstorm.CookiePunch:Klaro:acceptSelected
+ close: Sandstorm.CookiePunch:Klaro:close
consentModal:
- title: 'Sandstorm.CookiePunch:Klaro:consentModal.title'
- description: 'Sandstorm.CookiePunch:Klaro:consentModal.description'
- privacyPolicy:
- name: 'Sandstorm.CookiePunch:Klaro:consentModal.privacyPolicy.name'
- text: 'Sandstorm.CookiePunch:Klaro:consentModal.privacyPolicy.text'
+ description: Sandstorm.CookiePunch:Klaro:consentModal.description
+ title: Sandstorm.CookiePunch:Klaro:consentModal.title
consentNotice:
- changeDescription: 'Sandstorm.CookiePunch:Klaro:consentNotice.changeDescription'
- description: 'Sandstorm.CookiePunch:Klaro:consentNotice.description'
- learnMore: 'Sandstorm.CookiePunch:Klaro:consentNotice.learnMore'
- privacyPolicy:
- name: 'Sandstorm.CookiePunch:Klaro:consentNotice.privacyPolicy.name'
- imprint:
- name: 'Sandstorm.CookiePunch:Klaro:consentNotice.imprint.name'
- ok: 'Sandstorm.CookiePunch:Klaro:ok'
- save: 'Sandstorm.CookiePunch:Klaro:save'
- decline: 'Sandstorm.CookiePunch:Klaro:decline'
- close: 'Sandstorm.CookiePunch:Klaro:close'
- acceptAll: 'Sandstorm.CookiePunch:Klaro:acceptAll'
- acceptSelected: 'Sandstorm.CookiePunch:Klaro:acceptSelected'
- app:
+ changeDescription: Sandstorm.CookiePunch:Klaro:consentNotice.changeDescription
+ description: Sandstorm.CookiePunch:Klaro:consentNotice.description
+ learnMore: Sandstorm.CookiePunch:Klaro:consentNotice.learnMore
+ testing: Sandstorm.CookiePunch:Klaro:consentNotice.testing
+ contextualConsent:
+ acceptAlways: Sandstorm.CookiePunch:Klaro:contextualConsent.acceptAlways
+ acceptOnce: Sandstorm.CookiePunch:Klaro:contextualConsent.acceptOnce
+ description: Sandstorm.CookiePunch:Klaro:contextualConsent.description
+ decline: Sandstorm.CookiePunch:Klaro:decline
+ ok: Sandstorm.CookiePunch:Klaro:ok
+ poweredBy: Sandstorm.CookiePunch:Klaro:poweredBy
+ privacyPolicy:
+ name: Sandstorm.CookiePunch:Klaro:privacyPolicy.name
+ text: Sandstorm.CookiePunch:Klaro:privacyPolicy.text
+ purposeItem:
+ service: Sandstorm.CookiePunch:Klaro:purposeItem.service
+ services: Sandstorm.CookiePunch:Klaro:purposeItem.services
+ purposes:
+ advertising:
+ description: Sandstorm.CookiePunch:Klaro:purposes.advertising.description
+ title: Sandstorm.CookiePunch:Klaro:purposes.advertising.title
+ functional:
+ description: Sandstorm.CookiePunch:Klaro:purposes.functional.description
+ title: Sandstorm.CookiePunch:Klaro:purposes.functional.title
+ marketing:
+ description: Sandstorm.CookiePunch:Klaro:purposes.marketing.description
+ title: Sandstorm.CookiePunch:Klaro:purposes.marketing.title
+ performance:
+ description: Sandstorm.CookiePunch:Klaro:purposes.performance.description
+ title: Sandstorm.CookiePunch:Klaro:purposes.performance.title
+ save: Sandstorm.CookiePunch:Klaro:save
+ service:
disableAll:
- title: 'Sandstorm.CookiePunch:Klaro:app.disableAll.title'
- description: 'Sandstorm.CookiePunch:Klaro:app.disableAll.description'
+ description: Sandstorm.CookiePunch:Klaro:service.disableAll.description
+ title: Sandstorm.CookiePunch:Klaro:service.disableAll.title
optOut:
- title: 'Sandstorm.CookiePunch:Klaro:app.optOut.title'
- description: 'Sandstorm.CookiePunch:Klaro:app.optOut.description'
+ description: Sandstorm.CookiePunch:Klaro:service.optOut.description
+ title: Sandstorm.CookiePunch:Klaro:service.optOut.title
+ purpose: Sandstorm.CookiePunch:Klaro:service.purpose
+ purposes: Sandstorm.CookiePunch:Klaro:service.purposes
required:
- title: 'Sandstorm.CookiePunch:Klaro:app.required.title'
- description: 'Sandstorm.CookiePunch:Klaro:app.required.description'
- purposes: 'Sandstorm.CookiePunch:Klaro:app.purposes'
- purpose: 'Sandstorm.CookiePunch:Klaro:app.purpose'
- poweredBy: 'Sandstorm.CookiePunch:Klaro:poweredBy'
+ description: Sandstorm.CookiePunch:Klaro:service.required.description
+ title: Sandstorm.CookiePunch:Klaro:service.required.title
diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml
index 7acba01..b0d137a 100644
--- a/Configuration/Settings.yaml
+++ b/Configuration/Settings.yaml
@@ -12,24 +12,27 @@ Sandstorm:
CookiePunch:
consent:
privacyPolicyUrl: /privacy
+ elementID: "klaro"
+ noAutoLoad: false
+ htmlTexts: false
+ embedded: false
+ groupByPurpose: true
storageMethod: cookie
cookieName: cookie_punch
cookieExpiresAfterDays: 120
+ default: false
mustConsent: true
acceptAll: true
hideDeclineAll: false
- default: false
- groups:
- default:
- title: Sandstorm.CookiePunch:Groups:default.title
- description: Sandstorm.CookiePunch:Groups:default.description
- consent:
- default: true
- purposes:
- analytics: Analytics
- elements:
- block: true
- group: default
- options:
- message: Sandstorm.CookiePunch:Elements:options.message
-
+ hideLearnMore: false
+ noticeAsModal: false
+ disablePoweredBy: false
+ additionalClass: ~
+ blocking:
+ tagPatterns:
+ script:
+ "*":
+ block: true
+ iframe:
+ "*":
+ block: true
diff --git a/Examples/Settings.Basic.yaml b/Examples/Settings.Basic.yaml
deleted file mode 100644
index 68b7b6e..0000000
--- a/Examples/Settings.Basic.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-Sandstorm:
- CookiePunch:
- purposes:
- mediaembeds: Media Embeds
- groups:
- media:
- title: Bar
- purposes:
- - mediaembeds
- description: Some bar description
- elements:
- "https://www.youtube.com/embed/":
- type: iframe
- block: true
- group: media
diff --git a/Examples/Settings.CookiePunch.Basic.yaml b/Examples/Settings.CookiePunch.Basic.yaml
new file mode 100644
index 0000000..871fc09
--- /dev/null
+++ b/Examples/Settings.CookiePunch.Basic.yaml
@@ -0,0 +1,21 @@
+Sandstorm:
+ CookiePunch:
+ consent:
+ purposes:
+ mediaembeds: Media Embeds
+ services:
+ anchor:
+ title: Anchor FM
+ description: Podcast Player
+ purposes:
+ - mediaembeds
+ blocking:
+ tagPatterns:
+ script:
+ "Packages/Neos.Neos":
+ block: false
+ "Packages/Unikka.Slick":
+ block: false
+ iframe:
+ "https://anchor.fm":
+ service: anchor
diff --git a/Examples/Settings.CookiePunch.FullConsentConfig.yaml b/Examples/Settings.CookiePunch.FullConsentConfig.yaml
new file mode 100644
index 0000000..6a4fb97
--- /dev/null
+++ b/Examples/Settings.CookiePunch.FullConsentConfig.yaml
@@ -0,0 +1,64 @@
+Sandstorm:
+ CookiePunch:
+ consent:
+ privacyPolicyUrl: /privacy
+ # You can customize the ID of the DIV element that Klaro will create
+ # when starting up. If undefined, Klaro will use 'klaro'.
+ elementID: "klaro"
+ # Setting this to true will keep Klaro from automatically loading itself
+ # when the page is being loaded.
+ noAutoLoad: false
+ # Setting this to true will render the descriptions of the consent
+ # modal and consent notice are HTML. Use with care.
+ htmlTexts: false
+ # Setting 'embedded' to true will render the Klaro modal and notice without
+ # the modal background, allowing you to e.g. embed them into a specific element
+ # of your website, such as your privacy notice.
+ embedded: false
+ # You can group services by their purpose in the modal. This is advisable
+ # if you have a large number of services. Users can then enable or disable
+ # entire groups of services instead of having to enable or disable every service.
+ groupByPurpose: true
+ # How Klaro should store the user's preferences. It can be either 'cookie'
+ # (the default) or 'localStorage'.
+ storageMethod: cookie
+ # You can customize the name of the cookie that Klaro uses for storing
+ # user consent decisions. If undefined, Klaro will use 'klaro'.
+ cookieName: cookie_punch
+ # You can also set a custom expiration time for the Klaro cookie.
+ # By default, it will expire after 120 days.
+ cookieExpiresAfterDays: 120
+ # You can change to cookie domain for the consent manager itself.
+ # Use this if you want to get consent once for multiple matching domains.
+ # If undefined, Klaro will use the current domain.
+ cookieDomain: ~
+ # You can change to cookie path for the consent manager itself.
+ # Use this to restrict the cookie visibility to a specific path.
+ # If undefined, Klaro will use '/' as cookie path.
+ cookiePath: ~
+ # Defines the default state for services
+ default: false
+ # If "mustConsent" is set to true, Klaro will directly display the consent
+ # manager modal and not allow the user to close it before having actively
+ # consented or declines the use of third-party services.
+ mustConsent: true
+ # Show "accept all" to accept all services instead of "ok" that only accepts
+ # required and "default: true" services
+ acceptAll: true
+ # replace "decline" with cookie manager modal
+ hideDeclineAll: false
+ # hide "learnMore" link
+ hideLearnMore: false
+ # show cookie notice as modal (small bar, not visible if mustConsent=true)
+ noticeAsModal: false
+ # You can also remove the 'Realized with Klaro!' text in the consent modal.
+ # Please don't do this! Klaro is a free open source tool.
+ # Placing a link to our website helps klaro to spread the word about it,
+ # which ultimately enables klaro to make their tool better for everyone.
+ # So please be fair and keep the link enabled. Thanks :)
+ disablePoweredBy: false
+ # you can specify an additional class (or classes) that will be added to the Klaro `div`
+ additionalClass: ~
+ # You can override CSS style variables here. We currently do not support
+ # "theme" from the original klaro config.
+ # styling -> see Settings.CookiePunch.Styling.yaml
diff --git a/Examples/Settings.CookiePunch.FullServiceConfig.yaml b/Examples/Settings.CookiePunch.FullServiceConfig.yaml
new file mode 100644
index 0000000..ab7acbc
--- /dev/null
+++ b/Examples/Settings.CookiePunch.FullServiceConfig.yaml
@@ -0,0 +1,47 @@
+Sandstorm:
+ CookiePunch:
+ consent:
+ purposes:
+ mediaembeds: Media Embeds
+ services:
+ # Each service should have a unique (and short) key/name.
+ footube:
+ # If "default" is set to true, the service will be enabled by default
+ # Overwrites global "default" setting.
+ # We recommend leaving this to "false" for services that collect
+ # personal information.
+ default: true
+ # The title of you service as listed in the consent modal.
+ title: Foo Tube
+ # The description of you service as listed in the consent modal.
+ description: Crazy Foo Media Service
+ # The purpose(s) of this service. Will be listed on the consent notice.
+ # Do not forget to add translations for all purposes you list here.
+ purposes:
+ - mediaembeds
+ # A list of regex expressions or strings giving the names of
+ # cookies set by this service. If the user withdraws consent for a
+ # given service, Klaro will then automatically delete all matching
+ # cookies.
+ cookies:
+ - # exact match of cookie name in browser
+ pattern: "_foo_media"
+ path: "/"
+ domain: "foo.media.com"
+ - # pattern match of cookie name in browser
+ # IMPORTANT: do not wrap regex with /.../
+ pattern: "_foo.*$"
+ patternIsRegex: true
+ path: "/"
+ domain: "foo.media.com"
+ contextualConsentOnly: true
+ # If "required" is set to true, Klaro will not allow this service to
+ # be disabled by the user.
+ required: false
+ # If "optOut" is set to true, Klaro will load this service even before
+ # the user gave explicit consent.
+ # We recommend always leaving this "false".
+ optOut: false
+ # If "onlyOnce" is set to true, the service will only be executed
+ # once regardless how often the user toggles it on and off.
+ onlyOnce: true
diff --git a/Examples/Settings.CookiePunch.Styling.yaml b/Examples/Settings.CookiePunch.Styling.yaml
new file mode 100644
index 0000000..58462ff
--- /dev/null
+++ b/Examples/Settings.CookiePunch.Styling.yaml
@@ -0,0 +1,43 @@
+Sandstorm:
+ CookiePunch:
+ consent:
+ styling:
+ button-text-color: ""
+ font-size: ""
+ font-family: ""
+ title-font-family: ""
+
+ green1: ""
+ green2: ""
+ green3: ""
+
+ blue1: ""
+ blue2: ""
+ blue3: ""
+
+ red1: ""
+ red2: ""
+ red3: ""
+
+ light1: ""
+ light2: ""
+ light3: ""
+
+ dark1: ""
+ dark2: ""
+ dark3: ""
+
+ white1: ""
+ white2: ""
+ white3: ""
+
+ border-radius: "0"
+ border-style: ""
+ border-width: ""
+
+ notice-left: ""
+ notice-right: ""
+ notice-top: ""
+ notice-bottom: ""
+ notice-max-width: ""
+ notice-position: ""
diff --git a/Examples/Settings.Example.yaml b/Examples/Settings.Example.yaml
deleted file mode 100644
index b91f65d..0000000
--- a/Examples/Settings.Example.yaml
+++ /dev/null
@@ -1,73 +0,0 @@
-Neos:
- Neos:
- fusion:
- autoInclude:
- "Sandstorm.CookiePunch": true
- Fusion:
- defaultContext:
- "CookiePunch": Sandstorm\CookiePunch\Eel\Helper\CookiePunch
- "CookiePunchConfig": Sandstorm\CookiePunch\Eel\Helper\CookiePunchConfig
-
-Sandstorm:
- CookiePunch:
- consent:
- privacyPolicyUrl: /privacy
- storageMethod: cookie
- cookieName: cookie_punch
- cookieExpiresAfterDays: 120
- # cookieDomain: .example.org
- mustConsent: true
- # button in consent modal next to save button
- acceptAll: true
- # button in consent modal on the right -> decline
- hideDeclineAll: false
- default: false
- groups:
- default:
- title: Sandstorm.CookiePunch:Groups:default.title
- description: Sandstorm.CookiePunch:Groups:default.description
- consent:
- required: true
- cookies:
- - /^ga/i
- media:
- title: Sandstorm.CookiePunch:Groups:media.title
- description: Sandstorm.CookiePunch:Groups:media.description
- purposes:
- - videoembeds
- - analytics
- purposes:
- analytics: Analytics
- videoembeds: Video Embeds
- elements:
- block: true
- group: default
- options:
- message: Sandstorm.CookiePunch:Elements:options.message
- messageClass: block-them-all-message
- patterns:
- # Slick
- "Packages/Unikka.Slick":
- type: script
- block: false
-
- # Jonnitto.Plyr
- "Packages/Jonnitto.Plyr":
- type: script
- group: media
- block: true
- "https://www.youtube.com/embed/":
- type: iframe
- block: true
- group: media
-
- # anchor.fm
- # "https://anchor.fm":
- # type: iframe
- # group: media
- # block: true
-
- # Neos
- "Packages/Neos.Neos":
- type: script
- block: false
diff --git a/README.md b/README.md
index 42c7798..eca768b 100644
--- a/README.md
+++ b/README.md
@@ -1,96 +1,490 @@
# Sandstorm.CookiePunch
-This Neos package provides a general approach for blocking elements like script tags and iframes before the markup reaches the browser and therefore provides a general approach for blocking cookies or other concepts of tracking user behaviour. It also provides a UI in the browser for displaying a cookie-consent and partially unblocking groups of elements.
+This Neos package provides a general approach for blocking elements like script tags and iframes before the markup reaches the browser and therefore provides a general approach for
+blocking cookies or other concepts of tracking user behaviour. It integrates [Klaro](https://heyklaro.com/docs/) as UI for displaying a cookie-consent and unblocking groups of elements
+after the user consented.
## Features
-* helpers to block elements (scripts and iframes) before the markup is sent to the client
-* possible blocking modes:
- * block all + allowed list
- * allow all + blocked list
-* grouping of elements
-* patterns to target elements in markup
-* blocking of HTML snippets created by the editor (Neos.NodeTypes.Html:Html)
-* cookie-consent (provided by Klaro.js) to block/unblock grouped elements
-* localization support
-* useful default config and styling
-* SCSS to customize cookie-consent styling
+- eel helpers to block elements (scripts and iframes) before the markup is sent to the client
+- eel helper to place contextual consents for any part of the markup
+- a easy way to configure blocking via yaml config supporting patterns to target elements in markup
+- localization support via Yaml and/or Fusion
+- data source providing all services e.g. as a dropdown in the inspector
+- **an awesome cookie-consent provided by [Klaro](https://heyklaro.com/docs/)** :heart: directly bundled with this package
+ - supports unblocking of elements
+ - supports contextual consents to temporarily/permanently unblock content by consenting directly on the element without the need to open the consent modal
+ - You definitely need to check out their project on GitHub ;)
## Installation
`composer require sandstorm/cookiepunch`
-## Basic Setup
+## Basic Configuration and Usages
-### STEP 1: Adding the consent-modal
+### Step 1: Adding the consent-modal
-In your `Overrides.fusion` or `Root.fusion` add
+Create a new fusion file `CookiePunch.fusion` in `.../Resources/Private/Fusion` with the following content:
```neosfusion
prototype(Neos.Neos:Page) {
- // This adds the javascript and css needed for the cookie-consent
- head.javascripts.cookiePunchConsent = Sandstorm.CookiePunch:Consent
+ head.javascripts.cookiepunchConsent = Sandstorm.CookiePunch:Consent
+ # Block Global
+ @process.blockIframes = ${CookiePunch.blockIframes(value, !node.context.inBackend)}
+ @process.blockScripts = ${CookiePunch.blockScripts(value, !node.context.inBackend)}
}
```
-This will add the needed js and css to your page. If you reload the page you should see the consent-modal.
+This will add the needed js and css to your page. If you reload the page you should see the consent-modal. Now all `