BYU Academic Calendar

New Drupal Modules - 24 January 2018 - 11:31am
Academic Calendar Module For Drupal 8

This module generates a block that you can display on your websites. The module displays all academic calendar information and it can't be customized or limited to only certain academic calendar items.


Fontawesome library.

To Use

1. Git clone or Download the module. If you download it, make sure to remove '-master' from the module folder name.
2. Make sure you have included Fontawesome, either through the module or by adding this library to your theme in the libraries file:

Categories: Drupal

myDropWizard.com: Use the Backup and Migrate module in Drupal 6? Audit your permissions!

Planet Drupal - 24 January 2018 - 11:20am

As you may know, Drupal 6 has reached End-of-Life (EOL) which means the Drupal Security Team is no longer doing Security Advisories or working on security patches for Drupal 6 core or contrib modules - but the Drupal 6 LTS vendors are and we're one of them!

Today, a security update for the Backup and Migrate module for Drupal 7 was released for a Critical issue that could allow arbitrary PHP execution - see the security advisory.

While arbitrary PHP execution is scary, this issue is actually about the permissions provided by the Backup and Migrate module not being marked as potentially dangerous. The new release simply marks those permissions appropriately.

There won't be a security release for this issue for Drupal 6!

This is because Drupal 6 doesn't provide a way to mark permissions as dangerous. It doesn't even allow a separate description for the permissions, which we could use to call out the danger (the machine name used in code is the same as the name shown to users - this is no longer the case in Drupal 7 and newer).

However, marking the permissions as dangerous isn't the real fix! The real fix is auditing your permissions to "verify only trusted users are granted permissions defined by the module."

This is something you can do with Drupal 6, even without a new release. :-)

So, in summary: no security release for Drupal 6 - go audit your permissions.

If you'd like all your Drupal 6 modules to receive security updates and have the fixes deployed the same day they're released, please check out our D6LTS plans.

Note: if you use the myDropWizard module (totally free!), you'll be alerted to these and any future security updates, and will be able to use drush to install them (even though they won't necessarily have a release on Drupal.org).

Categories: Drupal

Just Giving API

New Drupal Modules - 24 January 2018 - 7:56am

Provides integration between Webforms and the Just Giving API to provide a mechanism for users to sign up and create just giving events without leaving parent site.

Categories: Drupal

Persian ِDatepicker

New Drupal Modules - 24 January 2018 - 4:45am

Persian Datepicker module uses a jQuery to provide an inline rendering of date's popup widget Focus on the input to open an interactive Persian calendar in a small overlay.Persian Datepicker uses the Solar Hijri Calendar. The Solar Hijri Calendar is the official calendar of Iran which is the one of the oldest calendar in the world, as well as the most accurate calendar in use today.

Categories: Drupal

Blocked role

New Drupal Modules - 24 January 2018 - 4:43am

This is a small utility module that serves that provides one simple functionality - blocking users belonging to selected role (or roles) from login in to the website.

Categories: Drupal

Daniel Pocock: apt-get install more contributors

Planet Drupal - 24 January 2018 - 3:21am

Every year I participate in a number of initiatives introducing people to free software and helping them make a first contribution. After all, making the first contribution to free software is a very significant milestone on the way to becoming a leader in the world of software engineering. Anything we can do to improve this experience and make it accessible to more people would appear to be vital to the continuation of our communities and the solutions we produce.

During the time I've been involved in mentoring, I've observed that there are many technical steps in helping people make their first contribution that could be automated. While it may seem like creating SSH and PGP keys is not that hard to explain, wouldn't it be nice if we could whisk new contributors through this process in much the same way that we help people become users with the Debian Installer?

Paving the path to a first contribution

Imagine the following series of steps:

  1. Install Debian
  2. apt install new-contributor-wizard
  3. Run the new-contributor-wizard (sets up domain name, SSH, PGP, calls apt to install necessary tools, procmail or similar filters, join IRC channels, creates static blog with Jekyll, ...)
  4. write a patch, git push
  5. write a blog about the patch, git push

Steps 2 and 3 can eliminate a lot of "where do I start?" head-scratching for new contributors and it can eliminate a lot of repetitive communication for mentors. In programs like GSoC and Outreachy, where there is a huge burst of enthusiasm during the application process (February/March), will a tool like this help a higher percentage of the applicants make a first contribution to free software? For example, if 50% of applicants made a contribution last March, could this tool raise that to 70% in March 2019? Is it likely more will become repeat contributors if their first contribution is achieved more quickly after using a tool like this? Is this an important pattern for the success of our communities? Could this also be a useful stepping stone in the progression from being a user to making a first upload to mentors.debian.net?

