Basic ProcessWire website workflow - Part Four

Reading time ~11 minutes

Introduction

Following Part 1, Part 2 and Part 3.

In this post we will make the final touches and personalizations to our website. Let’s see what are going to do:

  • Implement a basic Sitemap
  • Implement ProcessWire Roles and Permissions
  • Tweak CKEditor a little bit
  • Implement a little countermeasure to avoid bots to read emails
  • Implement the Facebook plugin
  • Add the cookie notification

Also this post concludes this series on ProcessWire, but don’t worry, I’m planning to write again on this subject.

But now, let’s dive in!

Sitemap

The default site profile of ProcessWire offers a basic Sitemap template right out of the box, however it is not tailored for multilingual sites, because you get a different sitemap for each language, for example:

  • site.com/it/sitemap.xml
  • site.com/de/sitemap.xml
  • site.com/de/sitemap.xml

We need to “glue” multilanguage sitemaps together. This can be achieved with a handy snippet available on the processwire-recipes.com website, a directory which

”[…] aims to collect mini-tutorials for common and not-so-common ProcessWire tasks and problems.”

The code is really easy and at this point of the series you should immediately understand what it does. You can also add additional controls to the renderSitemapChildren function in order to skip pages that you don’t want to publish.

ProcessWire RBAC

Notice: the concepts explained in this section are valid for all versions of ProcessWire, however a few enhancements have been introduced only from the 2.6.15 version. If you notice missing features in your PW version you might consider to upgrade it.

ProcessWire offers a really easy and powerful way to manage Users, Roles and Permissions. The important things to keep in mind are the following:

  • Permissions are assigned to Roles,
  • one or more Roles are assigned to each User,
  • each visible Page uses a Template,
  • each Template has access settings, where you can define which roles have access to the basic actions (view, edit, create and add children) on Pages using said template.

Users

The User ($user API variable) is the current user viewing the page, which can be the guest account (if not logged in), the superuser or any other user added to the system.

Roles

Roles are a way of grouping multiple users and assigning permissions to that group.

ProcessWire includes two roles by default:

  • guest: this role is automatically given to all anonymous site users. You should not give this role any access other than page-view permission.

  • superuser: this role has all-inclusive access to the site without limitation. This role should only be given to the most trusted users that operate the site. Superuser has all permissions regardless of what you assign with the superuser role.

Notice: A user can have multiple roles, however to keep things simple it’s advised to have only one for each user.

Roles are applied to the context of a Page by way of template access control settings. These can be accessed from the template editor Access tab (Setup > Templates > Edit Template > Access). From here you can define what roles are allowed to view, edit, create, add new pages, and more.

Permissions

Permissions in ProcessWire are objects of type Permission (a type of Page object). They each represent permission to access something, or to perform some action.

Now with these concepts in mind we are going to define a new editor role for our site, with specific permissions for specific pages, in order to let our client manage the site by himself without the risk of making unwanted changes.

Click on Access > Roles > Add New and use editor as role name. Next, add the following permissions to our new role, or use just the ones that you feel comfortable with. Don’t forget to read the full documentation, before making unwise choices:

  • page-edit: a user with this permission does not actually have edit access to any pages until they also have edit access assigned at the template level (Access tab)
  • page-edit-recent
  • page-sort
  • page-lister
  • page-view
  • profile-edit: if you want the user to edit his profile and change his password.

Now we can create a new User with this brand-new role. Click on Access > Users > Add New, choose a name, a password, write the email address and select the editor role.

At this point, the last thing to do, is to define the permissions on a template-basis. I suggest you to open a new browser window (not a new tab) and log in as the new user, so you can see immediately the results, as you make the required changes as superuser.

Let’s start from the home template. Click on Setup > Templates > Home, check the “yes” box on “access” tab to enable access control. Next to the “editor” role, check boxes for View and Edit. Finally select “yes” to allow edit-related access to inherit to children.

With this configuration, any user with the editor role is allowed to edit all the pages under the page tree, but it cannot add new pages in any of the nodes. Ideally we want at least, to let him add new nodes under news and galleries.

Let’s edit the news-index template (the one that groups all the news under the url /news/). Enable access control and check the box for “Add Children” for the editor role. Finally edit the news template and check the box for “Create pages”.

Repeat the same procedure for the gallery-index and gallery templates. Make sure to reload the other browser’s window to check that the results match your expectations.

Of course the topic is much more large than this, we just scratched the surface.

Tweak CKEditor

Justify Plugin

The default configuration of CKEditor in ProcessWire is fine in most of the cases, however sometimes you just need more options for your content. CKEditor comes with tons of different plugins for all the needs, you can easily get lost trying to search the one that suits your requirements.

For example, one of the things I miss from the default configuration, is the option to justify the text: left/right alignment, center and justify. CKEditor offers a nice plugin for this purpose, just download it and place the content in the folder /site/modules/InputfieldCKEditor/plugins/. Next you have to change the default appearance of the CKEditor toolbar. You can change this option for each field that uses the CKEditor as Inputfield.

For example let’s change the body field. In the Input tab go to the Plugins section and check the box next to the justify plugin. Finally scroll up to the CKEditor Settings and change the CKEditor Toolbar content with the following:

Format, Bold, Italic, -, RemoveFormat
NumberedList, BulletedList, -, Blockquote
JustifyLeft, JustifyCenter, JustifyRight, JustifyBlock
PWLink, Unlink, Anchor
PWImage, Table, HorizontalRule, SpecialChar
PasteText, PasteFromWord
Scayt, -, Sourcedialog

