Apr 18 2015
Apr 18

By default Search API (Drupal 7) reindexes a node when the node gets updated. But what if you want to reindex a node / an entity on demand or via some other hook i.e. outside of update cycle? Turned out it is a quite simple exercise. You just need to execute this function call whenever you want to reindex a node / an entity:

  1. search_api_track_item_change('node', array($nid));

See this snippet at dropbucket: http://dropbucket.org/node/1600 search_api_track_item_change marks the items with the specified IDs as "dirty", i.e., as needing to be reindexed. You need to supply this function with two arguments: entity_type ('node' in our example) and an array of entity_ids you want to be reindexed. Once you've done this, Search API will take care of the rest as if you've just updated your node / entity. Additional tip: In some cases, it's worth to clear field_cache for an entity before sending it to reindex:

  1. // Clear field cache for the node.

  2. cache_clear_all('field:node:' . $nid, 'cache_field');

  3. // Reindex the node.

  4. search_api_track_item_change('node', array($nid));

This is the case, when you manually save / update entity values via sql queries and then want to reindex the result (for example, radioactivity module doesn't save / update a node, it directly manipulates data is sql tables). That way you'll ensure that search_api reindexes fresh node / entity and not the cached one.

Apr 18 2015
Apr 18

I had a case recently, where I needed to add custom data to the node display and wanted this data to behave like a field, however the data itself didn't belong to a field. By "behaving like a field" I mean you can that field at node display settings and able to control it's visibility, label and weight by dragging and dropping that field. So, as you may have undestood, hook_preprocess_node / node_view_alter approach alone wasn't enough. But we do Drupal right? Then there should be a clever way to do what we want and it is here: hook_field_extra_fields() comes for help! hook_field_extra_fields() (docs: https://api.drupal.org/api/drupal/modules!field!field.api.php/function/hook_field_extra_fields/7) exposes "pseudo-field" components on fieldable entities. Neat! Here's how it works, let's say we want to expose a welcoming text message as a field for a node, here's how we do that:

  1. /**

  2. * Implements MODULE_NAME_field_extra_fields().

  3. */

  4. function hook_field_extra_fields() {

  5. $extra['node']['article']['display']['welcome_message'] = array(

  6. 'label' => t('Welcome message'),

  7. 'description' => t('A welcome message'),

  8. 'weight' => 0,

  9. );

  10. return $extra;

  11. }

As you see in example above, we used hook_field_extra_fields() to define an extra field for an enity type of 'node' and 'article' bundle (content type). You can actually choose any other type of entity that's available on your system (think user, taxonomy_term, profile2, etc). Now if you'll clear your cache and go to display settings for Node -> Article you should see 'A welcome message' field available. Ok the last bit is to actually force our "extra" field to output some data, we do this in hook_node_view:

  1. /**

  2. * Implements hook_node_view().

  3. */

  4. function MODULE_NAME_node_view($node, $view_mode, $langcode) {

  5. // Only show the field for node of article type

  6. if ($node->type == 'article') {

  7. $node->content['welcome_message'] = array(

  8. '#markup' => 'Hello and welcome to our Drupal site!',

  9. );

  10. }

  11. }

That should be all. Now you should see a welcome message on your node oage. Please note, if you're adding an extra field to another entity type (like, taxonomy_term for example), you should do the last bit in this entity's _view() hook.

UPDATE: I put code snippets for this tutorial at dropbucket.org here: http://dropbucket.org/node/1398

Apr 18 2015
Apr 18

I'm a big fan of fighting with Drupal's inefficiencies and bottlenecks. Most of these come from contrib modules. Everytime we install a contrib module we should be ready for surprises which come on board with the module.

One of the latest examples is Menu item visibility (https://drupal.org/project/menu_item_visibility) that turned out to be a big trouble maker on one of my client's sites. Menu item visibility is a simple module that let's you define link visibility based on a user's role. Simple and innocent... until you look under the hood.

The thing is Menu item visibility stores it's data in database and does a query per every menu item on the page. In my case it produced around 30 queries per page and 600 queries on menu/cache rebuild (which normally equals to the number of menu items you have in your system).

The functionality that this module gives to an end user is good and useful (according to drupal.org: 6,181 sites currently report using this module) but as you see, storing these settings in db can become a huge bottleneck for your site. I looked at the Menu item visibility source and came to this "in code" solutions that fully replicates the module functionality but stores data in code.

Step 1.

Create a custom module and call it like Better menu item visibility., machine name: better_menu_item_visibility.

Step 2.

Let's add the first function that holds our menu link item id (mlid) and role id (rid) data:

  1. /**

  2. * This function returns a list of mlid's with a list of roles that have access to link items.

  3. * You can change the list to add new menu items or/and roles

  4. * The list is presented in a format:

  5. * 'mlid' => array('role_id', 'role_id),

  6. */

  7. function better_menu_item_visibility_menu_item_visibility_role_data() {

  8. return array(

  9. '15' => array('1', '2'),

  10. '321' => array('1'),

  11. '593' => array('3'),

  12. // Add as many combinations as you want.

  13. );

  14. }

This function returns an array with menu link item ids and roles that can access the item. If you already have Menu item visibility installed, you can easily port the data from the db table {menu_links_visibility_role} into this function.

Step 3.

And now let's do the dirty job and process the menu items:

  1. /**

  2. * Implements hook_translated_menu_link_alter().

  3. */

  4. function better_menu_item_visibility_translated_menu_link_alter(&$item, $map) {

  5. if (!empty($item['access'])) {

  6. global $user;

  7. // Menu administrators can see all links.

  8. if ($user->uid == '1' || (strpos(current_path(), 'admin/structure/menu/manage/' . $item['menu_name']) === 0 && user_access('administer menu'))) {

  9. return;

  10. }

  11. $visibility_items_for_roles = better_menu_item_visibility_menu_item_visibility_role_data();

  12. if (!empty($visibility_items_for_roles[$item['mlid']]) && !array_intersect($visibility_items_for_roles[$item['mlid']], array_keys($user->roles))) {

  13. $item['access'] = FALSE;

  14. }

  15. }

  16. }

In short this function skips access check for user 1 and for user that has 'administer menu' permission and does the access check for link menu items listed in better_menu_item_visibility_menu_item_visibility_role_data. As you see, instead of calling database it gets data from the code which is really fast. Let me know what you think and share your ways of fighting with Drupal's inefficiencies.

Apr 18 2015
Apr 18

Drupal Views offers us a cool feature: ajaxified pagers. When you click on a pager, it changes the page without reloading the main page itself and then scrolls to the top of the view. It works great, but sometimes you may encounter a problem: if you have a fixed header on your page (the one that stays on top when you scroll the page) it will overlap with the top of your view container thus scroll to top won't work preciselly correct and the header will cover the top part of your view.

I've just encountered that problem and making a note here for the future myself and, probably yourself, about how I solved this problem. If you'll look into the views internal, you'll see it uses internal Drupal JS Framework command called viewsScrollTop that's responsible for scrolling to the top of the container. What we need here is to override this command to add some offset to the top of our view.

1. Overriding JS Command

Thankfully, Views is flexible enough and provides hook_views_ajax_data_alter() so we can alter js data and commands before they got sent to the browser, let's overwrite viewsScrollTop command with our own. In your custom module put something like this:

  1. /**

  2. * This hook allows to alter the commands which are used on a views ajax

  3. * request.

  4. *

  5. * @param $commands

  6. * An array of ajax commands

  7. * @param $view view

  8. * The view which is requested.

  9. */

  10. function MODULE_NAME_views_ajax_data_alter(&$commands, $view) {

  11. // Replace Views' method for scrolling to the top of the element with your

  12. // custom scrolling method.

  13. foreach ($commands as &$command) {

  14. if ($command['command'] == 'viewsScrollTop') {

  15. $command['command'] = 'customViewsScrollTop';

  16. }

  17. }

  18. }

Now, everytime Views emits viewsScrollTop command, we replace it with our own custom one customViewsScrollTop.

2. Creating custom JS command

Ok, custom command is just a JS function attached to Drupal global object, let's create a js file and put it into it:

  1. (function ($) {

  2. Drupal.ajax.prototype.commands.customViewsScrollTop = function (ajax, response, status) {

  3. // Scroll to the top of the view. This will allow users

  4. // to browse newly loaded content after e.g. clicking a pager

  5. // link.

  6. var offset = $(response.selector).offset();

  7. // We can't guarantee that the scrollable object should be

  8. // the body, as the view could be embedded in something

  9. // more complex such as a modal popup. Recurse up the DOM

  10. // and scroll the first element that has a non-zero top.

  11. var scrollTarget = response.selector;

  12. while ($(scrollTarget).scrollTop() == 0 && $(scrollTarget).parent()) {

  13. scrollTarget = $(scrollTarget).parent();

  14. }

  15. var header_height = 90;

  16. // Only scroll upward

  17. if (offset.top - header_height < $(scrollTarget).scrollTop()) {

  18. $(scrollTarget).animate({scrollTop: (offset.top - header_height)}, 500);

  19. }

  20. };

  21. })(jQuery);

As you may see, I just copied the standard Drupal.ajax.prototype.commands.viewsScrollTop function and added header_height variable that equals to the offset/fixed header height. You may play with this value and set it according to your own taste. Note the name of the function Drupal.ajax.prototype.commands.customViewsScrollTop, the last part should match your custom command name. Save the file in your custom module dir, in my case it's: custom_views_scroll.js

3. Attaching JS to the view

There are multiple ways to do it, let's go with with the simplest one, to your custom_module.info file add scripts[] = js/custom_views_scroll.js and clear caches, that'll make this file to be autoloaded on every page load. That's all, since now, your views ajax page scrolls should be powered by your customViewsScrollTop instead of stock viewsScrollTop, see the difference?

Apr 18 2015
Apr 18

If you have a fieldgroup in a node, you may want to hide it on some conditions. Here's how to do that programmatically. At first, we need to preprocess our node like this:

  1. /**

  2. * Implements hook_preprocess_HOOK().

  3. */

  4. function MODULE_NAME_preprocess_node(&$variables) {

  5. }

The tricky part starts here, if you'll google for "hide a fieldgroup" you'll get lots of results referencing a usage of field_group_hide_field_groups() like this snippet: http://dropbucket.org/node/130.

While this function perfectly works on forms it is useless if you apply it in hook_preprocess_node() (at least I couldn't make it work). The problem is fieldgroup uses 'field_group_build_pre_render' function that is get called at the end of the preprocessing call and populates your $variables['content'] with a field group and its children, so you can't alter this in hook_preprocess_node(). But as always in Drupal there's a workaround. At first let's define some simple logic in our preprocess_node() to determine if we want to hide a field group:

  1. /**

  2. * Implements hook_preprocess_HOOK().

  3. */

  4. function MODULE_NAME_preprocess_node(&$variables) {

  5. if ($variables['uid'] != 1) {

  6. // You can call this variable any way you want, just put it into $variables['element'] and set as TRUE.

  7. $variables['element']['hide_admin_field_group'] = TRUE;

  8. }

  9. }

Ok, so if user's id is not 1 we want to hide some fantasy 'admin_field_group'. We define logic here and pass result into elements array that is to be used later. As I previously noted, field group uses 'field_group_build_pre_render' to combine fields into a group, so we just need to alter this call in our module:

  1. /**

  2. * Hide admin field group on a node display.

  3. */

  4. function MODULE_NAME_field_group_build_pre_render_alter(&$element) {

  5. if (isset($element['hide_admin_field_group']) && isset($element['hide_admin_field_group'])) {

  6. $element['hide_admin_field_group']['#access'] = FALSE;

  7. }

  8. }

We made a check for our condition and if it is met, we set field group's access to FALSE that means: hide the field group. So now you should have a field group hidden on your node display. Of course, this example is the simplest case, you may add dependencies on node view_mode, content type and other conditions, so sky is the limit here. You can find and copy this snippet at dropbucket: http://dropbucket.org/node/927 I wonder, if you have another way of doing this?

Apr 18 2015
Apr 18

This screencast shows how you can use a cloud provider like Digital Ocean to install a working copy of ELMSLN by copying and pasting the following line into the terminal:

yes | yum -y install git && git clone https://github.com/btopro/elmsln.git /var/www/elmsln && bash /var/www/elmsln/scripts/install/handsfree/centos/centos-install.sh elmsln ln elmsln.dev http [email protected] yes

Obviously, this is for development purposes only at this time, but I hope it shows you a glimpse of the level of automation we are getting to and where you could easily take this in the future. We already have a Jenkins instance on campus that can perform these same operations against any new server after doing some manual (ew) SSH hand shakes and user account creation.

I pause in the video to let the installer run through but still, that's all it takes to get it up and going; copy and paste into a new CentOS 6.5 box and hanging out for a few minutes. While you wait you can modify your local /etc/hosts file to point to the address (which the command will print what to copy and paste where at the end).

This will eventually replace the current Vagrant install routine so that we're using the same exact one in what we recommend for blank servers, for travis builds, for vagrant and beyond. If you need more help with setting up ssh keys and using the digital ocean interface, some tutorials are linked to below.

Note: This is not an endorsement of Digital Ocean and they are simply included in this article because I've been messing around with their service for testing purposes.

Apr 18 2015
Apr 18

Welcome to the new Drupal @ PSU!

We hope you enjoy the site so much that we want you to have it. No really, go ahead, take it. Steal this site. We did, and we’re proud of that fact. This site is actually a fork of the Office of Digital Learning’s new site that just launched recently.

How did we steal this? Using backup and migrate and having access to the source for the theme, we were able to spin the ODL site up at a new location. From there, we used Drush Recipes to further optimize the site for SEO and performance. Then using Node Export to get a few default pieces of content migrated, Default Config + Features for all the exportables and profiler builder to author the install routine, we have the same site as before but sanitized and fully released to the public (including ourselves)!

This post isn’t just to brag about open sourcing a site though, it’s about how you can now spin this site up really fast (or any other) in PSU DUG’s Nittany Vagrant project. Nittany Vagrant has a few goals that make it unique compared to other Vagrant offerings:

We want to boil our jobs down to answering questions

We all run almost the same series of commands to get started. Drush dl views, ctools, features, admin_menu, jquery_update, etc. So instead of all that, we wanted to come up with a method of helping to standardize site builds to put newbees on the same playing field as long time developers. This has always been a driving force behind the Nittany distribution, but now we’re taking it a step further. Instead of having a traditional install profile, we have a server and site build process that try to get at what you are looking to accomplish.

Right now it asks if you are doing front end development, if you need SEO tools, if you want the base line we recommend, and it even gives you the option of starting your new site build out from the Publicize distribution, drupal from a repo (which could be an install profile at that point) or by ssh binding to a server and pulling it down to work on locally!

We want mirror a RHEL based environment

Most setups you see are Ubuntu / Debian based. That’s great except most of higher education has standardized development on RHEL for long term stability and support (RHEL supports packages for like 20 years or something). Nittany Vagrant is built on top of CentOS 6.5, which is about as similar as you’ll get without paying money.

We wanted a small, clean Vagrant routine

We’ve been burned before by Chef and provisioning scripts in Vagrant. We end up using Chef for Vagrant management and then managing Chef and its cookbooks more then just fixing the small issues that prop up. This time around we wanted to use something as simple as possible for everyone in our community to be able to jump in and help so we stuck with bash, drush and drush recipes to do all the heavy lifting.

It’s already helping get other people involved as we have 6 members of the local PSU DUG community now with commits to the Nittany-Vagrant repo where in the past it was always 1 or 2.

Show me

Here’s a video I recorded showing the current state of Nittany Vagrant as of this writing and what you can do with it now just by answering questions. This is only the begininig though as we want to get into site provisioning and replication, as well as the ability to move this entire process from vagrant to being applied to remote servers (which has already been shown to work on Digital Ocean).

Apr 18 2015
Apr 18

The year is 2020.

We’ve managed, through automated testing, Travis CI, Jenkins CI and crontabs; to completely eliminate downtime and maintenance windows while at the same time increasing security and reducing strain on sys admins. There are very few “sys admins” in the traditional sense. We are all sys admins through Vagrant, docker, and virtualization. We increasingly care less about how scripts work and more about the fact that they do, and that machines have given us feedback ensuring their security. They don’t hope our code is insecure, they assume that it is and instead treat every line authored by a human as insecure.

We’ve managed to overcome humanity’s mountains of proprietary vendors, replacing their code and control with our own big ideas, acted upon by which helps build the tools we need for us. We have begun to bridge the digital divide on the internet, not through training, but by refusing to be solely driven by financial gains.

We are open source. And we are a driving force that will bring about the Singularity (if you believe in such a thing). So we did it gang, it took awhile but wow, we do almost nothing and we’ll always be employed because we know how the button or the one-line script works. Congrats! Time to play Legos and chew bubble gum right?

Or is this just some far off, insane utopia that developers talk about over wine in “The valley”.

This vision of the future, 5 years out, isn’t as crazy as it might sound if you see the arch of humanity. In fact, I actually believe we’ll start to get to that point closer to 2018 in my own work and at a scale 1000s of times beyond what was previously thought possible. This is because of the convergence of several technologies as well as the stabilization of many platforms we’ve been building for some time; yes, all that work we’ve been doing, releasing to Github, drupal.org, and beyond… it’s now just infrastructure.

Today’s innovation is tomorrow’s infrastructure and this becomes the assumed playing field by which new ideas stand on. Take Drupal’s old slogan for instance, Community Plumbing. That thing we all paid for significantly at one time, but now just take for granted; that thing is becoming even more powerful then any of us could have imagined.

So, enough platitudes. (ok maybe just one more)

“Roads… Where we’re going we don’t need road.”

This next series of posts that will start to roll out here are things I’d normally save for presentations, war gaming sessions and late night ramblings with trusted colleagues. I’m done talking about the future in whispers; it’s time to share where we’re going by looking at all the roads and how they’ll converge. After all, the future of humanity demands it.

If you haven’t seen the video “Humans need not apply” then I suggest you watch it now and think. What can I do to help further bring about the end of humanity… Ok wait, not that, that’s too dark. Let’s try again…

What can I do and what do I invest in knowledge wise to help be on the side developing the machines instead of the side automated into mass extinction (career wise).

Hm… still pretty dark? No no, that’s pretty spot on. What job are you be working towards today so that 5 years from now you are still relevant? I hope that the videos to be released in the coming days provide a vision of where we’re heading (collectively) as well as some things to start to think about in your own job.

What are you doing right now that can change the world if only you spoke of it in those terms?

Apr 18 2015
Apr 18

Whenever there is a constraint on the number of developers in a pool, it can make it more difficult to solve issues. As we have been developing Nittany-Vagrant, I have found that there is definitely a smaller pool of developers running on a Microsoft Windows host for their vagrant based virtual machines.

The extra credit problem of the day for me was how to allow vagrant to automatically size a virtual machine's memory pool when utilizing VirtualBox as the VM provider on Windows. This is a well known solution on OSX:

`sysctl -n hw.memsize`.to_i / 1024 / 1024 / 4

However, it took a bit of digging to figure out a way that could be reliably reproduced for the folks that are using our Nittany-Vagrant tool on Windows hosts.

Standard with Microsoft Windows is a command line interface to the Windows Management Interface (WMI) called WMIC. WMIC has a component that allows you to read/edit system information. In particular:

wmic os get TotalVisibleMemorySize

will pull the total memory that is available to Windows. However, this also produces a number of headers that we don't want. We can then use grep to pull a line that starts with digits:

grep '^[0-9]'

Use Ruby to cast it as an int (just to be sure):

.to_i

and then divide it by 1024 (to get MB instead of KB).

We then only want to use 1/4 of the RAM, so we divide it by 4 and slap it into the vm memory size customization:

v.customize ["modifyvm", :id, "--memory", mem]

That's it! That's all... but there were a few other catches that made this ... less intuitive than one would hope.

  1. grep doesn't exist on Windows systems. However, if you install git-scm for windows, it installs a number of GNU like tools including ssh and grep. If you ensure that these (located in "C:\Program Files (x86)\Git\bin") are on your path, you get grep. The easiest way to make sure this happens is to select the third option "Use GIT and optional Unix tools from the Windows Command Prompt" when installing git-scm. Winner.
  2. determining your host...
    RbConfig::CONFIG['host_os']
    
  3. will report what your host operating system is... kind of ... With git-scm installed, it reports as "mingw32". With this, you can specify the command to run to retrieve the memory size based upon what OS is being reported. This is more trial and error than it probably should be, however, it does work. If necessary, use:
    puts RbConfig::CONFIG['host_os']
    
    to be able to determine what your OS is reporting so you can branch appropriately in your Vagrantfile.

This leaves us with:

if host =~ /mingw32/
              mem = `wmic os get TotalVisibleMemorySize | grep '^[0-9]'`.to_i / 1024 / 4
              if mem < 1024
                mem = 1024
              end
end
v.customize ["modifyvm", :id, "--memory", mem]

Hopefully, that helps some independent windows based developer out there... Cheers, +A

Header image - Vagrant - courtesy of mike krzeszak Creative Commons 2.0

Apr 17 2015
Apr 17

In this episode we cover an overview of the Drupal 7 Views module. The Drupal Views module is probably the most popular Drupal module and is installed in almost every Drupal 7 website I build. It’s so popular in fact that it’s included in Drupal 8 by default.

The Views module allows you to easily build and format lists of content on your Drupal 7 site. If you need to build a simple list of Nodes, Views can do that. If you need to build a table listing, Views can do that too. In this video, we will go through an introduction and overview of Views, as well as a few example views. You will learn about the different types of content you can display with Views, different display settings, and other Views options.

This video is built to be an introduction for beginners and newcomers to Drupal to teach the basics of the Drupal 7 Views module. In this video you will create two views. The first will be a page view that displays a list of articles on your Drupal website. The second will be a block view that shows the titles of the last three articles on your Drupal website. Using the skills you learn in this video, you will be ready to tackle more complicated problems that can be solved with views.

Apr 17 2015
Apr 17

The overall aim was to create a site that allowed BHoF to tell compelling narratives about the vast number of artifacts in their collection.

By providing meaningful connections between different objects and stories, they hoped to increase user engagement and encourage a deeper journey through the site -- and hoped to inspire more people to visit the Hall of Fame itself as well.

Digital Asset Management System (DAMS)

The BHoF has a very large archive, and is currently in the profess of digitizing it. Part of the brief for this project was to provide a Digital Asset Management System (DAMS) for long-term storage of these digitized assets.

After some investigation, the DAMS BHoF and Cogapp selected was Islandora. This combines Fedora Repository -- a best-of-breed digital object store -- with a management interface that is fully integrated into Drupal. Using Islandora allows the BHoF to administrate digital assets and web content from within the system, and stores those assets according to archival best practices.

Islandora gives the National Baseball Hall of Fame and Museum the opportunity to store and publish over 100 years of history in images.

Deliver content (Paragraphs)

With such a vast amount of content, BHoF needed a less conventional way to capture and present their pages. A typical approach would have involved numerous different content types and fields, with large amounts of body content entered to a WYSIWYG editor. Cogapp instead chose to use Paragraphs, another great contrib module that provides a better way to deliver content.

What this enabled us to do was create pages that can be built up out of a variety of smaller structures (the paragraph types or *bundles*), each of which has a predefined set of fields. For example, a page might be built out of a mixture of paragraphs containing generic items like text and images, as well as more particular items like a Hall of Fame inductee.

Building pages in this way gives them a freeform feel, but the data remains structured for full control over presentation. To this end, each paragraph item can use its own theming template, which is defined as paragraphs-item--PARAGRAPH-ITEM-NAME.tpl.php. More generally, all paragraphs are Drupal entities, so they can be administrated, manipulated, and presented using all the power that this allows. When constructing a page using paragraphs, users are presented with the option to add a paragraph of a particular type:

Paragraph of a particular type
This example shows instances of two paragraph types: a subtitle and a reference to a Hall of Famer's profile.

 a subtitle and a reference to a Hall of Famer's profile

In summary, the Paragraphs module offers us:

  • An extendable content area
  • The ability to add complex (but structured) content
  • Fully rearrangeable layout using drag-and-drop
  • Finer control over output than just using WYSIWYG

Reach content (Entity references)

Drupal has excellent content support, with associations between content defined using the entity reference module. By combining entity reference fields with paragraphs, we created a way to pull in content from inside paragraphs. This allows us to:

  • Reach content regardless of source (locally added images vs DAMS assets)
  • Support user onward journeys (reach other content)
  • Support social media sharing (assets and content)

A major advantage of our approach was the use of individual preprocessors for each content type. We used this to create a seamless experience on content viewing by our users. By individually preprocessing each content type we are able to:

  • Interchangeably use locally hosted images and DAMS assets:
    • As hero images
    • As sidebar images
    • As full size images on content
    • As slideshows
  • Have finer control on content (e.g. automatically generate an inline table of contents)
  • Create different Twitter cards based on content type
  • Integrate other sources of content from the CMS.

Present content (Entity view modes)

View modes provide entities with a mechanism to select which fields to display, and a way to display them, through templates. We use view modes to gain even finer control on HTML output on the referenced entities in much the same way we did with paragraph type templates. Drupal comes with two default view modes per content type, 'full mode' and 'teaser'. To add additional view modes we used hook_entity_info_alter.

View modes are administrated from the 'Manage Display' tab of a content type:

View modes

Each view mode:

  • Has its own display fields
  • Has its own template file
  • Applies its own mode-specific logic (e.g. for slideshows, full images, etc)
  • Allows front-end work with templates rather than the Drupal theming system.

Engage users (Extra fields)

The ability to share pages over social media with Drupal is straightforward, and there are several proven modules for doing this. In this case, however, we had slightly different requirements.

We wanted to engage users and facilitate discussions through social media integration. When a user is visiting a page in BHoF she is not just viewing a single item: she is reading text, seeing images that may be coming from the DAMS, interacting with slideshows, viewing Hall of Famers' profiles, and so on.

We wanted to provide a way to share a page as well as any other asset that was appearing in that page. Our approach was to use <a href="https://api.drupal.org/api/drupal/modules!field!field.api.php/function/hook_field_extra_fields/7">hook_field_extra_fields</a> to add extra (pseudo) fields. Next, hook_node_view is used to create the logic within each extra field. In this scenario, each extra field contains a social media share link (e.g. https://developers.facebook.com/docs/plugins/share-button).

Extra fields act as any other field in a entity with its own display settings. This allowed us to re-use our previous approach, making share links available through view mode templates, for each individual item. Also, preprocessing each content type made it possible to provide relevant information on different twitter cards depending on the asset being shared (e.g. twitter card large image or article).

Apr 17 2015
Apr 17

Angie Byron is Director of Community Development at Acquia. For this interview, during the final day of DrupalCon Amsterdam, we were able to find an empty auditorium. Alas, filming with my brand-new GoPro camera, we got off to a topsy-turvy start...

RONNIE RAY: I’ve had you upside down.

ANGIE BYRON: Oh hahaha!

I go by Angie Byron or webchick, and more people know me as webchick than Angie Byron.

Today, what I love to do at DrupalCons, on the last day of the sprint days, is just walk around all the tables and see what everyone is working on, cause there’s hundreds of people here and they’re all sort of scratching their own itches on everything from Drupal-dot-org to, like, what is the newest coolest content staging thing gonna be?, to how are we going to get Drupal 8 done?

And everybody working together and collaborating with people they don’t get to see all the time, it’s a lot of fun for me.

I feel like we made a lot of really great decisions about the Drupal 8 release management stuff here that we’ll be able to put into practice, and help try and focus efforts on getting the critical issues resolved, trying to clean up the loose ends that we still have, and getting the release out the door faster.

And the other thing I’m going to work on for the next month is something called Drupal Module Upgrader, which is the script that can help contrib modules port their modules to Drupal 8. It automates a lot of that task.

Now that Beta is here it’s a great time for people to update their modules, so I want to work on tools to help facilitate that.

RR: What are you reading, besides books on Drupal?

AB: Not much. Although I love reading kids books, because I have a daughter who’s 16 months now and she loves to be read to. So my latest books I’ve been reading are Where is the Green Sheep? and Go, Dog, Go! and a bunch of Richard Scarry stuff and things like that because she loves to know what everything’s called. She loves books.

There’s a Dr. Seuss book called Oh, The Places You’ll Go! That book is dark, man, that is like a dark book. It’s entertaining. I remember it from when I was a kid but I don’t remember it like that!

RR: Music?

AB: I listen to a lot of old music cause I’m one of those curmudgeonly people who thinks the best music was already made. So, like I’ve been having like a ‘70s rock, ‘80s pop, ‘90s punk rock, like – that’s sort of what’s in my chain all the time. Hair metal, junk like that. How to relive my kid-age stuff.

I think the community has grown to such an enormous size now that I guess one thing I wonder about, – not really worry about– but am curious about, is if can we still maintain that small-knit community feel that we had back when I started, when we were 70 people at a DrupalCon – not the 2,500 people we have now.

It’s cool to kind of walk around DrupalCon, especially on a sprint day, especially because I feel we have retained that – and people are finding people to connect with and cool things to work on and stuff like that.

I think it’s something we all need to collectively be intentional about is, you know, it’s not just enough that Drupal is just a great software project, it’s also about the people and trying to maintain that welcome feeling – that got us all in the door – for generations to come.

So that’s something I would leave as a parting note.

Apr 17 2015
Apr 17

This session was presented at Bay Area Drupal Camp, San Diego Drupal Camp, Phoenix Drupal Camp, and Stanford Drupal Camp.

Have you written a few simple modules for Drupal 7, and are a little bit nervous to find out the changes you'll be facing in Drupal 8?

Latest slides can be seen at: mrf.github.io/drupal8modules

Working code samples are at: github.com/mrf/drupal8examples

The topics covered should be easily understood by anyone who is comfortable writing PHP. If you are still learning the basics of writing modules things might move a bit too quickly, but you should come anyway! I'll be covering the concepts introduced to the Drupal world via Drupal 8 that you will be using most frequently. The focus will be on what you NEED to know to write functional modules. I'll do my best to stay away from the cool possibilities and elegant architecture that we get with Drupal 8, but sometimes the excitement is too much for me to handle. Following a quick review of object oriented basics to get our bearings I will dive into an overview of: Configuration Management, Routes, Permissions, Annotations and Plugins. Lets upgrade our brains so we can feel comfortable writing simple Drupal 8 modules from scratch.

Pull requests welcome!

Apr 17 2015
Apr 17

Recently we had the task of loading data from a content type with 350 fields. Each node is a University’s enrollment data for one year by major, gender, minority, and a number of other categories. CSV exports of this data obviously became problematic. Even before we got to 350 fields, with the overhead of the Views module we would hit PHP timeouts when exporting all the nodes. If you’re not familiar with Drupal's database structure, each field’s data is stored in a table named ‘field_data_FIELDNAME’. Loading an entire node means JOINing the node table by entity_id with each related field table. When a node only has a handful of fields, those JOINs work fine, but at 350 fields the query runs slow.

On this site we’re also plotting some of the data using highcharts.js. We really hit a wall when trying to generate aggregate data to plot alongside a single university's. This meant loading every node of this content type to calculate the averages, which turned our slow query into a very slow query. We even hit a limit on the number of database JOINs that can be done at one time.

In retrospect this is a perfect case for a custom entity, but we already had thousands of nodes in the existing content type. Migrating them and implementing a custom entity was no longer a good use of time. Instead, we added a custom table that keeps all the single value fields in a serialized string.

The table gets defined with a hook_schema in our module's .install file:

function ncwit_charts_schema() {
 
  $schema['ncwit_charts_inst_data'] = array(
    'description' => 'Table for serialized institution data.',
    'fields' => array(
      'nid' => array(
        'type' => 'int',
        'default' => 0,
        'not null' => TRUE,
        'description' => 'node id for this row',
      ),
      'tid' => array(
        'type' => 'int',
        'default' => 0,
        'not null' => TRUE,
        'description' => 'intitution term id that this data belongs to',
      ),
      'year' => array(
        'type' => 'int',
        'default' => 0,
        'not null' => TRUE,
        'description' => 'school year for this node',
      ),
      'data' => array(
        'type' => 'blob',
        'not null' => FALSE,
        'size' => 'big',
        'serialize' => TRUE,
        'description' => 'A serialized array of name value pairs that store the field data for a survey data node.',
      ),
    ),
    'primary key' => array('nid'),
  );
 
  return $schema;
}

The most important part of the array is 'data' with type 'blob', which can be up to 65kB. Not shown is another array to create a table for our aggregate data.

When a new node is saved hook_node_insert() is invoked. hook_node_update() fires both when a new node is saved and when it's updated.

/**
 *  Implements hook_node_insert().
 *  save serialized field data to inst_data table for a new node
 *  For a new node, have to use this
 */
function ncwit_charts_node_insert($node) {
  ncwit_charts_serialize_save($node);
}
 
 
/**
 *  Implements hook_node_update().
 *  save serialized field data to inst_data table
 */
function ncwit_charts_node_update($node) {
  if (isset($node->nid)) {
    // we're also calling this function from hook_node_insert
    // because hook_node_update doesn't have the nid if is a new node
    ncwit_charts_serialize_save($node);
  }
  else {
    return;
  }
}

Now we actually process the fields to be serialized and store. This section will vary greatly depending on your fields.

function ncwit_charts_serialize_save($node) {
  // save each value as a simple key => value item
  foreach ($node as $key => $value) {
    $data[$key] = $value[LANGUAGE_NONE][0]['value'];
  }
 
  $fields = array();
  $fields['nid'] = $node->nid;
  $fields['tid'] = $node->field_institution_term[LANGUAGE_NONE][0]['tid'];
  $fields['year'] = $node->field_school_year[LANGUAGE_NONE][0]['value'];
  $fields['data'] = serialize($data);
 
  db_merge('ncwit_charts_inst_data')
    ->key(array(
      'nid' => $node->nid,
    ))
    ->fields($fields)
    ->execute();

When a node is deleted we have some clean-up to do.

/**
 *  Implements hook_node_delete().
 *  Also remove node's data from inst_data
 */
function ncwit_charts_node_delete($node) {
  if ($node->type !== 'data_survey') {
    //only care about data_survey nodes
    return;
  }
 
  $query = db_select('ncwit_charts_inst_data', 'i');
  $query->fields('i')->condition('i.nid', $node->nid);
  $result = $query->execute();
  $data = $result->fetchAssoc();
  if ($data > 0) {
    db_delete('ncwit_charts_inst_data')->condition('nid', $node->nid)->execute();
  }
}

When first installed or when fields get changed, we added a batch process that re-saves the serialized strings. Aggregate data is calculated during cron and saved in another table. Rather than loading every node with JOINs, the data comes from a simple query of this custom table.

Pulling the data out of the database and calling unserialize() gives us a simple associative array of the data. To pass this data to highcharts.js we have a callback defined that returns the arrays encoded as JSON. Obviously this gets more complicated when dealing with multiple languages or multi-value fields. But in our case almost everything is a simple integer.

This process of caching our nodes as serialized data changed our loading speed from painfully slow to almost instant. If you run into similar challenges, hopefully this approach will help you too.

Apr 17 2015
Apr 17

Why should I mix .Net and PHP?

The PHP ecosystem is half broken. Bad coded snippets, lack of enterprise level libraries. The big base of PHP developers are amateurs with no real software background. Yet sometimes users and companies are driven by market forces to use some PHP based software such as Drupal, Wordpress, etc. But PHP has been a long way since what it was at the start of the 2000's and has now almost any feature you would expect from a modern programming language (sort of). There are also productivity oriented development tools like Visual Studio integration (PHP Tools) and more and more tools are coming into the market that have boosted the developing on PHP productivity. Automated testing, continuous integration, package distribution, and many other features have been consolidating over the last few years.

Being able to consume .Net code allows you not to get stuck by all of the half-baked PHP ecosystem. Whenever you need an enterprise level library (PDF generation, Word and Excel manipulation, etc.) that is only available in .Net it can be used seamlesly. You can even enjoy faster development by using enterprise level development tools such as Visual Studio or more solid software by moving part of your code to the .Net framework.

Understanding how it works

The NetPhp libraries are split into two main components:

Historically, consuming .Net assemblies from PHP is done by means of the com_dotnet extension (included in PHP core). The problem of using the extension as-is is that it is there are a big number of issues and rigidity when consuming your assemblies. For example, you are limited to using .Net 3.5 or lower compiled assemblies, and any binary you want to consume need to be decorated as COM Visible (so you need to recompile and interface anything you plan to use).

With NetPhp all those restrictions have been overcome, allowing you to consume any type of compiled .Net library (no mater what framework version) giving flexibility as to how is the type loaded where you can even specify the exact location of the dynamic link library to get it loaded real time.

The NetPhp classes use the com_dotnet php extension to instantiate some classes inside the compiled NetPhp binary that allow us to interact with any .Net library. You can even mix .Net runtime versions in the same process.

How to install the NetPhp binary

The NetPhp binary is a COM Visible dynamic link library (.dll) that you must register (system wide) as a COM object. To do so, use the regasm tool. You can register a COM object with regasm and there is no need (but you could) to bind it to a specific file in your file system.

The regasm tool is bundled with the .Net framework and you will find a copy in the location:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe

I recommend the following steps to register the binary:

  • Copy the binary file to your PHP installation directory (where the php.exe and php-fastcgi.exe are located) such as c:\php\php5_6\netutilities.dll
  • Run a simple regasm command with no parameters "regasm 'c:\php\php5_6\netutilities.dll'" (remeber to use an elevated command prompt)

To ensure that the type has been properly installed use OleView (comes with the Windows SDK included with Visual Studio) just type "oleview" in your Visual Studio Developer Console. You can download a copy of oleView (x86 and x64 at the end of this article).

Remember that Windows is split between x86 and x64. Because your are probably using the x86 version of PHP, you must register the assembly using the x86 version of regasm and you will only see it with the x86 version of OleView.

Once in OleView open the .Net category:

And look for the netutilities.* COM objects:

Configure your PHP application to use the NetPHP libraries

The next step is to bring the NetPhp php library into your PHP project. 

The library is available on Github and there is a composer package for it.

You can download the files directly from Github and drop them into project, but you will need to manually setup an autoloader.

The recommended way of including it into your project is to use composer.

Add this to your composer.json:

{
    "require": {
        "drupalonwindows/netphp": "dev-master"
    }
}

And run the composer install command.

Your application is now ready to consume any .Net binary be it a custom library of yours, or any of the types inside the .net framework.

Using NetPhp: Importing types and libraries

All the magic in NetPhp revolves around the MagicWrapper class. This class must aware of a .Net type (a type can be any kind of .Net type, be it a regular class, an enum, etc...) in order to be instanced.

In order to obtain an instance of the MagicWrapper you need to use the NetManager class. The NetManager class is used to register you assemblies and type aliases, and then retrieving a MagicWrapper instance of any type inside of any of the registered assemblies.

The NetManager class has 3 methods:

  • RegisterAssembly($assemblyPath, $alias): Registerr an assembly
  • RegisterClass($assemblyName, $class, $alias): Register an alias for a type inside an assembly
  • Create($assembly, $class): Retrieve a MagicWrapper that is aware of the specified type in the specified assembly
RegisterAssembly($assemblyPath, $alias)

Use RegisterAssembly to make the manager aware of a specific assembly and asign it an alias for future reference. You can use a strongly typed name or the path to a dll file.

For example, to register one of the .Net frameworks assemblies to use any of the types defined inside the mscorlib assembly:

$manager = new \NetPhp\Core\NetManager();
$manager->RegisterAssembly('mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089', 'mscorlib');

You can use your custom compiled DLL (you can target any .Net framework version and there is no need to make it COM visible so you can use any of the already compiled libraries that you have):

$manager = new \NetPhp\Core\NetManager();
$manager->RegisterAssembly('d:\\mypath\\mybinary.dll', 'MyLibrary');

You can give aliases to any full qualified type name in an assembly with the RegisterClass method so that you can later use short names to acces those types:

$manager->RegisterClass('mscorlib', 'System.Collections.ArrayList', 'ArrayList');

Once an assembly is registered, you can retrieve a MagicWrapper with the Create() method;

$m = $manager->Create('mscorlib', 'ArrayList');

Or without using the class alias:

$m = $manager->Create('mscorlib', 'System.Collections.ArrayList');

You do not need to register an alias to create a MagicWrapper for a type, but you must register an assembly.

Using NetPhp: The MagicWrapper/NetProxy

After using the Create() method of a NetManager you will be served an instance of NetProxy. We will go into details as to what the MagicWrapper does, but you must know that internally the NetProxy is simply a convenience wrapper over the MagicWrapper and that usually you will not directly operate on the internal MagicWrapper isntance of the NetProxy.

From now on we will talk without difference between the NetProxy and MagicWrapper.

You can retrieve the internal MagicWrapper at any time from a NetProxy instance using the GetWrapper() method.

A MagicWrapper by itself does not represent the instance of an object, what it does represent is a .Net Type awarenes. It can hold .Net objects inside it, and perform operations on them such as calling methods, accessing properties or instantiating classes.

The NetProxy has the following public methods:

  • Get($host): Used to obtain an instance of NetProxy because it cannot be instantiated directly. Host must be always an instance of MagicWrapper.
  • GetType(): Returns a string representation of the .Net type that is being wrapped.
  • Val(): Gives you the object that is being wrapped by the internal MagicWrapper, if the type can be converted to a PHP native type it will do so, otherwise you will get the COM instance (quite useless).
  • UnPack(): Returns the MagicWrapper COM instance. If your assembly is COM Visible you can directly interact with the returned COM object for better performance.
  • Instantiate(...$args): Create an instance of the type that the MagicWrapper is aware of. The instance is stored internally by the magic wrapper and you should operate on the NetProxy as if it was the .Net instance itself. Because constructors can be overloaded, you cannot pass NULL arguments to a constructor because type inference cannot be done on NULL objects.
  • Enum($value): Similar to Instance() but used for enums. Stores internally a reference to an Enum value that can be used to call methods that receive an Enum parameter.
  • IsNull(): Check if the internal instance is null. This will always return true before you call Instantiate() or Enum().
  • AsIterator(): If the internal .Net type is a collection, this method will return an instance of NetProxyCollection that you can use from PHP as if it was a regular array to perform enumerations.

Let's see all this into action with an example:

$manager = new \NetPhp\Core\NetManager();
$manager->RegisterAssembly('mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089', 'mscorlib');
$manager->RegisterClass('mscorlib', 'System.Collections.ArrayList', 'ArrayList');
$list = $manager->Create('mscorlib', 'ArrayList')->Instantiate();
// Retrieve a NetProxyCollection instance wrapper
$list = $list->AsIterator();  
// Check the .Net type.
$net_type = $list->GetType();
$this->assertEquals('System.Collections.ArrayList', $net_type);
// Populate the ArrayList contents
for ($x = 0; $x < 200; $x++) {
  $list->Add("Object {$x}");
}
// Make sure that count() works.
$this->assertEquals(200, count($list));
// Iterate over the collection
foreach ($list as $item) {
  echo $item->Val();
}

We have seen what public methods the NetProxy exposes, but we have not said yet that you can call any method or property of the internal .Net type directly on the NetProxy.

In the previous example we called the Add() method on the NetProxyCollection instance, but this  method really belongs to the System.Collections.ArrayList class.

When calling methods and accessing properties the return types are PHP native if they are compatible they will be returned in their PHP representations, otherwise we will get an instance of NetProxy wrapped over the .Net instance.

The following .Net types can be converted directly to PHP types:

  • System.String
  • System.Int32
  • System.Double
  • System.Boolean
  • System.Byte
  • System.Decimal
  • System.Char
  • System.Single
  • System.Void

When using the NetProxyCollection as an iterator the elements will be also retrieved with their native types when available.

Apr 16 2015
Apr 16

Previously, I posted my thoughts on the Acquia Certified Developer - Back End Specialist exam as well as my thoughts on the Certified Developer exam. To round out the trifecta of developer-oriented exams, I took the Front End Specialist exam this morning, and am posting some observations for those interested in taking the exam.

Acquia Certified Developer - Front End Specialist badge

My Theming Background

I started my Drupal journey working on design/theme-related work, and the first few Drupal themes I built were in the Drupal 5 days (I inherited some 4.7 sites, but I only really started learning how Drupal's front end worked in Drupal 5+). Luckily for me, a lot of the basics have remained the same (or at least similar) from 5-7.

For the past couple years, though, I have shied away from front end work, only doing as much as I need to keep building out features on sites like Hosted Apache Solr and Server Check.in, and making all my older Drupal sites responsive (and sometimes, mobile-first) to avoid penalization in Google's search rankings... and to build a more usable web :)

Exam Content

A lot of the questions on the exam had to do with things like properly adding javascript and CSS resources (both internal to your theme and from external sources), setting up theme regions, managing templates, and working with theme hooks, the render API, and preprocessors.

In terms of general styling/design-related content, there were few questions on actual CSS and jQuery coding standards or best practices. I only remember a couple questions that touched on breakpoints, mobile-first design, or responsive/adaptive design principles.

There were also a number of questions on general Drupal configuration and site building related to placing blocks, menus, rearranging content, configuring views etc. (which would all rely on a deep knowledge of Drupal's admin interface and how it interacts with the theme layer).

Results

On this exam, I scored an 86.66%, and (as with the other exams) a nice breakdown of all the component scores was provided in case I want to brush up on a certain area:

  • Fundamental Web Development Concepts : 90%
  • Theming concepts: 80%
  • Sub-theming concepts: 100%
  • Templates: 75%
  • Template functions: 87%
  • Layout Configuration: 90%
  • Performance: 80%
  • Security: 100%

Not too surprising, in that I hate using templates in general, and try to do almost all work inside process and preprocess functions, so my templates just print the markup they need to print :P

I think it's somewhat ironic that the Front End and general Developer exams both gave me pretty good scores for 'Fundamentals', yet the back-end exam (which would target more programming-related situations) gave me my lowest score in that area!

Summary

I think, after taking this third of four currently-available exams (the Site Builder exam is the only one remaining—and I'm planning on signing up for that one at DrupalCon LA), I now qualify for being in Acquia's Grand Master Registry, so yay!

If you'd like to take or learn about this or any of the other Acquia Certification exams, please visit the Acquia Certification Program overview.

Apr 16 2015
Apr 16

Apr. 16 2015

How does mobile-friendliness affect Google search rankings?

Google reports:

Starting April 21, we will be expanding our use of mobile-friendliness as a ranking signal. This change will affect mobile searches in all languages worldwide and will have a significant impact in our search results. Consequently, users will find it easier to get relevant, high quality search results that are optimized for their devices.” (Google Webmaster Central Blog, 2015)

In other words, if you want your website to rank higher on searches for different size devices such as mobile phones or tablets, it is in your best interest to begin implementing a mobile-friendly layout. If you are new to the concept, Google provides the "Google Guide to Mobile-Friendly Websites," which covers the basic information, requirements and steps for creating a mobile-friendly site. This guide contains tips that relate to being able to perform online tasks easily and choosing themes that remain consistent throughout varying devices.

Is my website mobile-friendly?

There are a number of free online tests that will run checks on your website to determine its level of mobile-friendliness. Websites such as http://responsivetest.net/ and http://www.responsinator.com/ are good test sites that allow visitors to see what thier site will look like when displayed on different screen sizes (i.e. desktop, tablet or mobile).

Google also has a Mobile-Friendly Test specifically directed towards their new search algorithm. Instead of presenting a site on different devices, Google’s test checks to see if the website passes certain mobile-friendly requirements that are taken into consideration by their search algorithm. Because this is the test that a website must pass in order to meet the new search algorithm’s criteria, it is a must for those who want to rank higher in mobile Google searches.

Should I implement mobile-friendliness on my website?

Yes, if you want to obtain the maximum potential your site has for being searched, you should. In today’s technological setting, over half of all web searches are performed through mobile devices. Cisco claims that “Global mobile data traffic grew 69 percent in 2014. Global mobile data traffic reached 2.5 exabytes per month at the end of 2014, up from 1.5 exabytes per month at the end of 2013” (Cisco Visual Networking Index (VNI), 2015). While mobile traffic rapidly increases, companies realize they need to incorporate new marketing tactics such as creating a clear mobile-friendly agenda for their web properties. eMarketer predicts that “in 2015, mobile search will surpass desktop, and by 2018, mobile search ad spending will make up 76.7% of all digital search ad spending” (eMarketer, 2014).

What are ways I can make my website mobile-friendly?

There are multiple solutions to making your site mobile-friendly. Three main options entail creating a mobile application version or a mobile version of your website, or implementing responsive web design (RWD) to your website. At Achieve Internet, we strongly believe RWD is the best solution to creating a mobile-friendly website.

Mobile applications are also a popular option. An application can display your site’s content in a simple, user-friendly fashion. Since Google now incorporates app indexing, an organizations mobile app can also be searched on Google. App indexing presents “deep links to your app [that] appear in Google Search results on Android so users can get to your native mobile experience quickly and easily” (Google Developers). However, applications are very specific to a business compared to a blog or news app that feeds information. Building a complete business-specific app takes siginicant time, effort, and planning. It can also become a costly option since there are a plethora of unique deliverables and technical development requirements involved.

Mobile versions of a website can also be created to provide users with a mobile-friendly experience. Mobile websites utilize a different URL than your main site, and are made to display easily-digested versions of its content. This means a mobile website might have bigger buttons and more spread out content, making it easier for the user to access what they need on the site. Although, one big problem with creating a mobile version is that there may be content that gets left out. Some aspects of the original website make layouts or functionality in a mobile version difficult and must be removed

Responsive Web Design (RWD) is a reliable option and common practice utilized in mobile-friendly web development. It allows a site to adaptively present itself on mulitple screen sizes or devices. Below is an example of the Achieve-built Grammy Amplifier website shown on a mobile device as well as a tablet and desktop.

Mobile & Tablet

 

Desktop

http://www.grammyamplifier.com

Because different devices have different screen sizes, developers incorporate Cascading Style Sheets 3 (CSS3) to satisfy device display requirements. This implementation greatly improves the user experience as visitors will be able to see a clear, simple layout of the website no matter what device they are viewing on.

Should I implement RWD?

Yes, if your website focuses on presenting content in a complex manner such as an eCommerce or marketing site that requires multiple layers of functionality we recommend implementing RWD. RWD will convert all the content from your original site and make it easier to navigate on different screen sizes. Unlike updating a mobile website’s content, RWD makes it possible for mobile versions of your website to stay up to date with the original site display. It keeps all of the content available for users as well.

What do we have to look forward to?

Forrester states:

Many developers tell Forrester that they use responsive web design (RWD) as their web design philosophy, but the highest adoption rate by vertical is less than 20%. This suggests that many organizations are currently working on responsive website projects for the first time” (Forrester Research, 2014).

That is not the case here at Achieve, we have gained a lot of experience implementing RWD for many of our clients who’ve requested it. Because of these projects, Achieve developers have already acquired layouts and good mobile-friendly development practices. With more site owners contacting us about making their sites mobile-friendly due to Google’s new search algorithm, we will only develop more skills in RWD as we proceed.

Don’t wait until your site becomes obsolete in Google rankings and user experience. Achieve can help you get your site to be mobile-friendly and segue in to the future. As technology advances at such a rapid speed make sure your company is prepared to take advantage of all it has to offer.

For more information about mobile-friendly & responsive web design, refer to any of our previous posts:

?      A Drupal Developers Guide to Responsive Web Design

?      Does Your Site Need Responsive Web Design?

?      Why You Should Design For Mobile First

?      Responsive Web Design - Fact Sheet

Apr 16 2015
Apr 16

Drupal is more fun - meet Karen Grey

I sat down with Karen Grey at Drupal Camp Brighton 2015 to find out more about who she is and what she does with Drupal. I apologize for taking her out of the code sprints for that time! Since we spoke, Karen has taken on a position as Senior Drupal Developer at i-KOS in their Brighton office.

During our conversation, we touch on the difference between early Drupal 6 and working with Drupal 7 now, how public contribution helps companies build their reputation and build passion and excitement in employees, Drupal's tough-love coding standards, how Drupal's steep learning curve pays off ("I've used other CMS's, they're not fun to use.") in enjoyment and community, the expense of the project discovery phase when using proprietary software compared to open source, personalization on the web as the next big thing (shoutout Acquia Lift and Context DB!), and more!

Guest author dossier

  • Name: Karen Grey
  • Twitter: @greenybeans84
  • Drupal.org profile: karengreen
  • Work affiliation: Senior Drupal Developer, i-KOS Brighton office
  • LinkedIn profile: Karen Grey
  • A recent Drupal contribution: Commerce Smartpay module
  • Which Drupal version you started with: Drupal 6. "I built my own CMS for my final year project at university, so I understood what a CMS is and does and when I was introduced to Drupal, I thought it was pretty cool."

jam's favorite photo of Karen

Karen Grey's magnificent moustache!

Interview video

[embedded content]

Karen Grey, Senior Drupal Developer
Apr 16 2015
Apr 16

 String Telephone Drupal 7 does not have built-in support for representational state transfer (REST) functionality. However, the RESTful Web Services module is arguably the most efficient way to provide resource representations for all the entity types, by leveraging Drupal's powerful Entity API. Unmodified, the module makes it possible to output the instances of the core entity types – node, file, and user – in JSON or XML format. Further entity type resources and formats are possible utilizing hooks in added code.

As with any REST solution, the RESTful Web Services module supports all four of the fundamental operations of data manipulation: create, read, update, and delete (CRUD). The corresponding RESTful API HTTP methods are POST, GET, PUT, and DELETE, respectively.

Anyone hoping to learn and make use of this module – especially for the first time – will likely be frustrated by the current project documentation, which is incomplete, uneven, and lacking clear examples. This article – a brief overview – is intended to introduce what is possible with this module, and help anyone getting started with it.

We begin with a clean Drupal 7 installation (using the Standard profile) running on a virtual host with the domain name "drupal_7_test". After installing and enabling the module, we find that it does not have the configuration user interface one might expect. In the demonstration code below, we focus on the node entity type.

Nabbing a Node

The simplest operation – reading an entity instance – is performed using a simple GET request containing the machine name of the entity type and the entity's ID.

To allow an anonymous user to read the node using REST, it is insufficient to grant that role the "View published content". Moreover, the "Bypass content access control" permission has no effect. Rather, the module establishes an "Access the resource" permission for each entity type, which also must be enabled for anonymous users. (When testing anonymous access from a web page, be certain you’re not logged into the website in the same browser, because then you are already authenticated.)

In this example, we read the fields in the first page in the Drupal database (node/1), which has a title of "Page Title" and a body field of only "Body text". To display the information in JSON format, in a web browser, the URL would be: http://drupal_7_test/node/1.json

The results are, as expected, in JSON:

{
  "body": {
    "value":"\u003Cp\u003EBody text.\u003C\/p\u003E\n",
    "summary":"",
    "format":"full_html"
  },
  "nid":"1",
  "vid":"1",
  "is_new":false,
  "type":"page",
  "title":"Page Title",
  "language":"und",
  "url":"http:\/\/drupal_7_test\/node\/1",
  "edit_url":"http:\/\/drupal_7_test\/node\/1\/edit",
  "status":"1",
  "promote":"0",
  "sticky":"0",
  "created":"1402821494",
  "changed":"1403394617",
  "log":"",
  "revision":null,
  "comment":"1",
  "comments":[],
  "comment_count":"0",
  "comment_count_new":"0"
}

If you get an HTTP 403 error ("Forbidden"), verify the two required permission settings for anonymous users accessing nodes.

To display the same information as XML, we need only alter the path extension:
http://drupal_7_test/node/1.xml

The information is the same, but in a substantially different format:

<node>
  <body>
    <value>
      <p>Body text</p>
    </value>
    <summary/>
    <format>full_html</format>
  </body>
  <nid>1</nid>
  <vid>1</vid>
  <is_new/>
  <type>page</type>
  <title>Page Title</title>
  <language>und</language>
  <url>http://drupal_7_test/node/1</url>
  <edit_url>http://drupal_7_test/node/1/edit</edit_url>
  <status>1</status>
  <promote>0</promote>
  <sticky>0</sticky>
  <created>1402821494</created>
  <changed>1403394617</changed>
  <log/>
  <comment>1</comment>
  <comments/>
  <comment_count>0</comment_count>
  <comment_count_new>0</comment_count_new>
</node>

To get all of the nodes – or at least the first 100, by default – remove the entity ID: http://drupal_7_test/node.json

If we again want to access that first node only, but not use a URL, then we can employ cURL on the commandline: curl -X GET http://drupal_7_test/node/1.json

More descriptive options, such as --request GET, can be chosen. To see details of operations that may be helpful for debugging, add the -v option (a.k.a. --verbose).

If you do not want anonymous REST requests to have access to your website's content, use HTTP authorization. Apparently, the simplest way to do so is to enable the Basic Authentication Login submodule (restws_basic_auth). Connect by utilizing a username that has the appropriate "Access the resource" permission and begins with the (mandatory lowercase) string "restws". Assuming that the user "restws_user" has a password of "password", then we can display the first node with this command: curl -X GET http://drupal_7_test/node/1.json -u restws_user:password

The aforesaid username pattern could be represented as the regular expression /^restws.*/. That pattern can be customized in the website's settings.php file. For instance, to grant authorization only to those usernames beginning with the string "WS_", one adds the following (case-sensitive) regex to the settings.php file: $conf[ 'restws_basic_auth_user_regex' ] = '/^WS_.*/';

Creating or Changing a Node

Rather than using the conventional content management UI for adding an entity resource, we can do it with REST – specifically, a POST request. There are several ways to accomplish this: using the core function drupal_http_request(), or cURL PHP code, or cURL on the commandline, which we will use here. Returning to the XML format, we can use a file based upon the one output earlier, containing only those elements needed to create a new node with some content in the body field:

<node>
  <type>page</type>
  <title>New Page Title</title>
  <body>
    <value>
      <p>New body text</p>
    </value>
  </body>
</node>

Assuming that the file is named create.xml, we can create a new node with this command:

curl -X POST -H "Content-Type: application/xml" -d @create.xml \ 
    http://drupal_7_test/node -u restws_user:password

The the output in the command window indicates that a second node, node/2, has been created:

<?xml version="1.0" encoding="utf-8"?>
<uri resource="node" id="2">http://drupal_7_test/node/2</uri>

If the XML file were missing an essential element, such as the node type, we would receive an error message such as: 406 Not Acceptable: Missing bundle: type

Modifying an existing node is similar, but instead of using the POST method, use PUT and specify a node ID. The XML file needs even fewer elements:

<node>
  <title>Modified Page Title</title>
  <body>
    <value>
      <p>Modified body text</p>
    </value>
  </body>
</node>

The cURL command is straightforward:

curl -X PUT -H "Content-Type: application/xml" -d @modify.xml \ 
   http://drupal_7_test/node/2 -u restws_user:password

The output will not include any <uri> element containing the node ID, since no new one was created.

Nuking a Node

To remove any entity resource – in this case, the first node in the database – use the DELETE method:

curl -X DELETE http://drupal_7_test/node/1 -u restws_user:password

The baffling, yet correct, output is merely:

[]

Using this module, one can also: filter the results when querying for multiple resources (by specifying the user ID or taxonomy ID); sort by one of the properties (either in ascending or descending direction); change the default limit of 100 resource references. For debugging purposes, you can enable the logging of the details of all web service requests to a specified file, with a simple addition to the Drupal settings.php file, for example:

$conf['restws_debug_log'] = DRUPAL_ROOT . '/restws_debug.log';

If in your own explorations, you discover additional techniques and pitfalls, please consider publishing them, as there appears to be both interest and confusion as to how to leverage this module fully.

Image: "String Telephone" by psd is licensed under CC BY 2.0

Apr 16 2015
Apr 16

Volunteers sprintingThis week is National Volunteer Week, a week to recognize that volunteerism is a building block to a strong and thriving community.  The Drupal Community is no different: as an open-source project our volunteers are vital to the health and growth of our project.  There are so many roles and levels of contribution within our Drupal ecosystem that we at the Drupal Association wanted to highlight how much your contribution means to us and our work.  I took some time and asked around, here’s some of the glowing praise our staff has to say about our phenomenal volunteers. 

Amanda Gonser“I am continually impressed with the volunteers that I get to work with.  Not only do they rock at their jobs, but they are so dedicated to the work that they do for Drupal and the Cons specifically!  Anyone who has volunteered for a Con knows that it is a large undertaking, and a responsibility that isn't taken lightly. These volunteers come back each week with positive attitudes, valuable ideas and great results.  Although I have only been at the Association for a little over six months, I can truly say that these volunteers are what gives our Cons the 'special sauce' and I am lucky to get to work with volunteers from around the globe on a daily basis.” 

- Amanda Gosner, DrupalCon Coordinator

Holly Ross“Most of my day is spent with Drupal Association staff, who have the luxury of getting paid to think about Drupal for 8 hours a day. A good chunk of my job is working with volunteers though-- the Board of Directors, Drupal.org Working Groups, Community Organizers, DrupalCon session speakers. So many of you give so much of your time and your smarts back to the project and the community, and it's my privilege and duty to learn from you all.”

- Holly Ross, Executive Director

Neil Drumm"I look forward to working working with community volunteers to help build and improve Drupal.org. The site would not be where it is today without everyone's work."

- Neil Drumm, Drupal.org Lead Architect

Megan Sanicki“I want to thank Cathy and Jared for being my sprint mentor at DrupalCon Latin America. I made my first comment on the issue queue. It felt so good to cross into that world finally, even if it is was just a baby toe crossing over.”

- Megan Sanicki, COO

Leigh Carver“It feels like I’m hearing news every day about the amazing programs our community members put together all over the world — from Los Angeles to Uganda and beyond. Without help from amazing community volunteers who donate time working on social media, in the issue queues, or even volunteers who take a brief moment to drop a note in my inbox (“have you seen this?”), these stories would never be shared with our wider community.” 

- Leigh Carver, Content Writer

Today, we invite you to take a few minutes to recognize your fellow Drupal contributors by tweeting or sending a message via IRC to appreciate each other.  After all, without our volunteers, our Drupal Community would not be as lively, bright, and welcoming.  Want to lend a hand?  Our get involved page has plenty of ways to volunteer with the project.

Apr 16 2015
Apr 16

Drupal has a solid Ajax interface, we can hook into the Ajax events at various places. I will explain some 5 important methods,

1) beforeSerialize - called before data is packed and runs before the beforeSend & beforeSubmit

2) beforeSubmit - called before the ajax request

3) beforeSend - called just before the ajax request

4) success - called after ajax event returns data

5) complete - called after the request ends

Lets say you want to capture some ajax event (in built or made by other module) to do some event like Views refresh. We can use a very simple logic to do that.

(function($) {
    Drupal.behaviors.timetracker = {
        attach: function(context, settings) {
        /*Task submit ajax*/
        for (ajax_el in settings.ajax) {    
          if (Drupal.ajax[ajax_el].element.form) {
             if (Drupal.ajax[ajax_el].element.form.id === 'TYPE-node-form') {
               //called before the ajax request
               Drupal.ajax[ajax_el].beforeSubmit = function(form_values, element_settings, options) {
               //Do something                      
               }

               Drupal.ajax[ajax_el].beforeSend = function (xmlhttprequest, options) {

                //Do something                      
              }

              //called before data is packed
              Drupal.ajax[ajax_el].beforeSerialize = function(element_settings, options) {
               //Do something     
              }              

             //Called after ajax event returns data
              Drupal.ajax[ajax_el].success = function(response, status) {
                 // Trigger views refresh refresh the activity view
                 $('.view-id-activity').trigger('RefreshView');
                 //Pass back to original method
                 Drupal.ajax.prototype.success.call(this, response, status);
             }

             Drupal.ajax[ajax_el].complete = function(response, status) {
            }
       }
      }
    }
  }
}
});

In my case, I get all the forms that are set for Ajax handling and compare them with my node form. Once the form submission happens and the ajax data is returned, "success" method will get called. As the new data is added, I here refresh the respective view with the inbuilt Drupal procedure to refresh View.  Note, I use  Drupal.ajax.prototype.success.call to make sure the core function runs at the end, otherwise you may notice inconsistency.

I hope this sheds some light, let me know if you need some inputs from me.

Apr 16 2015
Apr 16

This is the story of how I built a first prototype for LinkForward, a web application for power networkers, and how I built it in record time using Drupal (12 hours), without a single line of custom code.

Today, MVP (Minimum Viable Product) is a part of every startup founder’s vocabulary. But almost 10 years after Steve Blank first published his ideas on customer development in "The Four Steps to the Epiphany”, I’ve seen myself and countless other startup enthusiasts over-invest in the development of their first prototype for web applications. When I talk with founders about their startup they will often say they are building an MVP and then immediately go on listing a long list of complex expensive features they believe their product will not be viable without (instant messaging, video chat, you name it). The worst is, I’ve done the same several times now. In the beginning of the year, when I got the idea for LinkForward, I decided to do things differently.

The goal

LinkForward is a web application that makes it easier to build and maintain a high quality professional network. Its goal is to make it easy for 2nd degree connections - that don’t know each other but that have someone in common - to introduce each other to their own network. I started building it as a side project because I felt that there is a serious need for a tool that makes it easier to be a power networker. Since mid 2014 I have been working much more consciously on my network. Even though I had returned to Belgium 5 years ago, I realized that I wasn’t really connected into the IT scene at home. Along the way I started feeling that there is an important gap in my networking toolset.

I’ve now got over 2k connections, and many of them I no longer remember. I would love to have a tool that helps me make stronger, more meaningful connections. That helps me build a vibrant, active network with those people that will help me make a bigger impact on the world. Just before New Year, I had joined a friend and her co-founder to advise them about their startup. To implement their idea they wanted to build an AI that would be able to make recommendations to people. In that discussion I suggested them to think of using a network of people as an alternative for expensive and complex AI, this is how I got the idea for LinkForward.

What is wrong with Linkedin

I really love Linkedin, I was never really good at organising business cards, and Linkedin gave me a much better alternative to keep track of my professional network. While Linkedin is great for retaining business connections, it’s inadequate if you want to actively foster your relationships. I see 3 big problems:

  1. In the name of greater engagement Linkedin is actively seducing their users to waste time on empty/shallow interactions: Linkedin’s news feed is saturated with listicles and other sensational but forgettable content. I don’t think that a single click “like XYZ’s new profile picture” helps you build a meaningful relationship in a professional context.
  2. All the incentives are geared towards indiscriminately accepting connections. Recruiters and sales people, the premium users on Linkedin need to build as many connections as possible to increase the number of people they can reach. As a result on a weekly basis I get connection requests from accounts that are obviously fake but that have already accumulated over a hundred connections.
  3. Behaviour reinforcement loops in the system were primarily built for new users (there are some positive improvements on this area recently, but the mass market nature of the system means it is not primarily geared towards power users).

Pretotyping

A little while back I read Pretotype it a free book by Alberto Savoia. While his ideas are very similar to the Minimal Viable Product that Steve Blank popularised, this book helped me to finally get it. You see, when Steve Blank introduced MVP he left it really open what viable meant exactly. And there are a lot of interpretations that range from:

  • Landing page: A page that explains a product before it is built and that lets people sign up to receive notifications about the product.
  • Crowdfunding campaign: Using a platform like Kickstarter or Indiegogo to raise funds from your future customers.
  • Mockup prototype: A prototype built in a mockup tool, be it Balsamiq, Powerpoint, or something similar.
  • Concierge MVP: a manual service, where the founder offers a service that mimicks the product as you envision it to be working in the future.
  • Mechanical turk MVPs (or also “Wizard of Oz MVP”): On the outside it looks as if everything is running automatically, people interact through a web interface with your product, but on the inside you are doing the most expensive interactions by hand.
  • Minimum Loveable Product: a counter action against MVPs that were too minimal. Often focussing on design, to make a product more “loveable”.

The problem is that most startup founders go from demand validation (e.g. talking with potential customers, landing pages, mockups or crowdfunding campaigns) straight to their Minimum Loveable Product. In the process a lot of founders invest loads of time and money in demand that was only validated as an idea. And this is where a lot of people fail badly: they get initial traction and start investing in an idea that people think is great, but there is a really big difference between something that sounds great and something that will actually work.

That is why I’ve learned the hard way that you should build a pretotype before you build your version one. And your pretotype should be modelling the engine of your startup, the key interaction that you believe will be bringing value to your customers.

If the engine doesn’t work you can add all the whistles and bells you want, they will not make your startup a success. On the other hand if you can get that basic interaction going, even if it’s only for a small group of people, and not very effectively, you can start experimenting how you can get from there to a product that people will not just like but actually love.

Pretotyping LinkForward with Drupal

So how do you build your startup’s engine? For LinkForward the initial idea was that introduction requests would be the engine of the community platform: When a user signs up, they can ask an introduction request from the community. When another user in the network knows someone who would be a good introduction, they can flag that person and receive an email they can forward to the person in question.

First iteration (8h) - from idea to pretotype

I built the first iteration for LinkForward on two consecutive evenings, in about 8 hours of work. To do so I used Drupal Gardens, a hosted Drupal solution built by Acquia. With it, it’s really easy to get a Drupal site started without any developer or system administrator knowledge.

It had been a while since I last built a Drupal site, and my Drush knowledge had become a bit rusty (read I forgot everything). I could have asked my colleagues to set up a site for me, or have brushed up my command line knowledge, but I wanted to show that it is possible to make a prototype in Drupal without any real coding skills. The only thing I asked help with was the setup of the nameserver so that I could have a real domain and not just a subdomain.

Setting up the introduction request was really easy: I just added the fields for it to the user profile. The most of my time I spent on tweaking the View that was going to display one user’s ask at a time and the 2 flags I created to let a user interact with the system. Since I didn’t want to involve a themer, I had to do some trial and error positioning the fields using an HTML table (ok maybe this is a bit more hardcore Drupal skill, but I personally don’t consider HTML to be code, since you are manipulating the output directly).

Go live (4h) - inviting the first users

After these 2 evenings I spent another 4 hours doing some extra polishing. I’m not sure anymore when I wrote the content for the home page and the about page, but after approximately 12 hours of work, I went onto Skype and pinged about 70 friends, mostly from the Drupal community, who I thought the product might be relevant for. That is how I got the first 7 users.

Several friends suggested me to check out BNI (Business Network International), "the world's largest referral organization" founded in 1985 by Dr. Ivan Misner. I found a chapter in Ghent that was having their weekly meetup on Wednesday at 7am, I called them up and was able to attend the next morning. From the approximately 30 people that morning 12 signed up for an account.

The 3rd group I recruited from was the attendees at BootCircle, the monthly meetup I organize for startup founders in Ghent and Leuven. I also handed out flyers (black&white hand torn copy machine quality) at a few other meetup events I attended, that got me another 12 participants. Including a few colleagues that brought the total to about 40 participants. Meetup.com, a site that facilitates the organisation of local "user group” style events is a really powerful tool for setting up ad hoc meetings where you can get feedback quickly from people in your target audience.

Engagement experiments

With this initial group of people, I could already see that the engine was not yet working: most of the people that signed up didn’t return, even after they had been prompted. The engagement rate was also rather low. That is why I took the site off of Drupal Gardens so that I could do a few experiments with gamification modules.

I used the user points module in Drupal to create introduction points: every time you flagged that you wanted to introduce somebody, a point was awarded to you and subtracted from the person you indicated you could make an introduction for, a typical gamification scheme. Initially I used flag actions for this from the flag module. But I bumped into some of the limitations of the flag module, and in the end I decided to power up.

This is why I installed the rules module. Rules is Drupal’s blackbelt toolbox, it allows you to model complex business logic without a single line of code. Sending emails, adding or removing points, but also publishing and unpublishing nodes, there are few things you can’t do out of the box with Rules.

I wanted to encourage my users to invite their friends to the platform. Setting this up is trivial with the invite module if you are fine with a simple email invitation system. It’s also possible to extend the module with other types of invitations, but those don’t come out of the box. The invite module works together nicely with the user point module, so that you can award points when a member invites a new user to the platform.

At some point I thought I might be able to improve engagement if I would offer offline introduction groups a virtual place to facilitate the introductions they made. That is why I installed the organic groups module that allows you to set up sections of your site where users get different permissions depending on their group membership.

To make it easier to create a new account and to login, I added Hybridauth a module that lets you integrate with a host of social login services. With it, you can create a new account on the site with a single click of a button, copying your information from the social network service.

Francis, a founder friend who I am masterminding with about LinkForward, suggested that we might increase engagement if a customer could add more than one introduction request. I moved the request fields into their own content type and refactored the views and flagging system to enable it.

All of these changes happened on the live site in configuration only. So not in a code driven way, using features, the way we normally build sites for our customers. I would strongly recommend against this kind of live fine tuning for established business platforms where customers have a fitness and continuity expectation. For a startup however, this kind of agility and live tweaking makes Drupal an extremely powerful platform that allows you to learn at minimal cost in really short time frames. With proper warning, I believe this could even be used in an enterprise environment for a beta pilot.

Summary: Why Drupal is a great tool for modeling startups

  • It is clickable, you don’t need to write code
  • Easy to build a complex content model and to visualize it in rich data display that you can build with views
  • It has the building blocks to create viral loops with modules like the Invite module
  • You can use it to create gamification processes with the User points module
  • Social login is easy to set up with Hybrid Auth, and allows you to easily recognise spam accounts
  • You can model complex business logic with the Rules module
  • User interaction processes can be built with the Flag module

Conclusion - More refactoring ahead

Linkforward is not yet working the way I want it to - its engine is still sputtering - but through the experiments I’ve done in the past months I’ve learned a lot of valuable lessons. Crucially those lessons were really affordable: I estimate I’ve spent about 80-100 hours of my own time, my assistant has spent about 10 hours sending emails as part of one of the experiments, I had about 10 hours of technical support from our developers to set up the site and to install the modules.

Next for Linkforward I’ve got a big overhaul in mind and I’m still considering if I want to throw away the current site, copy over the content and rebuild, or if I want to continue working with the existing site base. There is a minor image upload bug that I don’t want to waste developer time on, so I might as well just restart for the new prototype. I can copy over a lot of the configuration work, so that wouldn’t be such a big deal.

I’m really excited about this project for another reason: It demonstrated that it is possible to provide a lot of value for very little developer time. That is why with Pronovix we’ve decided to launch a service based on this principle: dripdojo.com. It is a service specifically designed for intrapreneurs or entrepreneurs who would like to take a hands on role in the design of their innovation project. The goal is to help them validate the engine of their idea before larger investments are made.

We’ve also been actively using our experiences when advising our startup customers, nobody can afford investing in features that people won’t use, especially not when you are trying to launch your startup...

Apr 15 2015
Apr 15

Almost everyone who does any form of Drupal development uses Drush - it's the Swiss Army Knife of the Drupal world. Drush is the Drupal Shell, and it lets you do a whole lot of amazing things with Drupal sites without actually going to the site, logging in, and clicking buttons.  It's a command-line tool (and since I'm an old UNIX hand, it's just right for me.

Despite the fact that we all use Drush, it's pretty clear that some of us use it better than others. I'm often really impressed with seeing someone else use it effectively, with powerful aliases, and doing workflow things with drush that I could hardly imagine. And let's face it, we can't always have a mentor at hand.

This book, Drupal for Developers Second Edition,  can be your mentor. It's a pretty quick read (a little over 150 pages) as technical books go. It covers a lot of territory along the way, though.  As all these books seem to do, it starts out with installing Drush on your server, and then moves forward into using it.  Though I've been using Drush for some time now, I never have quite been able to grasp the more advanced uses, like using Drush to move code and features from development to test to production, for example.  This book give a really good idea of how to do some of those functions.

It's also good at giving simple examples of doing things like developing code to interact with Drush, and getting the most out of Drush in a developer enviromnent.

The chapters in the book cover a lot

  1.   Keeping your code and database synced up in different environments.
  2. Running and monitoring tasks in Drupal
  3. Doing debugging and error handling in Drush- I found this chapter particularly enlightening (and as it turns out I really wish I had read it last week when I desperately needed it.)
  4. Managing local and remote environments - running remote environments in Drush, and writing concise aliases.
  5. Setting up a development workflow using Drush - this gave me some great ideas for streamlining things I now do by hand - I'm really looking forward to trying this out.

You can buy a copy of this book at the Packt web site, and also at most technical book stores and online sellers such as Amazon .

Now if I only understood why this is the Second Edition when the first was apparently never published?

Apr 15 2015
Apr 15

Almost everyone who does any form of Drupal development uses Drush - it's the Swiss Army Knife of the Drupal world. Drush is the Drupal Shell, and it lets you do a whole lot of amazing things with Drupal sites without actually going to the site, logging in, and clicking buttons.  It's a command-line tool (and since I'm an old UNIX hand, it's just right for me.

Despite the fact that we all use Drush, it's pretty clear that some of us use it better than others. I'm often really impressed with seeing someone else use it effectively, with powerful aliases, and doing workflow things with drush that I could hardly imagine. And let's face it, we can't always have a mentor at hand.

This book, Drush for Developers Second Edition,  can be your mentor. It's a pretty quick read (a little over 150 pages) as technical books go. It covers a lot of territory along the way, though.  As all these books seem to do, it starts out with installing Drush on your server, and then moves forward into using it.  Though I've been using Drush for some time now, I never have quite been able to grasp the more advanced uses, like using Drush to move code and features from development to test to production, for example.  This book give a really good idea of how to do some of those functions.

It's also good at giving simple examples of doing things like developing code to interact with Drush, and getting the most out of Drush in a developer enviromnent.

The chapters in the book cover a lot

  1.   Keeping your code and database synced up in different environments.
  2. Running and monitoring tasks in Drupal
  3. Doing debugging and error handling in Drush- I found this chapter particularly enlightening (and as it turns out I really wish I had read it last week when I desperately needed it.)
  4. Managing local and remote environments - running remote environments in Drush, and writing concise aliases.
  5. Setting up a development workflow using Drush - this gave me some great ideas for streamlining things I now do by hand - I'm really looking forward to trying this out.

You can buy a copy of this book at the Packt web site, and also at most technical book stores and online sellers such as Amazon .

Now if I only understood why this is the Second Edition when the first was apparently never published?

Apr 15 2015
Apr 15

On a sunny Amsterdam morning, we catch Morten (Tag1 Consulting, Geek Röyale) as he speeds through DrupalCon’s RAI Convention Center on an urgent Viking mission. We waylay him long enough for this brief, Danish-accented, rapid-fire chit-chat.

MORTEN: I am Morten, also known as MortenDK.

RONNIE RAY: You gave a talk this morning?

MORTEN: Yes, I gave a talk about the Drupal 8 Twig project, which is the new theming layer for Drupal. And I gave a demo on all the new and exciting things we have in it.

So that was really good to show off from a front-ender’s perspective everything that was done over the last couple of years and how the new system is going to work in Drupal 8. It was a real gas to finally really show it off. People could see we’re not just lying, but it’s actually real.

RR: So, can I ask you, what are you reading now?

MORTEN: What?

RR: Any books, any magazines?

MORTEN: Ah – oh – uh – (bleep) – what’s the name of it? I actually have it on an audio file, it’s a fantasy story about... uh.. a lot of blood, a lot of personal vendettas. Good clean fun. But actually I haven’t had the time to read for a long time because I’ve been doing so much work on the Drupal project and I’ve been moving. Also, I took up my old hobby of painting miniatures again, just to geek out.

I’m a metal-head so pretty much anything... been into a lot of Opeth, a Swedish metal band – kind of a grown man’s metal. (Indecipherable.)

RR: Do you follow anyone on Twitter or FaceBook?

MORTEN: A couple, but normally not. Interviews with musicians are not always the most interesting thing, it’s the same thing as interviews with sports people, “So how did it go today?” “We played really hard!” “On the new album, we’re going to really show off.” So that’s kind of like... a couple of people... there’s a Swedish band called Arch Enemy I’ve been following closely.

RR: What’s the most exciting thing about Drupal 8 for you?

MORTEN: It is the front-end, the Twig system and the templates, and the way we have shifted focus in the front-end completely around, from being an afterthought to a whole new system that is built for front-enders instead of built by back-enders to front-enders. It’s kind of, we’ve taken control over our own destiny, and that I think is going to be the killer app for Drupal 8.

868
Apr 15 2015
Apr 15

It’s national library week and we could all probably learn good habits from those fastidious and oh-so-organized people in our lives: librarians.

Ahh, libraries. The smell of books, the sounds of pages turning, the incessant Karaoke singalongs of the library workers. OK, maybe the last one is a bit far-fetched, but we all know it’s founded in some truth. The fact remains that libraries are a hallowed ground of information consumption and organization.

That organization doesn’t happen by dint of chance. No, there’s a lot of hard work that goes into maintaining a collection, and these steps taken by your local library workers might inspire us to approach our websites with the same set of diligent hands. Get sorting, people!

Photo of Leeds Library courtesy of Michael D Beckwith.

Shelf-reading

Picture this: You’re scanning the stacks for that volume of poetry by your favorite Tang Dynasty era scribe, and whaddaya know — it’s not in its right place! Typical, amiright? Actually, it’s very atypical.

Library workers actively “read” the codes on the spines of books to ensure that they are arranged in correct order. Think of it as an analog version of web-crawling. Someone literally walks through the stacks and pulls misaligned books from the shelf in order to get them back to their rightful place. It’s continuous, tedious and probably the bane of a librarian’s existence. But it must be done.

Your site must organize content in a conscientious and intuitive manner for users to find what they need. Similar to identifying a book by it’s code, a good admin will identify the different content types and then start putting the pieces in place for a user-friendly website.

Weeding

"Next to emptying the outdoor bookdrop on cold and snowy days, weeding is the most undesirable job in the library. It is also one of the most important. Collections that go unweeded tend to be cluttered, unattractive, and unreliable informational resources."

- Will Manley, "The Manley Arts," Booklist, March 1, 1996, p. 1108.

 

That quote really does say it all. And then it cites in clinical fashion. #LibraryStyle

Ever had a garden that was choked by invasive, persistent weeds? The only remedy is to pull those opportunistic plants by their roots and turn the soil for good measure. Libraries have to do something similar in order to remove old, non-circulating and damaged books that are clogging the shelf space. Sayonara, unwanted copies of Steve Wozniak’s Joke Book!

The post-audit process for a Drupal site should follow similar principles of economy and usefulness: was this custom module really needed for the UI? If it’s taking up space and not serving the users, then it’s gotta go! 

Cleaning up a site the Promet Way

One thing that helps get your site in good working order is a thorough audit.  Check out our presentation from DrupalCorn 2014 to get the skinny on how we drill down to a site’s components with the Drupal Site Audit.

Have a website that needs organizing? Drop your contact info in the form below and someone from Promet’s team will be in touch!

Apr 15 2015
Apr 15

Weekly Module Review - #7 Fast Permissions Administration, insert permissions without issues!

This week we’ll talk about FPA (Fast Permissions Administration), a very cute module I only discovered recently.

One of the issues I spotted in our work when you manage a large size website is the NOT usability of the permissions page. I give you an example:

We have a website with 10 roles and 20 / 30 modules. This is more than enough to render the permissions page not practicable.

Having this issue, I searched on drupal.org and I found this module that suits to our case!

Paradoxically this module completes more options respect to the default page, but it renders easier and intuitive the default page itself! Let’s start showing on how to install it.

FPA is a contrib. module of Drupal, so to download it is enough to go to the download page of Drupal modules and search Fast Permissions Administration (https://www.drupal.org/project/fpa).

The installation of the module is traditional, so I do not stop too much.

Once downloaded the module from the link gave above, put it on the sites/all/modules/contrib folder and enable it on the modules page, that you can find on the following link: yourwebsite.it/admin/modules.

After having activated it and going to the permissions page, we will see it completely different and redesign:

But let’s see it in detail:

On the left side there are available all the permissions gather by module. In fact, clicking on the desired module will be visualized only the permissions linked to it.

Going on we can find a series of options that make easy the visualisation of the permissions that interested to us, in fact:

On the Filter part is possible insert custom filters, I explain me better: this field rings around a particular format: “permission@module

  • Permission —> the permission name (or a name part) we are looking for.
  • Module —> the module with which we want to filter.

Practical example, I want to find a permission to administrate the blocks. I’ll write on the field:

Administer@Block

And the page will show us only all the permissions that contain the word Administer inside the Block module.

In Roles part we can simply filter and visualize all the permissions of a specific role.

Same thing for Display permissions that are, part that allows, as said the title itself, to filter the permissions for Checked and Not Checked.

As the module itself suggests, this option gives its best in combination with the previous one. In fact it’s possible see indeed all the selected permissions or not, only if it’s visualize just a role.

As the last module part we find the permissions, filtered for the selected module. For example, selecting on the left the Administration menu module, it’s possible visualize only the modules linked to it, with this formatting:

We have more methods and possibility to select the permissions! In fact if we select the checkbox we find on the right of the permission:

is possible give this permission to all the roles available on the website.

But, if we want to give all the permissions relating to a determinate module to a role the procedure is easier. It’s enough click on the checkbox available under the role, as show in the image:

NB: Once selected the permissions, remember to save!

And even for this module is all! I’ll definitely use it for the website I’m going to analyze, what about you? Write me on the comments!

Apr 15 2015
Apr 15

In the final video of the 3 part series, we look at creating and configuring a Drupal sub-theme. Specifically, we will be created a sub-theme based off of the Zen theme. If you aren’t familiar with Zen, it is a very popular base theme used by thousands of designers as a starting point when building a custom website theme.

So what is a base theme? A base theme is simply a theme that's default stylings can be used IF the sub-theme doesn’t override it. In other words, a base theme provides the frame of the house and a custom sub-theme provides the finishes. You might be thinking why not just modify the Zen base theme. While you COULD do this, it is NOT recommended. The main reason you would avoid this idea is because when Zen gets updated by the community and you want to pull in those new changes (updates) you will override all of your custom work within those files. That is not good. If however you use a sub-theme updates will never occur, unless you yourself do them.

In the video, I walk you through getting both a zen base and sub-theme created. During this video, you will learn which files need to be modified to correctly tie in your sub-theme with Zen. Lastly, I will show you how you can add template files (the files that control the structure of the site) to your sub-theme. Knowing how to modify these files is crucial to being able to have complete control over the structure of your website.

Apr 15 2015
Apr 15

Let us give the floor to Jack Dawson, founder of Big Drop Inc. He shared his thoughts and ideas about Drupal with the readers of our blog.

Drupal is an open source CMS (content management system), which means that its block of code is available for extension and modification by anyone with programming knowledge. This is as opposed to close source/proprietary software, whose creators retain its IP rights. Open source software does not come with any fees, and it is fully modifiable to fit any user requirements.

Drupal is one of the three most popular open source CMS, the other two being WordPress and Joomla. While it may not be the most popular of the three, it certainly is the most flexible and powerful within the trio and is the choice of many developers where there is need for technical muscle. Drupal can be used to host many different content types e.g. blogs, password protected content, message boards, forums etc.

How Drupal is updated and improved

Like every other open source web platform, Drupal does have an existing community of developers who are responsible for updating and improving the features within the CMS. From a creation by eight friends in Antwerp in 2000, Drupal has grown to its present capacity, with an open source community of 800,000 members. It runs some of the world’s most powerful sites, including WhiteHouse.gov.

Now, there are two concepts in Drupal: nodes and modules. Nodes are pieces of content/code; nodes can be anything – polls, articles, products, pages etc. Nodes are like templates, that the development team defines in order to enable addition of new content with pre-set attributes.

Modules however, are pieces of code designed to extend the functionality of Drupal. When a developer wants to do something on Drupal and finds that there’s no feature for it, he/she will design a module to perform that task, and then this module, called a ‘contributed module’ will be embedded in Drupal’s core modules so that other people can use it as well.

Where and why to use Drupal

As we said, Drupal is the most powerful, sophisticated and flexible CMS, thus it will not be useful for every web project. Drupal is advisable for technically complex websites, which start out large and have the potential for getting larger in time.

  • Cost. First, Drupal is free for installation and use, and so are most of its extensions, which puts it far above its competitors. For instance, MS SharePoint has the same technical capability as Drupal, but its licensing fees make it relatively unaffordable. There are some plugins in Drupal that you many need to buy, but many of them are available free.
  • User support. Another advantage that Drupal offers is a large and friendly user international community that you can turn to when you hit a wall. With a team of over 800,000 qualified developers and 330,000 websites running on Drupal, you can be sure someone has a solution for your problem and you can get it easy. There is also paid user support available through various consultancies if that is what your company needs.
  • Flexibility. Everything in Drupal is customizable, everything. If you need to have something on your site, you can. Period.
  • eCommerce. Drupal has the best reviews for its out-of-the-box and excellent eCommerce solutions for large enterprise sites including payment support, custom eCommerce modules and a host of other capabilities.
  • Traffic. Drupal has the ability to carry efficiently the amounts of traffic a huge website is likely to generate without bogging down the site. It does this through an in-built caching system. That is why it is the platform chosen by UniversalMusic.com, WhiteHouse.gov and other high-traffic sites.

Author bio: Jack Dawson is a web developer and UI/UX specialist at BigDropInc.com

He works at a design, branding and marketing firm, having founded the same firm 9 years ago.

He likes to share knowledge and points of view with other developers and consumers on platforms.

FEM
Apr 15 2015
Apr 15

I have been building apps recently that integrate a REST API which subscribes users to a Drupal web app via SMS, they are simultaneously subscribed in the telecom operators database. Conditions must be checked to keep the users status in sync with Drupal and the operator. Other conditions that I won’t cover here include recurring billing or the free trial period.

This is a practical example of how using the REST protocol allows technologies that are completely different to communicate with each other. The technologies in our stack include SMS, mobile billing and a Drupal web app.

First create the URL endpoint by using hook_menu

function my_module_menu() {
$items['my_url/send'] = array(
'title' => 'send',
'page callback' => 'my_module_send_page',
'access callback' => TRUE
);
return $items;
}

When a mobile originated text message “MO” is sent from the customer handset to the shortcode created for our app, a relay message is sent from the telecom integrator’s API and hits the endpoint created with hook_menu on our web app. We then use a GET request to get the values from the values posted to our endpoint url. Parameters include product identification information, partner ID, customer MSISDN and subscription method, as well as other info. We also run an additional API call to check if the MSISDN/phone number is valid and if there is enough money on the customer account.

Here we have the beginning of the callback function that runs when our endpoint is hit.

function my_module_send_page() {

if (isset($_GET['Origin'])) {
$mobile = $_GET['Origin'];
$PricePointId = $_GET['PricePointId'];
$prodId = $_GET['ProductId'];
$mtmo = time() . 'MO';

There are many conditions in the business requirements, which determine different messages in the $text variable to the customer. Success/failure, weekly/monthly, arabic/english, below is the case if success and weekly PricePointId is selected. There is also a check for what language is selected, here we use the language value in the user object, we get this from what language the user selects on the registration form. We then pass back the correct language in the $text variable in a post request using CURL with everything else. Here is some more of the callback function.

if ($PricePointId == XXXXXX) {
if($user->language == 'en') {
$text = 'You have successfully subscribed
}
else {
$text = '??? ??????? ??????? ????? ???? ‘
}
}

$data2 = array(
'Password' => 'test',
'ProductId' => $prodId,
'PricePointId' => $PricePointId,
'SenderId' => 92235,
'OpId' => XXX,
'Destination' => $mobile,
'Text' => $text,
'ExtTxId' => $mtmo,
);

$qry_str = drupal_http_build_query($data2);
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, 'http://integrator-api-endpoint/sendMT?' . (string) $qry_str);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);

Here we get the result from the CURL post to the telecom API.
If the result is greater than one that is success, so we create the user in Drupal and we send a custom email using drupal_mail().

if($result > 0) {
$obj->field_product = $prodId;
$obj->save(); */
$smart_db->changeUserRoles($user->uid , 'subscribe');
$smart_db->changeplan($user->uid, $prodId, $free = TRUE);
$to=$user->mail;
drupal_mail('user', 'register_no_approval_required', $to, user_preferred_language($user, $default = NULL), array('account' => $user), variable_get('site_mail', ''));
}
}

Apr 15 2015
Apr 15

I've been a long-time Omega themer (and I especially love Omega 4), but outside of Drupal I always use Bootstrap as a starting point for styling a site. The Bootstrap theme has come a long way since I last evaluated it, so I gave it another try recently. It was tricky to set up a subtheme, so I'm sharing my steps here.

I found some clues from this article, but refined the process a bit.

Download the Bootstrap base theme

There hasn't been a stable release of the Bootstrap theme recently (as of the time of this writing), so I grabbed the latest DEV which contains lots of bug fixes and extends Bootstrap theming support into more nooks and crannies of Drupal's interface. If you have drush:

drush dl bootstrap-7.x-3.x-dev

Create your sub-theme

You could do this the hard way, by copying the "starterkits/less" folder out of the bootstrap theme folder into your own space (e.g., "sites/default/themes", renaming "less" to something like "bootstrap_subtheme"). Or, just use drush:

drush cc drush
drush dl bootstrap-wizard

(Choose to make it a sub-theme of Bootstrap, using the LESS starterkit.)

Install Bootstrap library source code

Since we're compiling the CSS from LESS, we won't need the Bootstrap distribution, but we will need the source code. Also, the Bootstrap JS files are included via our sub-theme's .info file. So grab the latest Bootstrap 3 release (3.3.4 at the time of this writing) and install it into your sub-theme (in our example above, "bootstrap_subtheme/bootstrap"). The only folders you need are "fonts", "js", and "less".

Tweak the sub-theme LESS

Inside the "less" folder of your sub-theme, there are several .less files. The main one is style.less, which is what you'll compile later. It brings in bootstrap.less (which is a copy of the same file in your bootstrap library folder), and then adds Drupal overrides, and then some blank header, content, and footer files.

You can keep your bootstrap.less file as-is, and comment out the components you don't want. Or you can scrap it all and use something like this:

@import "variables";
@import "../bootstrap/less/bootstrap.less";

This will import your local variables.less file, and then the rest of Bootstrap's source. Speaking of variables.less, the one that shipped with the starterkit at the time of writing had deprecated Bootstrap variables, so I rewrote mine to basically load in the variables from the Bootrap library and then override the ones I care about. That way I can easily upgrade the Bootstrap library at a later date with minimal need to update my sub-theme's LESS. My variables.less looks like this:

// Import Bootstrap's variables, then override them below.
@import "../bootstrap/less/variables.less";

// Update path to fonts.
@icon-font-path: "../bootstrap/fonts/";

Note that I changed the icon path. This fixed the references being broken when my LESS compiled to CSS.

Compile your LESS to CSS

Compiling your LESS is pretty easy. You need to install LESS first, but it should be as simple as:

npm install -g less

Then from your theme's folder, execute the following to compile your LESS into your sub-theme's style.css:

lessc less/style.less > css/style.css

That's it! You now have a LESS-powered sub-theme. Add your custom theming to the built-in header.less, content.less or footer.less files. I usually prefer to create a separate file for each type of thing—content type, navigation, homepage, etc). Just remember to remember to reference any additional files in style.less.

Last thoughts

Unless you already have it a newer version of jQuery on your site somehow, you'll probably want to install jQuery Update and configure it to use at least jQuery 1.9, the minimum requirement for Bootstrap.

Oh, and don't forget to enable your new sub-theme!

Apr 14 2015
Apr 14

DrupalCon Los Angeles is less than a month away, and we couldn't be more excited for the great lineup of sessions and training opportunities. We're thrilled to announce that the schedule is now live on the website, so you can begin building your own dream DrupalCon schedule and planning your day. BOFs are also open, so make sure you claim your space soon -- they go quickly!

Build Your Schedule

The schedule for DrupalCon Los Angeles is live, which means that you can start planning out every detail of your Los Angeles experience. You can start the hard work of choosing the sessions, BOFs, and social events you want to attend, and build your own schedule right on the DrupalCon site.

You can use the master schedule to build your own personal schedule by clicking the add to my schedule text under the events you wish to attend.

You can also access your personal schedule from the master schedule and your profile. If you've accidentally added an item to your schedule and want to take it off, don't panic! There's a button on your profile that will let you easily remove items from your DrupalCon Los Angeles schedule.

Claim a BoF

With the online booking feature, you don’t have to wait until DrupalCon Los Angeles to claim your BoF. But BOF rooms go fast, so claim one today. Keep in mind these tips on how to run a successful BoF:

  • Do be respectful -- adhere to our code of conduct and respect BOFs that have already been schedule
  • Do encourage openness and inclusivity in your BOFs. Encourage participation.
  • Don't be afraid to split the group up into smaller groups -- everyone should have a chance to share his or her insight.
  • Do collaborate with the owners of similar BOFs.
  • Do feel free to find a moderator if you think it'll be necessary.
  • Don't use BOFs as an opportunity to run a sales pitch or product demo.

Sign up for a Training

Sessions and BOFs aren't the only opportunity to learn at DrupalCon -- we've got a lot of great training oportunities lined up for our attendees. If you haven't already, check out all of the awesome trainings we have available for you for Monday, May 11. Tickets are selling quickly, so snag yours today.

Check Out the Full Schedule

Apr 14 2015
Apr 14

We recently had a new client contact us and ask if we could move their sites over to Pantheon so they could do some in-house development work. Of course we can do that for you! We recommended doing a Site Assessment for them, just to make sure we know what we're dealing with. Our Site Assessment gives us a good understanding of the state of a client's current site.

It is not only in Freelock's best interest, but the client's as well, to know what we're getting into before we can even set reasonable expectations of what it will take to change. So, we typically start out with the assessment and review before doing any work on a new site.

But, our client was hesitant to purchase the Site Assessment, which would not only be helpful for their IT staff, but also extremely beneficial to their upper management. So, we began the process of flying blind with the site migration. Then, all of a sudden, we ended up running into so many critical problems, that we were surprised their website had been so neglected in the first place!

It turns out that our client's site had been hacked. While it had been patched for the "Drupalgeddon" Drupal core security patch of October 2014, we found malicious code embedded in the Drupal core. This underscores the importance of regular site maintenance, which Freelock offers to over 30 of our clients.

It also turns out that we were not dealing with one "domain access" site as we had been told, but really 3 "multi-sites" under a single shared code base, a configuration Pantheon explicitly does not support. So, in addition to finding malicious code on all of their sites, we found that the project involved not setting up 2 sites in Pantheon, but 4!

We ended up cleaning the core hacks we found... but at this point we still don't know if the hacker left any back doors on our client's sites that might allow them future access. We stressed the importance to analyze all of their sites, to be able to give them an answer, with any confidence, on whether they are still vulnerable or not. Unfortunately, we still have not heard back....

With a site assessment we dig deep into the site to detect whether or not it has been hacked, including scanning the database for executable code, comparing all module code against known good copies, and evaluating whether the environment is set up to properly withstand attacks.

We see this time and time again. A client comes to us either in an emergency, or wanting some specific one-off job done (which we love taking care of!!), but they don't want to put the time in to investigate the root cause of the problems with their site, or use the budget to apply permanent fixes for those problems. Having a good understanding of the current state of your site, and mitigating for those risks ahead of time, will save a lot of time and energy in the long run for clients whose lifeblood are their websites.

We've found that some of our most successful clients know exactly what is under the hood of their websites, engage development personnel often, keep their websites up-to-date, and constantly reinvest a percentage of their website revenue (generally 1-10%) to keep their site fresh and responsive. Sometimes this takes in-house personnel who are exceptional at development, or in our case, creating a longterm partnership with us to help you achieve your business goals through building and refining your website presence. We encourage you to contact us and build a longterm partnership to help you realize your website's potential!

Apr 14 2015
Apr 14

Drupal 8 is just around the corner, and the Drupal community is excited!

We want to make sure that as many people as possible can use Drupal 8. However, many new Drupal 8 users will need training, which can be expensive and difficult to find.

So, we started a Kickstarter project to create Drupal 8 training and give it away for free!

Sounds intriguing? Watch the video to find out more ...

What Drupal 8 training will we create?

The initial goal for the project is to raise $10,000. That will allow us to create 50 introductory videos for Drupal 8.

These will be given away completely free to the Drupal community.

We'll put the videos on YouTube and make the files available for anyone to download.

Hopefully, by making the video files available for download, the training will be translated into other languages, helping Drupal 8 reach the widest possible audience.

Here are the videos we plan to create:

  • Why Drupal 8? (10 videos) 
  • Drupal 7 vs Drupal 8 differences (10 videos)
  • Drupal Beginner (30 videos)

Visit the Kickstarter

What happens if the goal is reached?

If we pass the initial goal, we'll create another bundle of 50 videos every time we raise an additional $5,000.

These extra videos will also be given away free!

Extra Videos #1. The Intermediate Bundle ($15,000 goal)

  • Site management, security backups, updates (10 videos)
  • Drupal Intermediate class (30 videos)
  • An example site building class (10 videos)

Extra Videos #2. The Theming Bundle ($20,000 goal)

  • Introduction to Twig (10 videos)
  • Creating a Drupal 8 theme (40 videos)

Extra Videos #3. The Module Bundle ($25,000 goal)

  • Introduction to Symfony (10 videos)
  • Creating a Drupal 8 module (40 videos)

Extra Videos #4. The Development Bundle ($30,000 goal)

  • Drupal 8 web services (20 videos)
  • Configuration management (20 videos)
  • Introduction to Composer (10 videos)

Extra Videos #5. The Upgrading Bundle ($35,000 goal)

  • Upgrading a site from Drupal 7 to 8 (20 videos)
  • Upgrading a module from Drupal 7 to 8 (15 videos)
  • Upgrading a theme from Drupal 7 to 8 (15 videos)

Visit the Kickstarter

Anything more we need to know?

Yes, if you support the Kickstarter project, you'll get this excellent t-shirt!

drupal-tshirt

Visit the Kickstarter

Apr 14 2015
Apr 14

If you have been to the Mediacurrent blog before you have probably seen my Top 50 modules lists for Drupal 6 and 7. This current list will be my final update for Drupal 7. My last blog from 2012 was in dire need of updating so I have gone through one last time to give our readers my a good list of modules to start with for their next Drupal 7 site.

If you have visited Drupal.org recently you will notice that there are literally thousands of modules available to download. This can be very intimidating for new users who are just getting started building Drupal sites. The secret for newbies to know is that most developers continually use a few dozen of the same modules on almost every project.

As a 9 year veteran of Drupal I like to share my list of modules that I personally use on almost every site I build. If you are just getting started, this is a good list to begin with. If you are an intermediate or even an expert developer it can be helpful to skim the list to see if there are any modules that can help you on your next project.

If you are getting start be sure to take a look at the Panopoly distribution. This is a great way to get a lot of preconfigured modules and editorial tools out of the box. I highly recommend you check it out!

NOTE: I have tried to indicate on the list where I have made changes. You will see several 'New' and 'Updated' labels. 'New' does not mean new to Drupal, but rather new to the list.

Enjoy! Send your feedback and hate mail to my Twitter account @drupalninja or leave a comment below. Thanks!

  • Address Field
    Address field allows you to collect an address from within a field and has Views integration.

  • Admin Views + Views Bulk Operations *Update
    Admin views will replace Drupal core administrative lists with Views. This makes it much easier to modify these lists (such as the /admin/content screen). This module uses VBO which adds bulk operations to administrative views.

  • Date
    Allows ‘date’ fields to be added to content with beautiful javascript-powered popup calendars and has Views integration.

  • Email
    This module allows you to add email address as fields in Drupal 7 which is a pretty common use case.

  • Entity Reference *New
    This module is similar to the References module in that it allows you to reference one entity to another. Entity reference is now in Drupal 8 core so this is the module we recommend using. One word of caution, the entity reference select widget can have performance consequences for large lists of content.

  • Field Collection
    This module allows you to create composite fields for Drupal content types. Field collections are 'entities' in Drupal 7. This is a VERY handy module. The module includes Views integration although it can be a bit advanced for novice site builders.

  • Field Group
    In Drupal 7 you need this module to group fields together on a content type. This is helpful for editors as it provides visual clarity as to how fields should be grouped together on a page.

  • File Field Sources
    This module provides a handy file widget for content forms. The Media module also provides a widget with a popup dialog but sometimes “filefield sources” is a better fit.

  • Image Link Formatter *New
    This module is very handy for the common use case where you want to render an image as a linked image using a link field as the value.

  • Link
    Allows you to add ‘link’ fields to content and has Views integration.

  • Media
    This module is ubiquitous with file field widgets in Drupal 7. The Media module provides an interface for managing media in Drupal and has many extensions available. The downside of this module is that it does have a history of being buggy.

  • Menu Block
    While we avoid using the block module at all in favor of Panels sometimes we will enable the block module solely to be able to use this module. The menu block module allows site builders to create a slice of a menu that can be embedded as a block.

  • Module filter *New
    This module is a must have for the /admin/modules page which can get very long and difficult to navigate. The module filter organizes modules and provides a search box.

  • Panels *Update
    Since my last post, the Mediacurrent team (as well as many other Drupal shops) has coalesced around using Panels as the site building tool of choice. With custom Panel layouts you can control the entire page output with the ability to heavily customize the markup. Due to the rise HTML frameworks (e.g. Bootstrap, Foundation, etc.) it is critical to have strong control over the Drupal markup that renders on the page. We find that Panels can handle all our use cases without requiring additional site building tools (e.g. D.S., Context, etc.).

  • Panelizer *New
    This tool is a nice compliment to Panels, in that it gives editors the ability to customize layouts per entity instance. This gives us the ability to empower editors with much more flexibility in how they build out pages. Panelizer can be used for virtually any entity type and view mode.

  • Pathauto
    The standard for automatic path aliasing. A must-have module.

  • Rules
    This module is a swiss-army-knife tool for all sorts of tasks that in the past might have required custom code. You can send emails, set breadcrumbs, all sorts of tasks.

  • Search API *New
    For site builders that need to customize search, this module is the only way to go. The Search API will require additional modules (e.g. Search API DB, Search API Solr, etc.) depending on the search engine used.

  • Smart Trim *New
    This module is a must have for site builders. Now maintained by Mediacurrent! Smart Trim gives developers much better options for providing trimmed content teasers.

  • Views
    This is the reason why you are using Drupal. Views in now in Drupal 8 core!

  • Views RSS *New
    Out of the box, Drupal does not give a lot of control over how RSS is rendered by Views. This module allows developers to the tools they need to customize RSS display.

  • Webform
    A must-have module for every site. Often used for contact forms and has all kinds of useful functionality.

  • Admin
    I used this module quite often for Drupal 6 sites but I now use Admin Menu or Navbar.

  • Captcha + Recaptcha
    Captcha’s are not quite as beloved as they once were for spam prevention. While still an option, there are captcha alternatives such as Honeypot.

  • CCK
    This module had some useful functionality when migrating from Drupal 6 but I don’t use this module much any more for D7 sites.

  • Colorbox
    Colorbox is a fairly good lightbox module and so it was a tough call to remove from the list. I think for new users colorbox works great. For highly customized sites though I find custom integrating a lightbox plugin is actually easier than fighting one of the modules to product the output I am wanting.

  • Content Taxonomy
    While this module has some useful taxonomy, the core taxonomy term widget is good enough for most use cases.

  • Context
    While Context has some useful functionality I have found that I can use other tools in place of Context. Panels and Rules most notably provide most of the functionality I used to need Context to provide.

  • Display Suite
    Similar to the Context module, Panels is a suitable replacement for what Display Suite can do. Display Suite’s approach is interesting, and preferred by some users over Panels. For many though, Panels can do more than Display Suite can do alone without requiring additional site building modules.

  • IMCE
    The Media module adds an image button dialog to Wysiwyg and so I don’t use IMCE any longer.

  • Menu Breadcrumb
    While this module is useful, it does not handle every use case. Often breadcrumb rules are complex enough to require custom logic outside of Menu Breadcrumb.

  • References / References Dialog
    While these modules are good in their own right, we have migrated to the ‘Entity reference’ module which is included in Drupal 8 core.

  • Styles
    This module is no longer needed to customize file entity display.

  • Views PHP
    While this module is handy, it presents a security risk in that you have to enable the PHP module. It is recommended to find alternatives.

  • Views Slideshow
    This is a good module but I am finding that I would rather integrate a 3rd party jquery slideshow manually as opposed to using Views Slideshow which can be buggy and difficult to customize. That being said, for beginners this is still a pretty good module to use for rotating content.

  • Apr 14 2015
    Apr 14

    Google Analytics is the world's most popular tool to gain quality online insights. Drupal offers a module to leverage its potential to the fullest. In this article, we will help you configure the Drupal Google Analytics module.

    The biggest advantage this module offers is that you don’t have to copy the tracking code to each page you wish to track. Pasting the Tracking ID in the module’s configuration page will be enough.

    The 2 screenshots below showcase the kind of data you can access once you are done aligning your Drupal site with Google Analytics. While the first screenshot showcases real-time data (traffic on your site at the moment), the second one highlights data for a particular time period.

    This article will help you configure Drupal Google Analytics to take you through such insights for your brand. We will be performing this on Drupal 7. So let’s get started!

    Creating a Google Analytics account and copying the Tracking ID

    1. Go to www.google.com/analytics. Click Access Google Analytics on the top-right.

    2. Sign up for a Google Analytics account.

    3. On successful sign-up, you will be taken to a page that allows you to create a new account.

    You will have to enter data for the following fields:

    • Account Name: Type your company's name here.
    • Website Name: You can either type in your website's URL (for example, mywebsite.com) or give it in plain words (MyWebsite). It can be provided the same value as Account Name.
    • Website URL: Type the URL of the website for which you seek to enable tracking.
    • Industry Category: Choose the industry that best suits your company.
    • Reporting Time Zone: Select your time zone.
    • Data Sharing Settings: These check boxes are already ticked by default. You can leave them as is.

    Refer the screenshot below for more details:

    4. Click Get Tracking ID at the bottom of the page.

    5. A pop-up with Google Analytics’ Terms of Service appears. Click I Accept.

    6. The new page will feature the Tracking ID. Copy this to a secure location. You will need it while configuring the Google Analytics module.

    Installing and configuring the Google Analytics module

    1. Visit here to download and unzip the latest tar.gz file to your modules folder.

     2.  Go to your Drupal site. Click Modules at the top-level menu. 

     3.  Search for the module. A quick search will reveal it under STATISTICS. Tick the box against Google Analytics:

     4.  Click Save Configuration.

    Search for Google Analytics again and click Configure.

     5.  In the new page, paste the Property ID in the Web Property ID box under General Settings:

    Clicking Save configuration will get you started with default settings. This is enough to drive basic SEO analytics for your website.

     6.  You will be able to configure further under Tracking scope. I have left most of these settings as they are:

    1. Domains: Specify whether you want to track a single site, multiple sub-domains or multiple top-level domains.

      ii.  Pages: This setting allows you to select the pages you intend to track or not track. You can provide values in the text below. By default, the module already lists a set of values (admin, admin/*, etc.). Alter them only if you need to.

      iii. Roles: All user roles defined for your site appear here. Tick the boxes of roles you wish to track. It’s ideal not to tick every box because you will end up with a lot of muddled data. Use this option wisely or ignore! 

      iv.  Users:  "No customization allowed" will enforce your choice of tracking for users. Choose any of the other options if you have given users the opportunity to use the “Opt-in or out of tracking” permission. This gives users the freedom to decide whether they should be tracked on your site or not.

      v.  Links and downloads: This is where you specify the links and downloads you wish to track. The text box lists the file extensions you wish to track.

      vi.  Messages: Do you wish to track messages generated on your site? If yes, tick the boxes accordingly. I have left them alone.

      vii.  Search and Advertising: I have ticked the box against Track internal search to monitor keywords being searched on my site. If you are using AdSense ads, then it will be wise to tick the second box. 

    P.S.: After you configure Google Analytics, you can analyze the internal keywords used on your site by going to the following path: Behavior -> Site Search -> Overview. Refer the screenshot below:

      viii.  Privacy: Tick these boxes if you wish to hide the IP addresses of site visitors and if you wish to use the "Do not track" header.

     7.  CUSTOM DIMENSIONS and CUSTOM METRICS

    These sections are for those who have previously worked with dimensions and metrics. These are user-created values that help track statistics that are generally not monitored by Google Analytics.

     8.  Configure Advanced Settings

    Here is where you can set up the location to cache the data or add a custom javascript.   

    Click Save Configuration.

    You have now successfully configured the module.

     9.  Testing whether Google Analytics is operational 

    It may take a couple of hours or a day for Google Analytics to be set up for your site. After it is activated, you can log in to your account. Your homepage will be similar to the one below. Click All Web Site Data. You will be directed to the Google Analytics dashboard.

     10. Accessing analytical data

    The first thing you see on your dashboard is the site traffic for your site. You can select a time period for which you want view traffic. This option is available in the top-right corner:

    Specify a time period and you will be able to view corresponding traffic as shown in my screenshot below:

    You can also view real-time traffic to understand the number of visitors on your site at this very moment. For this, you will have to adjust the time period to the current date:

    After this, follow the path Real-Time -> Overview to view the number of visitors active on your site at this very moment.

    Note that my configuration was pretty basic. You could play around with the configuration in the Google Analytics module to arrive at more refined settings for your business.

    Apr 14 2015
    Apr 14

    Ace up sleeve

    Drupal 8 is right around the corner; it's time to start brushing off your old textbooks, taking notes, asking questions, and preparing for all the awesomeness coming your way.

    For most of us, Drupal 8 represents a departure from what we've come to know about how to create with Drupal. In short, we've got a learning curve we're going to have to overcome before we can be proficient with Drupal 8. But I'm here to tell you: it’s okay, we're in this together, and, given the proper learning environment and a little bit of guidance, you'll be Drupal 8 ready in no time.

    In the glorious words of Douglas Adams, “Don't panic!”

    While most of us have a tendency to want to jump right into the documentation and start poring over code samples, this is a good opportunity to take a step back and make sure we're ready to learn before we dive in. So let’s take a minute to think about education theory and the environment we put ourselves in when preparing to learn a new technology. How do we remove blockers from the learning process and set ourselves up for success?

    Consider:

    • What is my motivation for learning this?
    • Where can I practice what I'm learning?
    • How will I know if I have learned the right thing?

    How motivated are you?

    Are you learning for fun, or for work?

    Because you want to, or because you have to?

    Our motivation – and our understanding of it – allows us to decide whether it is worth the investment in time and energy necessary to learn something new today – right now – which we may not use until tomorrow.

    One of the best ways to assess whether or not you've learned something is to teach it to someone else. Lucky for you, you're not the only one embarking on the quest to learn Drupal 8; there are plenty of opportunities to share your new knowledge with others. Local user groups, co-workers – even friends on IRC – all represent great teaching opportunities. Moreover, these interactions often turn into discussions, and discussions are one of the best ways to get beyond the how and into the why.

    In addition to practicing by teaching, you can also practice your new Drupal 8 skills by assisting with Drupal 8 itself, or helping to improve the documentation and making it easier for the next person to learn.

    My third question is: How will you know if you’ve learned the right things? This will, of course, depend on your motivation. If your motivation was to become a better-rounded programmer, and you learn OOP where you only knew functional programming before, I'd say you've accomplished your goals.

    I encourage you to stop reading now and take a moment to think about these three questions and see if you can answer them for yourself. It may seem trivial but I believe that knowing why is just as important as knowing how.

    Ready to learn?

    Great. Here are some excellent resources to help get you started, and some basic terminology so at least you'll know what you don't know.

    The following is by no means a comprehensive list of all the things you'll ultimately need or want to know, but it does provide some general background knowledge that will be applicable to everyone writing code for Drupal 8. A lot of it will also be assumed knowledge by many people already working with Drupal 8, so having at least a cursory understanding of these topics will make it easier to follow along with documentation and converse with others on the subject.

    In order to take fuller advantage of the PHP language, and what are considered to be best practices for modern PHP based web applications, Drupal 8 has chosen to require a minimum of PHP version 5.4. Doing so opens the door to better leverage modern object-oriented programming patterns, which is good for you because it allows Drupal to be more flexible and less tightly-coupled than ever before. It also helps bring Drupal 8 more in line with the syntax, patterns, and methodologies that many other PHP based frameworks are using. One of the big hopes here is that this will allow Drupal to attract more PHP developers and at the same time allow existing Drupal developers to become better overall PHP programmers.

    For those of us making the transition from Drupal 7, this means that the syntax of our modules is going to look quite a bit different: The important thing to remember is that everything you could do in Drupal 7 you can still do in Drupal 8 once you learn the new patterns. One good resource for adapting your knowledge of Drupal 7 to the new way of doing something in Drupal 8 is the change records available on Drupal.org. I've also found that doing a side-by-side comparison between how something is implemented in Drupal 7 core vs. Drupal 8 core can go a long way towards pointing me in the right direction: even if I don't completely understand how it's working, at least I have working code and a better knowledge of what I don't know.

    As a developer, make sure you're familiar with basic OOP syntax and patterns, which is now assumed knowledge for anyone doing Drupal 8 development. Also pay particular attention to namespaces (which allow for better compartmentalization of code, and eliminate the namespace conflict problems inherent in Drupal 7's architecture) as well as the concept of late static binding (which allows for the constructor injection used throughout Drupal), both of which you'll encounter early and often.

    Speaking of OOP design patterns in Drupal, dependency injection (DI) is a pattern that you'll absolutely want to become familiar with. DI is being applied throughout Drupal in order to ensure a less tightly-coupled system by providing dependencies as arguments instead of hard coding them.

    "Wait, what was that?" you say.

    Although the pattern sounds complex, it is actually straightforward and, in my experience, is often just giving a fancy name to something you're already doing. Be prepared to hear the term used frequently, and understand the basics of setter injection and constructor injection – the two forms of dependency injection used most frequently in Drupal.

    In addition to using the DI pattern, Drupal 8 also provides a Dependency Injection Container; in essence, a global object where you can simply request the service you need, and it'll configure and provide the appropriate object already initialized and usable.

    Need to query the database? Get a database connection object from the Dependency Injection Container and it'll already be configured to connect to the appropriate database server using the correct username, password, and other data. As a module developer, that means you can just start making queries, with no need to worry about what database is being used in the background or the specifics of connecting to it with PHP.

    PSR-0 and PSR-4 (or PHP Specification Request 0 and 4) are patterns for standardizing the name, location, and content of files, which makes it possible for Drupal to locate and load files on an as-needed basis. Neither standard is specific to Drupal – the standards are put forth by the PHP Framework Interoperability Group with the hope of allowing greater compatibility between PHP code libraries. By adopting these standards, Drupal 8 is able to include third party libraries like Guzzle and components from other frameworks like Symfony 2 in a clean way. At the time this article was written, both PSR-0 and 4 are in use in Drupal 8, though that is subject to change. Either way the patterns are very similar and learning both won't hurt.

    Because files are now located in specific known places, and their contents are also known, Drupal can perform auto loading without requiring a Drupal 7 style registry. As a module developer, this allows you to instantiate a new object of a specific type without having to ensure you've loaded the file containing the class definition first. It also reduces the amount of code and thus memory that PHP needs for each request, and increases the findability of a particular file or class definition in the codebase. Once you understand the pattern, you only have to repeat it and Drupal will take care of the rest.

    Remember hook_block_info() from Drupal 7?

    Implementations of this hook return an array that provides metadata which specifies things like the title of the block and an optional cache granularity setting. For performance reasons, it's best to have this kind of metadata available without having to access a database. Annotations provide a mechanism for encoding metadata about a class within the comments for that class, keeping the configuration and the actual code close to one another for discoverability purposes, and allowing Drupal to access some general information about the block this class represents, without the hassle of instantiating an object first.

    Although you can accomplish quite a bit without ever using annotations, sooner or later you're going to encounter it, probably either creating custom blocks or working with the Field API.

    While we're on the topic of metadata, it's also worth mentioning YAML. A recursive acronym for YAML Ain't Markup Language, YAML is a human readable syntax for representing configuration in static files. Drupal 8 makes use of YAML in numerous places, including as the default storage mechanism for configuration data provided by the configuration management system, as a way for theme and module developers to describe basic properties of their project (like name and description, replacing Drupal 7 .info files), and as a way, in the routing system, for module developers to define the various ways in which incoming requests to Drupal are mapped to the PHP code they should execute.

    The YAML syntax itself is straightforward; learning it will be of huge value and little trouble. Once you've mastered the syntax though, understanding the various configuration options that it can be used to define will require understanding the respective Drupal subsystem that makes use of the YAML file in question.

    One of the biggest misconceptions in the Drupal community right now is that you'll be required to learn Symfony 2 in order to be a Drupal 8 developer. I don’t think this is true.

    If you're going to start hacking on core, then yes, you'll want to brush up on the various Symfony 2 components that have been included. But as a day-to-day module developer, you're not likely to encounter much that will require you to know Symfony 2.

    Bottom line: many of the patterns and concepts that you need to know for Drupal are also used by the Symfony 2 project, so learning Symfony 2 will only make you a better Drupal developer – and a better PHP developer.

    I could go on listing topics, but that should be enough documentation to get you going, along with a final bit to keep in mind as you wend your way through all these resources.

    About a year ago I was at a company retreat and I posed a question to my coworkers: “How can I help you learn Drupal 8?”

    What we realized was that we were all capable of reading the documentation, and content to look at code examples in order to understand how any particular system worked, but that the more important and difficult question was “why?”

    Why does CMI use YAML for its default data storage?

    Why should I extend FormBase instead of just creating my own class for building a form?

    When you can figure out why specific decisions were made, you'll also understand the potential limitations of those decisions, and you'll be capable of pushing Drupal to its limits. So while you're poring over documentation and sample code remember to take a moment to ask, "Why this way?"

    Resources

    PHP 5.4 - Modern PHP

    Importance: Critical
    Difficulty: Easy

    PHP - Namespaces

    Importance: Critical
    Difficulty: Easy

    Dependency Injection

    Importance: Critical
    Difficulty: Moderate

    General information on DI

    DI in Drupal

    PSR-0 & PSR-4

    Importance: Critical
    Difficulty: Easy

    Annotations

    Importance: Moderate
    Difficulty: Moderate

    YAML

    Importance: Critical
    Difficulty: Easy

    Symfony 2

    Importance: Good to know
    Difficulty: Hard

    The basic Symfony 2 documentation is extremely good and can be worked through over the course of a couple days. Like Drupal though, mastering Symfony 2 will take much longer, and learning all the moving parts will require actually making use of them in real-world scenarios.

    Image: ©iStockphoto.com/lisegagne

    Apr 14 2015
    Apr 14

    expo imageMarketing is a key factor to growing Drupal adoption and spreading the goodness of Drupal. One way to do that is by exhibiting at key industry events. The CMS Garden team has done a great job getting Drupal included in some key events in Europe and now the Drupal Association will take on a parallel effort.

    The initiative will be an experimental “co-marketing” campaign to promote Drupal in the European marketplace. It is called a “co-marketing” campaign because it will be crowdfunded by a group of Drupal businesses (if you would like to find out how your Drupal business can get involved, keep reading). This is a pilot program that will allow us to experiment with the best ways to promote Drupal in the global marketplace and reach the CMS evaluator audience.

    Why Europe? Data from our DrupalCon surveys show that relative to DrupalCon North America, DrupalCon Europe has a higher percentage of developer attendees but a lower percentage of CMS “evaluator” attendees. From that standpoint, it makes sense to target Europe evaluators in this pilot program. The evaluators we are targeting in the pilot program are digital marketers who have significant sway over CMS selection.

    So what’s the plan?

    This year, Drupal Association will secure exhibit space at two European digital marketing industry events (dmexco in Germany and Festival of Marketing in the UK). We will exhibit as Drupal and together with representatives from the anchor sponsors who have already signed on (including Wunderkraut (Germany), Wunder (UK) and Deeson (UK), we will promote Drupal and the sponsoring companies’ expertise and successes with Digital Marketing and Drupal. Leads generated from the exhibit presence will go to the sponsoring companies. We are offering first right of refusal to sponsor the effort to Drupal Premium Supporting Partners, followed by other Supporters.

    Why these two events? There are many events in Europe that target the audiences we want to reach. After researching attendee types, costs and other factors, we determined the abovementioned events make the most sense for this pilot project.

    If you would like to learn more about how your business can participate in this exciting initiative, please contact Johanna Bergmann. [email protected].

    Apr 14 2015
    Apr 14

    Blink Reaction has announced it has begun to offer free live public Drupal training online, in NYC and in other major markets.The free classes will focus on Drupal 8 adoption and will include Site Building classes formerly offered at $799.

    Announcing the decision to offer free Drupal training, Blink CEO Nancy Stango explained the decision.

    Building a robust Drupal ecosystem requires attention to all the things. We can’t just build great software. For many people formal training is the best way to learn and we need to lower obstacles to Drupal adoption everywhere. Providing this training free of charge on a regular schedule is part of our contribution back to the community.

    Included in each free class listing is an appeal to support the Drupal Association by becoming a paid member.

    Blink has been delivering paid public training since 2011 through the Blink Institute and has offered free training during Global Drupal Training days since the start of the program. 

    Visit our training pages for more information and to register for a free training.

    If you’re interested in Developing for Drupal 8 register for our Drupalcon LA class, ‘Introduction to Symfony/Getting Ready for Drupal 8.’ Half of all proceeds goes to support the Drupal Association.

    Why is this class free?

    Providing this class free of charge is one of the many ways we give back to the open source community. 

    Blink is highly committed to helping organizations and individuals adopt Drupal successfully. At Blink we believe great training helps create great, results-oriented websites. That's a win-win-win for you, Drupal and Blink.

    Please consider supporting the Drupal Association instead. Individual membership is only $15.

    And if you’re interested in Developing for Drupal 8 register for our Drupalcon LA class, ‘Introduction to Symfony/Getting Ready for Drupal 8.’ Half of all proceeds goes to support the Drupal Association.

    Drupal Association Supporter

    Apr 14 2015
    Apr 14

    After making it’s first Drupalcon appearance to a sold out crowd in Austin, I’m really excited to be offering an updated version of our class in LA. 

    Since Austin we’ve offered the class in Drupalcon Amsterdam and Drupalcon Bogota. Each time it has been filled to capacity and tickets are already going fast for Drupalcon LA.

    This year we’ve focused even more on the Symfony components that are most important for developing in Drupal 8.  We’re spending additional time in Drupal 8 too since we are oh so close to a release. 

    The class will be led by Blink Drupal 8 Solutions Engineer Jesus Olivas, lead contributor on the Drupal Console project supported by Blink. Jesus will also share some of the latest new features he's built in the Console project. No fewer than eight Blink developers will be supporting Jesus so that we can give each and every participant a hands on experience.

    Register for the class now on the Drupalcon LA site.

    Pages