Could this wizard be generic enough to help multiple communities, helping people share a plugin for Mozilla, contribute their first theme for Drupal or a package for Fedora?

Not just for developers

Notice I've deliberately used the word contributor and not developer. It takes many different people with different skills to build a successful community and this wizard will also be useful for people who are not writing code.

What would you include in this wizard?

Please feel free to add ideas to the wiki page.

All projects really need a couple of mentors to support them through the summer and if you are able to be a co-mentor for this or any of the other projects (or even proposing your own topic) now is a great time to join the debian-outreach list and contact us. You don't need to be a Debian Developer either and several of these projects are widely useful outside Debian.

Categories: Drupal


New Drupal Modules - 24 January 2018 - 1:59am
Categories: Drupal

miggle: learning Drupal in a week - my first job experience

Planet Drupal - 24 January 2018 - 1:38am
learning Drupal in a week - my first job experiencefriends of miggle Wed, 24/01/2018 - 09:38 Upon arriving I was welcomed to the office and settled in at a desk. Initially, I was tasked with exploring Drupal and what it could do. Acquia Dev Desktop was the first application I opened and after experimenting with some of the prebuilt sites I began to gather an understanding of Drupal and why it is used. 
Categories: Drupal

INsReady: Single Sign-on using OAuth2 and JWT for Distributed Architecture

Planet Drupal - 23 January 2018 - 9:35pm

Single sign-on (SSO) is a property, where a user logs in with a single ID and password to gain access to a connected system or systems without using different usernames or passwords, or in some configurations seamlessly sign on at each system. A simple version of single sign-on can be achieved over IP networks using cookies but only if the sites share a common DNS parent domain. ---- https://en.wikipedia.org/wiki/Single_sign-on

As the definition suggests, one can imagine that SSO becomes one critical part of the system design and user experience design for complex and distributed system, or for a new application to integrate with the existing connected system. With SSO enabled, a system owner can manage access control at a centralized place, therefore granting users permissions cross multiple subsystem is organized. On the other hand, as an end user, he/she only needs to secure one set of credentials to access multiple resources or to access functionalities whose distributed architecture is hidden from the user.

As we entering 2018, our software becomes more complex and its services become more ubiquitous. Let's use Google's SSO for example to illustrate the demand for a modern SSO:

  • A user can sign in with password once for both Gmail.com and YouTube.com
  • A user can go to Feedly.com or New York Times and use the "Sign-in with Google" to authorize third parties to access the user's data
  • A user can sign in with password on a mobile device to sync all photos or contacts from Google
  • A Google Home device can connect to multiple people's Google accounts, and read out their calendar events when needed
  • YouTube.com developers can use Polymer as frontend technology, and authenticate with YouTube.com backend to load the content via web services API

You might not realize the complexity of such system to support the modern use cases above until your system needs one, and you need to develop the support. Let's translate the above use cases into SSO technical requirements:

  • Support SSO cross multiple domains
  • Support Password Grant (sing-in directly on the web), Authorization Code Grant (user authorizes third-party), Client Credentials Grant (Machine sign-in), and Implicit Grant (third-party web app sign-in)
  • Support distributed architecture, where your authentication server is not necessary on the same domain or at the same server as your resource servers
  • Web services API on resources server can effectively authenticate requests
  • No technology lock-in for authentication server, resource servers as well as client-side apps.
  • Support a seamless user authorization experience cross different client-side technology (Web, Mobile or IoT), and cross different first-party and third-party applications

Fortunately, we can leverage existing open standards and open source software to implement a SSO for a distributed system. First, we will rely on OAuth 2.0 Authorization Framework and JSON Web Token (JWT) open protocols. OAuth 2.0 is used to support common authentication workflows; in fact, the above 4 types of grants in the requirements are the terminologies borrowed from OAuth 2.0 protocol. JWT protocol is used to standardize the sharing of a successful authentication result cross clients apps and resources servers. The protocol allows resources server to trust a client request without double checking with authentication server, which lowers the amount of communication within a distributed system, therefore increases the performance of overall authentication and identification. For more technical details on how to use OAuth 2.0 and JWT for authentication, please see Stateless authentication with OAuth 2 and JWT - JavaZone 2015.

