Jump to content
joshua

PrivacyWire - Cookie Management & async external asset loading

Recommended Posts

Hi @joshua and fellow cookie munchers. I might have spotted another glitch in the cookie matrix.

What I did/tested: 

I changed the version number in the settings.

What happened:

  1. nothing until I cleared the ProCache cache (which is fine I guess), then afterwards...
  2. the cookie banner showed up again and asked for consent (which was expected) BUT...
  3. all external media assets, tracking scripts, etc. were still loading (which was unexpected)
  4. giving consent closed the banner (fine) BUT it came right back on the next page

Why did it happen:

The test user had already given consent and therefore and old entry existed in the local storage which said sure give me cookies and whatever BUT it didn't recognize the new version and therefore didn't revoke the old opt-in/consent on first load with the new version AND wasn't updated after opting in again.

TL;DR

Changing the version number in the settings does not reset/clear/delete/revoke all previously given and stored local storage settings and won't update after giving consent again to the new version.

  • Like 2

Share this post


Link to post
Share on other sites

Thanks @wbmnfktr for noticing this!

There really was a bug with the version number and async loading of scripts etc.

I fixed this in V0.2.5.

After changing the version number in the backend (and refreshing ProCache - especially when you have activated the option to minify local Javascript) PrivacyWire will check the version number first before handling the elements requiring consent.
 

  • Like 3
  • Thanks 1

Share this post


Link to post
Share on other sites

Today there are two updates for PrivacyWire (newest Version V0.2.7 )

1. The update of elements after giving consent now observs more attributes (also srcset for responsive images and width/height attributes - especially good for iFrames)

2. When the user wants to choose the detailled cookies, there is now a option to show another "Accept All" Button instead of the "Toggle" Button - configurable via module config.

  • Like 3
  • Thanks 1

Share this post


Link to post
Share on other sites
On 9/29/2020 at 2:52 PM, DV-JF said:

Is there an opposite option to only show an element if a specific data-category isn't allowed?

I added a feature for this in todays 0.3.0 (not pushed the release tag yet, as there was a lot of rewriting to implement this feature).

If you want to show an opt-in element instead of the consent-required element, just add a data-attribute data-ask-consent="1". Here is an example:

<iframe src="" data-src="https://www.example.com/" data-category="marketing" data-ask-consent="1" frameborder="0" height="400" width="400"></iframe>

In this case, the iframe gets only loaded, when cookies of type "marketing" are allowed. If not, the user will be asked for consent. The text of the consent-window is configurable in the module config.
The markup of this message also includes an css class with the type of cookie, if you want to style them specifically.

  • Like 5

Share this post


Link to post
Share on other sites

@joshua thanks for the module.
would you consider changing the header tag into a div?

<header class="privacywire-header"></header>

Some might using page header in their css-files without a class. It might get into style conflicts. What do you think?

  • Like 1

Share this post


Link to post
Share on other sites

@ngrmm I had a similar issue and went kind of a different route and added role="main" to my main header and excluded it later on in my PrivacyWire CSS.

header:not([role=main]) {
    // here you go
}

For the moment that should work out quiet nice without any or at least only minor issues - at least when you are working with less, sass, SCSS and similar.

 

  • Like 3

Share this post


Link to post
Share on other sites

Thanks a lot for this wonderful module! It works like a charm, except for one little problem:  When I use the "Accept all" button I have to reload the website for the changes to take effect. Selecting specific categories and clicking the "Save preferences" button has immediate effect. Is this an indented behaviour or am I missing something here? 

  • Like 1

Share this post


Link to post
Share on other sites

@ngrmm thanks for your input. Semantically header tags are allowed to have multiple instances within one page (e.g. one main page header and one header per <article> etc.).
But I see the point - within the cookie banner a <header> might not be the best semantical element to choose.

To provide backwards compatibility (if someone has already styled the PrivacyWire <header> via CSS) I will add an option to configure the output tag between <header> and <div>.

 

  • Like 2

Share this post


Link to post
Share on other sites

@snck Thank you!