Notice that we added a new group of items JustifyLeft, JustifyCenter, JustifyRight, JustifyBlock that will appear in our editor.

Allow extra content

Sometimes it’s useful to write additional HTML code inside the CKEditor to have more control on the output. For example you might want to add a simple Bootstrap 2-column layout (even if there are a couple of plugins for this purpose) or maybe just add a <div class="clearfix"></div> code to reset the floats. By default CKEditor strips out all the unrecognized content for security reasons. You can easily notice this fact using the Source functionality inside the editor. For this reason we have to be explicit and define exactly which content is allowed in the editor.

Go back to the body configuration and in the Extra Allowed Content for example you can use this line div(clearfix) to allow div tags with a clearfix class. You can check the documentation for more information.

I just introduced you a couple of concepts on the CKEditor configuration. The topic is much more large than this and is not strictly related to ProcessWire. However if you happen to use a plugin or a feature that may interest the PW community please feel free to share it in the comments section.

Email Obfuscation

The topic on how to prevent email addresses from being automatically recognized and harvested by spammers is also very large and discussed. Over the years many obfuscation methods appeared, with different levels of effectiveness. Nobody can be 100% sure to have his own email addresses always at safe, but we can try to implement some countermeasures that require just a couple of clicks.

A few years ago I stumbled upon this interesting article by Silvan Mühlemann, in which he compared different methods of email obfuscation on a timespan of a year and a half. The results are well synthesized in this answer on superuser.com.

After reading the article I decided to use the CSS Code direction trick for obfuscating all the emails on my sites. Basically it consists in writing the email address backwards and then reversing it using a simple CSS rule, something like:

<span style="unicode-bidi: bidi-override; direction: rtl;">moc.niamod@sserdda</span>

However this approach has a few drawbacks:

  • Requires the user to type out the address (i.e., a mailto: link won’t work)
  • The email address will display backwards if CSS is unavailable (screenreaders and such).
  • Copy/pasting the address will show it backwards.

However we can easily solve the first and third problems using JavaScript:

<a onclick="this.href='mailto:'+ this.innerHTML.split('').reverse().join('')" style="unicode-bidi:bidi-override; direction: rtl;" title="Email Me">moc.niamod@sserdda</a>

What are your favorite approaches for obfuscating emails? Let me know.

Cookies

The EU legislation on cookies, since the change made in 2009 to the Article 5 (3) of the ePrivacy directive, requires

“prior informed consent for storage or for access to information stored on a user’s terminal equipment.”

Here in Italy we got compliant with the EU Cookie Law only in 2015, not without controversy. Even today the legislation is still unclear on different aspects. By looking to other sites and after reading tons of articles I decided to make a few changes on my websites:

  • Write an extended privacy policy to provide more detailed information about the use of cookies and the instructions to disable/delete them for every browser.
  • Anonymize the IP addresses for Google Analytics
  • Implement a banner notice to seek and obtain a user’s consent before using third-party cookies.

In this section I will focus on this last point. I decided to use the coockiechoices script provided by Google which is really easy and straightforward to implement. Just take a look to the code:

<script type="text/javascript" src="{$config->urls->templates}/scripts/cookiechoices.js"></script>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function(event) {
	cookieChoices.showCookieConsentBar("{__("This site uses cookies. By continuing to browse the site, you are agreeing to our use of cookies.", 'site--templates--views--template-tpl')}", "{__("I agree", 'site--templates--views--template-tpl')}", "{__("More info", 'site--templates--views--template-tpl')}", "{$pages->get(1101)->url}");
});
</script>

We are using a simple banner to show a translatable message to our visitors informing them that the site uses cookies. The banner also contains a the link to the extended cookie policy.

In the next section we will check that the user has given his consent before displaying the Facebook social plugin.

Facebook Social plugin

Facebook plugins are really easy to implement. Just point your browser to https://developers.facebook.com and follow the instructions. Usually I use the Page Plugin to embed the Facebook page inside the website, so the visitors can Like the Page without actually leaving the site. The instructions are straightforward however, following the previous paragraph, we need to display the plugin in an asynchronous way. For this reason we have to make a couple of tweaks to the included script. Add the following HTML just after the <body> tag inside the template.tpl file:

First we need to include the SDK JavaScript on the page. Let’s edit the template.tpl file and add the following right after the <body> tag.

<div id="fb-root"></div>

Next insert the Facebook generated code where you want to display the page plugin. My personal preference is to insert it in the footer. An example could be

<div class="fb-page" data-href="<your page url>" data-width="555" data-small-header="false" data-adapt-container-width="true" data-hide-cover="false" data-show-facepile="true"></div>

and finally, load the Facebook JavaScript SDK to initialize the plugin only if the user has given consent to the cookie message:

if (document.cookie.indexOf("displayCookieConsent") >= 0) {
	loadAsyncFB();
}

function loadAsyncFB()
{
    var js, fjs = document.getElementsByTagName('script')[0];

    if (document.getElementById('facebook-jssdk')) return;

    js = document.createElement('script');
    js.id = 'facebook-jssdk';
    js.src = "//connect.facebook.net/it_IT/sdk.js#xfbml=1&version=v2.5&appId=<your app ID>";
    fjs.parentNode.insertBefore(js, fjs);
}

That’s it for this series! Hope you enjoyed it.

Easily impersonate any user in a Laravel Application

Basic Middleware to allow impersonate functionality on a Laravel Application. Continue reading