Regarding to building the authentication sever, where all users and machines will sign-in, authenticate, authorize, or identify themselves, the critical requirement for the authentication server is that this server implements OAuth 2.0 protocol and use JWT as the bearer token. As long as the authentication server implements the protocols, the rest of facilitating features can be built on any technology. I like use simple_oauth module with Drupal 8, because out-of-box, this solution is the whole application, including users, consumers and tokens management. Particularly, I have been helping to optimize the user experience of user authorization process for different use cases. If you are not familiar with Drupal, a particular distribution Contenta CMS has pre-packaged simple_oauth and its dependencies for you.

Once the authentication server is in place, we will implement the protocol and workflows on resource server and client-side apps. This part is largely up to your resource server and client-side technologies you picked. We are building this part of integration with Node.js, Laraval, Drupal 7 and Drupal 8 applications. As the time of writing, we have published the module oauth2_jwt_sso on Drupal 8.

I leave the extensibility, limitation, and more technical details of this SSO solution for the upcoming DrupalCon Nashville session. I will include the session video here in late Apri, 2018.

Files:  SSO diagram.pngTag: SSOOAuth2JWTDecoupledDistributedArchitectureSecurityDrupal Planet
Categories: Drupal

PreviousNext: Better image optimisation in Drupal

Planet Drupal - 23 January 2018 - 7:08pm

When optimising a site for performance, one of the options with the best effort-to-reward ratio is image optimisation. Crunching those images in your Front End workflow is easy, but how about author-uploaded images through the CMS?

by Tony Comben / 24 January 2018

Recently, a client of ours was looking for ways to reduce the size of uploaded images on their site without burdening the authors. To solve this, we used the module Image Optimize which allows you to use a number of compression tools, both local and 3rd party.

The tools it currently supports include:

We decided to avoid the use of 3rd party services, as processing the images on our servers could reduce processing time (no waiting for a third party to reply) and ensure reliability.

Picking your server-side compression tool

In order to pick the tools which best served our we picked an image that closely represented the type of image the authors often used. We picked an image featuring a person’s face with a complex background - one png and one jpeg, and ran it through each of the tools with a moderately aggressive compression level.

PNG Results Compression Library Compressed size Percentage saving Original (Drupal 8 default resizing) 234kb - AdvPng 234kb 0% OptiPng 200kb 14.52% PngCrush 200kb 14.52% PngOut 194kb 17.09% PngQuant 63kb 73.07% Compression Library Compressed size Percentage saving Original 1403kb - AdvPng 1403kb 0% OptiPng 1288kb 8.19% PngCrush 1288kb 8.19% PngOut 1313kb 6.41% PngQuant 445kb 68.28% JPEG Results Compression Library Compressed size Percentage saving Original (Drupal 8 default resizing) 57kb - JfifRemove 57kb 0% JpegOptim 49kb 14.03% JpegTran 57kb 0% Compression Library Compressed size Percentage saving Original 778kb - JfifRemove 778kb 0% JpegOptim 83kb 89.33% JpegTran 715kb 8.09%

Using a combination of PngQuant and JpegOptim, we could save anywhere between 14% and 89% in file size, with larger images bringing greater percentage savings.

Setting up automated image compression in Drupal 8

The Image Optimize module allows us to set up optimisation pipelines and attach them to our image styles. This allows us to set both site-wide and per-image style optimisation.

After installing the Image Optimize module, head to the Image Optimize pipelines configuration (Configuration > Media > Image Optimize pipeline) and add a new optimization pipeline.

Now add the PngQuant and JpegOptim processors. If they have been installed to the server Image Optimize should pick up their location automatically, or you can manually set the location if using a standalone binary.

JpegOptim has some additional quality settings, I’m setting “Progressive” to always and “Quality” to a sweet spot of 60. 70 could also be used as a more conservative target.

The final pipeline looks like the following:

Back to the Image Optimize pipelines configuration page, we can now set the new pipeline as the sitewide default:

And boom! Automated sitewide image compression!

Overriding image compression for individual image styles

If the default compression pipeline is too aggressive (or conservative) for a particular image style, we can override it in the Image Styles configuration (Configuration > Media > Image styles). Edit the image style you’d like to override, and select your alternative pipeline:

Applying compression to existing images

Flushing the image cache will recreate existing images with compression the next time the image is loaded. This can be done with the drush command 

drush image-flush --all


Setting up automated image optimisation is a relatively simple process, with potentially large impacts on site performance. If you have experience with image optimisation, I would love to hear about it in the comments.

Tagged Image Optimisation
Categories: Drupal