Normally the "Accept all" button should do the exact same thing. I'm looking into this right now.

Share this post


Link to post
Share on other sites

I fixed these two topics in 0.3.2.
@snck: There really was a bug with the "Accept all" Button - thanks for noticing!

@ngrmm: You can choose now in the module config which header tag you want 😉
For keeping backwards compatibility, the default value still is <header>.

  • Like 5

Share this post


Link to post
Share on other sites

@joshua what do you think about the idea to have a style.css file instead of the styling inside your js?
 

Share this post


Link to post
Share on other sites

@ngrmm That actually was my first type of implementation (separating css and js), but as the CSS file would be very small (554 Byte), it actually is slower to load these two connections vs. loading only one JS file with the CSS included ( even with HTTP/2 - I tested it alot!).

This is the total amount of styles used by PrivacyWire (beautified for better readability):

.privacywire {
    position: fixed;
    bottom: -250%;
    left: 0;
    right: 0;
    box-shadow: 0 -1px 3px rgba(0, 0, 0, .3);
    opacity: 0;
    background: #fff;
    z-index: 1;
    padding: 1rem;
    transition: bottom .3s ease-in, opacity 1s ease-out
}

.privacywire .privacywire-header {
    font-weight: 700
}

.show-banner .privacywire.privacywire-banner,
.show-message .privacywire.privacywire-message,
.show-options .privacywire.privacywire-options {
    bottom: 0;
    opacity: 1;
    transition: bottom .3s ease, opacity .3s ease
}

.privacywire button[hidden],
[data-ask-consent-rendered="1"],
div.privacywire-ask-consent-blueprint {
    display: none
}

You could do the following:

1. Uncheck the config checkbox "Add basic CSS Styling":

grafik.png.a35fcb159fae0b193a4918cffc22b8a8.png
2. Add the styles to your own stylesheet.

  • Like 4

Share this post


Link to post
Share on other sites

Nice work!

Question:

I'm finding myself in need of many changes in the banner template, so I had to hook-replace the module's 'render' method.

Would be useful to isolate the path retrieving code in separate hookable functions? Like this:

    /**
     * checks for a banner template alternate path
     * @return string   the path of the banner template file
     */
    public function ___getBannerTemplate()
    {
        return $this->wire('config')->paths->$this . 'PrivacyWireBanner.php';
    }

    /**
     * checks for a javascript file alternate path
     * @return string   the path of the banner template file
     */
    public function ___getJsFile()
    {
        return ($this->add_basic_css_styling) ? $this->wire('config')->urls->$this . "js/PrivacyWire.js" : $this->wire('config')->urls->$this . "js/PrivacyWireUnstyled.js";
    }

Then, I could use it (I am using it, actually) like this (in /site/ready.php):


// my front pages are all extending a FrontPage class
// see https://processwire.com/blog/posts/pw-3.0.152/#new-ability-to-specify-custom-page-classes
if (page() instanceof FrontPage) {

    $wire->addHookAfter('PrivacyWire::getBannerTemplate', function ($event) {
        $event->replace = true;
        $default_path = $event->return;
        $filename = pathinfo($default_path, PATHINFO_BASENAME);
        // my override is in /site/templates/modules/PrivacyWire/PrivacyWireBanner.php
        $override_path = paths()->templates.'modules/PrivacyWire/'.$filename;
        $event->return = is_readable($override_path) ? $override_path : $default_path;
    });

}

 

Or even simpler (for me 😂), those could be two new config keys, like 'alternateBannerTemplate' and 'alternateJsFile'.

 

