Planet Drupal

Subscribe to flux Planet Drupal
Drupal.org - aggregated feeds in category Planet Drupal
Mis à jour : il y a 39 min 18 sec

Zivtech: Use Gulp for Drupal 8 with Teams, Part 1: Gulp Setup

mer, 26/10/2016 - 17:57

Gulp is a mainstay of front-end development nowadays. Of course, like all front-end development tools, there is a massive proliferation of build systems, from Webpack to SystemJS and Grunt to Gulp. Yet, we at Zivtech find ourselves using mostly Gulp, particularly when dealing with Drupal 8 projects.

This article is the first of a series of posts where I outline how Zivtech uses Gulp. In this first part, I'll talk about our reasoning and setup process.

Why does Zivtech use Gulp for Drupal 8?

The choice of Gulp over other front end tools is due to how Drupal utilizes front-end assets. It's perfectly fine to use something like Webpack or Browserify with Drupal, but those all-encompassing, "build and combine all the things!" systems are best used for projects that don't have a built-in asset pipeline. For example, Drupal concatenates and minifies CSS and JS for us, and it's really just over-compiling (is that a word?) to use something that Drupal obviates.

Also, we use Gulp over Grunt or even Broccoli (because yes, that's a thing too) strictly because Zivtech does a lot of node.js development as well. The concept of streams and buffers in Gulp are used throughout node.js, and it makes sense that we'd align with our other development.

Many projects and distributed teams

As a client services company, Zivtech has many projects and several teams working on projects. Thus, our building tasks have to be somewhat abstract so as to apply to most situations. So the first step to conquering the Gulp pipeline is figuring out a way to make the tasks themselves static, but let the configuration remain changeable.

Some examples of these changeable settings include: the website address that Browsersync should proxy when watching your development. It's possible that this website address could change on a per-user basis too. Also, the website name would change on a per-site basis too.

Within each project, we could just alter the Gulp tasks directly to account for these differences. Yet some people on the team may not be too familiar with Gulp and you might be sending them into the weeds trying to suss out "that one weird setting" they should change.

At this point you might be thinking we should make a settings file for each project's Gulp tasks, and you'd be correct if so! The Gulp tasks remain the same, but the settings always change.

As it turns out, Drupal 8 has a preferred method for settings files: the YAML format. Being a flexible guy, I vote for just sticking with what the system wants. Thus, our new settings files will be written in YAML.

Using YAML for Gulp settings

First, let's think about how we're going to implement settings from a big picture perspective. We've already determined that we'll work in YAML and we'll have a default group of configuration settings available. We also want each member of the team to be able to override some settings to fit their situations.

It makes sense that we'll have a file called default.gulpfile.yml for the default settings. Gulp should merge another file, we'll call it gulpfile.yml, on top of the default. The default settings get tracked in Git or your chosen version control system, but the other one should not. This allows for complete flexibility of any setting you or one of your teammates might want.

In default.gulpfile.yml, start off by creating some basic settings:

themeName: "myTheme" themeDescription: "myTheme description"

Next, create a gulpfile.yml to contain your customized settings:

themeName: "myRenamedTheme"

When Gulp runs, the themeDescription setting should match default, but the themeName setting should be overridden.

Finally, in your gulpfile.js:

(function () { 'use strict'; var gulp = require('gulp'); var yaml = require('js-yaml'); var fs = require('fs'); var assign = require('lodash.assign'); // read default config settings var config = yaml.safeLoad(fs.readFileSync('default.gulpfile.yml', 'utf8'), {json: true}); try { // override default config settings var customConfig = yaml.safeLoad(fs.readFileSync('gulpfile.yml', 'utf8'), {json: true}); config = assign(config, customConfig); } catch (e) { console.log('No custom config found! Proceeding with default config only.'); } })();

Now, when you run any Gulp task, your config files will get merged by lodash. One day, Object.assign will be more widely available, and lodash won't be needed any longer. For now, things work fine this way.

You'll notice that loading the custom config is in a try ... catch block. We do that so there are no show-stopping errors if the custom config is not found. Additionally, if it's not found we can let the user know that only default settings are in use.

Wrapping up

Well, this has been a high-level explanation of how and why we use Gulp at Zivtech for D8 projects.

In the coming articles in this series, I'll expand on the simple gulpfile.js and default.gulpfile.yml files started. I plan to outline our process for linting and compiling CSS, linting and compiling JavaScript, and a couple extra tasks too, like integrating Bower and favicon generation. Until then!

Catégories: Elsewhere

Mediacurrent: Top Drupal 8 Modules

mer, 26/10/2016 - 15:24
INTRODUCTION TO JAY’S MODULE LIST

Welcome back to another Top Modules blog post from Mediacurrent. Last year, I wrote the final top Drupal 7 modules list but never fear, we are back again with some great modules for Drupal 8. These are modules I strongly recommend because I use them on most new builds.

Catégories: Elsewhere

DrupalEasy: DrupalEasy Podcast 188 - Pants and Pokemon (Matt Glaman - Drupal 8 Development Cookbook)

mer, 26/10/2016 - 14:18

Direct .mp3 file download.

Anna and Mike are joined by Matt Glaman to discuss his new Drupal 8 Development Cookbook book, the status of Drupal Commerce, using Composer, as well as current news and a pick of the week.

Interview DrupalEasy News Three Stories Sponsors Picks of the Week Upcoming Events Follow us on Twitter Five Questions (answers only)
  1. Photography.
  2. iA Writer.
  3. Buy a new house and move.
  4. Seal.
  5. DrupalCamp Atlanta 2013.
Intro Music Subscribe

Subscribe to our podcast on iTunes, Google Play or Miro. Listen to our podcast on Stitcher.

If you'd like to leave us a voicemail, call 321-396-2340. Please keep in mind that we might play your voicemail during one of our future podcasts. Feel free to call in with suggestions, rants, questions, or corrections. If you'd rather just send us an email, please use our contact page.

Catégories: Elsewhere

Pantheon Blog: Fixing the Composer Global Command

mar, 25/10/2016 - 20:38
One of the most commonly documented ways for a PHP command line tool to be installed is via the composer global require command. This command is easy to document and easy to run, which explains its popularity. Unfortunately, this convenient function has a darker side that can cause some pretty big problems.
Catégories: Elsewhere

MTech, LLC: ¿Cómo hacer una migración de csv file con imágenes?

mar, 25/10/2016 - 19:13
How to Migrate Images into Drupal 8 Using CSV Source

For our migration we have a .csv file with random data you want to migrate into Drupal 8:

Ada Hernández Tue, 10/25/2016 - 11:13
Catégories: Elsewhere

Tag1 Consulting: Tag1 Quo: Finding a Place in the (Version) Universe, Part 2

mar, 25/10/2016 - 18:33
sam Tue, 10/25/2016 - 09:33

When we left off last time, we’d assembled a definition of what versions are. Now, we’re going to dive into how we use them: comparing them to one another!

The general goal is straightforward enough: we want to know if, say, 6.x-1.0 is less than 6.x-1.1. (Yup!) Or if 6.x-1.0-alpha1 is less than 6.x-1.0. (Also yup!) Let’s rewrite these two examples as tuple comparisons:

Catégories: Elsewhere

Four Kitchens: Launch Announcement: MDedge.com

mar, 25/10/2016 - 18:16

MDedge is a digital and print publisher providing resources for health industry professionals. […]

Catégories: Elsewhere

myDropWizard.com: Clients don’t want to be billed hourly for site maintenance - even if they say they do!

mar, 25/10/2016 - 18:11

As Drupal professionals, you and I know that all sites need maintenance and support after they're launched. There's security updates, bugs, minor tweaks and questions to be answered. Clients might not know that, so it's our job to educate them.

We find that it's easiest to discuss this before development starts on their new site, rather than after it's done, but whenever it happens, you'll need to agree to a plan for when things come up.

Most Drupal shops and freelancers default to "hourly as needed". Usually clients will go along with that - or even insist on it!

However, we strongly believe that billing hourly for site maintenance and support is WORSE for clients (and you).

Read more to find why - and learn a better way to do it!

Catégories: Elsewhere

Drupalize.Me: The New Drupal 8 Initiatives

mar, 25/10/2016 - 17:24

You may have heard of a variety of Drupal 8 initiatives during the development cycle leading up to Drupal 8.0.0 being released in 2015. These were officially recognized efforts to get a variety of big changes into Drupal 8, and included projects such as configuration management, Views in core, and multilingual improvements. A lot of work from those initiatives is now part of Drupal 8. Not everything got in though, and as time moves on some priorities for new work will always shift.

Catégories: Elsewhere

qed42.com: New Module - CSSgram recreating Instagram like filters for Drupal 8

mar, 25/10/2016 - 15:52
New Module - CSSgram recreating Instagram like filters for Drupal 8 Body

CSSgram module supplements Drupal Image styling experience by making Instagram like filters available to your Drupal 8 site images, we do this with help of CSSgram library. 

Beauty of this module is, it simply uses css to beautify your image.

Few CSSGram sample filters applied to an image.

 

How CSSGram Module works?

CSSGram module uses CSSGram Library for adding filter effects via CSS to the image fields. Module extends Field Formatter Settings to add image filter for that particular field. CSSGram extends field formatter settings and hence these filters can be applied on top of the existing available image formatters and image presets. Allowing you to use your desired image preset along with CSSGram filters.
 

Using CSSGram
  1. Download and enable CSSGram module (https://www.drupal.org/project/cssgram)

  2. Visit Manage Display of content type and for the desired image field, click on the setting link under format column.

  3. Select Filter option lets us choose from the available image filters. Just select the desired image filter and hit update button.

  1. Save the settings and visit the content display page.

Developer Support

Devs have the option to use these filters anywhere on the site by just attaching the ‘cssgram/cssgram’ library and then applying any of the available css filter class to the wrapper element.

function mymodule_preprocess_field(&$variables) { // Add desired css class. $variables['attributes']['class'] = 'kelvin'; // Attach cssgram library. $variables['#attached']['library'][] = 'cssgram/cssgram'; }

 

PURUSHOTAM RAI Tue, 10/25/2016 - 19:22
Catégories: Elsewhere

TimOnWeb.com: Add reCaptcha to your Drupal 7 forms programatically

mar, 25/10/2016 - 14:46

If you want to add Google's reCaptcha (https://www.google.com/recaptcha/intro/index.html) to your Drupal 7 forms programmatically you need to follow these two steps:

1) Install and enable captcha (https://www.drupal.org/project/captcha) and recaptcha (https://www.drupal.org/project/recaptcha) modules. The best ...

Read now

Catégories: Elsewhere

InternetDevels: Some great health care websites built with Drupal

mar, 25/10/2016 - 14:02

Let’s feel Drupal’s pulse! It looks like the popular site-building platform is doing great. It remains a perfect fit for all kinds of sites.

Read more
Catégories: Elsewhere

qed42.com: Programmatically updating URL aliases using Batch API in Drupal 8

mar, 25/10/2016 - 11:53
Programmatically updating URL aliases using Batch API in Drupal 8 Body

Drupal has always had excellent support for human-friendly URL’s and SEO in general, from early on we have had the luxury of modules like pathauto offering options to update URL for specific entities, token support and bulk update of URLs. Though bulk update works for most cases, there are some situations where we have to update URLs programmatically, some of the use cases are:

  • Multisite setup -- When your setup has many sites, its inconvenient to use bulk update UI to update aliases for each of your sites. Programmatically updating the aliases is a good choice and can be executed via the update hooks.
  • Conditional Update -- When you wish to update aliases based on certain conditions.

 

In Drupal 8 Pathauto services.yml file we can see that there is a service named ‘pathauto.generator’ which is what we would need. The class for corresponding to this service, PathautoGenerator provides updateEntityAlias method which is what we would be using here:

public function updateEntityAlias(EntityInterface $entity, $op, array $options = array())

 

EntityInterface $entity: So, we need to pass the entity (node, taxonomy_term or user) here. String $op: Operation to be performed on the entity (‘update’, ‘insert’ or ‘bulkupdate’). $options: An optional array of additional options.

Now all we need is to loop the entities through this function, these entities may be the user, taxonomy_term or node. We will be using entityQuery and entityTypeManager to load entities, similar to the code below

$entities = [];   // Load All nodes.   $result = \Drupal::entityQuery('node')->execute();   $entity_storage = \Drupal::entityTypeManager()->getStorage('node');   $entities = array_merge($entities, $entity_storage->loadMultiple($result));   // Load All taxonomy terms.   $result = \Drupal::entityQuery('taxonomy_term')->execute();   $entity_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');   $entities = array_merge($entities, $entity_storage->loadMultiple($result));   // Load All Users.   $result = \Drupal::entityQuery('user')->execute();   $entity_storage = \Drupal::entityTypeManager()->getStorage('user');   $entities = array_merge($entities, $entity_storage->loadMultiple($result));   // Update URL aliases.   foreach ($entities as $entity) {     \Drupal::service('pathauto.generator')->updateEntityAlias($entity, 'update');   }

This works fine and could be used on a small site but considering the real world scenarios we generally perform this type of one-time operation in hook_update_N() and for larger sites, we may have memory issues, which we can resolve by involving batch API to run the updates in the batch. 

Using Batch API in hook_update_n()

As the update process in itself a batch process, so we can’t just use batch_set() to execute our batch process for URL alias update, we need to break the task into smaller chunks and use the $sandbox variable which is passed by reference to update function to track the progress.  

The whole process could be broken down into 4 steps:

  • Collect number of nodes / entities we would be updating the URL for.
  • Use the $sandbox to store information needed to track progress.
  • Process nodes in groups of a certain number (say 20, in our case ).
  • And finally setting the finished status based on progress.
function mymodule_update_8100(&$sandbox) { $entities = []; $entities['node'] = \Drupal::entityQuery('node')->execute(); $entities['user'] = \Drupal::entityQuery('user')->execute(); $entities['taxonomy_term'] = \Drupal::entityQuery('taxonomy_term')->execute(); $result = []; foreach ($entities as $type => $entity_list) { foreach ($entity_list as $entity_id) { $result[] = [ 'entity_type' => $type, 'id' => $entity_id, ]; } } // Use the sandbox to store the information needed to track progression. if (!isset($sandbox['current'])) { // The count of entities visited so far. $sandbox['current'] = 0; // Total entities that must be visited. $sandbox['max'] = count($result); // A place to store messages during the run. } // Process entities by groups of 20. // When a group is processed, the batch update engine determines // whether it should continue processing in the same request or provide // progress feedback to the user and wait for the next request. $limit = 20; $result = array_slice($result, $sandbox['current'], $limit); foreach ($result as $row) { $entity_storage = \Drupal::entityTypeManager()->getStorage($row['entity_type']); $entity = $entity_storage->load($row['id']); // Update Entity URL alias. \Drupal::service('pathauto.generator')->updateEntityAlias($entity, 'update'); // Update our progress information. $sandbox['current']++; } $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current'] / $sandbox['max']); if ($sandbox['#finished'] >= 1) { return t('The batch URL Alias update is finished.'); } }

The process of loading the entities will differ in case we are just updating a single entity type say nodes. In that case, we can use loadMultiple to load all the entities at once per single batch operation. That’s a kind of trade-off we have to do according to our requirements. The crucial part is using sandbox variable and splitting the job into chunks for batch processing.

PURUSHOTAM RAI Tue, 10/25/2016 - 15:23
Catégories: Elsewhere

Enzolutions: My second BADCamp

mar, 25/10/2016 - 02:00

Last week I had the opportunity of participating in my second BADCamp as part of my tour Around the Drupal world in 140+ days.

My first assistance was in 2012, a lot have changed from that time to now. At that time I was only assistant and was impress for the quality of the event and how vibrant was the community in San Francisco Bay Area.

The event itself doesn't change too much, the same venue, but a little more disperse in my opinion.

What change was my participation with Jesus Manuel Olivas one of my business partners at weKnow. We lead a training about Drupal 8 module development

Slides: [http://weknowinc.com/talks/2016/badcamp-training/]

Also we have a session about how to learn about Drupal 8 via debugging

Slides: http://weknowinc.com/talks/2016/badcamp-learn-drupal-8-via-debugging

Airplane Distance (Kilometers) San Jose, Costa Rica → Panama, Panama → San Francisco, USA 5.880 Previously 109.137 Total 115.017 Walking Distance (steps) Bay Area 58.408 Previously 1.936.685 Total 1.995.093 Train Distance (Kilometers) Today 0 Previously 528 Total 528 Bus/Car Distance (Kilometers) Today 796 Previously 2.944 Total 3.740
Catégories: Elsewhere

Palantir: Highlights From HighEdWeb 2016

lun, 24/10/2016 - 22:23
Highlights From HighEdWeb 2016 brandt Mon, 10/24/2016 - 15:23 Allison Manley Oct 24, 2016

HighEdWeb proved to be a valuable experience (again!) and we will be back.

In this post we will cover...
  • What makes HighEdWeb special
  • A few things we learned
  • Some of our favorite sessions

We want to make your project a success.

Let's Chat.

Last week I returned from the HigherEd Web Conference in Memphis, TN. This is one of my favorite conferences because the community is fantastic, the energy is high, the events are well-attended and create an inclusive atmosphere, and it’s just well-run. It’s also a very heavy Twitter user group . . . attendees love to tweet everything early and often, and each session is given its own hashtag so people can follow along. They also have a coveted award called the “Red Stapler” given for best in each track, culminating in a Best Of Conference award.

As if that wasn’t enough, the keynote speakers each year are amazing! This year, Kimberly Bryant of www.blackgirlscode.com was the first keynote. The community was so supportive of her organization’s work to bring computer science and code to young girls of color that people were donating money on the spot as she spoke, and tweeting it around to encourage others to keep the donations coming.

The final keynote was LeVar Burton. As the son of an educator, a Star Trek: The Next Generation actor, and Reading Rainbow creator, Mr. Burton is perfectly positioned to speak on the intersection of technology and education. He was funny, engaging, and accommodating. Plus he made everyone cry when talking about the important teachers in his life, and asked us to take a moment to reflect on ours. And kudos to the Reading Rainbow social media team, who were impressively following along with his talk and engaging via Twitter with the audience in real time.

This conference is mostly focused on implementers. It’s a conference of editors, designers, developers, admissions, and IT staff. This is a passionate group of people who want to do better by their schools via the school’s online presence, and I’m continually impressed by how creative the teams get within their limited resources (people, time and money). The smaller schools have the ability to be more nimble around internal politics and the lack of resources than larger institutions, but even the larger schools are making amazing things happen online.

Though this isn’t something that Palantir works in directly, schools and libraries are really getting savvy about social media. There were sessions on how schools were using Pinterest, the success around ways to text students (including admissions acceptances!), Snapchat (again . . . including admissions acceptances!), and more.

Schools are really looking about how to personalize and individualize the experience for students from a visual perspective, understanding that the younger generations are used to a personalized experience via Netflix, Spotify, and Amazon where recommendations can be made based on interests. Schools are responding to this by designing more around creating a “choose your own adventure” feel either through filtering majors and interests, or through messaging and branding in addition to social media.

I also learned a lot about the concerns that schools have in the areas of accessibility, crisis control, and rebuilding trust among faculty and administrators when past web projects either haven’t gone well, or due to internal power struggles over which content gets priority.

Between representing all the factions of a large organization, juggling the needs of multiple audiences, and having to keep up with the constantly changing workspace online, these small teams of web professionals have a lot to handle! And this annual meeting allows them to collaborate, learn from each other, compare notes, and celebrate their hard work.

Some Favorite Sessions

In addition to the Red Stapler winners, there were a lot of great sessions. Videos will be up on the schedule page eventually, but below are links to slides to some noteworthy ones:

My colleague Joe Allen-Black and I were able to give our presentation “Project Management: The Musical!” to this crowd as the last session on Monday. We added one more song since the last conference, and thankfully it all went smoothly without a full rehearsal! Considering the amounts of tweets there were related to the session and feedback we received in person, the attendees seemed to enjoy our musical take on how to get a project moving successfully from start to finish.

I learn so much from this conference every year about what the higher education community’s needs are for their online presence, what they are doing to solve those problems, and how we at Palantir can assist. HEW hosts regional conferences all over the country throughout the year, leading up to the big annual conference next October in Hartford, CT. I don’t yet know what my calendar holds for next year, but I look forward to being able to attend and see the great community of HEW often in 2017.

Stay connected with the latest news on web strategy, design, and development.

Sign up for our newsletter.
Catégories: Elsewhere

Chromatic: Responsive Images in Drupal 8 Using "srcset"

lun, 24/10/2016 - 17:26

There are a handful of tutorials out there that explain how to use Drupal 8's responsive image and breakpoint modules. However, from what I could find, none of them address how to instruct Drupal to output simple tags that leverage srcset instead of using the element. Using srcset can be preferable in many circumstances and as such, knowing how to use it in Drupal 8 will be good for most developers to understand. Since I was so confused on how to make this work, I thought it would be worth sharing.

Why srcset over ?

Others have done a much better job explaining the "why" of this approach, namely Chris Coyier and Jason Grigsby. Read those posts for the full picture (heh) but suffice to say, if you're only needing to change the resolution of an image at different viewport sizes/densities, you should use srcset instead of the element. If you need images that vary more specifically (i.e. different croppings, styles, etc.) then you should use the element. The reason srcset is preferred, is that it allows the browser to make informed decisions about which version of the image to serve, whereas the element explicitly tells the browser which images to use and when via media queries. Browsers know way more about our end users than we (developers) can ever know, so why not let them make the hard decisions?

In short:
  • Use srcset for different image sizes/densities across breakpoints.
  • Use when you need separate art direction/crops across breakpoints.
Convincing Drupal to Use srcset

Drupal's UI for responsive images is confusing and (maybe) rightfully so. Responsive images are confusing. As a rule, Drupal tries really hard to not make assumptions about what the user needs. While I understand why we (the Drupal community) built core this way, this can lead to interfaces that even seasoned professionals have a hard time understanding. In this case, it wasn't clear to me how (or if) I could instruct Drupal that I just wanted an element with srcset and sizes, not a full element. Each method I tried produced a element.

After some digging, I found the core issue where this development and discussion occurred. After skimming that thread and poking around the accepted patch, I knew that what I wanted was possible, but I still couldn't grok how to configure things in Drupal to get the desired output.

Further digging revealed that the default template responsible is called: responsive-image.html.twig. Here is the full file that ships with the Stable base theme:

{# /** * @file * Theme override of a responsive image. * * Available variables: * - sources: The attributes of the tags for this tag. * - img_element: The controlling image, with the fallback image in srcset. * - output_image_tag: Whether or not to output an tag instead of a * tag. * * @see template_preprocess() * @see template_preprocess_responsive_image() */ #} {% if output_image_tag %} {{ img_element }} {% else %} {% if sources %} {# Internet Explorer 9 doesn't recognise source elements that are wrapped in picture tags. See http://scottjehl.github.io/picturefill/#ie9 #} {% for source_attributes in sources %} {% endfor %} {% endif %} {# The controlling image, with the fallback image in srcset. #} {{ img_element }} {% endif %}

The key in this template is the output_image_tag boolean. When true, the template renders an tag instead of the tag. Inline documentation within the responsive_image module's template_preprocess_responsive_image() function explains that this output_image_tag variable is true when:

There is only one source tag with an empty media attribute. This means we can output an image tag with the srcset attribute instead of a picture tag.

In this context, Drupal is basically saying: if the user hasn't setup multiple breakpoints for this style AND there isn't any specific media query attached. Or in other words, the user doesn't want the theme to determine the images served but wants to put that onus on the browser via srcset.

Solution

If your use-case is to of the "resolution-switching" variety, here is how you get the desired output (no picture element) within Drupal:

  1. Skip creating specific breakpoints in your theme, they aren't needed with this approach.
  2. Setup your different image styles at admin/config/media/image-styles. Usually something like, Author Small, Author Medium and Author Large.
  3. Create a responsive image style at admin/config/media/responsive-image-style. Make sure the Responsive Image module is enabled first.
  4. Ensure "Responsive Image" is selected for the "Breakpoint group".
  5. Choose a suitable "Fallback image style". Click "Save". The following screen is where the secret sauce is.
  6. Under the "1x Viewport Sizing []" fieldset, Select "Select multiple image styles and use the sizes attribute."
  7. Select each of Image styles you'd like to use.
  8. Adjust the Sizes value as needed. The default here 100vw is hard-coded for a good reason, it's a pretty sane default and works well in most situations. Customize this is you want even finer control. More on Sizes.
  9. Adjust your content type (or other entity) to use your new responsive image style either by altering the display formatter or handling programmatically.
  10. Verify results!

For a thorough explanation of how all of the bits of the Responsive Image module work, see the documentation at admin/help/responsive_image with the _Help module enabled._

You should see something like this for the output of that image field now (formatted for readability):

We now have an element with a srcset attribute containing paths to each of our image styles, a sizes attribute and a fallback src attribute which points to our fallback image style.

Now our browser will automatically determine which image to serve up based on the client's viewport size, pixel density, etc. Also, if the client's browser doesn't yet support srcset, it will simply fall back to the value set in the src attribute.

Armed with this knowledge, you can configure your Drupal sites to leverage the power of srcset and allow the browsers of the world to do the hard work of determining which image style to serve to your users.

Catégories: Elsewhere

Unimity Solutions Drupal Blog: Drupal Board Staff Mixer

lun, 24/10/2016 - 13:28

During our Board Retreat, the Staff Board mixer gave us a chance to meet the staff members and the staff members to meet the Board. The staff's commitment and involvement to the project is amazing and definitely needs a pat on the back!

Catégories: Elsewhere

OSTraining: Upload PDF, Excel, Word Files to Drupal Content

lun, 24/10/2016 - 12:17

An OSTraining member asked how he could attach files such as PDFs, Excel Documents, Word Documents to his content. 

There are many ways to do this in Drupal, but the easiest approach is to use the "File" field.

  • Login to your Drupal site.
  • Go to Structure > Content types.
  • You either add the field to an existing content type, or you can create a new one for specifically adding the files:
Catégories: Elsewhere

Liip: Drupal SearchAPI and result grouping

lun, 24/10/2016 - 09:17

In this blog post I will present how, in a recent e-Commerce project built on top of Drupal7 (the former version of the Drupal CMS), we make Drupal7, SearchAPI and Commerce play together to efficiently retrieve grouped results from Solr in SearchAPI, with no indexed data duplication.

We used the SearchAPI and the FacetAPI modules to build a search index for products, so far so good: available products and product-variations can be searched and filtered also by using a set of pre-defined facets. In a subsequent request, a new need arose from our project owner: provide a list of products where the results should include, in addition to the product details, a picture of one of the available product variations, while keep the ability to apply facets on products for the listing. Furthermore, the product variation picture displayed in the list must also match the filter applied by the user: this with the aim of not confusing users, and to provide a better user experience.

An example use case here is simple: allow users to get the list of available products and be able to filter them by the color/size/etc field of the available product variations, while displaying a picture of the available variations, and not a sample picture.

For the sake of simplicity and consistency with Drupal’s Commerce module terminology, I will use the term “Product” to refer to any product-variation, while the term “Model” will be used to refer to a product.

Solr Result Grouping

We decided to use Solr (the well-known, fast and efficient search engine built on top of the Apache Lucene library) as the backend of the eCommerce platform: the reason lies not only in its full-text search features, but also in the possibility to build a fast retrieval system for the huge number of products we were expecting to be available online.

To solve the request about the display of product models, facets and available products, I intended to use the feature offered by Solr called Result-Grouping as it seemed to be suitable for our case: Solr is able to return just a subset of results by grouping them given an “single value” field (previously indexed, of course). The Facets can then be configured to be computed from: the grouped set of results, the ungrouped items or just from the first result of each group.

Such handy feature of Solr can be used in combination with the SearchAPI module by installing the SearchAPI Grouping module. The module allows to return results grouped by a single-valued field, while keeping the building process of the facets on all the results matched by the query, this behavior is configurable.

That allowed us to:

  • group the available products by the referenced model and return just one model;
  • compute the attribute’s facets on the entire collection of available products;
  • reuse the data in the product index for multiple views based on different grouping settings.
Result Grouping in SearchAPI

Due to some limitations of the SearchAPI module and its query building components, such plan was not doable with the current configuration as it would require us to create a copy of the product index just to apply the specific Result Grouping feature for each view.

The reason is that the features implemented by the SearchAPI Grouping are implemented on top of the “Alterations and Processors” functions of SearchAPI. Those are a set of specific functions that can be configured and invoked both at indexing-time and at querying-time by the SearchAPI module. In particular Alterations allows to programmatically alter the contents sent to the underlying index, while the Processors code is executed when a search query is built, executed and the results returned.
Those functions can be defined and configured only per-index.

As visible in the following picture, the SearchAPI Grouping module configuration could be done solely in the Index configuration, but not per-query.

Image 1: SearchAPI configuration for the Grouping Processor.

As the SearchAPI Grouping module is implemented as a SearchAPI Processor (as it needs to be able to alter the query sent to Solr and to handle the returned results), it would force us to create a new index for each different configuration of the result grouping.

Such limitation requires to introduce a lot of (useless) data duplication in the index, with a consequent decrease of performance when products are saved and later indexed in multiple indexes.
In particular, the duplication is more evident as the changes performed by the Processor are merely an alteration of:

  1. the query sent to Solr;
  2. the handling of the raw data returned by Solr.

This shows that there would be no need to index multiple times the same data.

Since the the possibility to define per-query processor sounded really promising and such feature could be used extensively in the same project, a new module has been implemented and published on Drupal.org: the SearchAPI Extended Processors module. (thanks to SearchAPI’s maintainer, DrunkenMonkey, for the help and review :) ).

The Drupal SearchAPI Extended Processor

The new module allows to extend the standard SearchAPI behavior for Processors and lets admins configure the execution of SearchAPI Processors per query and not only per-index.

By using the new module, any index can now be used with multiple and different Processors configurations, no new indexes are needed, thus avoiding data duplication.

The new configuration is exposed, as visible in the following picture, while editing a SearchAPI view under “Advanced > Query options”.
The SearchAPI processors can be altered and re-defined for the given view, a checkbox allows to completely override the current index setting rather than providing additional processors.

Image 2: View’s “Query options” with the SearchAPI Extended Processors module.

 

Conclusion: the new SearchAPI Extended Processors module has now been used for a few months in a complex eCommerce project at Liip and allowed us to easily implement new search features without the need to create multiple and separated indexes.
We are able to index Products data in one single (and compact) Solr index, and use it with different grouping strategies to build both product listings, model listings and model-category navigation pages without duplicating any data.
Since all those listings leverages the Solr FilterQuery query parameter to filter the correct set of products to be displayed, Solr can make use of its internal set of caches and specifically the filterCache to speed up subsequent searches and facets. This aspect, in addition to the usage of only one index, allows caches to be shared among multiple listings, and that would not be possible if separate indexes were used.

For further information, questions or curiosity drop me a line, I will be happy to help you configuring Drupal SearchAPI and Solr for your needs.

Catégories: Elsewhere

Dewy: 7 Of The Biggest Challenges When Drupal Grows At Your Higher-Education Institution

lun, 24/10/2016 - 08:00
Your web team has empowered your higher-ed insitution's digital presence with Drupal, and everything is awesome. But over time issues will arise that could pose significant risks to your institution. These are the biggest challenges and how they can be managed.
Catégories: Elsewhere

Pages