MidCamp - Midwest Drupal Camp: We are pleased to announce Chris Rooney will be our keynote speaker at MidCamp 2018

Planet Drupal - 23 January 2018 - 4:51pm
We are pleased to announce Chris Rooney will be our keynote speaker at MidCamp 2018

We are so excited to have Chris as our keynote speaker this year.  He is the President and Founder of Digital Bridge Solutions, a Drupal and Magento Agency here in Chicago that has been a supporter of MidCamp since its inception. 

His presentation at our 2017 event, Whitewashed - Drupal's Diversity Problem And How To Solve It, was a deep, and eye-opening look at diversity in Drupal, and the greater tech world, and how we can go about making it better.

Since then, he has been partnered with Palantir.net on an ambitious inclusion initiative working with students to introduce them to Drupal.  Last year, they brought a group of students from Baltimore to DrupalCon Baltimore.  They have held Drupal training sessions here in Chicago, and are currently working to bring students from Genesys Works and NPower to DrupalCon Nashville.

Chris' presentation will be a collective group journey into sensitive and vulnerable territories, but promises interactivity, a safe space for the exchange of ideas, and perhaps even a little humor.  We hope you join us for it.

Session Submissions close Friday!

MidCamp is looking for folks just like you to speak to our Drupal audience! Experienced speakers are always welcome, but our camp is also a great place to start for first-time speakers.

MidCamp is soliciting sessions geared toward beginner through advanced Drupal users. Know someone who might be a new voice, but has something to say? Please suggest they submit a session.

Find out more at: Buy a Ticket

Tickets and Individual Sponsorships are available on the site for MidCamp 2018.

Click here to get yours!

Schedule of Events
  • Thursday, March 8th, 2018 - Training and Sprints
  • Friday, March 9th, 2018 - Sessions and Social
  • Saturday, March 10th, 2018 - Sessions and Social
  • Sunday, March 11th, 2018 - Sprints
Sponsor MidCamp 2018!

Are you or your company interested in becoming a sponsor for the 2018 event? Sponsoring MidCamp is a great way to promote your company, organization, or product and to show your support for Drupal and the Midwest Drupal community. It also is a great opportunity to connect with potential customers and recruit talent.

Find out more at:

Volunteer for MidCamp 2018

Want to be part of the MidCamp action? We're always looking for volunteers to help out during the event.  We need registration table help, room monitors, help with setting up the venue, and help clearing out.  Sign up at http://bit.ly/midcamp-volunteer-signup and we'll be in touch shortly!

We hope you'll join us at MidCamp 2018!

Categories: Drupal

Dcycle: Caching a Drupal 8 REST resource

Planet Drupal - 23 January 2018 - 4:00pm

Here are a few things I learned about caching for REST resources.

There are probably better ways to accomplish this, but here is what works for me.

Let’s say we have a rest resource that looks something like this in my_module/src/Plugin/rest/resource/MyRestResource.php and we have enabled it using the Rest UI module and given anonymous users permission to view it:

<?php namespace Drupal\my_module\Plugin\rest\resource; use Drupal\rest\ResourceResponse; /** * This is just an example. * * @RestResource( * id = "this_is_just_an_example", * label = @Translation("Display the title of node 1"), * uri_paths = { * "canonical" = "/api/v1/get" * } * ) */ class MyRestResource extends ResourceBase { /** * {@inheritdoc} */ public function get() { $node = node_load(1); $response = new ResourceResponse( [ 'title' => $node->getTitle(), 'time' => time(), ] ); return $response; } }

Now, we can visit http://example.localhost/api/v1/get?_format=json and we will see something like:

{"title":"Some Title","time":1516803204}

Reloading the page, ‘time’ stays the same. That means caching is working; we are not re-computing our Json output each time someone requests it.

How to invalidate the cache when the title changes.

If we edit node 1 and change its title to, say, “Another title”, and reload http://example.localhost/api/v1/get?_format=json, we’ll see the old title. To make sure the cache is invalidated when this happens, we need to provide cacheability metadata to our response telling it when it needs to be recomputed.

Our node, when it’s loaded, contains within it all the caching metadata needed to describe when it should be recomputed: when the title changes, when new filters are added to the text format that’s being used, etc. We can add this information to our ResourceResponse like this:

... $response->addCacheableDependency($node); return $response; ...

When we clear our cache with drush cr and reload our page, we’ll see something like:

{"title":"Another title","time":1516804411}

We know this is still cached because the time stays the same no matter how often we load the page. Try it, it’s fun!