This would also cover the case of needing to change the header tag, so it could be dropped (just a thought, don't hit me in the head, you valiant head tag config defenders 😁).

Edited by The G
Corrected embarassing code blooper
  • Like 1

Share this post


Link to post
Share on other sites

@The G Your wish is my command 😅

I just added another config option for an alternative banner template file! In addition (to be even more flexible 😄 ) I included your idea of the hookable methods for banner template and js file.

grafik.thumb.png.deb17e56c5937565eb3a2b72a180b36c.png

/**
* checks for a alternate banner template path
* @return string   the path of the banner template file
**/
public function ___getBannerTemplateFile()
{
	return (!empty($this->alternate_banner_template) && file_exists($this->wire('config')->paths->root . $this->alternate_banner_template)) ? $this->wire('config')->paths->root . $this->alternate_banner_template : $this->wire('config')->paths->$this . 'PrivacyWireBanner.php';
}

So now you have to decide whether you prefer to hook or configurate 😄

--> 0.3.3 <--

  • Like 4
  • Thanks 2

Share this post


Link to post
Share on other sites

So, excited to use the updated version as I was, there was no time for RTFM - even if there was clearly written

without leading slash

, I merrily entered

/site/templates/modules/PrivacyWire/PrivacyWireBanner.php

and BANG!, ProcessWire shouted at me for wanting to use a not allowed path (because of the resulting double slash). I'm still trembling!

Since it breaks so hard, I'm wondering if the input could be somehow forced to loose the leading slashes forgotten by irresponsible people like yours truly. Sadly, I'm not well versed (yet!) in module configuration input validation/modification.

Or at least, write "without leading slash" in bold letters 😅

  • Like 1

Share this post


Link to post
Share on other sites

Oh, yes - I‘ll add a filter for the leading slash first thing tomorrow morning. Better than this error message 😅

  • Like 1

Share this post


Link to post
Share on other sites

Hey @joshua! Would you consider making this module installable via Composer?

Technically this just requires a) adding a composer.json file where you specify project name, type ("pw-module"), and a dependency for installer plugin (preferably wireframe-framework/processwire-composer-installer), b) adding the project to packagist.org, and c) (optional, but recommended) setting up a webhook between GitHub and Packagist so that new releases become automatically available at Packagist (or giving Packagist the permission to handle this step).

Here's an example composer.json from ProcessRedirects: https://github.com/apeisa/ProcessRedirects/blob/master/composer.json.

Thanks in advance for considering this 🙂

  • Like 3

Share this post


Link to post
Share on other sites

Hello all.

I decided to try PrivacyWire as had a request for one of my friends websites. So I proceeded to install and configure the module as needed, however I am stuck at how would the cookie consent appear on Home page (banner is not showing automatically). Can someone point me what am I missing as I checked 3 times the configs and did not find a markup to insert or a template to point to in the admin?

Share this post


Link to post
Share on other sites

Hello @wbmnfktr

I shall stop coding during late hours of the night. You were absolutely right that during my initial tests on localhost, I've slipped to close properly the body tag and that was causing the issue.

Thank you very much for the spotting and sharing what was obvious. It is all showing properly now, so I only would style it to fit the frontend.

  • Like 1

Share this post


Link to post
Share on other sites

Hi @joshua

i tried to have an iframe only be shown if consent is given.
This is my code:

<div data-category='external_media' data-ask-consent='0'>
	<div class='video_content' >";
		<iframe src='https://www.youtube-nocookie.com/embed/XXXXXXXXXX?enablejsapi=1' width='640' height='390' frameborder='0'></iframe>
	</div>
</div>

If consent for external_media is not given, the module asks you to give consent. „To load this element, it is required to consent to the following cookie category: External Media.“ 
But if consent is given, it does not show the div.video_content or the iframe. I tested to have some plaintext instead of the iframe and it works.

So this works:

<div data-category='external_media' data-ask-consent='0'>
	<div class='video_content' >
		<p>hello world!</p>
	</div>
</div>

And it looks like as if  0 or 1 for data-ask-consent does not make any difference.

UPDATE:
my fault, this works!
 

<div class='video_content' >";
	<iframe src='' data-src='https://www.youtube-nocookie.com/embed/XXXXXXXXXX?enablejsapi=1' data-category='external_media' data-ask-consent='0' width='640' height='390' frameborder='0'></iframe>
</div>

 