Even more fun is changing the title of node 1 and reloading our Json page, and seeing the title change without clearing the cache:

{"title":"Yet another title","time":1516804481} How to set custom cache invalidation events

Let’s say you want to trigger a cache rebuild for some reason other than those defined by the node itself (title change, etc.).

A real-world example might be events: an “upcoming events” page should only display events which start later than now. If we invalidate the cache every day, then we’ll never show yesterday’s events in our events feed. Here, we need to add our custom cache invalidation event, in this case “rebuild events feed”.

For the purpose of this demo, we won’t actually build an events feed, but we’ll see how cron might be able to trigger cache invalidation.

Let’s add the following code to our response:

... use Drupal\Core\Cache\CacheableMetadata; ... $response->addCacheableDependency($node); $response->addCacheableDependency(CacheableMetadata::createFromRenderArray([ '#cache' => [ 'tags' => [ 'rebuild-events-feed', ], ], ])); return $response; ...

This uses Drupal’s cache tags concept and tells Drupal that when the cache tag ‘rebuild-events-feed’ is invalidated, all cacheable responses which have that cache tag should be invalidated as well. I prefer this to the ‘max-age’ cache tag because it allows us more fine-grained control over when to invalidate our caches.

On cron, we could only invalidate ‘rebuild-events-feed’ if events have passed since our last invalidation of that tag, for example.

For this example, we’ll just invalidate it manually. Clear your cache to begin using the new code (drush cr), then load the page, you will see something like:

{"hello":"Yet another title","time":1516805677}

As always, the time remains the same no matter how many times you reload the page.

Let’s say you are in the midst of a cron run and you have determined that you need to invalidate your cache for response which have the cache tag ‘rebuild-events-feed’, you can run:


Let’s do it in Drush to see it in action:

drush ev "\Drupal::service('cache_tags.invalidator')->\ invalidateTags(['rebuild-events-feed'])"

We’ve just invalidated our ‘rebuild-events-feed’ tag and, hence, Responses that use it.

The dreaded “leaked metadata” error

This one is beyond my competence level, but I wanted to mention it anyway.

Let’s say you want to output your node’s URL to Json, you might consider computing it using $node->toUrl()->toString(). This will give us “/node/1”.

Let’s add it to our code:

... 'title' => $node->getTitle(), 'url' => $node->toUrl()->toString(), 'time' => time(), ...

This results in a very ugly error which completely breaks your site (at least at the time of this writing): “The controller result claims to be providing relevant cache metadata, but leaked metadata was detected. Please ensure you are not rendering content too early.”.

The problem, it seems, is that Drupal detects that the URL object, like the node we saw earlier, contains its own internal information which tells it when its cache should be invalidated. Converting it to a string prevents the Response from being informed about that information somehow (again, if someone can explain this better than me, please leave a comment), so an exception is thrown.

The ‘toString()’ function has an optional parameter, “$collect_bubbleable_metadata”, which can be used to get not just a string, but also information about its cache should be invalidated. In Drush, this will look like something like:

drush ev 'print_r(node_load(1)->toUrl()->toString(TRUE))' Drupal\Core\GeneratedUrl Object ( [generatedUrl:protected] => /node/1 [cacheContexts:protected] => Array ( ) [cacheTags:protected] => Array ( ) [cacheMaxAge:protected] => -1 [attachments:protected] => Array ( ) )

This changes the return type of toString(), though: toString() no longer returns a string but a GeneratedUrl, so this won’t work:

... 'title' => $node->getTitle(), 'url' => $node->toUrl()->toString(TRUE), 'time' => time(), ...

It gives us the error “Could not normalize object of type Drupal\Core\GeneratedUrl, no supporting normalizer found”.

ohthehugemanatee commented on Drupal.org on how to fix this. Integrating his suggestion, our code now looks like:

... $url = $node->toUrl()->toString(TRUE); $response = new ResourceResponse( [ 'title' => $node->getTitle(), 'url' => $url->getGeneratedUrl(), 'time' => time(), ] ); $response->addCacheableDependency($node); $response->addCacheableDependency($url); ...

This will now work as expected.

With all the fun we’re having, though let’s take this a step further, let’s say we want to export the feed of frontpage items in our Response:

$url = $node->toUrl()->toString(TRUE); $view = \Drupal\views\Views::getView("frontpage"); $view->setDisplay("feed_1"); $view_render_array = $view->render(); $rendered_view = render($view_render_array); $response = new ResourceResponse( [ 'title' => $node->getTitle(), 'url' => $url->getGeneratedUrl(), 'view' => $rendered_view, 'time' => time(), ] ); $response->addCacheableDependency($node); $response->addCacheableDependency($url); $response->addCacheableDependency(CacheableMetadata::createFromRenderArray($view_render_array));

You will not be surpised to see the “leaked metadata was detected” error again… In fact you have come to love and expect this error at this point.

Here is where I’m completely out of my league; according to Crell, “[i]f you [use render() yourself], you’re wrong and you should fix your code “, but I’m not sure how to get a rendered view without using render() myself… I’ve implemented a variation on a comment on Drupal.org by mikejw suggesting using different render context to prevent Drupal from complaining.

$view_render_array = NULL; $rendered_view = NULL; \Drupal::service('renderer')->executeInRenderContext(new RenderContext(), function () use ($view, &$view_render_array, &$rendered_view) { $view_render_array = $view->render(); $rendered_view = render($view_render_array); });

If we check to make sure we have this line in our code:


we’re telling our Response’s cache to invalidate whenever our view’s cache invaliates. So, for example, if we have several nodes promoted to the front page in our view, we can modify any one of them and our entire Response’s cache will be invalidated and rebuilt.

Resources and further reading

Here are a few things I learned about caching for REST resources.

Categories: Drupal

Commerce Bulk

New Drupal Modules - 23 January 2018 - 3:14pm

Provides a service for bulk creation of Drupal Commerce entities. For now just
product variations could be bulk created on a product add or edit form. See more on the module's Github repository:


Categories: Drupal

BYU Calendar

New Drupal Modules - 23 January 2018 - 2:07pm

This widget uses the Events API. You can read about BYU APIs here: https://calendar.byu.edu/byu-calendar-api-documentation

The specific API this module uses is: https://calendar.byu.edu/events-api

You can read more about the categories or see current values and information through: The All Categories API: https://calendar.byu.edu/all-categories-api

Categories: Drupal

Drupal.org Featured Case Studies: Chicago Park District Website

Planet Drupal - 23 January 2018 - 1:39pm
Completed Drupal site or project URL: https://www.chicagoparkdistrict.com/

The Chicago Park District owns more than 8,800 acres of green space, making it the largest municipal park manager in the nation. The Chicago Park District’s more than 600 parks offer thousands of sports and physical activities as well as cultural and environmental programs for youth, adults, and seniors. The Chicago Park District is also responsible for 28 indoor pools, 50 outdoor pools, and 26 miles of lakefront including 23 swimming beaches plus one inland beach.

Clarity redesigned, built, and hosts the official website for the Chicago Park District (CPD). Clarity designed and developed this user-friendly, mobile-responsive site, with a unified look and feel and marketing emphasis to promote CPD’s parks, programs, and events. The new website acts as a solution focused on its customers – “front end” visitors of the website and “back end” content administers – both of whom have a wide scope of needs.

Specifically, the new site provides the following improvements and features:

  • New Content Management System (CMS) Platform
    • Drupal 8, the latest version of the popular open-source framework;
    • Allows CPD to more easily integrate and connect to third-party tools, such as
      • ActiveNet, which provides externally-hosted ecommerce functions;
      • AppliTrack, which provides job postings;
      • Bonfire, which provides procurement and contracting opportunities;
      • MailChimp, which provides newsletter signup capabilities.
  • Updated design based on user focus group reactions to the old site, including
    • A cleaner, refreshed look built for devices of all sizes;
    • Home page updates that allow CPD staff to push more information in a more organized fashion;
    • Larger emphasis on maps (hugely important for such a large metropolitan area);
    • The ability to highlight features and attractions, such as artworks and natural areas, that CPD has to offer both residents and visitors;
    • Overall increased speed and performance.
  • Improved administrative functions that allow for
    • Distributed content responsibilities;
    • Workflow approvals to ensure editorial integrity;
    • More modular administrative tools allowing CPD to highlight location details such as accessibility features

With its new site, Chicago Park District is now poised to better serve the long-term needs of residents and visitors for years to come.

Categories: Drupal


New Drupal Modules - 23 January 2018 - 1:15pm
Categories: Drupal

License Field

New Drupal Modules - 23 January 2018 - 10:26am

This project was started in response to https://www.drupal.org/project/creative_commons/issues/2938260

Rather than a Creative Commons specific module, the idea is to add support for all SPDX license codes and let the user select the supported license per field instance.

The idea is that this field can be used on node content types as well as Media entities.