Edited by ngrmm
solved

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By bernhard
      DEPRECATED
      I'm using this module in several projects, but it will likely not see any updates in the future. I'm not happy with it and I'm looking for ways to develop better solutions. RockTabulator was my first try, but I'm also not 100% happy with that. The tabulator library is great, but my module implementation is not. I hope to get a good solution soon, but it will be a lot of work...
      ---
      Some of you might have followed the development of this module here: https://processwire.com/talk/topic/15524-previewdiscussion-rockdatatables/ . It is the successor of "RockDataTables" and requires RockFinder to get the data for the grid easily and efficiently. It uses the open source part of agGrid for grid rendering.
       
      WHY?
      ProcessWire is awesome for creating all kinds of custom backend applications, but where it is not so awesome in my opinion is when it comes to listing this data. Of course we have the built in page lister and we have ListerPro, but none of that solutions is capable of properly displaying large amounts of data, for example lists of revenues, aggregations, quick and easy sorts by the user, instant filter and those kind of features. RockGrid to the rescue 😉 
       
      Features/Highlights:
      100k+ rows Instant (client side) filter, search, sort (different sort based on data type, eg "lower/greater than" for numbers, "contains" for strings) extendable via plugins (available plugins at the moment: fullscreen, csv export, reload, batch-processing of data, column sum/statistics, row selection) all the agGrid features (cell renderers, cell styling, pagination, column grouping etc) vanilla javascript, backend and frontend support (though not all plugins are working on the frontend yet and I don't plan to support it as long as I don't need it myself)  
      Limitations:
      While there is an option to retrieve data via AJAX the actual processing of the grid (displaying, filtering, sorting) is done on the client side, meaning that you can get into troubles when handling really large datasets of several thousands of rows. agGrid should be one of the most performant grid options in the world (see the official example page with a 100k row example) and does a lot to prevent problems (such as virtual row rendering), but you should always have this limitation in mind as this is a major difference to the available lister options that do not have this limitation.
      Currently it only supports AdminThemeUikit and I don't plan to support any other admin theme.
       
      Download: https://gitlab.com/baumrock/FieldtypeRockGrid
      Installation: https://gitlab.com/baumrock/RockGrid/wikis/Installation
      Quikckstart: https://gitlab.com/baumrock/RockGrid/wikis/quickstart
      Further instructions: https://gitlab.com/baumrock/RockGrid/wikis/quickstart#further-instructions
      German Translation File: site--modules--fieldtyperockgrid--fieldtyperockgrid-module-php.json
      Changelog: https://gitlab.com/baumrock/FieldtypeRockGrid/raw/master/changelog.md
       
      Module status: alpha, License: MIT
      Note that every installation and uninstallation sends an anonymous google analytics event to my google analytics account. If you don't want that feel free to remove the appropriate lines of code before installation/uninstallation.
       
      Contribute:
      You can contribute to the development of this and other modules or just say thank you by
      testing, reporting issues and making PRs at gitlab liking this post buying me a drink: paypal.me/baumrock/5 liking my facebook page: facebook.com/baumrock hiring me for pw work: baumrock.com  
      Support: Please note that this module might not be as easy and plug&play as many other modules. It needs a good understanding of agGrid (and JavaScript in general) and it likely needs some looks into the code to get all the options. Please understand that I can not provide free support for every request here in the forum. I try to answer all questions that might also help others or that might improve the module but for individual requests I offer paid support (please contact me via PM).
       
      Use Cases / Examples:
      Colored grid cells, Icons, Links etc. The Grid also has a "batcher" feature built in that helps communicating with the server via AJAX and managing resource intensive tasks in batches:

      Filters, PW panel links and instant reload on panel close:

      You can combine the grid with a chart library like I did with the (outdated) RockDataTables module:

    • By Paul Greinke
      Hi there. I wrote a custom module for one of my projects. In fact I maybe want to use my module in other projects too. In order to be variable and customizable  I need to implement some custom hooks into my module. So I can afterwards hook into the my functions in order to modify them to match the needs of the new project.
      I tried simply defining functions with the '__' prefix. But that did not work. I'm imagining something like the following:
      <?php class MyClass { public function ___someFunction() { // Do something } } // ready.php $this->addHookBefore('MyClass::someFunction', function($event) { // some customization }); Is there a way to accomplish that? 
    • By adrian
      Hi everyone,
      Here's a new module that I have been meaning to build for a long time.
      http://modules.processwire.com/modules/process-admin-actions/
      https://github.com/adrianbj/ProcessAdminActions
       
      What does it do?
      Do you have a bunch of admin snippets laying around, or do you recreate from them from scratch every time you need them, or do you try to find where you saw them in the forums, or on the ProcessWire Recipes site?
      Admin Actions lets you quickly create actions in the admin that you can use over and over and even make available to your site editors (permissions for each action are assigned to roles separately so you have full control over who has access to which actions).
       
      Included Actions
      It comes bundled with several actions and I will be adding more over time (and hopefully I'll get some PRs from you guys too). You can browse and sort and if you have @tpr's Admin on Steroid's datatables filter feature, you can even filter based on the content of all columns. 

      The headliner action included with the module is: PageTable To RepeaterMatrix which fully converts an existing (and populated) PageTable field to either a Repeater or RepeaterMatrix field. This is a huge timesaver if you have an existing site that makes heavy use of PageTable fields and you would like to give the clients the improved interface of RepeaterMatrix.
      Copy Content To Other Field
      This action copies the content from one field to another field on all pages that use the selected template.
      Copy Field Content To Other Page
      Copies the content from a field on one page to the same field on another page.
      Copy Repeater Items To Other Page
      Add the items from a Repeater field on one page to the same field on another page.
      Copy Table Field Rows To Other Page
      Add the rows from a Table field on one page to the same field on another page.
      Create Users Batcher
      Allows you to batch create users. This module requires the Email New User module and it should be configured to generate a password automatically.
      Delete Unused Fields
      Deletes fields that are not used by any templates.
      Delete Unused Templates
      Deletes templates that are not used by any pages.
      Email Batcher
      Lets you email multiple addresses at once.
      Field Set Or Search And Replace
      Set field values, or search and replace text in field values from a filtered selection of pages and fields.
      FTP Files to Page
      Add files/images from a folder to a selected page.
      Page Active Languages Batcher
      Lets you enable or disable active status of multiple languages on multiple pages at once.
      Page Manipulator
      Uses an InputfieldSelector to query pages and then allows batch actions on the matched pages.
      Page Table To Repeater Matrix
      Fully converts an existing (and populated) PageTable field to either a Repeater or RepeaterMatrix field.
      Template Fields Batcher
      Lets you add or remove multiple fields from multiple templates at once.
      Template Roles Batcher
      Lets you add or remove access permissions, for multiple roles and multiple templates at once.
      User Roles Permissions Batcher
      Lets you add or remove permissions for multiple roles, or roles for multiple users at once.
       
      Creating a New Action
      If you create a new action that you think others would find useful, please add it to the actions subfolder of this module and submit a PR. If you think it is only useful for you, place it in /site/templates/AdminActions/ so that it doesn't get lost on module updates.
      A new action file can be as simple as this:
      class UnpublishAboutPage extends ProcessAdminActions { protected function executeAction() { $p = $this->pages->get('/about/'); $p->addStatus(Page::statusUnpublished); $p->save(); return true; } } Each action:
      class must extend "ProcessAdminActions" and the filename must match the class name and end in ".action.php" like: UnpublishAboutPage.action.php the action method must be: executeAction() As you can see there are only a few lines needed to wrap the actual API call, so it's really worth the small extra effort to make an action.
      Obviously that example action is not very useful. Here is another more useful one that is included with the module. It includes $description, $notes, and $author variables which are used in the module table selector interface. It also makes use of the defineOptions() method which builds the input fields used to gather the required options before running the action.
      class DeleteUnusedFields extends ProcessAdminActions { protected $description = 'Deletes fields that are not used by any templates.'; protected $notes = 'Shows a list of unused fields with checkboxes to select those to delete.'; protected $author = 'Adrian Jones'; protected $authorLinks = array( 'pwforum' => '985-adrian', 'pwdirectory' => 'adrian-jones', 'github' => 'adrianbj', ); protected function defineOptions() { $fieldOptions = array(); foreach($this->fields as $field) { if ($field->flags & Field::flagSystem || $field->flags & Field::flagPermanent) continue; if(count($field->getFieldgroups()) === 0) $fieldOptions[$field->id] = $field->label ? $field->label . ' (' . $field->name . ')' : $field->name; } return array( array( 'name' => 'fields', 'label' => 'Fields', 'description' => 'Select the fields you want to delete', 'notes' => 'Note that all fields listed are not used by any templates and should therefore be safe to delete', 'type' => 'checkboxes', 'options' => $fieldOptions, 'required' => true ) ); } protected function executeAction($options) { $count = 0; foreach($options['fields'] as $field) { $f = $this->fields->get($field); $this->fields->delete($f); $count++; } $this->successMessage = $count . ' field' . _n('', 's', $count) . ' ' . _n('was', 'were', $count) . ' successfully deleted'; return true; } }  
      This defineOptions() method builds input fields that look like this:

      Finally we use $options array in the executeAction() method to get the values entered into those options fields to run the API script to remove the checked fields.
      There is one additional method that I didn't outline called: checkRequirements() - you can see it in action in the PageTableToRepeaterMatrix action. You can use this to prevent the action from running if certain requirements are not met.
      At the end of the executeAction() method you can populate $this->successMessage, or $this->failureMessage which will be returned after the action has finished.
       
      Populating options via URL parameters
      You can also populate the option parameters via URL parameters. You should split multiple values with a “|” character.
      You can either just pre-populate options:
      http://mysite.dev/processwire/setup/admin-actions/options?action=TemplateFieldsBatcher&templates=29|56&fields=219&addOrRemove=add
      or you can execute immediately:
      http://mysite.dev/processwire/setup/admin-actions/execute?action=TemplateFieldsBatcher&templates=29|56&fields=219&addOrRemove=add

      Note the “options” vs “execute” as the last path before the parameters.
       
      Automatic Backup / Restore
      Before any action is executed, a full database backup is automatically made. You have a few options to run a restore if needed:
      Follow the Restore link that is presented after an action completes Use the "Restore" submenu: Setup > Admin Actions > Restore Move the restoredb.php file from the /site/assets/cache/AdminActions/ folder to the root of your site and load in the browser Manually restore using the AdminActionsBackup.sql file in the /site/assets/cache/AdminActions/ folder I think all these features make it very easy to create custom admin data manipulation methods that can be shared with others and executed using a simple interface without needing to build a full Process Module custom interface from scratch. I also hope it will reduce the barriers for new ProcessWire users to create custom admin functionality.
      Please let me know what you think, especially if you have ideas for improving the interface, or the way actions are defined.
       
       
    • By joshua
      As we often use Matomo (former known as Piwik) instead of Google Analytics we wanted to embed Matomo not only in the template code but also via the ProcessWire backend.
      That's why I developed a tiny module for the implementation.
      The module provides the possibility to connect to an existing Matomo installation with the classical site tracking and also via the Matomo Tag Manager.
      If you have also PrivacyWire installed, you can tell MatomoWire to only load the script, if the user has accepted cookies via PrivacyWire.
      To offer an Opt-Out solution you can choose between the simple Opt-Out iFrame, delivered by your Matomo installation, or a button to choose cookies via PrivacyWire.
      You'll find the module both in the module directory and via github:
      ProcessWire Module Directory MatomoWire @ GitHub MatomoWire @ Packagist ->installable via composer require blauequelle/matomowire I'm looking forward to hear your feedback!


    • By Robin S
      If your module has a lot of config fields you might want to divide them into groups inside a tabbed interface. Here is a demonstration module showing how this can be done.
      https://github.com/Toutouwai/ModuleConfigTabs

      Thanks to @kixe for providing my starting point in this forum topic.
×
×
  • Create New...