Categories: Drupal

Web Wash: Getting Started with Bootstrap in Drupal 8

Planet Drupal - 23 January 2018 - 8:00am
Bootstrap is a front-end framework for building websites. It ships prebuilt CSS and JavaScript components that make building sites fast. It comes with all sorts of common components that every website needs such as a grid system, buttons, drop-down, responsive form elements, carousel (of course) and so much more. As a developer I don't want to spend time styling yet another button. I just want to know which CSS class to add to an tag so it looks like a button and I'm good to go. One complaint about Bootstrap is you can spot it a mile away because a lot of developers use the default look-and-feel. When you see the famous Jumbotron you know it's a Bootstrap site. But with a little bit of effort you can make your site look unique.

Aten Design Group: Using Address Fields in Configuration Forms

Planet Drupal - 23 January 2018 - 7:40am

In Drupal 7, the Address Field module provided developers an easy way to collect complex address information with relative ease. You could simply add the field to your content type and configure which countries you support along with what parts of an address are needed. However, this ease was limited to fieldable entities. If you needed to collect address information somewhere that wasn’t a fieldable entity, you had a lot more work in store for you. Chances are good that the end result would be as few text fields as possible, no validation, and only supporting with a single country. If you were feeling ambitious, maybe you would have provided a select list with the states or provinces provided via a hardcoded array.

During my most recent Drupal 8 project I wanted to collect structured address information outside the context of an entity. Specifically, I wanted to add a section for address and phone number to the Basic Site Settings configuration page. As it turns out, the same functionality you get on entities is now also available to the Form API.

Address Field’s port to Drupal 8 came in the form of a whole new module, the Address module. With it comes a new address form element. Let’s use that to add a “Site Address” field to the Basic Settings. First we’ll implement hook_form_FORM_ID_alter() in a custom module’s .module file:

use Drupal\Core\Form\FormStateInterface;   function MYMODULE_form_system_site_information_settings_alter(&$form, FormStateInterface $form_state) { // Overrides go here... }

Don’t forget to add use Drupal\Core\Form\FormStateInterface; at the top of your file. Next, we’ll add a details group and a fieldset for the address components to go into:

function MYMODULE_form_system_site_information_settings_alter(&$form, FormStateInterface $form_state) { // Create our contact information section. $form['site_location'] = [ '#type' => 'details', '#title' => t('Site Location'), '#open' => TRUE, ];   $form['site_location']['address'] = [ '#type' => 'fieldset', '#title' => t('Address'), ]; }

Once the fieldset is in place, we can go ahead and add the address components. To do that you’ll first need to install the Address module and its dependencies. You’ll also need to add use CommerceGuys\Addressing\AddressFormat\AddressField; at the top of the file as we’ll need some of the constants defined there later.

use Drupal\Core\Form\FormStateInterface; use CommerceGuys\Addressing\AddressFormat\AddressField;   function MYMODULE_form_system_site_information_settings_alter(&$form, FormStateInterface $form_state) { // … detail and fieldset code …   // Create the address field. $form['site_location']['address']['site_address'] = [ '#type' => 'address', '#default_value' => ['country_code' => 'US'], '#used_fields' => [ AddressField::ADDRESS_LINE1, AddressField::ADDRESS_LINE2, AddressField::ADMINISTRATIVE_AREA, AddressField::LOCALITY, AddressField::POSTAL_CODE, ], '#available_countries' => ['US'], ]; }

There’s a few things we’re doing here worth going over. First we set '#type' => 'address', which the Address module creates for us. Next we set a #default_value for country_code to US. That way the United States specific field config is displayed when the page loads.

The #used_fields key allows us to configure which address information we want to collect. This is done by passing an array of constants as defined in the AddressField class. The full list of options is:

AddressField::ADMINISTRATIVE_AREA AddressField::LOCALITY AddressField::DEPENDENT_LOCALITY AddressField::POSTAL_CODE AddressField::SORTING_CODE AddressField::ADDRESS_LINE1 AddressField::ADDRESS_LINE2 AddressField::ORGANIZATION AddressField::GIVEN_NAME AddressField::ADDITIONAL_NAME AddressField::FAMILY_NAME

Without any configuration, a full address field looks like this when displaying addresses for the United States.

For our example above, we only needed the street address (ADDRESS_LINE1 and ADDRESS_LINE2), city (LOCALITY), state (ADMINISTRATIVE_AREA), and zip code (POSTAL_CODE).

Lastly, we define which countries we will be supporting. This is done by passing an array of country codes into the #available_countries key. For our example we only need addresses from the United States, so that’s the only value we pass in.

The last step in our process is saving the information to the Basic Site Settings config file. First we need to add a new submit handler to the form. At the end of our hook, let’s add this:

function MYMODULE_form_system_site_information_settings_alter(&$form, FormStateInterface $form_state) { // … detail and fieldset code …   // … address field code …   // Add a custom submit handler for our new values. $form['#submit'][] = 'MYMODULE_site_address_submit'; }

Now we’ll create the handler:

/** * Custom submit handler for our address settings. */ function MYMODULE_site_address_submit($form, FormStateInterface $form_state) { \Drupal::configFactory()->getEditable('system.site') ->set(‘address’, $form_state->getValue('site_address')) ->save(); }

This loads our site_address field from the submitted values in $form_state, and saves it to the system.site config. The exported system.site.yml file should now look something like:

name: 'My Awesome Site' mail: test@domain.com slogan: '' page: 403: '' 404: '' front: /user/login admin_compact_mode: false weight_select_max: 100 langcode: en default_langcode: en address: country_code: US langcode: '' address_line1: '123 W Elm St.' address_line2: '' locality: Denver administrative_area: CO postal_code: '80266' given_name: null additional_name: null family_name: null organization: null sorting_code: null dependent_locality: null

After that, we need to make sure our field will use the saved address as the #default_value. Back in our hook, let’s update that key with the following:

function MYMODULE_form_system_site_information_settings_alter(&$form, FormStateInterface $form_state) { // … detail and fieldset code …   // Create the address field. $form['site_location']['address']['site_address'] = [ '#type' => 'address', '#default_value' => \Drupal::config('system.site')->get('address') ?? [ 'country_code' => 'US', ], '#used_fields' => [ AddressField::ADDRESS_LINE1, AddressField::ADDRESS_LINE2, AddressField::ADMINISTRATIVE_AREA, AddressField::LOCALITY, AddressField::POSTAL_CODE, ], '#available_countries' => ['US'], ];   // … custom submit handler ... }

Using PHP 7’s null coalesce operator, we either set the default to the saved values or to a sensible fallback if nothing has been saved yet. Putting this all together, our module file should now look like this:

<?php   /** * @file * Main module file. */   use Drupal\Core\Form\FormStateInterface; use CommerceGuys\Addressing\AddressFormat\AddressField;   /** * Implements hook_form_ID_alter(). */ function MYMODULE_form_system_site_information_settings_alter(&$form, FormStateInterface $form_state) { // Create our contact information section. $form['site_location'] = [ '#type' => 'details', '#title' => t('Site Location'), '#open' => TRUE, ];   $form['site_location']['address'] = [ '#type' => 'fieldset', '#title' => t('Address'), ];   // Create the address field. $form['site_location']['address']['site_address'] = [ '#type' => 'address', '#default_value' => \Drupal::config('system.site')->get('address') ?? [ 'country_code' => 'US', ], '#used_fields' => [ AddressField::ADDRESS_LINE1, AddressField::ADDRESS_LINE2, AddressField::ADMINISTRATIVE_AREA, AddressField::LOCALITY, AddressField::POSTAL_CODE, ], '#available_countries' => ['US'], ];   // Add a custom submit handler for our new values. $form['#submit'][] = 'MYMODULE_site_address_submit'; }   /** * Custom submit handler for our address settings. */ function MYMODULE_site_address_submit($form, FormStateInterface $form_state) { \Drupal::configFactory()->getEditable('system.site') ->set(‘address’, $form_state->getValue('site_address')) ->save(); }

Lastly we should do some house cleaning in case our module gets uninstalled for any reason. In the same directory as the MYMODULE.module file, let’s add a MYMODULE.install file with the following code:

/** * Implements hook_uninstall(). */ function MYMODULE_uninstall() { // Delete the custom address config values. \Drupal::configFactory()->getEditable('system.site') ->clear(‘address’) ->save(); }

That’s it! Now we have a way to provide location information to the global site configuration. Using that data, I’ll be able to display this information elsewhere as text or as a Google Map. Being able to use the same features that Address field types have, I can leverage other modules that display address information or build my own displays, because I now have reliably structured data to work with.

Categories: Drupal

Views entity embed

New Drupal Modules - 23 January 2018 - 7:27am

Views entity embed module allows you to embed views using Embed module.

Categories: Drupal


Subscribe to As If Productions aggregator - Drupal