Jun 13 2019
Jun 13

Just when you think Drupal couldn’t get any dumber, it goes and adds some great new features….. And TOTALLY redeems itself!


via GIPHY

Released back in November of 2015, Drupal 8 has been slowly but steadily upping its game.

In case you’ve been lost in a jungle for the past couple of years, or maybe you just don’t keep up with that kind of thing, we’ve got you covered.

Here are just some of the things Drupal 8 and soon to be Drupal 9 have us jumping around like crazy apes about.

BigPipe

BigPipe is a technique that was invented by Facebook back in 2009 when they made the site twice as fast, which is an amazing feat in itself. 

How it works, is it first breaks pages up into multiple “sections”, which are then loaded in parallel so your users don’t have to wait for the page to be completely loaded before they can start interacting with it.

Page speed is extremely important, considering 47% of people expect your site to load in less than 2 seconds and 40% will abandon it entirely if it takes longer than 3 seconds.

Not only that, but Google has indicated site speed (and as a result, page speed) is one of the signals used by its algorithm to rank pages.

If you care about SEO, you should care about the speed of your pages.

Page SpeedSource: Google Developers

The BigPipe module was included in Drupal 8 core since 8.1 and became stable in 8.3.

Just having BigPipe enabled makes your pages faster with zero configuration needed. We can thank Drupal 8’s improved render pipeline & render API for that.

Yay Drupal 8!

Layout Builder

Drupal’s Layout Builder is probably what we are most excited about. 

For far too long, Drupal has been very restricting when it comes to building pages out and putting the content that you want, where you want it.

Think about if Display Suite and Panels had a baby gorilla. That’s Drupal’s new Layout Builder.

Layout Builder was introduced in Drupal 8.5.0 as an experimental core module, but as of Drupal 8.70, it is now stable and production ready!

It offers a powerful visual design tool and is meant for the following three use cases, according to Drupal.org:

Layouts for templated content. The creation of "layout templates" that will be used to layout all instances of a specific content type (e.g. blog posts, product pages).

Customizations to templated layouts. The ability to override these layout templates on a case-by-case basis (e.g. the ability to override the layout of a standardized product page)

Custom pages. The creation of custom, one-off landing pages not tied to a content type or structured content (e.g. a single "About us" page).

The Layout Builder gives developers/site builders the ability to drag and drop site-wide blocks and content fields into regions within a given layout.

layout builderSource: Drupal.org

With custom and unique landing pages being so important nowadays, this is finally the flexibility and freedom we need!

Media

Media management has always been an afterthought in Drupal. 

Today we consume more videos and pictures than ever, with the likes of Youtube, Instagram and Facebook.

According to Cisco, they predict that video will make up 80 percent of all internet traffic by 2019. That's like.... Today!!

Thanks to the Media in Drupal 8 Initiative, an experimental core media module was introduced in Drupal 8.4. Then in 8.5, it was moved to stable and has gotten even better in Drupal 8.6, with the addition of oEmbed, additional media type support, and a media library.

Media timelineSource: Webwash

Let’s break down all three of these for you.

Additional Media Type Support
Support for local audio, video, images and generic files, along with being able to embed remote YouTube and Vimeo videos.

oEmbed Support
Needed to handle the new remote video media type mentioned above.

Media Library
The most exciting of the three and pretty much speaks for itself as a library of all your media. Can use a grid view, which shows a thumbnail, title, and bulk edit checkbox, or a table view, if you prefer that sort of thing.

All-in-all, media management is still not where it needs to be, but all these additions to core are a massive jump in the right direction.

There is no reason to wait until Drupal 9

If you’re currently on Drupal 6 or 7 and aren’t totally pumped after reading this, you should be.

Finally, Drupal has given us the speed, flexibility, and freedom we need to improve workflow, save time and succeed online. 

What’s even better is that Drupal 9 will essentially be just like another minor core update in Drupal 8. It will be seamless unlike ever before. 

There is just no reason to wait. Make the update today and enjoy all these great features.

Let’s start a conversation about it.

Drupal Development Experts

Jun 10 2019
Jun 10

Why?

Because instead of building a radically new version of Drupal in a separate codebase, Drupal 9 is being built in Drupal 8.

You might be thinking… “Huh?!”

Well, what this means is that the upgrade experience will be as smooth as a monkeys bottom.

Drupal 9 will essentially be just like another minor core update in Drupal 8. 

What is a minor core update? Quite simply, it’s the middle number in the version of Drupal you are running.

Core updates come out roughly every 6 months and keeping your site up-to-date with these is critical in making sure it’s well maintained.

Drupal Patch MeaningPhoto credit: From Acquia webinar

Drupal 9 release date

So when is Drupal 9 expected to be released?

From the information we have so far, it's scheduled for the second quarter of 2020.

So why was this date chosen in the first place?

Simple. A little thing called Symfony 3.

Drupal 8’s biggest dependency is Symfony 3, which has an end-of-life date of November 2021.

This means that after November 2021, developers will not resolve any security bugs in Symfony 3, and Drupal will be in the same situation.

Drupal 9 will be using Symfony 4 or 5 and won’t have to worry about this issue.

Drupal 9 release datePhoto credit: From Acquia webinar

What does this mean for Drupal 6 or 7 sites?

Well, it means you’re missing out on a helluva lot of great new features, you have potential security risks and are flat our hindering yourself from being able to deliver amazing user experiences that will help your business grow.

If you’re on Drupal 6, support ended as far back as February 2016 and you’ve got serious unmitigated security risks.

You’re on Drupal 7, support ends in 2021 and we all know how fast time goes.

If you haven’t started planning or budgeting for this, its time to start now.

The migration from either 6 or 7 to 8/9 is going to be painful and cost-intensive but it will be the last great migration Drupal will need to incur.

Does this resonate with you? Let's chat!
 

Clutch 5 Star Review

May 07 2019
May 07

Back in September 2018, Dries Buytaert, founder and project lead of Drupal, announced, 

Drupal 7 will be end-of-life in November 2021, Drupal 9 will be released in 2020, and Drupal 8 will be end-of-life in November 2021. 

You can read the announcement and get further information on this here - https://dri.es/drupal-7-8-and-9

Since that announcement, Cheeky Monkey Media has been in a lot of conversations with businesses of all shapes and sizes, not-for-profit and for-profit, that are currently on the Drupal 7 CMS platform and are considering migrating to Drupal 8.

The first thing everyone needs to realize is the move to drupal 8 will be painful, and almost as expensive as building a Drupal website from scratch.

The second thing everyone should realize is that once they’re on Drupal 8, the move to Drupal 9 will be relatively painless.

As Dries announced in a later article,

...it should be much easier to upgrade to Drupal 9 than it was to upgrade to Drupal 8. Drupal 9 will simply be the last version of Drupal 8, with its deprecations removed.

You can read the full article here - https://dri.es/plan-for-drupal-9 

Cheeky Monkey Media has completed several migration projects to Drupal 8, both for our agency partners and our clients.

We’ve approached these projects in several different ways to help organizations make the migration “less painful” from process and a budget perspective, and I’m going to share them with you now.

First let’s make an assumption. 

Whenever we have conversations with organizations about the migration to Drupal 8, in addition to the migration there is typically some issues or challenges our clients want to address with their website while in the process of migration. 

They either want to fix issues with features and/or functionality, design, or all of the aforementioned. 

So let’s assume that you're not entirely happy with how your current D7 site is functioning, and/or you might be considering a redesign. I mean it makes sense. You’re looking at rebuilding your site anyways, so you might as well improve the results you’re getting from it in the process. 

To help illustrate the different approaches and how they will impact your budget, I've also included some mock budgets and timelines to illustrate the budget difference between the approaches. 

I know nothing about your site at this point except that it’s likely on Drupal 7. So, I decided to use nice round figures of $100,000 - $120,000 for option #1 below, which you might be thinking is your only option at this point, but our past projects have shown that this is not the case. 

Again, these budgets and timelines are by no means accurate, they’re just provided as reference.

Let’s take a look:

Option #1 - Discovery, migration to D8, fixing functionality issues and a redesign = $100,000 - $120,000, 8-10 months timeline

Pros:

  • Solve all your problems in one fell swoop… kill all your birds with one stone?... you get the picture :)

Cons

  • It’s difficult to see what makes the difference for your business. Was it improved performance based user experience that made the difference? Was it improved design user experience? Was it improved features/functionality?
  • It’s a big expenditure going out in a fairly short period of time.

Option #2 - Discovery, migration to D8, fixing functionality issues, no redesign = $90,000 - $110,000, 6-8 months

Pros:

  • You’re getting a lot accomplished and solving a lot of problems with this approach.
  • You’ll have a better idea what changes had the biggest impact.

Cons:

  • This may not be the approach you want to take if a redesign is part of your overall plan, as you would be paying for front-end development twice.

Option #3, Part 1 - D7 site assessment, fixing functionality issues, discovery/planning D8 migration = $30,000 - $40,000, 12 months

Option #3, Part 2 - D8 migration, no redesign = $60,000 - $70,000, 6 months

Pros:

  • This gets you where you need to go and allows you to measure success along the way without doing things twice unnecessarily, or paying for them to be done twice.
  • It’s like cleaning your house and doing a purge before you move. No-one wants to move a bunch of problems and stuff you don’t need to move. Fix performance issues, fix functionality/feature issues (at least the ones that make sense), and clean-up your code and your content. These will all be decisions you won’t have to make and challenges you have to figure out when you migrate.
  • There’s a 1.5 year draw-down of budget or expenditure, which might be an easier pill for some organizations to swallow.

Cons:

  • Again, as in Option #2, this may not be the approach you want to take if a redesign is part of your overall plan, as you would be paying for front-end development twice.

If you want to discuss either or all of these options to help you decide which path to D8 is best for you, feel free to reach out to us.

We’re happy to share our experiences with these various approaches and help you decide the best way for you and what your budget might look like.

Free Drupal Guide

Nov 08 2017
Nov 08

Are you almost finished setting up your Drupal website? At a glance, everything might look ready to go.

But, before you hit "publish," you need to make sure you haven't made any mistakes.

A writer proofreads before they post an article. Similarly, a developer should double check their work.

The last thing you want is to go live with your site and have something go wrong. Finding problems before you launch can save some headaches and embarrassment.

We've compiled a pre-launch, Drupal checklist. When it's complete, you'll rest easy knowing that your website is ready to go.

Security

Security is the first on this Drupal checklist because it's so important. Of course you want to rest easy knowing that your site is secure when it launches. You also want your users to have peace of mind knowing that their information is safe.

Double checking your site's security will ensure that there's nothing you've missed that could make you vulnerable to hackers.

File Permissions

Check that you've correctly configured that security permissions on your file permissions. The settings.php file should be secure to protect the information of the database connections.

Admin Account

When you're developing your Drupal page, you use an admin account. Don't forget to secure this account before you launch. If hackers got a hold of this account, the results would be devastating.

Hopefully, when you first started building your site, you renamed your admin account. A name that would be difficult to guess. Obviously, the password to this account should be hard to guess as well.

For added security, you can install the AES module.

Another security measure is to disable PHP error reporting. To do this, go to Site Configuration, then Error Reporting. Set the option to send errors to the log, which will keep them from displaying.

Once you feel comfortable that you're running a tight, safe ship, take care of your 404 errors.

404 Errors

Make sure that missing pages are taken care of. Drupal takes care of that automatically with a 404 error page where there is no block configured.

You can also try the modules Search 404 or 404 Block. The module tries to guess what a user is looking for by searching terms from the original URL.

This is a simple task that makes a difference. The next section gives you a lot more to do.

Modules

There are all sorts of different modules that you'll be using based on your site's needs. These are just some basic things to check that will apply to many sites. Still, assess whether all of these Drupal checklist items are relevant to you.

Disable and Uninstall

Disable any modules you know you don't need. Removing unnecessary modules will help with your website's startup time.

One module to consider uninstalling is the Boost module. This module is generally unnecessary and can interfere with Varnish caching.

You can also disable the server-side statistics module. Instead, use Google Analytics for your site stats. It's much more effective.

The Devels module is also something that could be removed as it's not needed in production. The Database logging core module is also one you could consider replacing with the Syslog core module. It can store logs much faster.

Install

There are some great SEO modules that will boost traffic to your site after you launch.

Some modules that are widely considered must-have SEO modules include XML Sitemap, Metatag, Pathauto, and Redirect.

After you've gotten rid of what you don't need and added the modules you do, move on to the next checklist item.

Drupal Development Experts

Server Configuration

If applicable to your site, you'll want to check upload sizes. This is to allow users to upload large MP3 and MP4 files from your site. To do this, enable your server to upload to a certain size.

Another step many developers forget it to double check email recipients. Make sure that all forms and modules are sending to the correct email addresses.

Now that you've checked those off, move on to making sure your content is ready to go.

Content

In this part of the Drupal checklist, you'll make sure all your content is displaying correctly.

RSS Feed

In Drupal, your RSS Feed is generated automatically. All new content published will automatically go to the front page of your feed.

If you'd like more control over your RSS feed you can use the Views RSS module. That way if you don't want something included in the feed, you can deny access to rss.xml.

Lorem Ipsum

One step people often forget before launching, is to run their site through a lorem ipsum scanner. You might think you've changed all the dummy text. But, if you have lots of pages to comb through, you might have missed some.

Unpublished Content

Ensure unpublished content won't suddenly publish when you're site goes live.

Check the filters on your views. Make sure that customized SQL includes a test of the status column.

If your content is all set, move on to the next category of the Drupal checklist, your site's performance.

Performance

When you launch your site you want to know that it's running at peak performance.

Cacheing

It's imperative that you check that your site's cache is fully configured. Caching will optimize your site's performance speed a great deal.

Views modules should be checked to see if they've done any pages or blocks. They have their cache switched off by default. Check that they are configured.

CSS and Javascript

When you've finished your development process you can compress your CSS and Javascript files.

Is Your Drupal Checklist Complete?

Then it's time to go live! If you've followed each step, you can be confident that your site is ready to be seen by the world.

Are you working on creating a Drupal website?

Tell us about it in the comments!

If you've come across any challenges, we can help. Between everyone on our team, we have over 100,000 hours of experience with Drupal. Contact us and tell us about your project.

Apr 06 2017
Apr 06

The Situation That Prompted Change

The monkey house (aka Cheeky Monkey Media) has been expanding a lot during the past few years. Our team has been growing. We’ve been working on more and larger projects, and we’ve been branching out to include more services.

As with any growth spurt, we’ve had to deal with a few growing pains.

The Challenge that Initiated Action: Lack of Consistent Working Environments

One of the things we noticed during this transition period was that we didn’t have have the best process for ensuring all developers were working in a consistent local environment. As a result, some developers were using MAMP, others XAMP or WAMP, others were even installing PHP and mysql separately.

Local environment (here) means that all of the developers have access to the exact same server apps and tools between each other, and that this set-up coincides with the way the website is set up in its live, production environment.

If your local environments aren’t set up to be consistent, you can end up with:

  • Php versions not matching production specs and other devs’ local machines,
  • Php or mysql configuration settings not being the same,
  • Php libraries not being installed,
  • Front end libraries being out of date or using different versions of ruby gems or node packages,
  • Other services, like Solr or redis or an email server, etc., not running as they do on live version of the site. 

t’s like you’re building one house, but each builder has his instance of the house set up differently and uses slightly different tools to build the house.

As you can imagine, this can get very problematic. You are likely to run into issues where the code works on dev environment A, but it doesn’t work on dev environment B. Or perhaps dev environment C gets a warning message, but dev environment A doesn’t. Or Sass can be compiled on dev environment B, but it’s giving a fatal error to dev environment D.

Every time, you run into this, you have to spend time and energy tracking down the compatibility problems, wasting valuable coding time, which leads to added stress and frustration, and reduces margins on a project.

And as everyone knows, time is bananas. We can’t have one bit of wasted banana peel lying around that isn’t being put to good profitable use.

Once we determined this, the task before us became clear: We needed to create a consistent working environment that matched the production environment in order to help new devs hit the ground running rather than getting caught in the mud.

Our overall objective was to increase productivity and enhance product quality.

The Goals

To help us achieve this, we set the following goals:

  • Make it really easy to install a new environment.
  • Make it easy to be able to run front end tasks (GRUNT build, etc).
  • Mimic the live server exactly.
  • Document and standardize (how to create a new config and how to use).
  • Make sure our solution works on Mac and PC.

Step One: Research Options

Initial discussions led us to consider some of the technologies the monkeys had used before or had heard about. Before choosing a technology, however, we knew we needed to do some more research. At the end of this process, we had narrowed down the technologies we could use as part of our solution to the following 4 options:

  • Drupal VM
  • Vagrant
  • Kalabox
  • Docker

Drupal VM is basically a Vagrant box configured for a standard type drupal experience. Kalabox uses Docker and makes use of a lot of wrapping User Interface, which makes the process a lot less hands-on.

Kalabox is a great tool right out of the box, but is currently specifically setup to connect only to Pantheon hosted repos and environments.

We use Pantheon for most of our builds so that was a selling point. That said, we wanted to make sure that the solution we built, could integrate with any platform and wouldn’t be so dependent on only projects set-up on Pantheon.

In the end we decided to go with Docker as it’s lighter weight than Vagrant, which sets up individual VMs for each project. Docker, on the other hand, can share certain containers that you might reuse from project to project. We also chose it because, although fairly young, it already has full native apps out for Windows and Mac that make the installation of the engine a much easier process.

A Little Bit More About Docker

Docker has been in the technology spotlight for the last couple years. Everyone is talking about it. For example, on February 11, 2016, Business Cloud News wrote:

Adoption of Docker’s containerisation technology has entered a period of explosive growth with its usage numbers nearly doubling in the last three months, according to its latest figures.

Similarly, Google Trends shows a significant increase in search term interest for “Docker” since 2013:

Docker Interest over timeImage Source: Screenshot https://www.google.ca/trends/explore?q=Docker

According to the official docker website:

Docker containers wrap a piece of software in a complete filesystem that contains everything needed to run: code, runtime, system tools, system libraries – anything that can be installed on a server. This guarantees that the software will always run the same, regardless of its environment.

In other words, Docker allows you to package up everything you might need to build a website in individual ‘containers’ so you can quickly load it up on your server. Since members of a team can all use the same Docker images, it means that you are all working in the same environment, using the same development dependencies.

Basic Docker Terminology

Docker image: an image contains single or multiple layers. For example, a solr image contains an ubuntu layer underneath. A docker image contains the tools, libraries, and software that your application needs to run.

Docker container: an instance of a docker image. For example, if you have a solr image, you can use this image to create multiple instance of image to run your indexing. Think about the image as the blueprint, and the containers as the products they create based on this blueprint.

Docker Compose: a tool for defining and running multi-container Docker applications. This is what you will use to define all the containers needed to run for a particular project. In the end, you will just run on docker compose command and it will download all the docker images and spin up the containers needed for the project.

You Chose the Technology… What Happened Next?

After we agreed on the technology, we got to the good stuff: monkey play.

Everyone on the team got a chance to get their hands dirty installing Docker, downloading images, building containers, and creating new images.

This was important because none of us had any experience with Docker previously, and we knew that we couldn't just have one person learn Docker. We would need to have more than one person that could support this initiative for all of our projects and help tweak and setup new configurations. That meant we all needed to familiarize ourselves with it.

Moreover, as a developer, getting a chance to play with different systems and tools is an awesome opportunity to make ourselves more well rounded developers.

The First Docker Iteration

As we were exploring our options with Docker images, we started discussing what the standard process for new projects would look like and how we wanted to document that. We decided that we wanted to identify:

  • Where the files we built would live?
  • Where the Docker files would live? 
  • How we would import new data and files?
  • How this process would transfer over to multiple projects, etc? 

Docker Compose

The Docker engine can run as many docker images at the same time as your computer will allow with its resources. What Docker Compose does for us is it allows us to have 1 file that collects all of the images that we want to run together for a specific project.

All we need to do is:

  1. create a .yml file called docker-compose.yml
  2. specify each container that we would like docker to build
  3. indicate any specific settings that we would like to pass along to that particular image for setup or for specifying shared spaces and connections with other containers.

Here’s a little snippet to help illustrate:

services:

mariadb:

image: wodby/drupal-mariadb

environment:

MYSQL_RANDOM_ROOT_PASSWORD: 1

MYSQL_DATABASE: drupal

MYSQL_USER: drupal

MYSQL_PASSWORD: drupal

php:

image: cheekymonkeymedia/jungle:7.0

environment:

PHP_SITE_NAME: dev

PHP_HOST_NAME: localhost:8000

volumes:

- ./:/var/www/html

We based our original docker-compose around a well thought out docker recipe that was specifically created for drupal: Docker4Drupal by Wodby.

Woodby’s docker-compose file comes with images for php, nginx, mariadb, phpmyadmin, mailhog and more. This setup ticked off a lot of our initial wants for our first release minus 1 big one: Front End Compiling.

One of our main goals identified in the “Consistent Local Environment” project was to make the front end compiling of our projects easier. At this point of our initial Docker iteration, we didn’t have that.

A Note On Front End Activities

One thing to note is that concurrent to this team working on a consistent local environment, we also had another team working on a more consistent front end build experience.

So, it was important to know what changes they wanted to make to our ‘normal’ front end process before we set about putting in the libraries needed to run the compiling.

Once we had this documented from the team working on a consistent front end build experience, we discovered that all we needed to support this new workflow beyond what we had initially, was to simply install the latest node js into our PHP container. But it turns out that it wasn’t that simple.

Trouble with Node-sass

The issue with node-sass involved the Linux distribution we used to build our Linux/PHP container.

The Docker4Drupal team had chosen Alpine because it’s a lightweight Linux distribution that seemed to be a good choice for Docker and after our research, we concurred.

But, apparently there was a downside.

Node-sass, an important front end library doesn’t currently support Alpine, and it was giving us build errors when we tried to Node Package Manager (npm) install our front end builds.

But, after some toiling with libraries and docker-compose build scripts, this bump in the road was finally smoothed out.

In the end we used Wodby’s php image as our base to work from but added to it the tweaks needed to be able to run node js inside. This php image, now named Jungle is also up on dockerhub for use by the community.

A Few Other Things We Learned

Along the way we also all got to learn a bit more about building custom images because we were also toying with the idea of building the container out of different Linux flavours like Ubuntu at that point too.

In addition, we got to play around with Kalabox as an alternative, which with our limited playing seems like a pretty good solution right out of the box, just FYI to all you Pantheon developers.

MVP (Minimum Viable Product) Specs

At the end of the day, what we ended up with:

  • A configured docker environment that works well with a Pantheon server running Drupal 7 on PHP 5.6 on a frontend the complies with Cheeky Monkey’s new Torsion theme, which will also be available for download soon. The Jungle is available for download now.
  • A new dev user experience that looks like this:
  1. Download Docker native app for windows or mac and install
  2. Clone the copy of our pantheon d7 docker compose build scripts
  3. Clone the copy of the pantheon repo Run ‘docker-compose up -d’ to start our containers
  4. Run easy commands to npm install inside the container for front end setup
  5. Ready to start coding
  • Easy to use commands are pre-built so that you can run common tasks within the container like Gulp builds and watches, drush commands, etc
  • We have containers for phpMyAdmin and an email client Mailhog for testing email sending

Next Steps

While we were happy with this initial product we had a few more needs and wants, including:

  • Add on a Drupal 8 / php7 version
  • Make sure we can use Xdebug in the container
  • Make it work on Windows 10
  • Support for projects using our old theme setup or just other front end setups in general
  • Put our custom docker images on the docker hub ← Feel free to pull them, if needed
  • Finalize our toolkit of helper scripts
  • Add in support for solr

We will cover this in the next article.

Feb 27 2017
Feb 27

At Cheeky Monkey, one of our goals is to have fun at work. After all, it's been said that the average worker spends 5 hours and 41 minutes per day at their desk, so why not make the most of it? That being said, we take our work very seriously and it shows. Cheeky Monkey was recently named not only as a top web design company in Canada, but also as one of the best web developers from leading technology research firm Clutch. Yeah, we’re pretty excited about that.

So why is this accomplishment something to share? It’s because Clutch is a greatly respected company that identifies leading software and technology firms that deliver results for their clients. Their purpose is to help start-ups, large enterprises and anyone in between find partners to address short or long term software needs. Clutch combines intricate questionnaires with verified client reviews to ensure that only the best of the best end up on their leaders’ matrixes, and we are honored to have been chosen twice to be on these well-refined lists! We’ve been chosen as a leader on both their CanadianWeb Developers and Canadian Web Designers leaders matrices!

We know that we have an incredible team that always strives to create the best products for our clients, but it’s always nice to know that our clients appreciate our hard-working and talented crew. Here are a few examples of the client reviews that helped us rise above the pack: 

“I can’t say enough good things about their team. They are incredibly helpful, flexible, quick to respond, and really committed to getting things done on time. We were previewing the website at a national conference and their developers were up for 48 hours to make sure everything was ready for the site demo.” – Education Non-Profit

“The experience I’ve had with Cheeky Monkey Media has certainly been very pleasant, so that definitely gives me confidence that they can do more. They are on top of things and every client seems to represent an opportunity they take very seriously. As I have more needs that come up, I will certainly be inviting them to quote on other projects or provide proposals for other solutions.” – Moving and Storage Company

“We were really impressed with their knowledge of Drupal. It is comforting to know that when you bring a project to Cheeky Monkey Media, they're already very knowledgeable. If they’re not familiar with the issue, they'll do research about it. You don't feel like there is a better solution. I can trust what they're telling me. I know that Cheeky Monkey Media has gained the respect of even our internal IT team.” – SEO for a University

Our goal has always been to make customer satisfaction our top priority which encompasses achieving their digital expectations, making the process fun from start to finish and defining our success by how successful our clients feel at the end of the project. We feel awesome knowing that we are right on track and we are ready to create more amazing designs for our past, present and future customers.

If you have a project you'd like help with, give us a shout. Send us an email at [email protected].

Feb 09 2017
Feb 09

Two weeks ago, I had the chance to sit down with the National Hemophilia Association (NHF)’s marketing and education team:

  • Jay Patel, Director of Online Marketing and Data Systems
  • Beth Marshall, Director of Communications
  • Kate Nammacher, Director of Education
  • Corinne Koenig, Manager of Education and Training

During our half-an-hour chat about their redesigned online community website Victory for Women, we covered:

  • Where Victory for Women fits within the overarching nonprofit
  • What the team hope to achieve with this initiative
  • What working on the project (with Cheeky Monkey) was like Why they decided to go with Drupal
  • What they learned
  • What advice they’d like to share with other nonprofit communicators about to undertake a similar project.

All four communicators are extremely passionate about the initiative, and I couldn’t help but feel inspired and energized as I listened to them share their story and insights. So, without further ado, here is a copy of our conversation. I hope you’ll find it as interesting and insightful as I did.

Building an Online Community: The Planning Phase

Tell me a bit about the National Hemophilia Foundation and Victory for Women’s role within the conglomerate?

Kate: The National Hemophilia Foundation has three main components of our mission, education, research and advocacy, and one of them is about education, which is where our team comes in.

Jay [thinking hard to remember the mission statement word for word]:

The National Hemophilia Foundation (NHF) is dedicated to finding better treatments and cures for inheritable bleeding disorders and to preventing the complications of these disorders through education, advocacy and research.

Kate: While the NHF serves people living with a wide variety of bleeding disorders, the foundation was initially founded primarily around hemophilia, which has a much higher incidence rate and prevalence in men and boys. So, a portion of our work is addressing the needs of women in the community who have historically been a much smaller focus.

Over time, not even that recently, there’s been a lot of movement and interest in making sure that women who have symptoms get a diagnosis and get the support they need.

And that’s really where Victory for Women came in many years ago when the program was started. At that time, there was a very simple website that had a little bit of information for women who maybe had symptoms but didn’t have a diagnosis, women with a diagnosis, and for providers.

What prompted the need for a redesigned website? What were you hoping to achieve with it?

Kate: We were looking at the website, and we noticed that there wasn’t a lot of traction on the site and that it wasn’t getting a lot of use, which got us thinking:

How can we grow the website to facilitate interest in advocacy of women at the ground level? The women in the bleeding disorders community are already very active and connected and chatting about these sorts of issues on a local level. How else can we better support them through a website?

How did you know this was something your community wanted?

Corrine: This idea came before us but was reaffirmed when we did a survey as part of another project.

Part of that survey showed that women really wanted to talk to each other, and that support was a key piece in how they felt cared for and advocated for. We felt that because the site was static before, just containing written information on it, we felt that a more community-based sharing site may be more appropriate and helpful for these women.

Comparing the old NHF Victory for Women with the new 2017 version

So, it sounds like the push to redesign the website came from a number of different directions, from within your organization itself, and from your community members?

Kate, Jay, and Corrine: Yes.

Integrating your Community Website With Your Over-Arching Strategy

How does this website fit into your overall online community strategy? Your marketing and communications strategy as a whole?

[Laughter.]

Kate: Yeah, that strategy has multiple components. As the education team, we have our own very limited lense of what we want to communicate, and it’s more the educational messages, you know: how to live a healthy, fulfilling life with a bleeding disorder.

The communication team has that, plus development.

And, our meetings and conferences travel services team has all these other things to communicate about our organization and what we do as a whole. So,

Victory for Women is primarily an educational and interactive website, whereas our broader website www.hemophilia.org provides more general information about NHF as a whole and our online magazine website (which is currently also getting redesigned) www.hemaware.org includes more news and general interest articles.

Also, to give a broader context for Victory for Women, in addition to the website, there are other programs that fall under Victory for Women:

  • We go out and do workshops at local chapter events, and
  • We develop written publications

We’ve been working on many other ways that we can support NHF chapters doing work with women locally, but our big initiative initially was getting the website revamped.

Corinne: We also have a website called Steps for Living that’s for all people living with bleeding disorders, and it really takes them step by step through how to live with a bleeding disorder through all stages of life, from young infants to teens, to adults.

We have a lot of resources on the site, along with some videos, but most of it is print based. You can’t really share it easily.

So, we’re trying to connect the information that’s already available for women on that site with the Victory for Women site. But we didn’t just want to the same thing for women. We wanted this to be different.

We wanted Victory for Women to be a place where women can actually share, not just get information. We wanted this to be a place where women can share their stories and connect to each other.

Jay: Victory for Women is a social sharing website, but yes, it is one of the channels we use to communicate with our constituents, which also include:

  • Email marketing
  • Social media channels like FaceBook, Twitter, Instagram, YouTube, and Flickr.

Facebook

Screenshot of NHF's Facebook pageA screenshot of the NHF’s FaceBook page.

Twitter

The NHF's Twitter pageA screenshot of the NHF's Twitter page

Instagram

The NHF's Instagram pageA screenshot of the NHF's Instagram page

YouTube

The NHF's youtube channelA screenshot of the NHF’s YouTube page.

Flickr

The NHF's photos on flickrA screenshot of the NHF’s Flickr page.

Victory for Women is basically one of those channels, and it targets women specifically.

What were some of those features, obviously social sharing, and the ability to comment, that were really key for Victory of Women to have, that you couldn't live without?

Kate: Definitely the sharing piece of it, and that women could ‘like’ posts. Although, instead of calling this feature ‘like,’ we called it ‘appreciates,’ because sometimes women will be sharing really hard things for which a ‘like’ may not be appropriate.

We also knew that the sharing component wouldn’t be enough to get women to come back again and again. We didn’t want women to come to the site, read one article, appreciate it, and then be done and never come back again.

We had to ask ourselves: what will cause women to want to engage and come back the site? We had to ask ourselves: how do we engage?

Different Content Formats and the Ability to Share User-Generated Content

That’s why we have different content formats. We’re launching our podcast on their soon, and there is an option where women can share videos and where we can share videos as an organization.

Victory for Women screenshot, different content types

At NHF we create a lot of educational content, and we wanted to make sure that that women had the opportunity to engage with the content in multiple formats so that hopefully, they would go, hmm, I wonder what’s on the there this week.

The Ability to Submit Questions and Receive Answers from Medical Professionals

We also wanted to give women the option to submit questions, that would be answered by a group of volunteer medical providers, medical providers, doctors, and nurses, etc.

Victory for Women website screenshot of question section

Differentiating Yourself from Your Competitors

This to us a key difference between what we’re doing and something like closed or limited groups on FaceBook.

By including this feature we could monitor it better, which is something that is really important in the healthcare realm where people who are not medical experts will absolutely share medical advice on, for example.

And, even as NHF, we’re not medical experts and we don’t provide medical advice. We work and partner with experts, but stress that every individual person needs to go see their specific doctor.

That said, we are able to give women the opportunity to submit their questions and pose these questions to our volunteer group experts who can chime in and use some of the broader language to give women some of those topline, initial things to start thinking about, so that they can then take those thoughts to their medical provider.

That was an important feature, because our research showed that women often felt like they weren’t being heard at their own doctor’s officers. So, if they aren’t being heard there, hopefully they can come to us, where they can get enough information to be able to have those conversations better, and get the care they need.

How do you define expectations around this feature?

When I was going through the project scope, I noticed that with that particular feature, when women submit a question, someone will respond within a day by email, and then you also respond on the website within a month. Is that to kind of help with some of those administrative costs and timewise? I know that's something lots of nonprofit's struggle with.

Kate: Yeah, I mean it's definitely partially that we only have so many people working on this project internally [laughter ensues]. We wanted to make sure that we were doing the feature justice. We know that the women want the immediate, to be immediately acknowledged for submitting.

It's probably, or it might be, a very urgent issue for them.

We also know that all of our working groups and all of our medical providers that sit and help us, are all volunteers and they are all running their own medical practices. They might not have the time to respond very quickly. We just wanted to make sure again, that expectations were clear up front. That way, people wouldn't then be disappointed. They'd know sort of what they're getting into and being aware of that.

Post Launch: Facilitating Community Participation and Engagement

Going back to the community side of things, how do you facilitate dialogue and community growth?

Going through the website, I noticed that you're doing something really interesting in that you have the community members themselves posting things, posting images, posting pictures, posting interesting videos that they've found, but then you also have a moderator, and then, in addition to that, it seems like you also have kind of like a community leader or series of community leaders ... I think they're called V4W[individual’s name].

[Everyone laughs, and points at Corrine, including Corinne who points at herself.]

Corrine: Yes, that’s me.

Kate [lifting her hand]: Me too.

What’s the strategy behind that, what are you hoping to achieve?

Corinne: We found, and this might come up again in things that maybe we wish we'd known, that although women said that they really wanted their voices to be heard, and that is still the truth, getting them to actually post that story online in this new venue and format has been challenging.

We launched the site, and we shared it on social media, but then we realized that not many things were coming in. And we didn't want our last post to stay as July 2016.

So we decided to embrace this blog style, spreading stories. We're going to embrace that and continue to spread the word and then hopefully our community members will see us sharing content and find it interesting. And, maybe, that will spark them to share something and will get the ball rolling.

Kate: One of us will find an article and share it with the rest of the office, and then someone will think: hey, that would be great for Victory for Women, we should post this. It’s our way of keeping the energy going and showing women in our community, that they don’t have to share their own stories. The site is a place where community members, can go: “Hey, these things are being talked about on the news and in the context of your/our bleeding disorder(s), let's talk about it.”

What kind of feedback have received from the community on this new initiative?

Corrine: Good question. On the one hand, people love the format and they love the way it looks. That didn’t surprise us.

Testing Concepts Before Launch

With all of our projects, we have these working groups that Kate alluded to, so we don’t just create something, throw it out there, and hope that it takes.

We run through a series of ‘look-throughs’ with consumers, individuals who have these disorders, and providers just to make sure we’re on target and on point.

When we ran these sessions, people loved this new look, especially compared to the last one. They thought it was going to be great. They thought it was very welcoming. They thought the concept of sharing your story was welcoming.

What Happens After the Launch

However, when we launched it, it didn’t take on as much as we wanted it to. I think one thing that contributes to that, is that the format makes it a little bit hard for people to have a constant dialogue going.

In Twitter, we can tweet something and then people can respond and have a conversation in real time.

The Pinterest-like format we used, we realized, is not super conducive to that. So, that’s one piece of feedback we’ve gotten. Communicating How to Use the Site We’ve also learned that we need to be even more detailed about how to use the site. So, that’s something that we’re going to be working on and sending information with our chapters to explain how you can use the site and what sort of content you can share.

So, the community isn’t sure what sort of content to share?

Corrine: I think people are unsure about whether or not to share their own story right away.

Kate: Right. But, they don’t have to just share their own story.

Corrinne: Yeah!

Kate: That's what we heard initially, that sharing stories was important. That's when women were excited about. And they eventually might share more stories, but they can also connect with others and share topics or have conversations.

Corinne: Other stuff, not just personal stories.

Kate: Questions

Corinne: Stuff going on in the community.

Which is why we also have the highlighted women at the bottom. We want to highlight what women are doing out there and give incentives for people to do stuff to then get on the site and get ideas from each other as well.

In other words, I think that just being more explicit about all the different ways women can engage on the website will hopefully be helpful.

It sounds like you’re really working hard to build that trust in the community and in each other to make women feel comfortable enough to share their stories. Is that right, is that kind of the focus right now?

Corinne: Yes, absolutely.

Kate: Yeah. That's why we went through all this. Women can share as themselves, or they can create some kind of little image in their own Victory for Women identity.

Some of this stuff is really personal, so some women may not want to share that they have a bleeding disorder and the details of their experience on the web where people can see it for eternity. So, we wanted to give them a chance to connect without exposing themselves completely if they weren’t comfortable doing that.

Jay: Women can post content anonymously without creating an identity or they can create an identity, but that identity doesn’t have to be real, so to speak, it can be a sort of personality.

That’s why we provide a bunch of avatars to select from to keep it fun and fresh and a little bit more personal.

Or, if women are more comfortable, they can upload their personal image and include their name, etc.

Reflecting Back: What You Learned

Let’s go back and look at some of the things you learned, the stuff you wish you knew at the start of the project, and the things that made you go crazy?

Jay: I can start.

Right now, when a user goes to post something, they’re prompted to indicate what they want to post from the very start. In future projects, I’d probably want this feature to handle multiple media types, whether it be a link, an audio, an image, or a video, without making the user indicate from the start what form of content they plan to post.

The feature would still include the option to include a descriptor (i.e. video or audit). That way, if we ever wanted to filter by everyone that’s posted videos, we could. However, I don’t think we need to actually provide 4 explicitly different content types.

Instead of providing different types of content that people can post, I think I would have switched to a format where people can just post, and then click a descriptor button to say what the content type is.

Kate: We knew that participation and engagement would be a challenge. I just don't know that we necessarily brainstormed or have implemented enough of our solutions yet.

For example, we knew who our competitors were, things like existing groups on FB that are already having some of those conversations in an unmonitored way. So, we knew, number one, that we would need to add additional value —articles, podcasts, videos, etc — and provide credibility our competitors didn’t have, but still keep the sharing format.

The additional content and how to get the women to fully engage on an ongoing basis are the parts we haven’t really figured out yet.

The Nonprofit Reality

But, you know we were also not able to launch all of our stuff at once. We still haven’t posted our first podcast, we still haven't done some of the things we need to do that will make the whole website seem more dynamic. Some of these things just haven’t been created yet, which I think for nonprofits is a reality.

Finding Ways to Engage

For us, posting all the latest news and always creating fresh content, is not a reality. Moreover, while we can share things going on in the news and ask for feedback to get the conversation going, NHF does not take a stand on news stories and products, etc.

So, I think looking at how people will truly engage with the site will take some trial and error. We're going to continue to try new things and finding new ways to get connect with women and get the world out there.

Finding Women That Want to Engage But Don’t Know The Site Exists

There are women that are very engaged in their local community, and they are probably getting that need (of wanting to share and finding other women that are going through the same thing) met in person. It's much safer to share that in person for some.

Whereas others might want the anonymity of the internet, and so we have to think through: how do we find those women that are a hundred miles from their nearest HTC, and haven't really tapped into any local organizations, who would really benefit from our site.

For example, a woman wrote from India and actually submitted content.

Corinne: Yeah, it's really exciting. We're excited about it. She submitted twice.

Kate: Yeah, so I think that we're continuing to try and figure out the best ways to make content fresh and new so women keep wanting to come back. Moreover, we want to make sure that they're getting the information they need, that, they're getting the information to live longer healthier lives even with a bleeding disorder.

Work in progress.

Let’s Talk Drupal

Since Cheeky Monkey specializes in Drupal, I have to ask: what made you decide to go with Drupal? What did you like, what didn't you like?

Jay: All of our websites have moved on to Drupal.

We wanted to streamline our content management systems because if our staff is going to start managing some of the content, it's important that the platform be the same setup that they're familiar with, no matter what website they're working on.

Also, it's open source, so, it's the perfect match for nonprofits. It also has a lot of modules and stuff in its app store, which means you really have a lot of flexibility without paying a lot of programming dollars.

Ladies, how do you find it to use on the admin side when you're updating stuff.

Kate: That was a thing for us too. We don't want to have to constantly harass Jay to update things for us, ... he's very patient with us. So, I think we wanted to make sure that we could find a system that most of our staff would be able to use to continually up to date things. That’s part of the challenge, as you mentioned, for nonprofits that are probably understaffed or have a lot of projects going, how do you make it simple to use. So the simpler you make the format, the more user-friendly, the better.

Corinne: Yes, we’ve definitely found it user-friendly. We're able to go in check things and post.

Jay: This was especially important for Victory for Women because it’s also a website where community members will be going to post content. So it really needed to be user-friendly.

Cheeky Monkey did a good job skinning the admin side to make sure it looks just as friendly as the front end. Victory for Women is probably our friendliest editor.

Advice for Other Nonprofits Who Would Like to Build a Community Website

For other nonprofits, others about to take on a project like this, what's your advice?

Think About Resources

Jay: Make sure you have the resources to keep content flowing and spend time cultivating end users that are going to be using the website.

Create a Task Force

Beth: I would say,

putting together, which I think we did, a task force, combined with not only the people that are going to be monitoring your website, but also the community members that will be using it so that you've got a lot of good input and a lot of good conversations about your final product.

This is important because whenever you say that you're going build something for a community of people, you want to make sure that you are really giving them what they want. You also want to make sure that what they say the want really is what they want.

Finally, you want to make sure that your task force has assessed all of the barriers to the development process and to the success of the community once the website goes live. Having that conversation as a group, as part of a larger community will I think make the process more successful.

Budget

Kate: I feel like we actually budgeted pretty well, and that Cheeky Monkey kept to cost.

The thing is, you can think as much as you want going in that you know exactly what you want, but it's only once you're in it and see it, that you begin to understand why some things cost what they do.

Leave yourself the leeway in your own budget for things that come up that might need to be added.

For example, during the development process you might see features that make you go, wow, to really make this work, we need to add this feature. Or, when you launch the website realize there are barriers you hadn’t thought of, that you need to get your development team fix.

We were fortunate enough to have that kind of wiggle room in our budget. So, we were able to make those tweaks, where we went: “Hey, well it'd be really awesome if we could do this....”

It was really awesome that we could do that because I know that that's not always true. As a nonprofit, you usually have a really set budget or are on a grant, which makes incorporating this sort of wiggle room into your budget a challenge.

Think About What You’re Going to do Post Launch

Beth: Also, just because the site is done, doesn’t mean that you’re done. In fact, that’s when a lot of your work is going to begin. So make sure that you have the roles prepared on who is going to be finding relevant topics to post about; welcome new members; basically build a community. Building a website is easy – monkeys can do it! (Hey! Our monkeys are pretty special!) Building a community is hard.

Conclusion

Wow! That was a ton of exceptional insight and feedback about building a community website and nurturing a flourishing online community. If you’d like to see the site in action or participate in the conversation, visit https://victoryforwomen.org. To learn more about the project process itself, check out the project case study.

Feb 09 2017
Feb 09

Two weeks ago, I had the chance to sit down with the National Hemophilia Association (NHF)’s marketing and education team:

  • Jay Patel, Director of Online Marketing and Data Systems
  • Beth Marshall, Director of Communications
  • Kate Nammacher, Director of Education
  • Corinne Koenig, Manager of Education and Training

During our half-an-hour chat about their redesigned online community website Victory for Women, we covered:

  • Where Victory for Women fits within the overarching nonprofit
  • What the team hope to achieve with this initiative
  • What working on the project (with Cheeky Monkey) was like Why they decided to go with Drupal
  • What they learned
  • What advice they’d like to share with other nonprofit communicators about to undertake a similar project.

All four communicators are extremely passionate about the initiative, and I couldn’t help but feel inspired and energized as I listened to them share their story and insights. So, without further ado, here is a copy of our conversation. I hope you’ll find it as interesting and insightful as I did.

Building an Online Community: The Planning Phase

Tell me a bit about the National Hemophilia Foundation and Victory for Women’s role within the conglomerate?

Kate: The National Hemophilia Foundation has three main components of our mission, education, research and advocacy, and one of them is about education, which is where our team comes in.

Jay [thinking hard to remember the mission statement word for word]:

The National Hemophilia Foundation (NHF) is dedicated to finding better treatments and cures for inheritable bleeding disorders and to preventing the complications of these disorders through education, advocacy and research.

Kate: While the NHF serves people living with a wide variety of bleeding disorders, the foundation was initially founded primarily around hemophilia, which has a much higher incidence rate and prevalence in men and boys. So, a portion of our work is addressing the needs of women in the community who have historically been a much smaller focus.

Over time, not even that recently, there’s been a lot of movement and interest in making sure that women who have symptoms get a diagnosis and get the support they need.

And that’s really where Victory for Women came in many years ago when the program was started. At that time, there was a very simple website that had a little bit of information for women who maybe had symptoms but didn’t have a diagnosis, women with a diagnosis, and for providers.

What prompted the need for a redesigned website? What were you hoping to achieve with it?

Kate: We were looking at the website, and we noticed that there wasn’t a lot of traction on the site and that it wasn’t getting a lot of use, which got us thinking:

How can we grow the website to facilitate interest in advocacy of women at the ground level? The women in the bleeding disorders community are already very active and connected and chatting about these sorts of issues on a local level. How else can we better support them through a website?

How did you know this was something your community wanted?

Corrine: This idea came before us but was reaffirmed when we did a survey as part of another project.

Part of that survey showed that women really wanted to talk to each other, and that support was a key piece in how they felt cared for and advocated for. We felt that because the site was static before, just containing written information on it, we felt that a more community-based sharing site may be more appropriate and helpful for these women.

Comparing the old NHF Victory for Women with the new 2017 version

So, it sounds like the push to redesign the website came from a number of different directions, from within your organization itself, and from your community members?

Kate, Jay, and Corrine: Yes.

Integrating your Community Website With Your Over-Arching Strategy

How does this website fit into your overall online community strategy? Your marketing and communications strategy as a whole?

[Laughter.]

Kate: Yeah, that strategy has multiple components. As the education team, we have our own very limited lense of what we want to communicate, and it’s more the educational messages, you know: how to live a healthy, fulfilling life with a bleeding disorder.

The communication team has that, plus development.

And, our meetings and conferences travel services team has all these other things to communicate about our organization and what we do as a whole. So,

Victory for Women is primarily an educational and interactive website, whereas our broader website www.hemophilia.org provides more general information about NHF as a whole and our online magazine website (which is currently also getting redesigned) www.hemaware.org includes more news and general interest articles.

Also, to give a broader context for Victory for Women, in addition to the website, there are other programs that fall under Victory for Women:

  • We go out and do workshops at local chapter events, and
  • We develop written publications

We’ve been working on many other ways that we can support NHF chapters doing work with women locally, but our big initiative initially was getting the website revamped.

Corinne: We also have a website called Steps for Living that’s for all people living with bleeding disorders, and it really takes them step by step through how to live with a bleeding disorder through all stages of life, from young infants to teens, to adults.

We have a lot of resources on the site, along with some videos, but most of it is print based. You can’t really share it easily.

So, we’re trying to connect the information that’s already available for women on that site with the Victory for Women site. But we didn’t just want to the same thing for women. We wanted this to be different.

We wanted Victory for Women to be a place where women can actually share, not just get information. We wanted this to be a place where women can share their stories and connect to each other.

Jay: Victory for Women is a social sharing website, but yes, it is one of the channels we use to communicate with our constituents, which also include:

  • Email marketing
  • Social media channels like FaceBook, Twitter, Instagram, YouTube, and Flickr.

Facebook

Screenshot of NHF's Facebook pageA screenshot of the NHF’s FaceBook page.

Twitter

The NHF's Twitter pageA screenshot of the NHF's Twitter page

Instagram

The NHF's Instagram pageA screenshot of the NHF's Instagram page

YouTube

The NHF's youtube channelA screenshot of the NHF’s YouTube page.

Flickr

The NHF's photos on flickrA screenshot of the NHF’s Flickr page.

Victory for Women is basically one of those channels, and it targets women specifically.

What were some of those features, obviously social sharing, and the ability to comment, that were really key for Victory of Women to have, that you couldn't live without?

Kate: Definitely the sharing piece of it, and that women could ‘like’ posts. Although, instead of calling this feature ‘like,’ we called it ‘appreciates,’ because sometimes women will be sharing really hard things for which a ‘like’ may not be appropriate.

We also knew that the sharing component wouldn’t be enough to get women to come back again and again. We didn’t want women to come to the site, read one article, appreciate it, and then be done and never come back again.

We had to ask ourselves: what will cause women to want to engage and come back the site? We had to ask ourselves: how do we engage?

Different Content Formats and the Ability to Share User-Generated Content

That’s why we have different content formats. We’re launching our podcast on their soon, and there is an option where women can share videos and where we can share videos as an organization.

Victory for Women screenshot, different content types

At NHF we create a lot of educational content, and we wanted to make sure that that women had the opportunity to engage with the content in multiple formats so that hopefully, they would go, hmm, I wonder what’s on the there this week.

The Ability to Submit Questions and Receive Answers from Medical Professionals

We also wanted to give women the option to submit questions, that would be answered by a group of volunteer medical providers, medical providers, doctors, and nurses, etc.

Victory for Women website screenshot of question section

Differentiating Yourself from Your Competitors

This to us a key difference between what we’re doing and something like closed or limited groups on FaceBook.

By including this feature we could monitor it better, which is something that is really important in the healthcare realm where people who are not medical experts will absolutely share medical advice on, for example.

And, even as NHF, we’re not medical experts and we don’t provide medical advice. We work and partner with experts, but stress that every individual person needs to go see their specific doctor.

That said, we are able to give women the opportunity to submit their questions and pose these questions to our volunteer group experts who can chime in and use some of the broader language to give women some of those topline, initial things to start thinking about, so that they can then take those thoughts to their medical provider.

That was an important feature, because our research showed that women often felt like they weren’t being heard at their own doctor’s officers. So, if they aren’t being heard there, hopefully they can come to us, where they can get enough information to be able to have those conversations better, and get the care they need.

How do you define expectations around this feature?

When I was going through the project scope, I noticed that with that particular feature, when women submit a question, someone will respond within a day by email, and then you also respond on the website within a month. Is that to kind of help with some of those administrative costs and timewise? I know that's something lots of nonprofit's struggle with.

Kate: Yeah, I mean it's definitely partially that we only have so many people working on this project internally [laughter ensues]. We wanted to make sure that we were doing the feature justice. We know that the women want the immediate, to be immediately acknowledged for submitting.

It's probably, or it might be, a very urgent issue for them.

We also know that all of our working groups and all of our medical providers that sit and help us, are all volunteers and they are all running their own medical practices. They might not have the time to respond very quickly. We just wanted to make sure again, that expectations were clear up front. That way, people wouldn't then be disappointed. They'd know sort of what they're getting into and being aware of that.

Post Launch: Facilitating Community Participation and Engagement

Going back to the community side of things, how do you facilitate dialogue and community growth?

Going through the website, I noticed that you're doing something really interesting in that you have the community members themselves posting things, posting images, posting pictures, posting interesting videos that they've found, but then you also have a moderator, and then, in addition to that, it seems like you also have kind of like a community leader or series of community leaders ... I think they're called V4W[individual’s name].

[Everyone laughs, and points at Corrine, including Corinne who points at herself.]

Corrine: Yes, that’s me.

Kate [lifting her hand]: Me too.

What’s the strategy behind that, what are you hoping to achieve?

Corinne: We found, and this might come up again in things that maybe we wish we'd known, that although women said that they really wanted their voices to be heard, and that is still the truth, getting them to actually post that story online in this new venue and format has been challenging.

We launched the site, and we shared it on social media, but then we realized that not many things were coming in. And we didn't want our last post to stay as July 2016.

So we decided to embrace this blog style, spreading stories. We're going to embrace that and continue to spread the word and then hopefully our community members will see us sharing content and find it interesting. And, maybe, that will spark them to share something and will get the ball rolling.

Kate: One of us will find an article and share it with the rest of the office, and then someone will think: hey, that would be great for Victory for Women, we should post this. It’s our way of keeping the energy going and showing women in our community, that they don’t have to share their own stories. The site is a place where community members, can go: “Hey, these things are being talked about on the news and in the context of your/our bleeding disorder(s), let's talk about it.”

What kind of feedback have received from the community on this new initiative?

Corrine: Good question. On the one hand, people love the format and they love the way it looks. That didn’t surprise us.

Testing Concepts Before Launch

With all of our projects, we have these working groups that Kate alluded to, so we don’t just create something, throw it out there, and hope that it takes.

We run through a series of ‘look-throughs’ with consumers, individuals who have these disorders, and providers just to make sure we’re on target and on point.

When we ran these sessions, people loved this new look, especially compared to the last one. They thought it was going to be great. They thought it was very welcoming. They thought the concept of sharing your story was welcoming.

What Happens After the Launch

However, when we launched it, it didn’t take on as much as we wanted it to. I think one thing that contributes to that, is that the format makes it a little bit hard for people to have a constant dialogue going.

In Twitter, we can tweet something and then people can respond and have a conversation in real time.

The Pinterest-like format we used, we realized, is not super conducive to that. So, that’s one piece of feedback we’ve gotten. Communicating How to Use the Site We’ve also learned that we need to be even more detailed about how to use the site. So, that’s something that we’re going to be working on and sending information with our chapters to explain how you can use the site and what sort of content you can share.

So, the community isn’t sure what sort of content to share?

Corrine: I think people are unsure about whether or not to share their own story right away.

Kate: Right. But, they don’t have to just share their own story.

Corrinne: Yeah!

Kate: That's what we heard initially, that sharing stories was important. That's when women were excited about. And they eventually might share more stories, but they can also connect with others and share topics or have conversations.

Corinne: Other stuff, not just personal stories.

Kate: Questions

Corinne: Stuff going on in the community.

Which is why we also have the highlighted women at the bottom. We want to highlight what women are doing out there and give incentives for people to do stuff to then get on the site and get ideas from each other as well.

In other words, I think that just being more explicit about all the different ways women can engage on the website will hopefully be helpful.

It sounds like you’re really working hard to build that trust in the community and in each other to make women feel comfortable enough to share their stories. Is that right, is that kind of the focus right now?

Corinne: Yes, absolutely.

Kate: Yeah. That's why we went through all this. Women can share as themselves, or they can create some kind of little image in their own Victory for Women identity.

Some of this stuff is really personal, so some women may not want to share that they have a bleeding disorder and the details of their experience on the web where people can see it for eternity. So, we wanted to give them a chance to connect without exposing themselves completely if they weren’t comfortable doing that.

Jay: Women can post content anonymously without creating an identity or they can create an identity, but that identity doesn’t have to be real, so to speak, it can be a sort of personality.

That’s why we provide a bunch of avatars to select from to keep it fun and fresh and a little bit more personal.

Or, if women are more comfortable, they can upload their personal image and include their name, etc.

Reflecting Back: What You Learned

Let’s go back and look at some of the things you learned, the stuff you wish you knew at the start of the project, and the things that made you go crazy?

Jay: I can start.

Right now, when a user goes to post something, they’re prompted to indicate what they want to post from the very start. In future projects, I’d probably want this feature to handle multiple media types, whether it be a link, an audio, an image, or a video, without making the user indicate from the start what form of content they plan to post.

The feature would still include the option to include a descriptor (i.e. video or audit). That way, if we ever wanted to filter by everyone that’s posted videos, we could. However, I don’t think we need to actually provide 4 explicitly different content types.

Instead of providing different types of content that people can post, I think I would have switched to a format where people can just post, and then click a descriptor button to say what the content type is.

Kate: We knew that participation and engagement would be a challenge. I just don't know that we necessarily brainstormed or have implemented enough of our solutions yet.

For example, we knew who our competitors were, things like existing groups on FB that are already having some of those conversations in an unmonitored way. So, we knew, number one, that we would need to add additional value —articles, podcasts, videos, etc — and provide credibility our competitors didn’t have, but still keep the sharing format.

The additional content and how to get the women to fully engage on an ongoing basis are the parts we haven’t really figured out yet.

The Nonprofit Reality

But, you know we were also not able to launch all of our stuff at once. We still haven’t posted our first podcast, we still haven't done some of the things we need to do that will make the whole website seem more dynamic. Some of these things just haven’t been created yet, which I think for nonprofits is a reality.

Finding Ways to Engage

For us, posting all the latest news and always creating fresh content, is not a reality. Moreover, while we can share things going on in the news and ask for feedback to get the conversation going, NHF does not take a stand on news stories and products, etc.

So, I think looking at how people will truly engage with the site will take some trial and error. We're going to continue to try new things and finding new ways to get connect with women and get the world out there.

Finding Women That Want to Engage But Don’t Know The Site Exists

There are women that are very engaged in their local community, and they are probably getting that need (of wanting to share and finding other women that are going through the same thing) met in person. It's much safer to share that in person for some.

Whereas others might want the anonymity of the internet, and so we have to think through: how do we find those women that are a hundred miles from their nearest HTC, and haven't really tapped into any local organizations, who would really benefit from our site.

For example, a woman wrote from India and actually submitted content.

Corinne: Yeah, it's really exciting. We're excited about it. She submitted twice.

Kate: Yeah, so I think that we're continuing to try and figure out the best ways to make content fresh and new so women keep wanting to come back. Moreover, we want to make sure that they're getting the information they need, that, they're getting the information to live longer healthier lives even with a bleeding disorder.

Work in progress.

Let’s Talk Drupal

Since Cheeky Monkey specializes in Drupal, I have to ask: what made you decide to go with Drupal? What did you like, what didn't you like?

Jay: All of our websites have moved on to Drupal.

We wanted to streamline our content management systems because if our staff is going to start managing some of the content, it's important that the platform be the same setup that they're familiar with, no matter what website they're working on.

Also, it's open source, so, it's the perfect match for nonprofits. It also has a lot of modules and stuff in its app store, which means you really have a lot of flexibility without paying a lot of programming dollars.

Ladies, how do you find it to use on the admin side when you're updating stuff.

Kate: That was a thing for us too. We don't want to have to constantly harass Jay to update things for us, ... he's very patient with us. So, I think we wanted to make sure that we could find a system that most of our staff would be able to use to continually up to date things. That’s part of the challenge, as you mentioned, for nonprofits that are probably understaffed or have a lot of projects going, how do you make it simple to use. So the simpler you make the format, the more user-friendly, the better.

Corinne: Yes, we’ve definitely found it user-friendly. We're able to go in check things and post.

Jay: This was especially important for Victory for Women because it’s also a website where community members will be going to post content. So it really needed to be user-friendly.

Cheeky Monkey did a good job skinning the admin side to make sure it looks just as friendly as the front end. Victory for Women is probably our friendliest editor.

Advice for Other Nonprofits Who Would Like to Build a Community Website

For other nonprofits, others about to take on a project like this, what's your advice?

Think About Resources

Jay: Make sure you have the resources to keep content flowing and spend time cultivating end users that are going to be using the website.

Create a Task Force

Beth: I would say,

putting together, which I think we did, a task force, combined with not only the people that are going to be monitoring your website, but also the community members that will be using it so that you've got a lot of good input and a lot of good conversations about your final product.

This is important because whenever you say that you're going build something for a community of people, you want to make sure that you are really giving them what they want. You also want to make sure that what they say the want really is what they want.

Finally, you want to make sure that your task force has assessed all of the barriers to the development process and to the success of the community once the website goes live. Having that conversation as a group, as part of a larger community will I think make the process more successful.

Budget

Kate: I feel like we actually budgeted pretty well, and that Cheeky Monkey kept to cost.

The thing is, you can think as much as you want going in that you know exactly what you want, but it's only once you're in it and see it, that you begin to understand why some things cost what they do.

Leave yourself the leeway in your own budget for things that come up that might need to be added.

For example, during the development process you might see features that make you go, wow, to really make this work, we need to add this feature. Or, when you launch the website realize there are barriers you hadn’t thought of, that you need to get your development team fix.

We were fortunate enough to have that kind of wiggle room in our budget. So, we were able to make those tweaks, where we went: “Hey, well it'd be really awesome if we could do this....”

It was really awesome that we could do that because I know that that's not always true. As a nonprofit, you usually have a really set budget or are on a grant, which makes incorporating this sort of wiggle room into your budget a challenge.

Think About What You’re Going to do Post Launch

Beth: Also, just because the site is done, doesn’t mean that you’re done. In fact, that’s when a lot of your work is going to begin. So make sure that you have the roles prepared on who is going to be finding relevant topics to post about; welcome new members; basically build a community. Building a website is easy – monkeys can do it! (Hey! Our monkeys are pretty special!) Building a community is hard.

Conclusion

Wow! That was a ton of exceptional insight and feedback about building a community website and nurturing a flourishing online community. If you’d like to see the site in action or participate in the conversation, visit https://victoryforwomen.org. To learn more about the project process itself, check out the project case study.

Ad Grant Experts

Dec 27 2016
Dec 27

AMP (Accelerated Mobile Pages)

The official definition:

The Accelerated Mobile Pages (AMP) Project is an open source initiative that embodies the vision that publishers can create mobile optimized content once and have it load instantly everywhere.

Our definition:

A way we can make our websites fling poo load and function as quickly and efficiently as possible in order to provide a much better mobile user experience.

Why Do We Need AMP?

Mobile devices... Mobile devices just aren’t as fast as desktop devices. Arguable, sure, when you’re using your mobile device to load a basic website over an ultra fast internet connection. That internet highway is not always so clear on a sunny day, though. You may not have LTE, 4G, 3G, 4 bars, 2 bars. You may have the crappiest connection known to mankind. But you still simply want that internets, cause you needs it, it’s your lifeline, your precioussss.

via GIPHY

For example, if you don’t read that article your boss told you to read, 5 minutes before the meeting, because the website was super slow and took 3 of those ultra precious minutes to load, and another 1.5 minutes to navigate... Well, you know the rest. That’s okay you can blame us, as long as you send more bananas.

Anyway, fast page load times and an efficient mobile experience are huge if you want an effective website.

We all like good looking and fancy websites that are fun and intuitive to use, even if we’re just using them for business purposes. Big beautiful imagery, responsive support (when your website responds 'effortlessly' to different screen sizes), animation, etc... all that nice stuff requires code, lots of it. It requires sexy imagery, nice clear imagery. You want to make sure you can see the individual hairs on those monkey butts, on your fancy retina screens. It all comes at a cost. A great cost. Loading time. AMP can help with that. Don’t believe us? Skip down to the case study to see the numbers.

AMP Solves your Page Load Speed and Efficiency Woes:

With AMP we do away with anything extraneous. We pick and choose what we absolutely need to make the user experience as efficient, clean, and fast as possible.

Imagery

All the images run through a pre-processing stage (on our drupal sites) that resize the image to be mobile friendly, and then AMP takes them, and loads them, JUST when you need them. On AMP, images don’t delay the page from loading, allowing you to get to that textual information as fast as possible.

Javascript

There is no user-written javascript allowed in AMP. This forces you to use their uber-efficient scripts and plugins to render things like off-canvas menus and provide little sharing widgets and such. I’m good with that, cause it works, and it’s fast. We want fast, we want our clients to experience fast.. Have you seen a monkey peel banana? It’s fast.

CSS

CSS - the stuff that determines how your website will look - it’s all loaded inline. See, we want to make as few server requests as possible. Imagine needing 100 things from your boss. Imagine how much it’ll slow him down if you ask him for each individual thing 1 thing at a time? Also, that’s really annoying, don’t do it. But to my point, we’re combining all the structure code (HTML) with the design code (CSS) in one big request. It’s faster, and better, … and less annoying.

AMP and Drupal Integration

So AMP and the big D have a base theme that helps out with integration. Might as well just use that, no sense in re-inventing any wheels. All we have to do is create a new sub-theme (based off the AMP theme), re-write some templates, include some helper plugins for menu and share functionality, and re-style it. We also dove deep into the twig templates themselves and removed a whole bunch of ‘container’ html code, and extraneous classes and things. We wanted to make the code as lean and efficient as possible.

Case Study: Drupal with AMP

What happened when we integrated our Drupal site with AMP? Speed. In the majority of page load tests, the “AMPlified” page loaded in half the time or quicker. The “AMPlified” pages also don’t send as many requests to the server. Huge win!

AMP performance- normal - Cheeky Monkey Case StudyThis is what our results looked like before we added AMP.AMP performance- post AMP - Cheeky Monkey Case Study...and this is what the results looked like after we added AMP. Pretty impressive, if we do say so ourselves.

  • Without AMP, we get 119 requests. When we use AMP, the server requests decrease to 19.
  • Without AMP, DOM (document object model) loads in 3.70 seconds. With AMP, DOM loads in 1.96 seconds.
  • We’re pretty happy with those numbers. We’re sure the folks on mobile lane will be as well.

Note: This is a one time screenshot, the numbers were obviously slightly different every page load, but the difference between the two remained dramatic.

Here’s another performance screenshot, just for fun:

Amp performance on Cheeky Monkey Media AMP case study - 2nd screen shoot - before AMPThis is us before AMP. Awesome, it's true, but... it turns out we can be even awesomer ...Amp performance on Cheeky Monkey Media AMP case study - 2nd screen shoot - after AMP...and, this is us after AMP. Things are looking even awesomer. Oh yeah!

A Recap of our AMP Experience

Overall our AMP experience was positive and resulted in some very impressive numbers in terms of load times.

Implementation was intuitive enough. The only hiccup we really had, was that some of the images on the body area were not being converted by AMP. AMP requires that the width and height attributes be applied to each image. (Drupal does not apply the attributes by default if they’re implemented through the CKEditor interface.) But, after a little pre-process magic, we made sure all the images had their width and height attributes applied.

I would highly recommend going the way of AMP, to get those pages loading quickly and efficiently. It just makes sense. Us monkeys don’t like waiting, and we don’t like making others wait. AMP took away that torturous pain and allowed us to walk right into banana heaven.

Need help making your mobile pages zooming fast? Let the business developer monkeys know. We love making things with our AMP toys. Contact us today!

Learn more about AMP and the positive effects it can have for your website by visiting our AMP page.

Dec 27 2016
Dec 27

AMP (Accelerated Mobile Pages)

The official definition:

The Accelerated Mobile Pages (AMP) Project is an open source initiative that embodies the vision that publishers can create mobile optimized content once and have it load instantly everywhere.

Our definition:

A way we can make our websites fling poo load and function as quickly and efficiently as possible in order to provide a much better mobile user experience.

Why Do We Need AMP?

Mobile devices... Mobile devices just aren’t as fast as desktop devices. Arguable, sure, when you’re using your mobile device to load a basic website over an ultra fast internet connection. That internet highway is not always so clear on a sunny day, though. You may not have LTE, 4G, 3G, 4 bars, 2 bars. You may have the crappiest connection known to mankind. But you still simply want that internets, cause you needs it, it’s your lifeline, your precioussss.

via GIPHY

For example, if you don’t read that article your boss told you to read, 5 minutes before the meeting, because the website was super slow and took 3 of those ultra precious minutes to load, and another 1.5 minutes to navigate... Well, you know the rest. That’s okay you can blame us, as long as you send more bananas.

Anyway, fast page load times and an efficient mobile experience are huge if you want an effective website.

We all like good looking and fancy websites that are fun and intuitive to use, even if we’re just using them for business purposes. Big beautiful imagery, responsive support (when your website responds 'effortlessly' to different screen sizes), animation, etc... all that nice stuff requires code, lots of it. It requires sexy imagery, nice clear imagery. You want to make sure you can see the individual hairs on those monkey butts, on your fancy retina screens. It all comes at a cost. A great cost. Loading time. AMP can help with that. Don’t believe us? Skip down to the case study to see the numbers.

AMP Solves your Page Load Speed and Efficiency Woes:

With AMP we do away with anything extraneous. We pick and choose what we absolutely need to make the user experience as efficient, clean, and fast as possible.

Imagery

All the images run through a pre-processing stage (on our drupal sites) that resize the image to be mobile friendly, and then AMP takes them, and loads them, JUST when you need them. On AMP, images don’t delay the page from loading, allowing you to get to that textual information as fast as possible.

Javascript

There is no user-written javascript allowed in AMP. This forces you to use their uber-efficient scripts and plugins to render things like off-canvas menus and provide little sharing widgets and such. I’m good with that, cause it works, and it’s fast. We want fast, we want our clients to experience fast.. Have you seen a monkey peel banana? It’s fast.

CSS

CSS - the stuff that determines how your website will look - it’s all loaded inline. See, we want to make as few server requests as possible. Imagine needing 100 things from your boss. Imagine how much it’ll slow him down if you ask him for each individual thing 1 thing at a time? Also, that’s really annoying, don’t do it. But to my point, we’re combining all the structure code (HTML) with the design code (CSS) in one big request. It’s faster, and better, … and less annoying.

AMP and Drupal Integration

So AMP and the big D have a base theme that helps out with integration. Might as well just use that, no sense in re-inventing any wheels. All we have to do is create a new sub-theme (based off the AMP theme), re-write some templates, include some helper plugins for menu and share functionality, and re-style it. We also dove deep into the twig templates themselves and removed a whole bunch of ‘container’ html code, and extraneous classes and things. We wanted to make the code as lean and efficient as possible.

Case Study: Drupal with AMP

What happened when we integrated our Drupal site with AMP? Speed. In the majority of page load tests, the “AMPlified” page loaded in half the time or quicker. The “AMPlified” pages also don’t send as many requests to the server. Huge win!

AMP performance- normal - Cheeky Monkey Case StudyThis is what our results looked like before we added AMP.AMP performance- post AMP - Cheeky Monkey Case Study...and this is what the results looked like after we added AMP. Pretty impressive, if we do say so ourselves.
  • Without AMP, we get 119 requests. When we use AMP, the server requests decrease to 19.
  • Without AMP, DOM (document object model) loads in 3.70 seconds. With AMP, DOM loads in 1.96 seconds.
  • We’re pretty happy with those numbers. We’re sure the folks on mobile lane will be as well.

Note: This is a one time screenshot, the numbers were obviously slightly different every page load, but the difference between the two remained dramatic.

Here’s another performance screenshot, just for fun:

Amp performance on Cheeky Monkey Media AMP case study - 2nd screen shoot - before AMPThis is us before AMP. Awesome, it's true, but... it turns out we can be even awesomer ...Amp performance on Cheeky Monkey Media AMP case study - 2nd screen shoot - after AMP...and, this is us after AMP. Things are looking even awesomer. Oh yeah!

A Recap of our AMP Experience

Overall our AMP experience was positive and resulted in some very impressive numbers in terms of load times.

Implementation was intuitive enough. The only hiccup we really had, was that some of the images on the body area were not being converted by AMP. AMP requires that the width and height attributes be applied to each image. (Drupal does not apply the attributes by default if they’re implemented through the CKEditor interface.) But, after a little pre-process magic, we made sure all the images had their width and height attributes applied.

I would highly recommend going the way of AMP, to get those pages loading quickly and efficiently. It just makes sense. Us monkeys don’t like waiting, and we don’t like making others wait. AMP took away that torturous pain and allowed us to walk right into banana heaven.

Need help making your mobile pages zooming fast? Let the business developer monkeys know. We love making things with our AMP toys. Contact us today!

Learn more about AMP and the positive effects it can have for your website by visiting our AMP page.

Dec 08 2016
Dec 08

PHP 7 Upgrade Gives Cheeky Monkey an Extra Little Something

When we decided to convert the Cheeky Monkey Media corporate site to PHP 7, we expected some improvements in web performance

  • We expected the site to run faster and smoother.
  • We expected the page loads to be quicker.
  • We expected these results to leave the end-user (the individual viewing the site) to have a more satisfactory user experience.

In reality, we got all these things, plus a new-and-improved corporate site with some mega pizzazz. The switch to PHP 7 gave our site renewed energy and speed, giving the end-user, blazing fast page loads and an overall quality experience.

You can make the shift too. Contact us today.

How to Transition a Site Hosted on Pantheon Cloud to PHP 7

Thus, in this segment, I’ll run you through the steps for making the transition over to PHP 7 for a site hosted on the Pantheon cloud and the tangible differences that you’ll be able to see and measure after making the switch, using New Relic.

The Basics: What does your site run on currently?

Before we talk about the steps involved, let’s take a look, under the hood. What was the Cheeky Monkey corporate site running on before the upgrade?

The Cheeky Monkey site is a D8 site hosted on Pantheon, which was running on PHP 5.5 with protection from Cloudfare,and AMP stacked on top of that.  

Upgrading your website? Make sure you set baselines and track results.

Before we upgraded, we decided to use New Relic APM Pro, which is a free service offered by Pantheon. New Relic APM Pro gives us the ability to get a real-time visual of our site’s performance. As such, we are able to gauge the differences before and after the upgrade.

Setting-Up New Relic

Speaking of New Relic, enabling it on Pantheon is extremely simple, all you need to do is turn it on and it opens up a whole new world of visibility on your website performance. It gives you eyes and ears all around your site.

It’s so powerful, that you get an in-depth look into:

  • How the website is performing,
  • Metrics on overall user satisfaction,
  • Alerts anytime something exceeds the limits that you set.

This way, instead of users complaining that something is not working or taking forever to load, you can nip it in the bud.

Decide what metrics of success you would like to measure before updating your website

The stats on the PHP 5.5 branch of our website for the PageSpeed score and Page Load Time are:

  • PageSpeed score: 87%
  • Page Load Time: 3.3s

We also decided to keep track of three other important statistics before and after the upgrade:

  • Apdex Score - an industry standard to measure users' satisfaction with the response time of web applications and services. Our target was 1.0, meaning, if the user received a response to their request in less than one second, the result is satisfactory. If the response takes between one to four seconds, the result is tolerable. Anything that takes more than 4 seconds is frustrating.
  • Web Transactions Time - the total execution time for our web application
  • Throughput - the amount of capacity that a website or application can handle

Our stats for these metrics on PHP 5.5 for the last month, were as follows:

new relic stats before php 7 upgradeCheeky Media stats on New Relic before we upgraded from PHP 5.5 to PHP 7.

  • Apdex Score - 0.93 (1.0)
  • Web Transactions Time - 241ms (app server), 6.78s (browser)
  • Throughput - 2.44 rpm

These figures, compared to the averages, were actually not bad. But, being the crazy monkeys that we are, we wanted to push it. We wanted to get the most out of Drupal, and we wanted our site to outperform these stats in every way possible.

Turns out converting a Drupal 8 site from PHP 5.5 to PHP 7 is totally doable!

So, we began the shift. Honestly, the shift was the most-simplest process ever!On Pantheon, turning a site into PHP 7 is as easy as pie with a cherry on top.All you need to do is create a pantheon.yml file in your Drupal root and have the content of that file look like this:

# Pantheon Configuration File.

api_version: 1

php_version: 7.0

While you’re at it, create a docroot

We figured that while we’re turning this site into PHP 7, why don’t we also create a nested docroot so that we can serve our site from the “web” sub directory. While, URL’s are limited to the web docroot, which is where our site’s code base lives, PHP isn’t. Using a nested docroot allows us to put PHP files into our web application one level above the web docroot, so that they can be accessible via PHP but will be hidden from the web. This is especially useful for us because we’re planning to use Composer to manage all our dependencies and perform updates.

And, on Pantheon, turning the site to use a nested docroot is just as easy. All we need to do is add the following line “web_docroot: true” to our already created pantheon.yml file. So, now, our file looks like this:

# Pantheon Configuration File.

api_version: 1

web_docroot: true

php_version: 7.0

Now, add this file to the docroot and run the following statement from your command prompt:

cd to “your docroot”

mkdir web && git mv -k $(find . -type f -maxdepth 1 | grep -v pantheon.yml) core drush modules profiles sites themes vendor web (D8)

This will automatically move all your D8 files and folders under the /web directory. Now, move any outstanding custom directories that were not moved by this command, manually, inside your /web directory.  

Commit your code back to Pantheon and test!

Before going live with a website upgrade, test the s$^% out of that bad boy!

Normally, if you’ve got a pretty straightforward site like our corporate site, you shouldn’t face any issues. The only error we had after making the switch was a PHP warning in the Geshi library that we had. The warning reported that it had a constructor which would be deprecated in future versions of PHP. We fixed that up and had our devs test it out, and once we got the thumbs up from them, we were ready to go live. So we did!

Upgrading to PHP 7 allowed us to outperform our initial benchmarks

Right off the bat, we noticed a considerable difference in the way pages were loading and rendering. On GT Metrics the data was as follows:

  • PageSpeed Score - 95% (web average is 72%)
  • Page Load Time - 3s (web average is 6.3s)

It was faster and smoother than before. We let the live site run for a couple of days to generate the new New Relic data before we actually took our measurements. The new data after the PHP 7 switch, for the metrics we were tracking, looked like this:

new relic stats after php 7 upgradeCheeky Monkey Media stats on New Relic after we upgraded from PHP 5.5 to PHP 7.

  • Apdex Score - 0.96 (1.0)
  • Web Transactions Time - 217ms (app server), 6.77s (browser)
  • Throughput - 2.86 rpm

PHP 5.5 to PHP 7 Upgrade: the Before and After Snapshot

Web Average

Cheeky Before

Cheeky After

PageSpeed Score

72%

87%

95%

Page Load Speed

6.3 sec

3.3 sec

3 sec

Apdex Score

N/A

0.93

0.94

Web Transactions Time

N/A

241ms (app server), 6.78 sec (browser)

361ms (app server), 6.44 sec (browser)

Throughput

N/A

2.44 rpm

3.35 rpm

The PHP 7 upgrade caused massive improvements to the end-user experience

From an end-user perspective, the page loads are frantically fast. You click. It renders.

No longer are we seeing the images and the background being placed on the pages. The new PHP 7 caching improvements have really done a job on page loads. They’re rendering so fast that it just feels more fluidic. 

It truly is a beautiful experience to feel the difference. This was what we wanted. This was what PHP 7 promised, and boy, did it deliver!

Increase your website's performance. Upgrade to PHP 7 today!

Dec 08 2016
Dec 08

PHP 7 Upgrade Gives Cheeky Monkey an Extra Little Something

When we decided to convert the Cheeky Monkey Media corporate site to PHP 7, we expected some improvements in web performance

  • We expected the site to run faster and smoother.
  • We expected the page loads to be quicker.
  • We expected these results to leave the end-user (the individual viewing the site) to have a more satisfactory user experience.

In reality, we got all these things, plus a new-and-improved corporate site with some mega pizzazz. The switch to PHP 7 gave our site renewed energy and speed, giving the end-user, blazing fast page loads and an overall quality experience.

You can make the shift too. Contact us today.

How to Transition a Site Hosted on Pantheon Cloud to PHP 7

Thus, in this segment, I’ll run you through the steps for making the transition over to PHP 7 for a site hosted on the Pantheon cloud and the tangible differences that you’ll be able to see and measure after making the switch, using New Relic.

The Basics: What does your site run on currently?

Before we talk about the steps involved, let’s take a look, under the hood. What was the Cheeky Monkey corporate site running on before the upgrade?

The Cheeky Monkey site is a D8 site hosted on Pantheon, which was running on PHP 5.5 with protection from Cloudfare,and AMP stacked on top of that.  

Upgrading your website? Make sure you set baselines and track results.

Before we upgraded, we decided to use New Relic APM Pro, which is a free service offered by Pantheon. New Relic APM Pro gives us the ability to get a real-time visual of our site’s performance. As such, we are able to gauge the differences before and after the upgrade.

Setting-Up New Relic

Speaking of New Relic, enabling it on Pantheon is extremely simple, all you need to do is turn it on and it opens up a whole new world of visibility on your website performance. It gives you eyes and ears all around your site.

It’s so powerful, that you get an in-depth look into:

  • How the website is performing,
  • Metrics on overall user satisfaction,
  • Alerts anytime something exceeds the limits that you set.

This way, instead of users complaining that something is not working or taking forever to load, you can nip it in the bud.

Decide what metrics of success you would like to measure before updating your website

The stats on the PHP 5.5 branch of our website for the PageSpeed score and Page Load Time are:

  • PageSpeed score: 87%
  • Page Load Time: 3.3s

We also decided to keep track of three other important statistics before and after the upgrade:

  • Apdex Score - an industry standard to measure users' satisfaction with the response time of web applications and services. Our target was 1.0, meaning, if the user received a response to their request in less than one second, the result is satisfactory. If the response takes between one to four seconds, the result is tolerable. Anything that takes more than 4 seconds is frustrating.
  • Web Transactions Time - the total execution time for our web application
  • Throughput - the amount of capacity that a website or application can handle

Our stats for these metrics on PHP 5.5 for the last month, were as follows:

new relic stats before php 7 upgradeCheeky Media stats on New Relic before we upgraded from PHP 5.5 to PHP 7.
  • Apdex Score - 0.93 (1.0)
  • Web Transactions Time - 241ms (app server), 6.78s (browser)
  • Throughput - 2.44 rpm

These figures, compared to the averages, were actually not bad. But, being the crazy monkeys that we are, we wanted to push it. We wanted to get the most out of Drupal, and we wanted our site to outperform these stats in every way possible.

Turns out converting a Drupal 8 site from PHP 5.5 to PHP 7 is totally doable!

So, we began the shift. Honestly, the shift was the most-simplest process ever!On Pantheon, turning a site into PHP 7 is as easy as pie with a cherry on top.All you need to do is create a pantheon.yml file in your Drupal root and have the content of that file look like this:

# Pantheon Configuration File.

api_version: 1

php_version: 7.0

While you’re at it, create a docroot

We figured that while we’re turning this site into PHP 7, why don’t we also create a nested docroot so that we can serve our site from the “web” sub directory. While, URL’s are limited to the web docroot, which is where our site’s code base lives, PHP isn’t. Using a nested docroot allows us to put PHP files into our web application one level above the web docroot, so that they can be accessible via PHP but will be hidden from the web. This is especially useful for us because we’re planning to use Composer to manage all our dependencies and perform updates.

And, on Pantheon, turning the site to use a nested docroot is just as easy. All we need to do is add the following line “web_docroot: true” to our already created pantheon.yml file. So, now, our file looks like this:

# Pantheon Configuration File.

api_version: 1

web_docroot: true

php_version: 7.0

Now, add this file to the docroot and run the following statement from your command prompt:

cd to “your docroot”

mkdir web && git mv -k $(find . -type f -maxdepth 1 | grep -v pantheon.yml) core drush modules profiles sites themes vendor web (D8)

This will automatically move all your D8 files and folders under the /web directory. Now, move any outstanding custom directories that were not moved by this command, manually, inside your /web directory.  

Commit your code back to Pantheon and test!

Before going live with a website upgrade, test the s$^% out of that bad boy!

Normally, if you’ve got a pretty straightforward site like our corporate site, you shouldn’t face any issues. The only error we had after making the switch was a PHP warning in the Geshi library that we had. The warning reported that it had a constructor which would be deprecated in future versions of PHP. We fixed that up and had our devs test it out, and once we got the thumbs up from them, we were ready to go live. So we did!

Upgrading to PHP 7 allowed us to outperform our initial benchmarks

Right off the bat, we noticed a considerable difference in the way pages were loading and rendering. On GT Metrics the data was as follows:

  • PageSpeed Score - 95% (web average is 72%)
  • Page Load Time - 3s (web average is 6.3s)

It was faster and smoother than before. We let the live site run for a couple of days to generate the new New Relic data before we actually took our measurements. The new data after the PHP 7 switch, for the metrics we were tracking, looked like this:

new relic stats after php 7 upgradeCheeky Monkey Media stats on New Relic after we upgraded from PHP 5.5 to PHP 7.
  • Apdex Score - 0.96 (1.0)
  • Web Transactions Time - 217ms (app server), 6.77s (browser)
  • Throughput - 2.86 rpm

PHP 5.5 to PHP 7 Upgrade: the Before and After Snapshot

Web Average

Cheeky Before

Cheeky After

PageSpeed Score

72%

87%

95%

Page Load Speed

6.3 sec

3.3 sec

3 sec

Apdex Score

N/A

0.93

0.94

Web Transactions Time

N/A

241ms (app server), 6.78 sec (browser)

361ms (app server), 6.44 sec (browser)

Throughput

N/A

2.44 rpm

3.35 rpm


The PHP 7 upgrade caused massive improvements to the end-user experience

From an end-user perspective, the page loads are frantically fast. You click. It renders.

No longer are we seeing the images and the background being placed on the pages. The new PHP 7 caching improvements have really done a job on page loads. They’re rendering so fast that it just feels more fluidic. 

It truly is a beautiful experience to feel the difference. This was what we wanted. This was what PHP 7 promised, and boy, did it deliver!

Increase your website's performance. Upgrade to PHP 7 today!

Nov 29 2016
Nov 29

Ever wonder what goes into a conference or other business event that participants will gush about (in a good way) for years? After an event of these mythical proportions, participants walk away raving about the food, the speakers, the social events, the aura, and the list goes on ...

But pulling off such an event is no easy feat. Thus, I decided to speak with Lead DrupalCon Coordinator Amanda Gonser to find out how she manages to make sure the DrupalCon event design is flawless and fits into the overall event planning process seamlessly.

(This video may cause unexpected bursts of laughter. If you cannot laugh in your current environment, please scroll down for the written version.)

[embedded content]

You Can’t Avoid Attending Events, and You Shouldn’t

Most of us have attended at least one business event or conference in the past year. Maybe one of those was even the 2016 DrupalCon in New Orleans, which took place last April. At Cheeky we’ve attended three in the past three months alone: MozCon in September, PubCon in October, and Ad:tech in November.

Events like these are exciting, informative, full of opportunity, and utterly exhausting. And, according the Content Marketing Academy, events you should be attending them for both your personal development and your business development.

When Events Go Bad

They can also be embarrassingly catastrophic: bad coordination between the event team, unfortunate venue choices, and poor customer service can make an event experience unbearable.

DrupalCon: When Events Go Well

Lucky for us in the Drupal sphere, the annual DrupalCon conferences, “where thousands of Drupal developers, system engineers, designers, project managers, functional analysts, … media, and business people gather to participate in learning sessions, talks, code sprints, and social events”, go off without a hitch. 

So, I decided to ask Amanda how she does it.

Planning a Spectacular Event: Incorporating Design and Branding

In particular, I wanted to know how she feels about working with us at Cheeky Monkey Media on design and branding for the event, and how the event design and branding plays into the overall process.

Despite an initial bout of nerves (I don’t know why, Amanda’s great), Amanda agreed to the interview:

Ya of course. We love Cheeky Monkeys so we are happy to help even if I get nervous so…

Wait, tell us more about Amanda!

Amanda Gonser, Lead DrupalCon CoordinatorMeet Amanda, Lead DrupalCon Event Coordinator.

Amanda: (laughs) That’s me.

I basically just live and breathe DrupalCon, which is the conference that we host a few times a year, normally two to three times a year. 

The conference itself is a gathering of people who use and build Drupal from all over the world.

An Event Is More Than Itself. A Spectacular Event Represents the Community

Amanda partners with the local Drupal Community in the host city in a number of different ways.

Your Event Should Help Grow and Support the Local Community

Amanda: I’m the person that reaches out to the local community and lets them know that DrupalCon is coming to their city, which is always very exciting. 

I try to make sure that throughout the whole process of having a DrupalCon, from when the community finds out the DrupalCon is happening in their city to when the event actually happening, the host community feels their city is being portrayed how they want it portrayed.

The DrupalCon is also about helping to grow the host community. It gives the local Drupal community the opportunity to get involved in various volunteer roles in the conference and just really working to continue to grow their drupal community throughout the process.

Your Event Should Inform and Entertain Your Audience (Your Larger Community)

Amanda: Another way I reach out to the community is the one that you mentioned with the all of the emails and all of the sessions and things.

I manage all of the community selected programming that happens, so it is a 150 plus sessions:

  • Summits, if you go to vertical summits  
  • Sprints, if you sprint with us on Fridays, or on the weekends before and after
  • Social events like Trivia Night, which is very famous, or Women in Drupal, which is a really huge networking event.

All of these different moving pieces of the Con are very community focused, and I am really excited to get to work with people on them.

Your Event Needs to be Cohesive Throughout: Branding and Design are Key

Amanda: The third arm of my living and breathing of DrupalCon is of course getting to work with designers like you guys at Cheeky Monkey

So the whole branding of the entire Con from the beginning when it’s still a secret (and Cheeky Monkey knows how to do a good job of keeping it secret), to the reveal, then all the way to the conference where you have T-shirts, and you have the program works. 

It’s this really long process, so it’s definitely something that I am excited to do each time with them.

[We’re blushing.] 

… We interrupt this program with a brief note on terms.

What is Drupal?

Managing Event Design and Branding in the Midst of Controlled Chaos

Next, I asked Amanda to tell me a little bit more about how the design process fits into the overall event planning process.

Spela: You’re constantly juggling and reprioritizing a whole bunch of tasks and dealing with the unexpected, so, where does the design process come in and what does that process look like for you in the midst all of this craziness?

Amanda: Yeah. The design process is this really long project that we have to see through from concept to reality (the actual event).

It’s something that is a constant in my mind, and something that I really enjoy doing. 

The whole process can take about 10 months, so it could get a little tiresome and you could get a little bogged down. So, it’s really helpful to have a partner like Cheeky Monkey that makes it exciting and fun throughout the whole thing. [We didn’t pay her to say that, honest.]

Start with what you want to highlight and the feelings you want to convey

Amanda: The original deliverables start when we find out about the city, which like I mentioned is a secret and there are only a few people from the local community who know. When we tell them, they get really excited, and then  we have them put together this document that sort of explains how they feel about their city, things that they want to highlight, and the kinds of feelings they want to convey about their city.

Work with the designer and stakeholders to turn essence into concept

Amanda: Then we give that document to Chris. 

Chris the designer that we work with at Cheeky Monkey, he is our designasaur, um and he’s fantastic.

Designasaur

 Chris Arlidge, Creative and Marketing Director at Cheeky Monkey Media

Chris takes all the words from various people in the community and he somehow translates them into these amazing concepts.

Don’t make just one concept. Brainstorm a few different ideas.

Amanda: Chris delivers multiple different concepts that we share with the local community to kinda make sure we are getting the vibe they would like.

For example, for Baltimore, the community put together this document and Chris saw all of their words and made these fantastic concepts. 

We had one about pirates because Baltimore is a very seafaring town. [So, Chris tried to incorporate Clipper Ships instead]

Baltimore clipper ship conceptBaltimore - Clipper Ship concept

And, while we loved that one, we decided piracy and the tech conference was probably not the best way to go. But it was awesome, very creative. 

The community also noted things about the show Hairspray, which was hilarious and lots of fun.

Beehive, hairspray imageBaltimore - Beehive, Hairspray concept

There is also a museum there that’s called the American Visionary Museum that is just really quirky and crazy.

And, of course, the one that won out in the end, is the Poe/raven concept. 

Baltimore Raven ConceptBaltimore - Raven conceptRaven conceptThe final design concept for DrupalCon Baltimore 2017. To see more of the style guide, check out the examples in our style guide blog.

So, just to be able to go from all these words to really these concrete themes and concepts is really a huge process in of itself.

Get buy in for your stakeholders (all of them)

Amanda: Once we have the concept dialed and we get buy in from the community and then our team at the Drupal Association, we move forward and sort of set what it’s going to be looking like for the whole con.

Prepare your style guide

Amanda: When we get buy in, that’s kinda where the overarching brand comes in and it’s more than just a logo

Be ready to put your project management skills to the test

Amanda: At that point we go into a really long project management process.

  • First we need to design a website.
  • Then we need to design everything that you’re gonna see at the conference. Be that signs or program guides or speaker pins, things like that.

To put that into perspective, if you’ve ever been to a DrupalCon you probably noticed but definitely didn’t count, unless you helped us put out signs, that we have about 150 different signs to make sure you know where you are going, when things are happening.

When you attend an event, you see these things, but you probably don’t ever think that someone has designed all of those.

I mean there’s just so much going on, so it’s really nice to have worked with Cheeky for quite a few conferences now. They get it and so its really helps to make the plates spinning definitely not fall.

[Could she be any sweeter?]

Picking a Design Partner: What you should look for…

After we talked a bit about the event design process, I asked Amanda what she looks for in a design partner. 

Amanda: When we have our call for designers we are really looking for two things:

1. We want to know the team 

2. But, we also want to see what they have done.

Personality: Your design partner needs to be someone you can build a partnership with.

Amanda: We like to see their personality show through, because we really really like to build a partnership as opposed to a client/vendor relationship. We like to see past work that they have done cuz that really shows a lot of their personality.

Experience: Does your event design partner know what they’re getting into?

Amanda: It’s a huge plus to see past conference work they have done. It shows you that the designer understands what they are getting themselves into. 

Not everyone knows how much work a conference is. It might be cool to have the brand of the website or something, but knowing that 150 signs are coming, um it’s nice to know that they are prepared.

Don’t forget to meet with prospective partners

Amanda: Once we move past the initial round, where we look at the responses to our call for designers, we like to have an interview (like a video call) with them. We want to meet them and see the interaction between us and them as well as how they interact on the team. 

It’s a really long project management process, so we want to make sure that we’re having a good time because at the Drupal Association, we have a lot of work, but we have a lot of fun doing it. We want to make sure that the team we are working with also has fun and that we want to work with them.

What is the most important factor in a client/vendor partnership?

Amanda: When you work with a vendor, there is always this apprehension: are they going to deliver on time, did I explain my needs well enough that they are going to give me exactly what I needed, um, they’re not answering an email, is it because they’re behind?

We’ve worked with Cheeky for a number of Cons now, and we’re really continuing to build on this really good communication base. I don’t worry about anything with Cheeky. [Phewph!] You guys always deliver. Everything is fantastic. We have a blast working with you. There’s a real peace of mind working with you.

It’s that trust. We want to want to work with these people. We don’t want to dread these meetings or feel like we’re pulling teeth to try and get a deliverable. We want to enjoy the working relationship. It’s important that we like the people.

Knowing that they’ve done events of this scale is also important. And that goes both ways. The designer knows that we’ve done events like this in the past, and they can trust that we are not going to be asking for outrageous things and that we do have processes. And then for us, as the Drupal Association, it’s nice to see that they’ve executed something like that before, and that we can have faith that everything is going to come together in the end.

Open communication Don’t forget communication.

Spela: For other event planners or marketers, or anyone that’s working on putting together a brand, be it for an event, or their organization as a whole or they’re trying to make their event brand fit and flow with the rest of their brand, what kind of advice do you have for them and for choosing a design partner?

Amanda: I think a lot of it comes down to communication. Cheeky has good processes so we are never worried about them delivering. We do our best to have our processes of the event and our waterfall working backwards from the event date, so that’s all solid to start.

But then really, it’s just the open communication. As the project lead from the Drupal Association, a lot of it falls on me to make sure that I’m communicating what we need and why. A lot of it is the why, because a lot of the how, Chris would know better how to do it than I would.

These are things that we’ve done multiple times now. I like the fact that they kind of jump in now and go, “hey, have you thought about trying it like this, or maybe it could be more efficient if we did it this way.” 

As long as we can get to the final result, I’m happy with however we can do it. 

It’s really more about the partnership and this open communication: why we need it, or who needs to sign off on it, or what it needs to include. Just making sure we are sharing all of the information up front so that it really can be collaborative.

That’s really what’s made us most successful as a team and for our events: having an open avenue of communication.

Spela: So really finding a team that you can trust, and collaborate with, and brainstorm with.

Amanda: Exactly. And have fun with as well.

If you’re apprehensive to talk to the person you need to talk to, you’re not going to share, and kind of kick the back story, or what your final goal is. 

Sharing all that information, it might not be the most important thing for that one tote bag that you need, but having it as this overarching understanding of what the goal of the conference is. 

It’s really about sharing what our mission is and what [you’re] trying to achieve so that [you] can partner with the designer and make that a reality.

The bonus question: What do branding and design mean to you?

I live and breath DrupalCon in three different ways, so I experience branding and design in three different ways.

  1. From a community standpoint, I want to make sure that they’re happy with the logo, not even the logo, just the brand. They want their city to shine. We want to make sure that we are conveying something, and giving people a bit of information about the city, even if they don’t know anything about it. I want to make sure the local community feels like their local community and their local culture is valued and shines through.
  2. For the Drupal Association, we use DrupalCon as a marketing vehicle, so I want to make sure that the Drupal brand is strong, and it communicates that this is the Drupal conference.
  3. The lastly, very event planner specific, when I look at a logo, I can say that’s an amazing logo, but if it can’t work on a big screen and a three-quarter-inch pin, or a presentation or a T-shirt, it’s not going to work. It needs to be very versatile. The brand needs to be very flexible.

It’s about communicating what Drupal is and the conference that is to come.

###

Wow, that was a lot of information.I owe a huge thank you to Amanda for taking the time to chat with me about the ins and outs of DrupalCon and how event design and branding fits into the overarching process.  Thanks, Amanda! We love working with you too!

If you have any thoughts on the subject and would like to contribute to the conversation, please include your comments below.

And, as always, if you have a project you’d like to collaborate on with the monkeys, give us a shout at [email protected] or visit our contact page.

Nov 29 2016
Nov 29

Ever wonder what goes into a conference or other business event that participants will gush about (in a good way) for years? After an event of these mythical proportions, participants walk away raving about the food, the speakers, the social events, the aura, and the list goes on ...

But pulling off such an event is no easy feat. Thus, I decided to speak with Lead DrupalCon Coordinator Amanda Gonser to find out how she manages to make sure the DrupalCon event design is flawless and fits into the overall event planning process seamlessly.

(This video may cause unexpected bursts of laughter. If you cannot laugh in your current environment, please scroll down for the written version.)

[embedded content]

You Can’t Avoid Attending Events, and You Shouldn’t

Most of us have attended at least one business event or conference in the past year. Maybe one of those was even the 2016 DrupalCon in New Orleans, which took place last April. At Cheeky we’ve attended three in the past three months alone: MozCon in September, PubCon in October, and Ad:tech in November.

Events like these are exciting, informative, full of opportunity, and utterly exhausting. And, according the Content Marketing Academy, events you should be attending them for both your personal development and your business development.

When Events Go Bad

They can also be embarrassingly catastrophic: bad coordination between the event team, unfortunate venue choices, and poor customer service can make an event experience unbearable.

DrupalCon: When Events Go Well

Lucky for us in the Drupal sphere, the annual DrupalCon conferences, “where thousands of Drupal developers, system engineers, designers, project managers, functional analysts, … media, and business people gather to participate in learning sessions, talks, code sprints, and social events”, go off without a hitch. 

So, I decided to ask Amanda how she does it.

Planning a Spectacular Event: Incorporating Design and Branding

In particular, I wanted to know how she feels about working with us at Cheeky Monkey Media on design and branding for the event, and how the event design and branding plays into the overall process.

Despite an initial bout of nerves (I don’t know why, Amanda’s great), Amanda agreed to the interview:

Ya of course. We love Cheeky Monkeys so we are happy to help even if I get nervous so…

Wait, tell us more about Amanda!

Amanda Gonser, Lead DrupalCon CoordinatorMeet Amanda, Lead DrupalCon Event Coordinator.

Amanda: (laughs) That’s me.

I basically just live and breathe DrupalCon, which is the conference that we host a few times a year, normally two to three times a year. 

The conference itself is a gathering of people who use and build Drupal from all over the world.

An Event Is More Than Itself. A Spectacular Event Represents the Community

Amanda partners with the local Drupal Community in the host city in a number of different ways.

Your Event Should Help Grow and Support the Local Community

Amanda: I’m the person that reaches out to the local community and lets them know that DrupalCon is coming to their city, which is always very exciting. 

I try to make sure that throughout the whole process of having a DrupalCon, from when the community finds out the DrupalCon is happening in their city to when the event actually happening, the host community feels their city is being portrayed how they want it portrayed.

The DrupalCon is also about helping to grow the host community. It gives the local Drupal community the opportunity to get involved in various volunteer roles in the conference and just really working to continue to grow their drupal community throughout the process.

Your Event Should Inform and Entertain Your Audience (Your Larger Community)

Amanda: Another way I reach out to the community is the one that you mentioned with the all of the emails and all of the sessions and things.

I manage all of the community selected programming that happens, so it is a 150 plus sessions:

  • Summits, if you go to vertical summits  
  • Sprints, if you sprint with us on Fridays, or on the weekends before and after
  • Social events like Trivia Night, which is very famous, or Women in Drupal, which is a really huge networking event.

All of these different moving pieces of the Con are very community focused, and I am really excited to get to work with people on them.

Your Event Needs to be Cohesive Throughout: Branding and Design are Key

Amanda: The third arm of my living and breathing of DrupalCon is of course getting to work with designers like you guys at Cheeky Monkey

So the whole branding of the entire Con from the beginning when it’s still a secret (and Cheeky Monkey knows how to do a good job of keeping it secret), to the reveal, then all the way to the conference where you have T-shirts, and you have the program works. 

It’s this really long process, so it’s definitely something that I am excited to do each time with them.

[We’re blushing.] 

… We interrupt this program with a brief note on terms.

What is Drupal?

Managing Event Design and Branding in the Midst of Controlled Chaos

Next, I asked Amanda to tell me a little bit more about how the design process fits into the overall event planning process.

Spela: You’re constantly juggling and reprioritizing a whole bunch of tasks and dealing with the unexpected, so, where does the design process come in and what does that process look like for you in the midst all of this craziness?

Amanda: Yeah. The design process is this really long project that we have to see through from concept to reality (the actual event).

It’s something that is a constant in my mind, and something that I really enjoy doing. 

The whole process can take about 10 months, so it could get a little tiresome and you could get a little bogged down. So, it’s really helpful to have a partner like Cheeky Monkey that makes it exciting and fun throughout the whole thing. [We didn’t pay her to say that, honest.]

Start with what you want to highlight and the feelings you want to convey

Amanda: The original deliverables start when we find out about the city, which like I mentioned is a secret and there are only a few people from the local community who know. When we tell them, they get really excited, and then  we have them put together this document that sort of explains how they feel about their city, things that they want to highlight, and the kinds of feelings they want to convey about their city.

Work with the designer and stakeholders to turn essence into concept

Amanda: Then we give that document to Chris. 

Chris the designer that we work with at Cheeky Monkey, he is our designasaur, um and he’s fantastic.

Designasaur

 Chris Arlidge, Creative and Marketing Director at Cheeky Monkey Media

Chris takes all the words from various people in the community and he somehow translates them into these amazing concepts.

Don’t make just one concept. Brainstorm a few different ideas.

Amanda: Chris delivers multiple different concepts that we share with the local community to kinda make sure we are getting the vibe they would like.

For example, for Baltimore, the community put together this document and Chris saw all of their words and made these fantastic concepts. 

We had one about pirates because Baltimore is a very seafaring town. [So, Chris tried to incorporate Clipper Ships instead]

Baltimore clipper ship conceptBaltimore - Clipper Ship concept

And, while we loved that one, we decided piracy and the tech conference was probably not the best way to go. But it was awesome, very creative. 

The community also noted things about the show Hairspray, which was hilarious and lots of fun.

Beehive, hairspray imageBaltimore - Beehive, Hairspray concept

There is also a museum there that’s called the American Visionary Museum that is just really quirky and crazy.

And, of course, the one that won out in the end, is the Poe/raven concept. 

Baltimore Raven ConceptBaltimore - Raven conceptRaven conceptThe final design concept for DrupalCon Baltimore 2017. To see more of the style guide, check out the examples in our style guide blog.

So, just to be able to go from all these words to really these concrete themes and concepts is really a huge process in of itself.

Get buy in for your stakeholders (all of them)

Amanda: Once we have the concept dialed and we get buy in from the community and then our team at the Drupal Association, we move forward and sort of set what it’s going to be looking like for the whole con.

Prepare your style guide

Amanda: When we get buy in, that’s kinda where the overarching brand comes in and it’s more than just a logo

Be ready to put your project management skills to the test

Amanda: At that point we go into a really long project management process.

  • First we need to design a website.
  • Then we need to design everything that you’re gonna see at the conference. Be that signs or program guides or speaker pins, things like that.

To put that into perspective, if you’ve ever been to a DrupalCon you probably noticed but definitely didn’t count, unless you helped us put out signs, that we have about 150 different signs to make sure you know where you are going, when things are happening.

When you attend an event, you see these things, but you probably don’t ever think that someone has designed all of those.

I mean there’s just so much going on, so it’s really nice to have worked with Cheeky for quite a few conferences now. They get it and so its really helps to make the plates spinning definitely not fall.

[Could she be any sweeter?]

Picking a Design Partner: What you should look for…

After we talked a bit about the event design process, I asked Amanda what she looks for in a design partner. 

Amanda: When we have our call for designers we are really looking for two things:

1. We want to know the team 

2. But, we also want to see what they have done.

Personality: Your design partner needs to be someone you can build a partnership with.

Amanda: We like to see their personality show through, because we really really like to build a partnership as opposed to a client/vendor relationship. We like to see past work that they have done cuz that really shows a lot of their personality.

Experience: Does your event design partner know what they’re getting into?

Amanda: It’s a huge plus to see past conference work they have done. It shows you that the designer understands what they are getting themselves into. 

Not everyone knows how much work a conference is. It might be cool to have the brand of the website or something, but knowing that 150 signs are coming, um it’s nice to know that they are prepared.

Don’t forget to meet with prospective partners

Amanda: Once we move past the initial round, where we look at the responses to our call for designers, we like to have an interview (like a video call) with them. We want to meet them and see the interaction between us and them as well as how they interact on the team. 

It’s a really long project management process, so we want to make sure that we’re having a good time because at the Drupal Association, we have a lot of work, but we have a lot of fun doing it. We want to make sure that the team we are working with also has fun and that we want to work with them.

What is the most important factor in a client/vendor partnership?

Amanda: When you work with a vendor, there is always this apprehension: are they going to deliver on time, did I explain my needs well enough that they are going to give me exactly what I needed, um, they’re not answering an email, is it because they’re behind?

We’ve worked with Cheeky for a number of Cons now, and we’re really continuing to build on this really good communication base. I don’t worry about anything with Cheeky. [Phewph!] You guys always deliver. Everything is fantastic. We have a blast working with you. There’s a real peace of mind working with you.

It’s that trust. We want to want to work with these people. We don’t want to dread these meetings or feel like we’re pulling teeth to try and get a deliverable. We want to enjoy the working relationship. It’s important that we like the people.

Knowing that they’ve done events of this scale is also important. And that goes both ways. The designer knows that we’ve done events like this in the past, and they can trust that we are not going to be asking for outrageous things and that we do have processes. And then for us, as the Drupal Association, it’s nice to see that they’ve executed something like that before, and that we can have faith that everything is going to come together in the end.

Open communication Don’t forget communication.

Spela: For other event planners or marketers, or anyone that’s working on putting together a brand, be it for an event, or their organization as a whole or they’re trying to make their event brand fit and flow with the rest of their brand, what kind of advice do you have for them and for choosing a design partner?

Amanda: I think a lot of it comes down to communication. Cheeky has good processes so we are never worried about them delivering. We do our best to have our processes of the event and our waterfall working backwards from the event date, so that’s all solid to start.

But then really, it’s just the open communication. As the project lead from the Drupal Association, a lot of it falls on me to make sure that I’m communicating what we need and why. A lot of it is the why, because a lot of the how, Chris would know better how to do it than I would.

These are things that we’ve done multiple times now. I like the fact that they kind of jump in now and go, “hey, have you thought about trying it like this, or maybe it could be more efficient if we did it this way.” 

As long as we can get to the final result, I’m happy with however we can do it. 

It’s really more about the partnership and this open communication: why we need it, or who needs to sign off on it, or what it needs to include. Just making sure we are sharing all of the information up front so that it really can be collaborative.

That’s really what’s made us most successful as a team and for our events: having an open avenue of communication.

Spela: So really finding a team that you can trust, and collaborate with, and brainstorm with.

Amanda: Exactly. And have fun with as well.

If you’re apprehensive to talk to the person you need to talk to, you’re not going to share, and kind of kick the back story, or what your final goal is. 

Sharing all that information, it might not be the most important thing for that one tote bag that you need, but having it as this overarching understanding of what the goal of the conference is. 

It’s really about sharing what our mission is and what [you’re] trying to achieve so that [you] can partner with the designer and make that a reality.

The bonus question: What do branding and design mean to you?

I live and breath DrupalCon in three different ways, so I experience branding and design in three different ways.

  1. From a community standpoint, I want to make sure that they’re happy with the logo, not even the logo, just the brand. They want their city to shine. We want to make sure that we are conveying something, and giving people a bit of information about the city, even if they don’t know anything about it. I want to make sure the local community feels like their local community and their local culture is valued and shines through.
  2. For the Drupal Association, we use DrupalCon as a marketing vehicle, so I want to make sure that the Drupal brand is strong, and it communicates that this is the Drupal conference.
  3. The lastly, very event planner specific, when I look at a logo, I can say that’s an amazing logo, but if it can’t work on a big screen and a three-quarter-inch pin, or a presentation or a T-shirt, it’s not going to work. It needs to be very versatile. The brand needs to be very flexible.

It’s about communicating what Drupal is and the conference that is to come.

###

Wow, that was a lot of information.I owe a huge thank you to Amanda for taking the time to chat with me about the ins and outs of DrupalCon and how event design and branding fits into the overarching process.  Thanks, Amanda! We love working with you too!

If you have any thoughts on the subject and would like to contribute to the conversation, please include your comments below.

And, as always, if you have a project you’d like to collaborate on with the monkeys, give us a shout at [email protected] or visit our contact page.

Nov 24 2016
Nov 24

Cheeky Monkey Media has been involved in the design and creation of the Drupal Association's North American DrupalCons since 2015.

  • DrupalCon Los Angeles in 2015 was inspired the work of Shepard Fairey and his propaganda/street art stylings.
  • DrupalCon New Orleans in 2016 was inspired by the rich French history and wrought iron that is so prevalent in New Orleans.
  • The upcoming DrupalCon in Baltimore in 2017 draws on the work of Edgar Allan Poe, and has a mysterious, almost moody edge to it.

Events of this scale take months of planning and preparation. The process and relationships between planning groups are key. The trick, however, is keeping all the moving pieces and deliverables (from the pins that get handed out to the signage that guides the attendees around the centre, to the website that handles all the registrations) consistent and on brand. That’s where our secret resource, the brand and web style guide, comes in.

What is a brand style guide?

A brand style guide can be as simple as a logo usage document, or as complex as an extremely comprehensive, granular document that includes many aspects of the brand. 

Larger companies are more likely to need more comprehensive guides. In either case, these documents are vital in helping your company internally, and also for aiding third party vendors for staying true to the brand look and feel. 

But what is it!?

One of the best definitions we’ve found to date comes from Shirley Chan’s blog post on 99designs:

A brand style guide takes the heart and soul of your brand—your mission, vision and values—and translates it into design. It also tells everyone exactly how to communicate your brand. … Put another way, [a brand style guide is] a reference tool that helps maintain consistency by demonstrating what a brand looks, feels, and sounds like.

A brand style guide needs to state and show by example one or (ideally) more of the following:

  • How the logo is supposed to be used (and in many cases, how it is NOT supposed to be used). This will usually include guidelines on the spacing, and size limitations of the logo.

The 1st two pages of the style guide Cheeky Monkey Media created for DrupalCon 2017 in Baltimore.

DrupalCon Baltimore style guide - logo usage guideImage Usage Example

  • Describe the colours that characterize the brand and illustrate how these colours are to b used. The brand style guide should show swatches detailing the values for media production: Pantone/CMYK for print, RGB for screen, and Hex for web).

DrupalCon Baltimore style guide - colour pallete

  • Typography should be used on anything (from internal documents to large, outward facing promotional pieces) associated with the brand. The guide will name and show examples of the font faces used in marketing materials, logo and in some cases provide examples of how headings and paragraph text is to be formatted.

Typography Example

  • Use of images. When you’re working with a brand, your own or someone else’s, you can’t just fling images about willy nilly. Thus, some brand guides will outline and show examples of what style of photos or illustrations the organization or company can use.
  • Iconography. If a company uses multiple icons to represent different branches of the company or uses icons for products, or marketing materials, the brand style guide will outline what these icons are, when, where, and how they can be used.
  • Brand Voice. Some brand guides will include a section on the brand voice or tone. Examples and scenarios will be given on how to write for the company, or answer questions, etc. At Cheeky, we really like the way MailChimp does their Content Style Guide.

Some brand style guides will also include a subsection where they focus websites.

The Web Style Guide

Here is an example of the style guide we prepared for the 2017 DrupalCon in Baltimore.

Web Style Guide

Web Style GuideThe web style guide focuses in on how headings, paragraphs, forms and all the other elements that make up the website should be formatted. 

Why You Need a Brand Style Guide

A brand style guide is an essential document. 

It Helps Your Internal Team Stay Consistent and On Brand

Most companies, large or small, may have more than one person ‘creating’ content or collateral for them. As an example, brand content can be created in-house by a:

  • designer,
  • administration assistant,
  • someone’s cousin who ‘knows how to use photoshop’
  • or even the CEO.

It’s important that all of these people have the same information about the brand and proper usage of its assets such as the logo, fonts, icons, illustrations, etc.

It Helps External Vendors Stay True to Your Brand Identity

Content can also be done by third-party individuals or vendors who have never worked with your brand and likely work with hundreds of other brands at the same time as they are working with you. Some examples include:

  • A marketing  agency like Cheeky Monkey Media
  • A freelance content writer or designer
  • Printers
  • Sign-makers

Having a brand document for these vendors is critical, and trust me, they will appreciate it. 

In other words,

A brand style guide helps your organization, your organization’s employees, and others collaborating with your organization stay consistent with all their collateral assets (from assets as simple as business cards and letterheads to a large promotional billboard or as multifaceted as annual events like the DrupalCons), communications, and brand perception

Not having a brand style guide can breed inconsistency that will only serve to weaken your brand, and, in many cases, make it look unprofessional or, in worst case scenario, be completely contradictory to your brand vision.

I love this! How Can I Get a Brand Style Guide?

Brand style guides are often created by graphic designers and brand managers. As I mentioned earlier, you can have relatively simple versions like a Quick Logo Usage guide, or very comprehensive documents (many pages in length). 

At Cheeky, we have both: the quick usage guide and a more comprehensive one. Having both is useful because we can use the quick guide for ‘basic’ tasks like checking colour and logo usage, and we can use the comprehensive guide when working with external vendors or when training new employees.

Creating a good brand style guide is no simple undertaking, and if you are considering it, I would recommend asking the designer or agency that developed your logo to create one for you. Though, it’s worth mentioning that whoever designed your logo should have, at the very least, provided some sort of logo usage guide.

If you no longer have access to the designer or agency that developed your initial logo, or would like another perspective, feel free to reach out to another agency (like Cheeky Monkey Media). Your brand is your organization’s essence. It deserves the very best.

And, if you have any questions about branding, brand strategy, or creating brand guidelines feel free to contact us!

Nov 24 2016
Nov 24

Cheeky Monkey Media has been involved in the design and creation of the Drupal Association's North American DrupalCons since 2015.

  • DrupalCon Los Angeles in 2015 was inspired the work of Shepard Fairey and his propaganda/street art stylings.
  • DrupalCon New Orleans in 2016 was inspired by the rich French history and wrought iron that is so prevalent in New Orleans.
  • The upcoming DrupalCon in Baltimore in 2017 draws on the work of Edgar Allan Poe, and has a mysterious, almost moody edge to it.

Events of this scale take months of planning and preparation. The process and relationships between planning groups are key. The trick, however, is keeping all the moving pieces and deliverables (from the pins that get handed out to the signage that guides the attendees around the centre, to the website that handles all the registrations) consistent and on brand. That’s where our secret resource, the brand and web style guide, comes in.

What is a brand style guide?

A brand style guide can be as simple as a logo usage document, or as complex as an extremely comprehensive, granular document that includes many aspects of the brand. 

Larger companies are more likely to need more comprehensive guides. In either case, these documents are vital in helping your company internally, and also for aiding third party vendors for staying true to the brand look and feel. 

But what is it!?

One of the best definitions we’ve found to date comes from Shirley Chan’s blog post on 99designs:

A brand style guide takes the heart and soul of your brand—your mission, vision and values—and translates it into design. It also tells everyone exactly how to communicate your brand. … Put another way, [a brand style guide is] a reference tool that helps maintain consistency by demonstrating what a brand looks, feels, and sounds like.

A brand style guide needs to state and show by example one or (ideally) more of the following:

  • How the logo is supposed to be used (and in many cases, how it is NOT supposed to be used). This will usually include guidelines on the spacing, and size limitations of the logo.

The 1st two pages of the style guide Cheeky Monkey Media created for DrupalCon 2017 in Baltimore.

DrupalCon Baltimore style guide - logo usage guideImage Usage Example
  • Describe the colours that characterize the brand and illustrate how these colours are to b used. The brand style guide should show swatches detailing the values for media production: Pantone/CMYK for print, RGB for screen, and Hex for web).
DrupalCon Baltimore style guide - colour pallete
  • Typography should be used on anything (from internal documents to large, outward facing promotional pieces) associated with the brand. The guide will name and show examples of the font faces used in marketing materials, logo and in some cases provide examples of how headings and paragraph text is to be formatted.
Typography Example
  • Use of images. When you’re working with a brand, your own or someone else’s, you can’t just fling images about willy nilly. Thus, some brand guides will outline and show examples of what style of photos or illustrations the organization or company can use.
  • Iconography. If a company uses multiple icons to represent different branches of the company or uses icons for products, or marketing materials, the brand style guide will outline what these icons are, when, where, and how they can be used.
  • Brand Voice. Some brand guides will include a section on the brand voice or tone. Examples and scenarios will be given on how to write for the company, or answer questions, etc. At Cheeky, we really like the way MailChimp does their Content Style Guide.

Some brand style guides will also include a subsection where they focus websites.

The Web Style Guide

Here is an example of the style guide we prepared for the 2017 DrupalCon in Baltimore.

Web Style Guide

Web Style GuideThe web style guide focuses in on how headings, paragraphs, forms and all the other elements that make up the website should be formatted. 

Why You Need a Brand Style Guide

A brand style guide is an essential document. 

It Helps Your Internal Team Stay Consistent and On Brand

Most companies, large or small, may have more than one person ‘creating’ content or collateral for them. As an example, brand content can be created in-house by a:

  • designer,
  • administration assistant,
  • someone’s cousin who ‘knows how to use photoshop’
  • or even the CEO.

It’s important that all of these people have the same information about the brand and proper usage of its assets such as the logo, fonts, icons, illustrations, etc.

It Helps External Vendors Stay True to Your Brand Identity

Content can also be done by third-party individuals or vendors who have never worked with your brand and likely work with hundreds of other brands at the same time as they are working with you. Some examples include:

  • A marketing  agency like Cheeky Monkey Media
  • A freelance content writer or designer
  • Printers
  • Sign-makers

Having a brand document for these vendors is critical, and trust me, they will appreciate it. 

In other words,

A brand style guide helps your organization, your organization’s employees, and others collaborating with your organization stay consistent with all their collateral assets (from assets as simple as business cards and letterheads to a large promotional billboard or as multifaceted as annual events like the DrupalCons), communications, and brand perception

Not having a brand style guide can breed inconsistency that will only serve to weaken your brand, and, in many cases, make it look unprofessional or, in worst case scenario, be completely contradictory to your brand vision.

I love this! How Can I Get a Brand Style Guide?

Brand style guides are often created by graphic designers and brand managers. As I mentioned earlier, you can have relatively simple versions like a Quick Logo Usage guide, or very comprehensive documents (many pages in length). 

At Cheeky, we have both: the quick usage guide and a more comprehensive one. Having both is useful because we can use the quick guide for ‘basic’ tasks like checking colour and logo usage, and we can use the comprehensive guide when working with external vendors or when training new employees.

Creating a good brand style guide is no simple undertaking, and if you are considering it, I would recommend asking the designer or agency that developed your logo to create one for you. Though, it’s worth mentioning that whoever designed your logo should have, at the very least, provided some sort of logo usage guide.

If you no longer have access to the designer or agency that developed your initial logo, or would like another perspective, feel free to reach out to another agency (like Cheeky Monkey Media). Your brand is your organization’s essence. It deserves the very best.

And, if you have any questions about branding, brand strategy, or creating brand guidelines feel free to contact us!

Nov 09 2016
Nov 09

Wondering how to get your site to rank higher? Are you using Drupal or thinking about using Drupal? You’ve come to the right place!

This definitive SEO guide for Drupal websites will give you tips on which SEO tools and Drupal modules you can use to rank higher in Google search results. There are a lot of different modules out there to help with various on-page factors and best practices; however, not all of them are necessary. And more importantly, installing extraneous modules can use up system resources and slow everything down. (You don’t want that.)

This post is for site owners running on Drupal, SEO-curious Drupal devs, and SEOs needing to know which modules to use with Drupal.

Here's the skinny on what modules you need and what you can keep offsite to check your on-site SEO. Just because there is a module for it, doesn’t mean you need to use it.

SEO 101: Basics to Ranking on Google

I’m sure you’ve heard this before, but simply optimizing your website with clean code and great keywords won’t guarantee that you rank. (Especially in competitive markets.) But it certainly helps.

In a nutshell, what you need to rank is a combination of a (1) well-optimized site, (2) content that is at least 30% better than other content ranking, (3) links to your website.

Drupal SEO Guide Overview

What we cover in this Drupal SEO guide is:

  1. Modules you need to install for SEO best practices
  2. Optional SEO modules
  3. Optional: Modules for content optimization
  4. Recommended offsite SEO tools

Drupal Modules That You Need

It’s best to keep it simple when it comes to installing SEO modules. Every time a module runs it can take away from system resources. So don’t get your devs to just add every module that might work as that can slow your site down. Site speed is a highly important ranking factor.

Having said that, these are the bare essentials that we recommend installing.

Metatag

The Metatag module allows you to update a long list of various meta tags These include the more popular tags, like the meta description, title tag, canonical URL, OG products, Twitter Card data, rel=next, rel=prev, and hreflang. It also includes much more obscure tags. (It's pretty loaded.) The full list is quite comprehensive.

Metatag can also be set up to automatically create a title tag and meta keywords. The title tag is an important on-page ranking factor, so this is a handy feature if you don’t have the time for someone to provide metadata for every blog post or product stock keeping unit(SKU). (Although we  recommend that you do take the time to optimize with keywords when you can.)

As for the meta keywords tag, don’t even bother. It’s an antiquated waste of time and makes keyword research that much easier for your competitors.

You can also easily update Open Graph and Twitter Card tags so that you can control the image, description, and title that get shared in your social shares. This can help entice people to click.

Twitter Markup ExampleExample of Twitter Markup in Use

Other great features are: multi-lingual support and flexibility for customization.

Have you upgraded to Drupal 8 yet? If so, it’s not fully ready for Drupal 8 yet. But there are initial betas available.

XML Sitemap

A simple way to look at XML sitemaps is that they are an easy way to submit your website -- and all of its pages -- to search engines. They are also a great way to establish your website as the original source of content.

Keep in mind that there are different strategies for sitemaps. If you have a very large site, you may want to consider separating your sitemaps into categories. Other options are video and image sitemaps.

A simple way to create an XML sitemap is to use the XML Sitemap module. It gets automatically updated anytime you add or remove pages on the website.

Because it's automatic, be sure to also do the following:

  • Remove any non-200 pages from the sitemap
  • Remove noindex pages
  • Make sure any blocked pages in your robots.txt are not included
  • Remove PPC pages from the sitemap
  • Remove non-canonical URLs from the sitemap
  • Sitemap too large. For large sites, you’ll want multiple sitemaps (can organize by category)

Pathauto

Pathauto automatically generates URL/path aliases for different types of content. It doesn’t require users to manually specify the path alias e.g. /category/title-of-article instead of /node/5.

This is important for search engine optimization because it creates intuitive URLs that are SEO friendly. (It also makes it easier for you to analyze your Analytics data when you can easily tell what the content of the page is about.)

The only current downfall of this module is that it isn’t great with multilingual support.

Redirect

The Redirect module is great for preventing duplicate content issues. (Which can hinder ranking well in search engines.)

Basically, it ensures that all content is available on one best URL.

This includes checking things like:

  • A trailing slash (which is a common duplicate content offender). It removes it if found.
  • Checks access to private URLS to make sure the user can access it.
  • Checks current URL for an alias and redirects it if not being used.

Google Analytics

The biggest benefit of this module is that you do not need to add tracking code to each page you want to track.

To use this, you first need to make sure you create a Google Analytics account to use. If you don’t have one yet, go get one now! Tracking your website is important, otherwise you have no idea if anyone is even using it.

With this module, you can also specify which links and downloads on your website you want to track. You can also track internal searches to see which keywords people are searching for on your site.

Optional SEO Modules

These modules are not as imperative as the ones listed above, yet can be helpful in the right scenario. If you find you are having issues with any of the problems listed below it’s worth the time to investigate the module.

Custom & Path Breadcrumbs

Breadcrumbs are good for both users and SEO if they are done well. (If they are not done well, they can lead to a super frustrating experience. But that’s for another blog post.)

There are a few different modules that you can use for breadcrumbs. They are Custom Breadcrumbs, Path Breadcrumbs, and Easy Breadcrumb. Of the three, Custom Breadcrumbs is by far the most popular (going by which ones are currently active on websites). That is likely because you have more freedom for customization with it. Other ones, like Easy Breadcrumb, are more for people who want to turn on the module and have it work.

In Drupal 8 this can be done without a module, but there is a lot of lines of code involved with breadcrumbs, so some people find modules easier to use.

Pathologic

The Pathologic module can help fix broken images and links caused by incorrect paths. An example of where this might happen is when the URL of the site changes or the content moves to a different server.

Another benefit of this set-and-forget module is that it can fix broken links and images in your site’s RSS feeds.

Alinks

Alinks automatically replaces keywords with links. You can customize the number of occurrences, (which is great as this could get ugly fast, otherwise). You can also select what content types to include.

The reason for doing this is to support your own internal content with links. You want to let search engines know “Hey! We think this page is really important!” for all of your money pages (e.g. products, services, and category pages). It can also help give a boost to your rankings when done properly. Tip: look for pages ranking on page two of search results and give them a boost to page one with onpage optimization and an internal link boost.

I highly recommend that you always add internal links manually whenever you post content. However, if it’s something that hasn’t been done and you have tons of content without any internal links, this module can work as a quick fix.

AMP

If you’ve been keeping up with SEO headlines lately, you have likely seen chatter about AMP: Accelerated Mobile Pages. Recently Google has announced a switch to a mobile-first mentality, and AMP is part of this initiative.

If you search on Google from your mobile phone, you’ll see that some pages listed in the search results have AMP listed beside them. For other searches (like news stories), the results all appear in a carousel above the organic results.

The primary reason for AMP is that pages load super duper fast. There are some limitations to AMP: the ability to easily share a URL (which you can do on-site), and the restriction to static and fairly basic HTML (for now). But that's what makes the pages load so fast. So there ya go.

Who needs to use AMP?

AMP has been primarily developed for publishers. News-type searches from your mobile phone will show AMP results in a carousel above organic search results. (Although in the near future I am sure we will start seeing more types of pages testing  AMP HTML.) Basically, if you have a blog, then AMP is something you need to seriously consider implementing.

AMP news carousel on googleAMP news carousel in the search results

The AMP module converts Drupal pages into pages that comply with AMP HTML standards.

This module still needs to be refined a bit as it only supports node pages at present. Also, it’s a Drupal 8 module, which a lot of the other tools we recommended don’t support yet. So there will be some priorities that will need to be sorted before upgrading to Drupal 8 so you can use this module.

My guess is that the AMP module will become a “must-install” some time in the near future.

Optional Content Optimization

These modules are ideal for people who want to try doing their SEO in-house without having a dedicated SEO person.

We have tried some of these out. Our personal conclusion is that that we can get all of the functionality we need out of the modules listed in the first section. However, we do know that these modules can be very important if you don't have an SEO person on-board to guide you.

Yoast SEO for Drupal

The Yoast SEO for Drupal module lets you select a focus keyword for a page, then it analyzes the page for usage of that keyword. It lets you know where you should add it (like in the title tag and H1) and if you’ve used it too many times (i.e. “keyword stuffing”).

This module is helpful if you’re not sure how to optimize pages. Looks like it lists some helpful on-page tactics in the module. The only thing I question is that the keyword minimum is 300 words. Which is great if your goal is to avoid thin content. However, if your goal is to rank in search results, then 300 words will likely not see you ranking for anything.

yoast seo for drupal screenshotScreenshot of the Yoast SEO for Drupal Plug-In

If you’re an SEO that knows what they are doing, then the Metatag plugin is all that you need.

Overall it’s helpful for people that need guidance with on-page optimization. Keep in mind, however, that it will use up system resources.

SEO Checklist

The SEO Checklist module literally creates a checklist for all of the SEO tasks that need to be completed. It’s a functional list that lets you check off what you’ve completed and lets you know what tasks remain. One feature that seems great for tracking, is the time date and time stamp after you save an item. This enables you to easily track traffic changes after making specific updates.

SEO Checklist screenshotScreenshot of the SEO Checklist

This module is good for people who already know what they are doing when it comes to SEO. It doesn’t provide any how-to sort of stuff. It’s also great for people running multiple websites so they can keep track of what still needs to be done

32,000 sites are currently using this module, so it certainly seems like one of the more popular SEO modules in use.

Content Optimizer

Content Optimizer is a tool that helps you to improve on-page optimization factors. It’s useful if you’re worried about things like over-optimizing your content. It seems like a decent plugin despite the fact that it tells you to add Meta Keywords. (Can everyone please just get over this tag and simply remove it from your tools?)

Another feature that sounds useful for everyone, is that it helps you to analyze competitor’s content and keyword usage.

You need to install a bunch of other plugins to use this one, so once again, if you know what you’re doing (aka how to optimize a web page) this tool is not necessary. You’re better off using just the Metatag plugin where you can to make mostly all of the on-page adjustments you’ll need.

Content Optimizer ScreenshotContent Optimizer Screenshot

Drupal SEO Tools

This is another Drupal SEO module I’ve seen mentioned in a few other blog posts. While in theory, it sounds really great as it covers a wide range of things, it hasn’t had any updates on it for years. I’d personally never recommend a tool that isn’t actively maintained.

Perhaps there is a good opportunity here for another Drupal shop to take over this module and run it co-branded with the original creators.

Offsite SEO Tools

The following are SEO tools that you can use off-site to help improve your on-page and onsite SEO. Not everything needs to be done with a module. Save your system resources and disk space for stuff you really need.

There are hundreds of different optimization tools out there to check hundreds of different things. For the sake of efficiency, I am listing out the ones that I personally use on a regular basis. Although, I’ve tried 100s of different tools over the years, I’ve tried to list out ones that are free (or at least offer some sort of limited capacity for free).

For a super comprehensive list of any possible SEO tool you could use, check out this amazing list of SEO tools from Annielytics.

Here are some essential SEO tools you can use to check out important on-site factors.

Check for Broken Links

Google Search Console: If you don't have Search Console added to your site, do it now. There are many things you can do, and one of them is to check for any 404 errors under the Crawl tab.

Screaming Frog: The free version of this software lets you crawl up to 500 pages per crawl. The paid version is unlimited. There’s a lot you can do with Screaming Frog, and it’s low cost compared to other options. (Seriously consider paying for a subscription if you need to crawl any site on a regular basis. Don't let its basic appearance steer you away.)

Schema Creation & Testing

First of all, if you’re not familiar with what Schema is, read this article and it will give you an idea of some of the types of Schema you’ve likely already encountered in search results.

recipes schema markup in serpsRecipe Schema Markup in Search Results

Schema & Structured Data Creation: This free website helps you to generate JSON-LD Schema for your website. It was created by SEO Joe Hall.  You can also use the Google Structured Data Markup Helper.

Structured Data Testing Tool: Created by Google to develop, test, and modify your structured markup.

Structured Data Markup Helper: This markup helper will help you to use microdata and JSON-LD.  It has ready-made categories, like Local Businesses, Restaurants, and Movies. It also helps you to add new features to your HTML emails if you use Gmail for things like Parcel Delivery, Flight Reservations, and Orders. (Basically for businesses that take orders or reservations).

Check Page Speed

Google Page Speed Tool:  Quickly helps you to identify how to make your site faster, and how to make it more mobile friendly.

google page speed tool resultsThe Force is not with this site

GTmetrix: This free tool is another helpful tool to get insights into how to speed things up on your site. It also has this cool feature where you can watch a video of your site starting up compared to the competition. Makes a strong case when selling the importance of site speed to a client.

gtmetrix screenshotGTmetrix Screen Shot

Log File Analysis

Screaming Frog Log File Analyser: Log file analysis can give you information on how Googlebot and other search engines are crawling your site. Find out what pages search engines think are the most important and which ones are barely getting crawled at all. Also find out what pages are broken, slow, uncrawled, or, orphaned. Overall very helpful.

Overview of Site SEO Issues

SEO Site Checkup: This is a free tool and is great for a quick check of on-page optimization issues.

Deep Crawl: This is a paid tool, but you can sign up on a month-to-month basis. You can get one-month for $79 USD a month, so not too expensive if you need a comprehensive crawl of your site. Deep Crawl does a full crawl of the site, but presents the data in a very easy-to-read and comprehensive overview of all SEO issues. It’s an extremely helpful crawling tool and presents data in an aesthetically appealing way.

SERP Snippet Optimization Tool

SEOmofo: I’ve tested other tools over the years and always come back to this one. It’s simple to use, provides an overview of what it will look like and lets you add stuff like the date to the meta description. Get a clear idea of what your page title and meta description will look like in search results

Keyword Tools

Google Keyword Planner: Compared to what it is now, this tool was once pretty badass. Sadly it lacks quite a lot these days, but it’s still one of the only ways to gather actual keyword data from Google. (You won’t find longtail keywords with this tool, but I recommend a couple of other tools below for that.) Because it's an AdWords tool, keywords that aren’t terms that people would advertise for, don’t have much data. It doesn’t provide precise data, but it does give you a decent idea of what the more popular keyphrases in a category are (i.e. what people are actively searching for).

Ubersuggest: This is a pretty sweet tool for finding longtail keywords. It pulls in data from Google Suggest, so it only makes sense that you will find impressive keyphrase opportunities here.

Soovle: Soolve is another tool that pulls suggest data, but it pulls from several engines, including YouTube and Amazon. The info isn’t as comprehensive as Ubersuggest, but the data from YouTube and Amazon can provide some good ideas.

SEMrush: This is super helpful to see what keywords other sites are ranking for (and your own site as well). There is a free version, but the data is limited. The paid version is a tool that many SEOs have come to love. It is useful for site crawls, ranking data, keyword research and onpage optimization recommendations.

If there are any other tools or modules you need to know about? Feel free to comment below and our team of monkeys will happily answer any questions that you have about tools or modules.

Sep 21 2016
Sep 21

Do you want to kick ass in the digital environment? We thought so! Our cheeky monkeys have been helping clients do just that since 2008—longer than many digital agencies have been around.

Our work speaks for itself, but we really like it when our clients speak on our behalf. Recently their input was in large part responsible for helping us make a list of the top digital agencies in Canada, compiled by Clutch, a B2B market research firm based in Washington, D.C.

We earned our spot on Clutch’s “Leaders Matrix” based on our previous work, market presence, and most importantly, client reviews conducted by Clutch analysts. Below are a few comments from some of the people we’ve worked with:

5 stars across the board“It is comfortable to know that when you bring a project to Cheeky Monkey Media, they’re already very knowledgeable.” 

“Cheeky Monkey consistently meets their commitments and communication has been excellent. I can tell that they are very competent in what they do."

“We felt that we got great value for our money with Cheeky Monkey Media…. We appreciated the interaction with the team at Cheeky Monkey and we got value from the ongoing connection that we have with them."

That’s the kind of praise and commitment that has kept us in business for so long. It’s also kept customers coming back to us again and again, and encouraged the kind of positive word-of-mouth that all businesses need to succeed.

Want to learn more about what our customers have said about us? We invite you to visit our Clutch profile. You can also find us on their Canadian SEO Companies and Canadian Web Designers pages.

Clutch - Top Digital Agencies, Canada 2016

Sep 15 2016
Sep 15

We have established ourselves as experts in the Drupal and Web development sphere. However, few people are aware that we bring much more to the table. We are a diverse team of creative thinkers, designers, and marketers with the single-minded desire to make your project a success. It takes more than just building a Website these days, so it's important to us that our clients know that engaging with Cheeky Monkey Media can be a full spectrum experience. 

To help illustrate our hidden talents, we put together this quick little reel highlighting just some of the “Other things we do”, things like graphic design, marketing, and SEO.

[embedded content]

AggData - Enhancing the Brand

AggData has been a client for a long time. We've helped Chris and his team with their latest web and user interface (UI) redesign and collateral materials - conference business cards, booth signage, white papers, and even Tee-shirt designs. Through all of these initiatives, we focused on enhancing the brand by strengthening their visual touch points; and, because we have been working with them all, along we were able to do this in a smoothly. You can read more about how we helped AggData strengthen their visual touch points and streamline their user interface in the case study.

White Paper CoverWhite Paper SpreadAggData Tees-shirt Design

DrupalCon Los Angeles 2015 - Conference Design & Branding

After working on the Drupal Job Boards, we were pleased when the Drupal Association (DA) invited us to compete for the ‘design and branding’ of the DrupalCon for 2015. Designing for a large conference like the DrupalCons, each with their own ‘identity’ based on the host city, is a challenging task. We were ready and attacked it like a troop of rampaging gorillas. You can learn more about how we worked with the DA to ensure DrupalCon Los Angeles looked phenomenal in the case study.

DCLA LogoProgram GuideDCLA Tee ShirtDCLA Venue Map

DrupalCon New Orleans 2016 - Conference Design & Branding

After the success of the DrupalCon LA designs, we were lined up to tackle the New Orleans Con. With a city with as much character as New Orleans we really had to up the game. Coordinating with the Drupal Association and creatives in New Orleans, we were able to create a unique and engaging visual identity. Utilizing our graphic design services, we went about sketching up logo concepts for the Drupal Association and local community members to review. The final logo design was inspired by the French history and royalty, as well as the wrought iron design that is prevalent in New Orleans architecture. You can read more about the process and project in our case study.

DCNOLA LogoNOLA Program Guide CoverNOLA Program Guide Inside PagesNOLA Poster and Venue Map

Cathi Shaw - Book Cover Design & Illustration

Cathi Shaw, a published author and educator, reached out to us to design the book covers for her Fantasy series “The Marked Ones”. This was truly an exciting project. We created a cohesive typographic and layout style for the series. The cover art for each book was approached differently. For example, for the second book (Finding refuge), we digitally painted from scratch. You can read more about how we helped Cathi in the case study.

Book Cover 1Book Cover 2

Drupal Association Tees - Tee Shirt Design

For those in the DrupalCon circles, Cheeky Monkey Media has gained a reputation for our custom designed DrupalCon tee-shirt giveaways. Our designs are always ‘cheeky’ and in some cases even controversial. Seeing our success with the tee-shirts, the Drupal Association asked us if we could design them a couple Con shirts they could sell or give away. We said, “hell yeah”.

DA Tee Shirts

DrupalCon Baltimore 2017 - Conference Design & Branding

Having secured our position as the Drupal Association design partners for the North American DrupalCons, we recently started the design work for the 2017 conference which will be held in Baltimore. This will likely be the moodiest and strangest design yet, and we were filled with joy that the local community and the Drupal Association loved the idea.

DC Baltimore Logo

BigSteelBox

A large storage container company, BigSteelBox came to Cheeky Monkey Media for help with their Pay Per Click campaigns, which included landing page design, SEO and Pay Per Click wizardry. When we were done, the results were astounding. BigSteelBox enjoyed a 629% increase in leads and 88% decrease in cost per lead. Win, win, and win. Read more about what we did for BigSteelBox.

BSB-SEO-Payperclick: increase leads by 629%, cost-per-lead decrease by 88%BSB Box Graphic

At the end of the day, it comes down to this:

We know that a website is a big commitment for any organization, and we don't want to just build you a website. Why? Because we know that a website on its own won't help you reach the objectives you've set out for your organization. In order for a website to help you maximize your ability to connect with your audience and convert them to donors, buyers, volunteers, or supporters, your website needs to be nurtured and incorporated into your overall communication strategy. That's why we don't want to leave you with just a website. We want to be there to help you nurture your website so that you succeed.

If you have any questions about how we can help you turn your biggest design and communication challenges into your biggest opportunities, let us know! We'd love the opportunity to get to know you and learn more about the opportunities on your plate.

Sep 01 2016
Sep 01

A user pathway (sometimes called user flow and user journey)  is the path a visitor takes on your website before completing the action you would like them to take.

You can tackle the user pathway, after you have completed your user research and user personas.

Here's how ...

Setting the Stage for the User

Pathway Step 1 - Determine what your Macro and Micro goals are 

For example, as a business solutions company that specializes in web development and design, and marketing communication, the final goal we would like visitors to our website to take is to contact us with a project or challenge they need help with.

As a nonprofit, your final goal might be to get a donation, a registration, or a contact form filled out.

This is not to say that you do not have other goals associated with your website. For example, other important goals (for me) for website are blog notifications and white paper sign-ups. These are considered micro goals. Micro goals are smaller actions that your audience can take, that will help lead them to the ultimate action, or Macro goal,  you would like them to take.

Step 2 - Figure out how your target audience finds you

For example, based on the user persona research I completed when I first started at Cheeky Monkey Media, I discovered that most of our clients find us one or two ways:

  • By doing a google search for Drupal Developers, Website Development, or something similar.

  • By going to the Drupal Association, or similar page, and finding us on a list associated vendors.

The work, however, does not stop there.

You will also want to consider how your clients found your competition. Perhaps they found them somewhere that you haven’t thought about taking advantage of.

For example, the user research, I conducted told me that while prospective clients didn’t learn about our company in this way, many did research on website design and development prior to looking into a solutions provider. Where did they go for this information?  Online articles.

This tells me that if clients couldn’t find us through blog posts and informational articles, we were missing a huge opportunity to connect with our target audience and help them find the solution for their challenge.  

Step 3 - Map out the process

From there, it was a matter of working through the interviews to determine the pathways users took from the home page.

User pathway to home

User pathways from about

User pathways from services

The blue arrows are the pathways we would like our users to take. Thus, at each point in the journey, we need to include a call to the next action we would like the user to take.

For example, anticipating that prospective clients will first want to know exactly what we do and then see how we have done it successfully in the past, we have a call to action from our services pages that leads the user to “our work” page.

CTA example

The Surprises

One pathway that is not outlined above, but that our user research suggests we need to add, is users who enter our website from our homepage, and then go straight to “our work” page. Had it not been for the conversations we’ve had with our clients and prospective clients, we would not have known that many prospective buyers of our solution, want to see work we’ve done in the past before they do anything else.

I’ve tentatively mapped out this pathway as follows:

User pathways from blog

In addition to informing us of a user pathway we had previously not considered on our website, the information we gleaned from our user research also told us that we needed to up our efforts to engage with our target audience earlier in their solution finding process - when they were researching and looking for information.

The Ultimate Step - Testing out your Predictions

Now that we’ve (1.) Done our research, and (2.) mapped out our suspected user pathways, it’s time to (3.) test and make sure we are on the right track!

This is where we go into the deep, dark world of google analytics. No, we kid, it’s actually pretty cool.
 

Now, I could walk you through how to do this, but this Kissmetrics blog by Eric Fettman does a fantastic job of doing just that. It has annotated diagrams and everything!

So, in the interest of working smarter, not harder, I am going to send you there: The Google Analytics Conversion Funnel Survival Guide
*And yes, I know the post is a bit old. However, as the comments at the bottom of the blog note, it is still very accurate.

That's it! Easy right?

If you're not finding it so easy, or, if you are stuck on more than user journeys, and don't know where to start, consider doing a website audit to determine where to focus your energy first!

Aug 29 2016
Aug 29

Running a campaign in AdWords can be a fantastic way to get more leads for businesses that rely on lead generation. It can also be an expensive money pit, if you’re not doing it right.

We’re going to share with you some fairly straightforward ways of reducing your cost per lead. Our PPC team recently reduced a client’s cost per lead by 629% while increasing the number of leads by 88%. Here is how we did it.

Add Keyword Negatives

Some people advise against using broad match terms altogether. They can be expensive and a big waste of clicks if done incorrectly. When done correctly, however, they can provide you with targeted keywords you might not have thought about (such as competitor terminology or industry slang).

Broad match terms can also provide you with an exceptional list of keyword insights that you can later use to organically optimize your site. This data is gold, so it's why I personally love using broad match terms (where appropriate) with lots of negatives.

Here’s how to find negative keywords to add:

  1. Use the Keyword Planning Tool to find out what NOT to rank for. Find a place to jot down all of the keywords you don’t want to rank for.

The example below uses a graphic design firm as an example. In this case, designers looking for potential leads will want to eliminate anyone looking for free stuff, or, to further their education. The words courses, programs and free will be added to the negative keyword list.

adding negative keywords in AdWords

  1. Review your Search Query report regularly. This report is found under the Keywords tab and provides a list of the actual keywords people that clicked on your ad used. Look for keywords that are either not relevant or too high in the sales funnel.

where to find the search query report in AdWords

 

Optimize Your Landing Pages

This is the most challenging item on this list. It is also the most important. There are many different ways to get leads (e.g. white papers, webinars, quote forms, contact forms, etc.), however, all of them require contact info. So it's logical to send visitors to a landing page with a form on it. Whatever you do, please don’t send them to your homepage or a generic services page.

Basecamp PPC landing page

If you don’t have the means (or the budget to pay someone) to create landing pages, consider using a platform like Unbounce or Instapage. These (and many other platforms) have an arsenal of landing page templates professionally designed. You simply need to update them with your content, logo, images and colours.

Lead Generation Templates From UnbounceLead Gen Templates from Unbounce

Landing page optimization tips:

  1. Make your form stand out
  2. Keep your form as short as possible
  3. Add testimonials
  4. Focus on benefits if product is emotional
  5. Focus on features if product is technical or for business
  6. Don’t add a bunch of links that take people off the page
  7. Use different landing pages for each product or service
  8. Incorporate top converting keywords into your headlines
  9. Use click-to-call where your phone number is displayed
  10. Make your copy easy to read (i.e. short sentences and paragraphs)
  11. Add logos from big brand clients (if you have them)
  12. Include trust and privacy signals

Test Your Landing Pages

Always continue testing your landing pages. After you’ve been running your AdWords campaign for a while you’ll definitely see clear winners when it comes to which types of keywords convert. Use these keywords to provide direction as to what content and headlines need to be on your landing pages.

You can use software to A/B test or you can just manually sort this out on your own. The Final URL report under the Dimensions tab in AdWords is where you find the performance data (including conversion rates) for all of your URLs.

final URL report in AdWors

Things to test on your landing pages:

  1. Headlines
  2. Form headers
  3. Form CTA
  4. Video
  5. Images
  6. Add prices
  7. Add locations
  8. Using bulleted lists

lead gen landing page for salesforce

Have Your Ad Copy Match Your Landing Page

Make sure that the landing page matches the copy that the user clicked on. If you’re advertising the lowest rates, but don’t make any mention of cost on your landing page, then the user will likely end up frustrated and leave. If you mention something free, but then list a price on the page when the visitor gets there, it will also result in a wasted click.

When someone clicks on your ad you’ve already set the expectation. Make sure you fulfill the need with your ad copy.

Increase Quality Score

According to Google, three factors affect your Quality Score.

  1. Expected clickthrough rate
  2. Ad relevance
  3. Landing page experience

Below is a screenshot from Wordstream on the impact of Quality Score on your CPA in 2013. As you can see, having a Quality Score of 10 saves you 80% over what it would be if that keyword had a score of 5.

quality score information from Wordstream

Here are some ways to improve your quality score:

  1. Group like keywords together. If your Ad Groups are tightly targeted it makes it easier to include these terms in your ads and landing pages.
  2. Create separate groups for keywords with low CTR. You might notice that a particular type of keyword always has a low clickthrough rate. Create a separate group for these and try to improve your CTR with ad copy.
  3. Write compelling ad copy. Higher clickthrough rates improve your quality score.
  4. Match your landing page headline to your ad copy.
  5. Create high quality landing pages.
  6. Use ad extensions (like Sitelinks and Call Outs). These increase your real estate in the search results and can improve clickthrough rates.

Custom Ad Scheduling

Under the Dimensions tab you can see Time of Day and Day of the Week the conversions took place. As an example, if you see that conversions are typically 300% more on Sundays, it makes sense to pause your ads on Sundays moving forward.

Same goes with Time of Day. You might notice that you don't get any conversions between the hours of 1:00 AM and 5:00 AM, so you should also pause your campaigns during this time. Save your budget for times of the day when conversion rates have proven to be higher.

dayparting in AdWords

Sort Keywords By Highest Cost

This last one might seem obvious, but is something I have seen overlooked many times when I’ve taken over an account. So here goes.

Start with an amount of time that will give you some good data (e.g. 3 to 6 months) and sort your keywords by cost. You’ll quickly see if there are keywords that are wasting your budget. If your target cost per lead is $17 and you see a keyword in there that has cost you $300 with no conversions, pause that keyword until you figure out what you need to do. It might just be that it’s a broad match term and you’ve wasted a lot of budget by forgetting to add negatives. It could also be that the keyword doesn’t match the user intent of your product or service offering. In any case, pause it until you sort out what the problem is.

If you are looking for some help with your PPC campaigns, feel free to reach out to the PPC team here at Cheeky Monkey Media.

Aug 27 2016
Aug 27

Do you want to rank on Google's Local 3-Pack? These are valuable positions for businesses with a local presence. 

Recently, Google changed the layout of the search results desktop. Now they look more like mobile search results. The Local 3  -Pack is now displayed before the organic search results on all devices.This is pretty huge.

Google Local Search Results on MobilePeople are likely to click on the map listing on their phone

So how the heck do you get yourself listed up there? If you are looking to outsource the task, look for someone who is familiar with local SEO. If you prefer a DIY approach, then patience, time and know-how are your friends.

Reviews, Reviews & More Reviews

In 2015 BrightLocal conducted a Local Search Survey. It found that 92% of consumers regularly or occasionally read online reviews. It also found that 68% said positive reviews made them trust a company more. This in itself should be enough motivation to go out and develop a strategy to get more reviews. (And to be super awesome to your customers.)

Bright Local Search ResultsPeople rely on reviews for purchase decisions

Google Reviews also happen to be a top ranking factor for the Google Local 3-Pack. The takeaway? People AND Google love reviews. So start thinking about some ways to develop a strategy to get more reviews (for both onsite and for Google). 

email request to review productAn email I received to review a product after purchasing it

Here are some ways to get more reviews:

  1. Call your customers and transcribe what they say.Ask them if it's okay to add their review to your website. 
  2. Send them an email and ask for a quick review of your product or services.
  3. Don't offer incentives if you don't have to. Most people will do it for free.
  4. Don't wait too long. Try to do it within a few days of someone receiving your product or service.
  5. If you feel embarrassed to ask, blame it on your SEO person saying it's great for your rankings. The person will likely appreciate your candor.
  6. Use a service like CustomerLobby or Yotpo.

Optimize your Google My Business Listing(s)

Optimized listings perform better because they look better. They also and provide more information. Google is always looking to provide the best information and experience. 

Aim to fill out your Google My Business profile(s) to 100% complete. There isn't a description field anymore, so it's straightforward to complete.

How to optimize your Google My Business listing(s):

  1. Claim your listing(s).
  2. Get rid of any duplicate listings.
  3. Use your actual business name. Do not add a city name or keyword if you do not always include this in your business name.
  4. Ensure that your address is how it is also displayed on your website and other directories.
  5. Use a local number and not a toll-free number.
  6. Ensure you are using the correct category.
  7. Be consistent with your category selection for all locations.
  8. Add profile and cover photos.
  9. Add other relevant pictures.
  10. Add business hours.
  11. Link back to the specific location page on your website if you have multiple locations. Just use your homepage if you only have one location.
  12. Use a login email that you associate with your domain name. Use [email protected] and not [email protected].

Local Maps Search ResultsExample of Google Maps results

Make Sure Your Site is Mobile Friendly

More people are using their mobile devices to search with than ever before. Take a look around when you’re in a public place and see how many people are using their phones at any given time.

So, how many people are using their phones for local search?

Google conducted a study in 2014 on Understanding Local Search Behavior. It found that 4 out of 5 people were searching on various devices for local information. 88% of people searched with local intent on their Smartphone.

4 out of 5 people conduct local searches on enginesPeople love Google

A mobile-friendly site is an important ranking factor when it comes to the Google Map 3-Pack rankings.

Some more interesting local mobile stats are found here.

How to make your site mobile friendly:

  1. First you need to check to see if it's already mobile friendly. You can check using Google's Mobile Friendly Test.
  2. Don't make a separate site just for mobile. It's more work and you can run into duplicate content issues.
  3. Use a responsive website design. This type of design automatically adjusts to fit on any device. Drupal is an amazing platform for this.
  4. Use at least a 14px font size. Anything less is too small.
  5. Use larger buttons. If they are too small it's hard for people to click on them.
  6. Use the viewport meta tag. It tells the browser the page needs to fit the screen.
  7. Always include the "View Full Website" option for people that prefer browsing this way.
  8. Check the Mobile Usability section in Google's Search Console on a regular basis. Make sure you don't have any mobile errors.
  9. Use YouTube for videos and not Flash. Flash won't work on tablets on mobile phones.

According to Google, these are the top 3 things you need to consider when developing a mobile website.

  1. Make it easy for consumers to complete their objectives.
  2. Measure the effectiveness of your site by how easy it is for someone to complete their tasks. Prioritize what common tasks people perform on your site and make it easy for them to do.
  3. Use responsive design.

Develop a Good Link Profile

Did you hear that getting links died back with the Penguin update? Think again. Links are still queen. The end goal is more for quality over quantity, though. (Although, a million high quality links will likely find you at top of the search results.) A high number of low-quality links will get you booted from search results. A high number of quality links will get you a promoted.

In June 2016 Dan Lieber and Andrew Shotland at Local SEO Guide studied over 30,000 websites. They discovered that links are still the bees knees when it comes to ranking locally. In fact, it’s one of the top ranking factors. (I know, I know. I also got excited when I thought I wouldn't have to worry so much about links anymore after the Penguin update.)

The 2016 Local SEO Ranking Factors study also found that links optimized with your keyphrase + city have a strong impact. Keep in mind this starts to get into a grey area since you need your inbound anchor text profile to look natural. So take heed.

How to get more links to your website:

  1. Get your site listed in local directories and in directories related to your niche. Make sure they have decent site authority, though. (I personally aim for over 30.)
  2. Promote amazing content. I know, I know. Much easier said then done. Examples, are whitepapers, infographics, super cool widgets people want to share, etc.
  3. Create a local resource list. Example: a restaurant can create a list of the best places to buy fresh, organic and local produce in the area.
  4. Use link building tools, like Ahrefs or Majestic SEO.
  5. Contribute content to a high ranking website. This is best if you don't associate yourself with your own website in the bio. Also be sure to link back to a useful page on your website, like a resource page. This seems more natural.

Optimize Your Location Pages On Your Website

Google is big on machine learning to understand human search queries and user intent. Yet,onpage keyword usage and optimization are still a necessity.

The study (mentioned above)  by Local SEO Guide found that having your city name and Province/State in your <title> tags, in URLs, and in page copy had little influence on Google My Business rankings. Which is pretty big news since this is something local SEOs have always done to improve rankings.

Yet, from a usability standpoint it still makes sense for the location name to show up in search results. so make sure you add it to your title tag for clickthrough.

title tag in the search results

The location in your main header lets people know they’ve arrived at the correct location when they land on your website. Don’t go crazy with adding the location all over the page (i.e. don’t sound like a spammy jerk). Use it where it makes sense.

Here’s what you need for each location page:

  1. H1 tag with the location in it; as long as you can keep it from sounding spammy
  2. <title> tag with your keyword target, business name, city and Province/State. Use a tool like the Mofo Description Tool to make sure you’re staying within the character limit.
  3. Meta description written with clickthrough in mind. Add a call to action if possible.
  4. Alt tags on your images
  5. Breadcrumbs e.g. Locations > Province > City. Also add Schema for your breadcrumbs as well.
  6. Schema for your location information
  7. Hierarchal folder structure e.g. www.yoursite.com/locations/location-A/
  8. No duplicate content on location pages. This is a tricky one since products and services usually don't change per each location
  9. Your full address listed for each location that is readable to bots (i.e. in HTML) and matches your Google My Business profile 
  10. The local phone number of each location
  11. Consider multiple location pages to cover various services and products offered. Keep in mind scalability and the ability to provide unique content for all pages
  12. Business hours (more for usability vs. ranking though)
  13. Optional: embed a Google Map to your location

Create Unique & Quality Content For Each Location

It’s easy and quite common to have similar content on each location page. I mean, who has the time to write unique content for 100 different locations selling the same stuff? But seriously, don’t fall prey to the “whatever is easiest” game. Content matters. And if you want to rank, don’t cookie cutter your location pages. 

Six ways to produce unique content for multiple locations:

  1. Feature employees with a picture and a quote about why they love working for your company. Or why they love living in that location. Or a little fun and interesting bio about them.
  2. Ask the manager of the location to write something without looking at the website first. It will likely be different than what is already on there.
  3. Add pictures of that specific location with a description.
  4. Provide a bit of history about that location, like when it all started. What used to be in that location before your company moved there?
  5. Reviews from customers specific to that location.
  6. Provide a list of local clients that use your products or services.
  7. Add a little section on why you like working in that specific city and what you like about the people that live there.

Ensure Citations Are Correct

Name, Address and Phone Number (NAP)accuracy is an important part of local SEO. Anything that lists your NAP is generally referred to as a citation.

Citations used to be a big deciding factor when it came to local search. There has been a recent shift and citations don’t hold the same weight anymore. Especially in competitive markets. At one point getting as many citations as possible was a helpful way to rank high in the Google Local 3-Pack. Now that people have caught on it’s become more challenging than that. (Like everything else in the world of SEO.)

Don’t dismiss citations altogether though. There are still relevant local directories that you need to be in (sites like Yellow Pages and Yelp). Citations are still considered a relevant link back to your site.Look for websites that are relevant to your niche and have high domain authority. Just don’t spend all your time focusing on this one aspect. Services like Whitespark and BrightLocal will build citations for you for you. Oftentimes this is more cost efficient than doing it yourself.

It’s also important that the information that already lives out there is correct. Dedicate some time to get all your citations cleaned up, starting at the data aggregator level.

What is a data aggregator?

Ever wondered where Google got all your business info before you had a chance to do it yourself? Search engines grab business information from various places. Amajor source of this information comes from data aggregators.

Aggregators get their data from places like Yellow Pages, phone records, utility records etc. These aggregators also provide info for other sites, like review sites and directories.

Below are two amazing illustrations from Moz Local. They illustrate the Local Search Ecosystems in Canada and the US.

Canadian Local Search Ecosystem

Canadian Local Search EcosystemYellow Pages and Industry Canada are the primary info providers

Primary data sources in Canada:

  1. Yellow Pages Group
  2. Industry Canada
  3. Acxiom
  4. Factual

 

United States Local Search Ecosystem

Local Search Ecosystem USAData sources in the US are different from Canada

Primary data sources in the US:

  1. Infogroup
  2. Factual
  3. Localeze
  4. Acxiom

How to clean up citations:

  1. Make sure that the primary data sources in your country (i.e. data aggregators) have the correct info for your business and all your locations
  2. Make sure your info is correct in Google Maps, Bing Maps, and Yelp
  3. Use a tool, like BrightLocal to check for incorrect NAP listings. You can also manually search for your business name, your current address, your phone number, and any old addresses.
  4. Correct any wrong info you find. Your name, address, and phone number needs to be IDENTICAL everywhere you find it. Some are easy to change and others require a higher level of involvement.

Where to get citations:

  1. Data aggregators
  2. Get local citations from sites like Yelp, Hotfrog, or Foursquare
  3. Local blogs
  4. Local directories. Search for "[your city] directory" or "[your state] directory".
  5. Industry specific directories. Search for "[your industry] directory" or even "[your keyword] directory" .
  6. Here is a list from Moz with best local citations by category.

Use a Local Phone Number

Use a local number vs. a toll-free number. This is important for local search. Especially if you have multiple locations.

A popular concern is: “What if my product or service is nationwide? Won’t people need the toll-free number as well?”

Answer: Many directories also give you an option to also list your toll-free number. If you care about ranking locally, then use a local number. Period. People that search from the other side of the country are unlikely to see your business in their local 3-pack since you don't have a physical location there.

Rank Well in Organic Search

The data from the Local SEO Guide study also uncovered a high correlation between ranking well in organic search and ranking high in the Google Local 3-Pack. No easy task right? True dat. But the great news is that all of the above tips will also help you rank well in organic search. It can be a lot of work, but the return on effort can be high.

You might have guessed it from reading this article, but Cheeky Monkey Media offers local search services and audits. We'd love to hear from you if you're interested in getting your site found more often in local search results.

Aug 09 2016
Aug 09

NOTE: This tutorial assumes you have some knowledge of Drupal web development, field and field display management. It will include some theming code examples.

If you've never heard of the Paragraphs module, it allows you to create "bundles" of fields and then call in those bundles via a paragraphs field on another entity. You can then add any number of these bundles into the entity, in any combination, to build out a page or some other super snazzy component.

Build bundles for a masthead, a pull quote, a banner, a simple text area... etc., and an editor now has a collection of tools to build dynamic pages, beyond the oldschool Title/Body/WYSIWYG situation. There are even modules that will help you get all parallaxy and animated with paragraphs.

The really beautiful thing is, you can nest paragraphs items. Yes, paragraphs items, within paragraphs items within... (The word Inception popped up a lot as we worked out various models).

Ok, so here's a practical example I built recently.

Part 1 - The Tools

Make sure you install the paragraphs module and a bootstrap based theme. You could use any theme and any carousel javascript library to do this, but bootstrap has carousel.js built in, and well, if you're not using Bootstrap, or Foundation based themes, you don't know what you're missing.

What I'm about to describe below for Bootstrap's Carousel will work exactly the same way with Foundation's Orbit. The only difference being slight changes in the markup and class names.

Part 2 - Fields and Entities

Create a paragraph bundle called "Slide". This will hold the fields for the content you consider one complete slide. It may be as simple as just an image field. You may want to include a text field and style the bundle to overlay the text with an image as the background. Whatever you want to see parading by on the screen.

The bundle you created is just an entity, so you can template and style this bundle any way you wish. It doesn't matter to the carousel. You may wish to use this slide component outside of the slideshow, maybe as a banner or something else. The magic comes with the next component.

Create a paragraph bundle called "Slide Container". As the name implies, this will hold the slides and do the work. You could call this "Carousel", or anything else, but I find it useful to include the word "container" as it will always be used to contain other paragraph bundles and it's useless alone. This naming convention extends to any other type of container bundle I make for other purposes.

The only field you really need on the next bundle is a Paragraphs field. Configure this field in the following way:

Make sure the widget type for the paragraphs field is "Embedded".

Label: Slides
Required: TRUE
Bundle: Check the slide bundle you created previously.
Item Title: Slide
Plural Item Title: Slides
Default View Mode: Preview *
Add Mode: Select List **
Number of values: 5 ***

* Using Preview as default view mode will render the bundle on the edit screen the same way it's rendered on the view screen. It will be contained inside a collapsed and draggable container, but will give you a good idea of how it's going to look once it's saved.

** You could choose Button for the Add Mode. With only one bundle available on this field it's going to render a button anyway, but if you have a whole bunch of bundles available on one paragraphs field using a select list keeps the UI less cluttered. This is important as things can get pretty complex with a lot of bundles flying around.

*** It's good to set limits on something like a carousel. Too many slides to load can have a negative impact on load times, etc. There are lots of reasons one might advise against ever using a carousel; this is just one. A google search on the topic may convince you to never use a carousel again... Oh well... maybe there's still something to be learned here.

On the Manage Display tab for this bundle, set the Slices field label to "Hidden" and the format to "Paragraphs Item".

Let's add one more field to this bundle for a little more control. Let's call it "Slide Interval". It's an "Integer" field type and "Text Field" widget. This will allow us to control how long the slides wait before changing.

I set a default value to 5000 and a suffix to "ms" for milliseconds. So the default slide interval will be 5 seconds.

On the Display settings for this field, just hide the field.

You'll notice on the Display Settings tab there is a sub tab for the "Paragraphs Editor Preview", view mode. (Remember when we set the default view mode to "Preview" earlier?) You can use this to set up how your fields are previewed. I usually match the default for field visibility.

One more thing to do and then on to some code!

We need to attach a Paragraphs field to a content type or some other entity we want to add slide shows to. For this tutorial just use a page content type or something. You can call this field Paragraphs, or Bundles, or Components, or whatever you want to think of these embedded bundles as.

Set the field settings as we did for the previous paragraphs field, changing titles and labels where appropriate. This time, you'll see 2 bundles in the bundles list. Just check the "Slide Container" bundle for now.

That's about it. You can create a page, then add a "Slide Container" to it. INSIDE the Slide Container, you'll see a button to "Add Slide". When you click that you'll get whatever fields you defined for the slide bundle. Add your image or other content there. Click the Collapse button on the Slide (not on the Slide Container), and the Slide bundle will collapse to preview mode.

Click "Add Slide" again, and repeat if you want, but I suggest at least 2 slides for this to demo well.

Now for the secret sauce...

Part 3 - Theming the Carousel

If you saved yourself some content with a couple of Slides inside a Slide Container, you may be a bit sad to see that it's not much to look at. It's kind of just sitting there stiffly like me at my first Jr. High dance when a girl asked me to get up and bust a move. Not very impressive - at - all...

Like many theming tasks we need 3 things: a hook_theme, a hook_preprocess and a tpl.php

Let's start with the preprocess actually, so we can set up a couple of variables for the tpl.

I usually use a feature module to hold all the config for the bundles and fields described above. But this code can go in a custom module, or even your theme. I'll prefix things with MY_THEME in the examples below.

 /** * Implements hook_preprocess_entity(). */ function MY_THEME_preprocess_entity(&$variables) { // Only act on paragraphs_item entity types of the slide_container bundle. if ($variables['entity_type'] == 'paragraphs_item' && $variables['paragraphs_item']->bundle === 'slide_container') { // Start active_class TRUE for the first slide. $variables['active_class'] = TRUE; // For setting the slide interval. $interval = field_get_items('paragraphs_item', $variables['paragraphs_item'], 'field_slide_interval'); $variables['interval'] = !empty($interval) $interval[0]['value'] : ‘5000’; } }

The 'active_class' variable will be set to FALSE in the tpl after the first slide is rendered.

Now we need hook_theme() to register our tpl.php file for these entities.

 /** * Implements hook_theme(). */ function MY_THEME_theme($existing, $type, $theme, $path) { return array( 'paragraphs_item__slide_container' => array( 'render element' => 'elements', 'path' => $path . '/templates', 'template' => 'paragraphs-item--slide_container', ) ); }

And now we package it all up with our tpl file which we’ll put in a /templates directory inside our theme (as defined in the hook_theme() function above): paragraphs-item--slide_container.tpl.php

The markup in here comes from the Bootstrap examples found here: https://getbootstrap.com/javascript/#carousel-examples

I've only inserted php to set some attributes and add our slide content found in field_slides, attached to this paragraph bundle. As I mentioned, this markup could just as easily be the Orbit markup from Foundation, or anything else for the js plugin of your choice.

  1. </p>
    
  2.  
    
  3. <div class="carousel slide" data-interval="<?php print $interval; ?>" data-ride="carousel" id="carousel-component-<?php print $id; ?>"><!-- Indicators -->
    
  4. <ol class="carousel-indicators"><!--?php foreach (element_children($variables['elements']['field_slides']) as $key) : ?-->
    
  5.  <li data-slide-to="<?php print $key; ?>" data-target="#carousel-component-<?php print $id; ?>">></li>
    
  6.  <!--?php endforeach; ?-->
    
  7. </ol>
    
  8. <!-- Wrapper for slides -->
    
  9.  
    
  10. <div class="carousel-inner" role="listbox"><!--?php foreach (element_children($variables['elements']['field_slides']) as $key) : ?-->
    
  11. <div class="item <?php if ($active_class) { print 'active'; $active_class = FALSE; } ?>"><!--?php print render($elements['field_slides'][$key]); ?--></div>
    
  12. <!--?php endforeach; ?--></div>
    
  13. <!-- Controls --><a class="left carousel-control" data-slide="prev" href="#carousel-component-<?php print $id; ?>" role="button"><span class="sr-only">Previous</span> </a> <a class="right carousel-control" data-slide="next" href="#carousel-component-<?php print $id; ?>" role="button"> <span class="sr-only">Next</span> </a></div>
    
  14.  
    
  15. <p>
    

As you can see we loop through all the field_slides elements first to set up the slide indicator list items, second to render each slide into the slide wrapper. Notice $active_class is set to FALSE after the first slide is given the active class. The active class tells carousel.js which slide is in view.

That's It!

Once all this is in place you should clear caches and reload your page. You should see your slides cycle through! You may need some more style tweaks, but this is all it takes to get a modular slider in Drupal with Bootstrap and Paragraphs.

Just think about how easy it is to manage this content. Create a page, add a Slide Container, add a Slide, repeat. It's very intuitive and easily managed. Think about how you could expand on it with different slides. Make a Video Slide, Testimonial Slide and more, all available in the one Slide Container, just by adding more bundles!

TROUBLE?

If the slider ain't slidin', make sure carousel.js is being included in your theme.

Jul 19 2016
Jul 19

On our first day as interns at Cheeky Monkey, we (Jared and Jordan) were given the task of exploring the somewhat uncharted waters of using Behat, an open source BDD (Behavior-driven development) testing framework, with Drupal 7.

Why BDD Testing?

We all know that testing is important, but why do we bother with “BDD” testing?

Behavior-driven development testing is exactly what it sounds like, testing the behavior of the site. This makes the tests very different than say a unit test.

Unit tests are often reliant on a small piece of code, such as an individual function, so if you change that function, you often have to change the test. With BDD tests, however, you write plain English “Scenarios” inside of specific “Features” or “Stories” to test how you expect the website to react in response to certain user actions. Having these tests available in your back pocket helps you catch bugs in unpredicted areas of your site when you’re implementing new features.

Now that we have the “why?” out of the way, it is time to get cracking on some serious detective work. We also need a sandbox to play around in with these foreign concepts. We set up a very basic Drupal 7 site on Pantheon and cloned it down on our local machines.

 

The Process:

Being relatively new to the world of development, and with Behat being fairly new to the world of Cheeky Monkey, we didn’t have many clues right off the bat. For the first few days of the project, we were on a quest to gather resources and knowledge. First stop? The wise sage, Google. We discovered that there was not a definitive Behat/Drupal tutorial out there, but there are plenty of little breadcrumbs to go off of. The most helpful resources for us were the Drupal Extension to Behat and Mink and the Behat Docs.

The first few days that we spent trying to piece everything together were filled with a constant flux of blind frustration, complete confusion and wonderful epiphanies. Over the course of around two weeks, we were able to put together a small set of features, or tests. Our intention was that they cover some basic Drupal 7 site functionality and can hopefully be implemented on most Drupal 7 projects going forward.

Installation

The following steps are what we ironed out to get Behat up and running on Drupal 7 sites locally.

  1. In your local project directory, create a folder called ‘behat’ inside of your sites folder: PROJECT/sites/Behat

  2. In your new Behat folder, create a composer.json file that looks like this:

Screen Shot 2016-07-06 at 10.53.39 AM.png

  1. From your command line, in PROJECT/sites/behat you will want to run $ composer install to get all of those dependencies installed. In order for this step to work, you will need composer installed on your machine.

  2. You will also need to create a behat.yml file that looks something like this, to configure your testing environment:

Screen Shot 2016-07-06 at 3.54.45 PM.png

6. We now need to initialize Behat. To do this, run: $ bin/Behat --init. This creates the features folder where you will write your tests, and your own FeatureContext.php file, where you can define custom steps. To learn more about this, visit the Behat and Drupal Extension documentation that we listed above.

Writing Tests

Now to actually writing the tests! This is the easy part. The tests are written using a language called Gherkin, in files with the extension ‘.feature’.

GitHub user mikecrittenden has a list of predefined Drupal behat steps that are available if you like to look at them in a browser.

The quick and easy way to view these steps, in our opinion, is to run $ bin/behat -dl in your terminal from the PROJECT/sites/behat folder.

Here is an example of a small and simple test to get a sense of how the tests are structured:

Screen Shot 2016-07-07 at 10.43.50 AM.png

In the above test, the “Feature” declaration is not processed by Behat as it is there for humans to understand what this .feature file is testing. The @api tag before the “Scenario” calls the Drupal API Driver.

  • Given’ is generally used to define some parameters of the environment of your website.
  • When’ is usually the actions taken by the user.
  • Then’ is usually saved for the expected behaviors of the site.

Executing Tests

Once the tests are written, you probably want to run them, right?

Luckily, once everything is correctly installed, running Behat tests is a breeze.

You just implemented a new feature onto your website and now you need to run your tests to make sure it didn’t accidently break a behavior.

In your command line, navigate to the PROJECT/sites/Behat folder and run the simple command $ bin/Behat. This tells Behat to find all of the *.feature files and test them against your website. Once it is done running you should be able to see all of your passing tests, and more importantly, any failing scenarios specifying the exact step that failed.

Now let’s say you have your core set of features and you have just written a new one. You don’t need to run all of the tests just to see if the new one works. In your command line, you start as you did before, just adding the path from your project’s Behat folder to that specific .feature file. For example, you made a new test and named it my_example.feature. You would simply run $ bin/Behat features/my_example.feature in your command line.

In Conclusion

While this is still a work in progress for us interns, we have learned a lot about Behat and hope that our new found knowledge will be of some help for the fine developers at Cheeky Monkey Media and for anybody else who wishes to cut back on unpredicted bugs!

Jul 12 2016
yan
Jul 12

This is part 3, of a 3 part tutorial for creating a custom module for drupal 7. If you haven't already done so, you may wish to look at part 1 and part 2 first. Anyway, here is the source code of this tutorial.

First of all, though, I have to apologize that I did not do a good job of keeping track of all of the changes made so far. I code everything before I start writing, so hopefully it is not too confusing.

There are few things I would like update this time so here is a list of the things that I want to cover in this tutorial:

  • Update the module menu, so each recipe operation has their unique path.
  • Implement helper functions to handle add/edit/update operations
  • Implement functions to handle recipe status changes via ajax call.
  • Implement functions to handle delete recipes.

 

Update the module menu, so each recipe operation has their unique path.

Time to update the hook_menu to clear up the mess that I left from my last tutorial. Let's use a constant for the recipe path, so it’s easier to update it. Add the following line to the top of the simple_recipe.module

  1. define ('SIMPLE_RECIPE_BASE_PATH', ‘simple_recipe');
    

Then let's make a menu item to list all recipes, so the end user could actually use this thing. Let’s add the following menu items to the hook_menu array.

  1. $items['user/%user/' . SIMPLE_RECIPE_BASE_PATH . '/list'] = array(
    
  2. 'title' => 'Listing all Recipes',
    
  3. 'type' => MENU_DEFAULT_LOCAL_TASK,
    
  4. 'weight' => 0,
    
  5. );
    

You might wonder why there is no callback for this path. If we declare menu item type to be MENU_DEFAULT_LOCAL_TASK we have to put the actual callback in other items, strange isn’t it? Anyways, let’s declare another menu item. Please add the following code to your hook_menu:

  1. $items['user/%user/' . SIMPLE_RECIPE_BASE_PATH] = array(
    
  2. 'title' => 'Simple Recipe',
    
  3. 'description' => 'List recipes',
    
  4. 'page callback' => '_simple_recipe_list_recipes',
    
  5. 'page arguments' => array(1),
    
  6. 'access callback' => '_simple_recipe_access_check',
    
  7. 'access arguments' => array(1),
    
  8. 'type' => MENU_LOCAL_TASK,
    
  9. );
    

This MENU_LOCAL_TASK has to do all the hard work.

Then, we need to update the path for add and edit operation.

  1. $items['user/%user/' . SIMPLE_RECIPE_BASE_PATH . '/add'] = array(
    
  2. 'title' => 'Add a Simple Recipe',
    
  3. 'description' => 'Add recipe',
    
  4. 'page callback' => 'drupal_get_form',
    
  5. 'page arguments' => array('simple_recipe_form'),
    
  6. 'access callback' => '_simple_recipe_access_check',
    
  7. 'access arguments' => array(1),
    
  8. 'type' => MENU_CALLBACK,
    
  9. );
    
  10. $items['user/%user/' . SIMPLE_RECIPE_BASE_PATH . '/edit/%'] = array(
    
  11. 'title' => 'Edit Simple Recipe',
    
  12. 'description' => 'Edit recipe',
    
  13. 'page callback' => 'drupal_get_form',
    
  14. 'page arguments' => array('simple_recipe_form'),
    
  15. 'access callback' => '_simple_recipe_access_check',
    
  16. 'access arguments' => array(1),
    
  17. 'type' => MENU_CALLBACK,
    
  18. );
    

As you can see, both operations use the same simple_recipe_form form. I need to make some changes to make it work. Basically add a hidden field to store recipe id to distinguish the insert and update operation. Let’s focus on updating this hook_menu for now. Register the last two operations, delete and status changes.

  1. $items['user/%user/' . SIMPLE_RECIPE_BASE_PATH . '/delete'] = array(
    
  2. 'title' => 'Delete Recipe',
    
  3. 'description' => 'Delete recipe',
    
  4. 'page callback' => 'drupal_get_form',
    
  5. 'page arguments' => array('simple_recipe_delete_form'),
    
  6. 'access callback' => '_simple_recipe_access_check',
    
  7. 'access arguments' => array(1),
    
  8. 'type' => MENU_CALLBACK,
    
  9. );
    

Since delete operation is quite destructive, we want to make confirmation form for this operation. The status change operation will be done via ajax, so we don’t need to create a form for that. The placeholder %user tells drupal to load a user object as a first argument, and the last % is a placeholder for recipe id.

  1. $items['user/%user/' . SIMPLE_RECIPE_BASE_PATH . '/status/%'] = array(
    
  2. 'title' => 'Update a Simple Recipe status',
    
  3. 'description' => 'Update recipe status',
    
  4. 'page callback' => 'simple_recipe_update_status',
    
  5. 'page arguments' => array(4),
    
  6. 'access callback' => '_simple_recipe_access_check',
    
  7. 'access arguments' => array(1),
    
  8. 'type' => MENU_CALLBACK,
    
  9. );
    

Implement helper functions to handle add/edit/update operations

Now we have all the menu item path re-arranged, we are going to need few functions to help us create, load and update recipes. The old simple recipe save function is not very flexible. It only allows us to save a new recipe and use a hardcoded value for status. Let's change that. Basically, I want to insert and update to be one function, that's why I am using db_merge function here. This function can be view as a combination of db_insert and db_update, so when rid (recipe id) present in the key() function, it will do an update. Otherwise, it will do an insert operation

  1. /**
    
  2. * Update simple recipe db, insert or update.
    
  3. * @param array $values
    
  4. */
    
  5. function simple_recipe_save_recipe($values = null) {
    
  6. global $user;
    
  7. $query = db_merge('simple_recipe')
    
  8. // Check if rid exist or not, if found do update otherwise do insert.
    
  9. ->key(array('rid' => isset($values['rid']) ? $values['rid'] : 0))
    
  10. ->fields(array(
    
  11. 'uid' => isset($values['uid']) ? $values['uid'] : $user->uid,
    
  12. // Make sure serialize form_value before passing to this function.
    
  13. 'form_values' => isset($values['form_values']) ? $values['form_values'] : '',
    
  14. 'status' => (int) $values['status'],
    
  15. 'timestamp' => REQUEST_TIME,
    
  16. ));
    
  17. $query->execute();
    
  18. }
    

Next, we are going to add delete function. This is really straight forward.

  1. /**
    
  2. * Delete a database record from db.
    
  3. * @param int $rid
    
  4. */
    
  5. function simple_recipe_delete($rid) {
    
  6. if (is_numeric($rid)) {
    
  7. $num_deleted = db_delete('simple_recipe')
    
  8. ->condition('rid', $rid)
    
  9. ->execute();
    
  10. }
    
  11. }
    

There are two functions to get recipes, one load a recipe for a given the recipe id. The other loads recipes for a given user and recipe status.

  1. /**
    
  2. * load a recipe from db.
    
  3. * @param int $noid
    
  4. * @return db record.
    
  5. */
    
  6. function simple_recipe_get_recipe($rid) {
    
  7. return db_select('simple_recipe', 'sr')
    
  8. ->fields('sr')
    
  9. ->where('rid = :rid', array(
    
  10. ':rid' => (int)$rid,
    
  11. ))
    
  12. ->execute()
    
  13. ->fetchAssoc();
    
  14. }
    
  15. /**
    
  16. * Load recipes from a given user.
    
  17. *
    
  18. * @param int $uid
    
  19. * User id.
    
  20. * @param int $status
    
  21. * recipe status, 0 disabled, 1 enabled, other load everything.
    
  22. * @return array of recipes objects
    
  23. */
    
  24. function simple_recipe_get_recipes($uid, $status = 2) {
    
  25. $query = db_select('simple_recipe', 'sr')
    
  26. ->fields('sr')
    
  27. ->condition('sr.uid', $uid);
    
  28. // Decide the what to load.
    
  29. switch($status) {
    
  30. case 0:
    
  31. // Disabled recipts.
    
  32. $query->condition('sr.status', 0);
    
  33. break;
    
  34. case 1:
    
  35. // Enabled recipts.
    
  36. $query->condition('sr.status', 1);
    
  37. break;
    
  38. default:
    
  39. // Load every recipts.
    
  40. break;
    
  41. }
    
  42. $result = $query->execute()
    
  43. ->fetchAll();
    
  44. return $result;
    
  45. }
    

Now, we are ready to update operations related to recipes.

Implement functions to handle recipe status changes via ajax call.

Here is the todo list:

  1. register a path for recipe status callback.
  2. create a callback function to change recipe’s status
  3. use drupal default ajax library to ajaxify the status update link
  4. update the recipe status operation label by using javascript

Step 1: register a path for recipe status callback.

We have registered the path user/%user/simple_recipe/status/% in the hook_menu already.

Step 2: create a callback function to change recipe’s status.

Let's implement the simple_recipe_update_status callback function. We load a existing recipe from database and flip the status value then save it.

  1. /**
    
  2. * Flip status flag for the given simple recipe id.
    
  3. * @param int $rid
    
  4. */
    
  5. function simple_recipe_update_status($rid) {
    
  6. $recipe = simple_recipe_get_recipe($rid);
    
  7. $recipe['status'] = (int) !$recipe['status'];
    
  8. simple_recipe_save_recipe($recipe);
    
  9. }
    

Step 3: use drupal default ajax library to ajaxify the status update link. 

Let’s create the link in the recipe listing page. Since the listing page is not a form. We can’t piggy-back on the form api to perform a ajax call. Therefore, we are going to use the core ajax library to ajaxify this link. Its very simple, we need to do two things. load the library and then update the link class. Modify _simple_recipe_list_recipes function, let's add the following line to the top of the function.

  1. drupal_add_library('system', 'drupal.ajax');
    

Then we need to add use-ajax class to the $operation variable which holds text either Enable or Disable.

  1. l(t($operation), "user/$account->uid/simple_recipe/status/$recipe->rid", array(
    
  2. 'attributes' => array(
    
  3. 'title' => 'Title here.',
    
  4. 'id' => $status_id,
    
  5. 'class' => array('use-ajax'), // Ajaxify this link.
    
  6. ),
    
  7. )),
    

Now, it's time to update the link text after each successful ajax call. We want to display label Enable when the recipe with status is 0 and Disable for status 1. We are going to do this using javascript. Add this line right after the for each loop.

  1. drupal_add_js(drupal_get_path('module', 'simple_recipe') . '/js/simple_recipe.js');
    

Step 4: update the recipe status operation label by using javascript.

Make sure you create a new directory call js inside our simple_recipe directory, then create a new file call simple_recipe.js. In order to update each recipe’s status, we need to be able to detect which recipe’s status link were clicked. In the Jquery ajaxSuccess function, we have a setting.url property, which stores the request url. We know the last segment of the path user/%user/simple_recipe/status/% holds the recipe id, so by extracting the id from the request URI we will be able to target the right element. add the following code to simple_recipe.js file.

  1. (function ($) {
    
  2. Drupal.behaviors.simple_recipe = {
    
  3. attach: function (context, settings) {
    
  4. // listen to ajax success event.
    
  5. // Then we are going to use url to determine which
    
  6. // recipe has been fired via ajax.
    
  7. // Once we get the id, then we can alter the recipe state text.
    
  8. $(document).ajaxSuccess(function(event, xhr, settings) {
    
  9. // Recipe id is after the string status/
    
  10. var pattern = /status\/(\d+)/;
    
  11. var str = settings.url;
    
  12. var result = str.match(pattern);
    
  13. // Only update recipe status if we have a valid id.
    
  14. if (result[1].length > 0) {
    
  15. var id = result[1];
    
  16. var id_selector = '#status-' + id;
    
  17. // Update text.
    
  18. if ($(id_selector).text() == 'Disable') {
    
  19. $(id_selector).text('Enable');
    
  20. }
    
  21. else {
    
  22. $(id_selector).text('Disable');
    
  23. }
    
  24. }
    
  25. });
    
  26. }
    
  27. }
    
  28. })(jQuery);
    

Implement functions to handle delete recipes.

Let's create a new form to display in the formation page. This form will have a hidden field that stores the recipe id.

  1. function simple_recipe_delete_form($rid) {
    
  2. $rid = arg(4);
    
  3. $recipe = simple_recipe_get_recipe($rid);
    
  4. $recipe = unserialize($recipe['form_values']);
    
  5. $form['warning'] = array(
    
  6. '#markup' => '
    

' . t('Are you sure you want to delete @name?', array([email protected]' => $recipe['name'])) . '

', ); $form['rid'] = array( '#type' => 'hidden', '#value' => $rid, ); $form['delte'] = array( '#type' => 'submit', '#name' => 'delete_btn', '#value' => 'Delete', ); return $form; }

Once the form is submitted, we will check for the hidden recipe id and delete it from the database. I am using very similar approach to distinguish the insert and update operation on the simple_recipe_form form. Note that instead of using drupal_goto we are using form_state to do the redirect, that's because we want to give the; other module a chance to process form as well.

  1. function simple_recipe_delete_form_submit($form, &$form_state) {
    
  2. if (!empty($form_state['values']['rid']) && !empty($form_state['triggering_element']['#name']) && $form_state['triggering_element']['#name'] == 'delete_btn') {
    
  3. $rid = $form_state['values']['rid'];
    
  4. simple_recipe_delete($rid);
    
  5. global $user;
    
  6. $form_state['redirect'] = 'user/' . $user->uid . '/' . SIMPLE_RECIPE_BASE_PATH;
    
  7. drupal_set_message(t('Delete successful.'));
    
  8. }
    
  9. }
    

Find the source code here:

Download Source Code

Need help with a Drupal project? Did you know that Cheeky Monkey Media works with other agencies that need extra hands on projects? Our Drupal Web Developers are ready to help. Call us!

Jul 05 2016
yan
Jul 05

Recently, I started using the Paragraphs Module to create landing pages.

If you haven’t used it before, go check it out. It’s really user-friendly. I feel like it’s a replacement for field collections. However, unlike field collections, paragraphs allow you to choose a different set of fields each time.

Contributed modules mentioned in this post:

Custom module:

Paragraphs class, download here.

Why use Paragraphs?

Paragraphs give end users more control. For instance, by using the Paragraphs and entity background modules together, it is possible for the end user to choose background images and colours.

Get it running.

Define the paragraph bundles you intend to use using their User Interface (UI). Since Paragraphs is an entity, you can add any field and manage their display mode, just like adding a new content type.

Create a new field of paragraph type on any node, and choose what paragraph bundle this field can reference to.

Set up landing page content type with Paragraphs

Here is an example of how I setup a landing page content type:

1) First, define 3 paragraph bundles: simple, advanced, and blocks paragraphs.

   1a) the simple paragraph has a title and body field.

   1b) the advance paragraph has a title, body, and field collection fields.

   1c) the block paragraph has a title, body and a block reference field (using block reference module, so end user can use embed slider, maps, views block, etc).

2) Download and configure the entity background module to allow background color and image for the above 3 paragraph bundles. There is a background image style, don’t forget to change that.

3) Since our design uses full a width background, I created a template file for a landing page content type and used a page preprocess function to load it.

4) Then I created a landing page content type, removed the body field and added a paragraph field with unlimited cardinality. (Make the above 3 paragraph bundles available to this field.)

5) Don’t forget to configure permissions to allow anonymous users to view the paragraph content.

The CSS targeting issue

Theming paragraphs can be a little tricky. The default paragraph class has a synchronization issue. Just like node id, you can’t guarantee that it will be the same on a different server. Therefore, we can’t use it for targeting each paragraph section individually. We also can’t use CSS nth-child selector on paragraph, because as soon as the end user changes the paragraph order on the backend, wrong CSS will be applied.

I tried the classy paragraphs module for assigning a class to each paragraph. You have to create a field and implement a hook to output a predefined class option list for each paragraph bundle. Since every paragraph bundle will be tied to the same set of predefined classes, it does not make sense in our use case.

What I really want is a way to target each individual paragraph section and make sure both local and other environments have the same class.

By studying the entity background, and class paragraphs modules, I came up with this paragraph class module. You can download the module here. This module creates a CSS class text field that allows end users to assign CSS class to each paragraph section.

To get it working do the following:

  • enable this module

  • go to each paragraph bundle editing page and enable it. (It will create a paragraph class field for the enabled bundle.)

  • whatever you enter in that text field will be converted to a single CSS class and output it on the entity container.

By manually entering the CSS class for each paragraph instance, we overcome the targeting issue for different environments.

Let me know if you have any questions or suggestions. Thanks for reading.

Jun 28 2016
Jun 28

I recently had to create a new layout that mimicked the Pinterest layout. Masonry to the rescue! (sorta...) With Drupal already crapping out the content via views, we could just use the Masonry views plugin right? Sorta. Well, it worked. ... sorta. There were problems, and I don’t like problems, only solutions.

I like a very NON-hacky way of doing things. Masonry views worked for the desktop screen size but failed miserably for anything smaller. We were working with a responsive design, so it was unacceptable. There was simply just no amount of tweaking the options and CSS that it came with, that I was happy with. I’m also not a fan of CMS plugins controlling layout. There tend to be crappy implementations and far less control. I don’t speak for everything, of course, just my experience.

I wanted to control.. as much as I could. So I abandoned the views plugin, and just decided to use the raw jQuery plugin, and use my own CSS.

This assumes ya know how to use requireJS and jQuery plugins.

Step 1 - The view.

So, the view just had to output the HTML, nothing else. Set the output format for the view to ‘Unformatted list’. Nice, just simple, clean Drupal output.

Step 2 - Including the jQuery plugin code.

I’m also not a fan of including boatloads of JS on every page so that you can use it “at some point” on some page on the site. Unnecessary load times, for all other pages.

RequireJS happiness ensued.

The main.js config file:

  1. requirejs.config({
    
  2.   paths: {
    
  3.        // vendor
    
  4.      'masonry': 'vendor/masonry.pkgd.min',
    
  5.  
    
  6.     // custom
    
  7. 'jquery': 'modules/jquery-global',
    
  8.       'community': 'modules/community'
    
  9.   }
    
  10. });
    
  11.  
    
  12. require([
    
  13.   'jquery',
    
  14.   ], function ($) {
    
  15.   'use strict';
    
  16.  
    
  17.    // DOM ready
    
  18.   $(function() {
    
  19.  
    
  20.   // js loaded only on community page
    
  21.    if ($('body').hasClass('page-community')) {
    
  22.      require(['community']);
    
  23.      }
    
  24.  
    
  25.   }); // DOM ready
    
  26. });
    

We’re telling require where to find the libraries and specific module files, that has the code we need. Then when DOM has loaded, we check to see if we’re on a specific page, if so, load up the required JS. The ‘community’ page is where the masonry plugin is required. So, let's look at that file (community.js).

  1. /**
    
  2.  * Community
    
  3.  * @requires jquery, masonry
    
  4.  */
    
  5. define([
    
  6.   'jquery',
    
  7.   'masonry'
    
  8. ], function ($, masonry) {
    
  9.   'use strict';
    
  10.  
    
  11.   /**
    
  12.    * object constructor
    
  13.    */
    
  14.   var Community = function() {
    
  15.   this.init();
    
  16.   };
    
  17.  
    
  18.   /**
    
  19.    * init community module
    
  20.    */
    
  21.   Community.prototype.init = function() {
    
  22.     var self = this;
    
  23.  
    
  24.    // init masonry
    
  25.        $( '.view-community .view-content' ).masonry( { itemSelector: '.views-row' } );
    
  26.  
    
  27.   /**
    
  28.    * DOM ready
    
  29.    */
    
  30.   $(function () {
    
  31.    var community = new Community();
    
  32.   });
    
  33. });
    

So now we have the masonry jQuery plugin only loading up on the community page. By inspecting the output of that view on the page, I was able to figure out which elements to target for masonry to know which is which regarding content. The ‘.view-row’ elements were each ‘element’ of content, while the “.view-community .view-content” was the parent.

That just gets the all the JS working, but will most likely still look like poo (technical monkey term). -- Time to start slinging that poo around until we have something nice to look at. Yes, we can actually polish a turd.

Step 3 - CSS(SCSS) Kung-Poo

  1. .view-community {
    
  2.   max-width: 100%;
    
  3.   margin: 0 auto;
    
  4.   .view-content {
    
  5.     width: 100%;
    
  6.     overflow: hidden;
    
  7.     .views-row {
    
  8.     width: 48%;
    
  9.      margin: 0 1%;
    
  10.       margin-bottom: rem-calc(20);
    
  11.         overflow: hidden;
    
  12.     border-radius: 15px;
    
  13.     background: $white;
    
  14.      font-size: rem-calc(12);
    
  15.     line-height: rem-calc(18);
    
  16.           @media #{$medium-up} {
    
  17.            font-size: rem-calc(16);
    
  18.             line-height: rem-calc(26);
    
  19.           }
    
  20.          @media #{$small-portrait-up} {
    
  21.            margin: 0 1%;
    
  22.       margin-bottom: rem-calc(20);
    
  23.         width: 48%;
    
  24.      }
    
  25.          @media #{$medium-up} {
    
  26.            margin: 0 1%;
    
  27.       margin-bottom: rem-calc(20);
    
  28.         width: 31%;
    
  29.      }
    
  30.          @media #{$large-up} {
    
  31.             margin: 0 1%;
    
  32.       margin-bottom: rem-calc(20);
    
  33.         width: 23%;
    
  34.      }
    

Okay, now we have something decent to look at.

  • So for mobile views, the elements take up 48% of the horizontal screen space, effectively having two elements per ‘row’.
  • Moving up from that, we just increase the font-size.
  • Then up from that, (a tablet layout), we have effectively 3 per row, and the for desktop we have 4 per row.
  • So this is much cleaner, leaner than having to fiddle with the views masonry plugin. It allows us to have much more control over the plugin itself, and the CSS.

Sometimes, it pays to just go back to doing things manually, especially if you want more control.

Jun 21 2016
Jun 21

Have you ever had a list of related items, related by say by a taxonomy term or another node, and needed some way to sort that list, fully, or even partially? If so, there are a few good views modules out there to help you out.

My first introduction to setting up a custom sort on a list of content was to use the Nodequeue module. Nodequeue is a multi-faceted module which has a lot of queue/listing functionality. One of which is integrating with views.

I’ll go through the steps necessary for setting up a nodequeue and linking it to your view to have it use your sorting.

Once you’ve got Nodequeue installed, creating a new nodequeue is straightforward. Go to Structure -> Nodequeues -> Add simple queue. For most nodequeues, you just need to enter a name, select the content types you want available to your queue, and that’s it.

Now that we’ve got a queue, we need to add content to it. You can do this two ways. I’ll start with the individual node method. Go to your content overview page, click edit for a node of type you just made available to your nodequeue. You’ll now notice the Nodequeue tab. Click on the Nodequeue tab, and then click Add to queue. That’s it. Now add as many nodes as you need custom sorted to your nodequeue. 

Add to nodeque

Now that we’ve got all the content added to the list, we can sort it. Go to Structure -> Nodequeues. Click view for your nodequeue. You can sort the content in your list however you like. You can also add content to your queue via an autocomplete text field on this form. 

sort-nodequeue

Next, we need to link your view and the nodequeue. Edit your view. If needed, open the Advanced tab on the right. Click Add under Relationships. Click Filter and select Nodequeue. Check the Nodequeue: Queue option, then Apply. Check Limit to one or more queues (recommended), and select your nodequeue. Do not click Require this relationship unless you want to restrict your list to the nodequeue. 

views-nodequeue-relationship

Now we need to apply the nodequeue’s sorting. Click Add under Sort Criteria. Click Filter and select Nodequeue. Check Nodequeue: Position in nodequeue and other parameter if you didn’t require the relationship, or Nodequeue: Position if you did, then click Apply. If you already had a sort on your view, click Rearrange under Sort Criteria and move the Nodequeue sort to the top. If not, it’s a good idea to have a backup sorting for the items you didn’t specifically sort.

Click Save on your view, and now check out your newly sorted list.

taxonomy-list-nodequeue-sorted

Now as much as that does get the job done, I find that to be a lot of work to be able to sort a pre-existing list. Luckily I ran across DraggableViews, whose sole purpose is to allow you to manually sort a pre-existing view.

I’ll go through the steps needed to get things all set up.

After enabling DraggableViews, edit your view. Add a new Page.

Change the Format to Table, make the settings For: this page (override). Leave settings as default.

Add the following fields to the display: Content: Nid, and Draggableviews: Content. When adding the fields, make sure you change the settings For: this page (override). In the Configure field settings, check Exclude from display for Content: Nid.

draggableviews-field-nid

Leave the defaults for Draggableviews: Content.

draggableviews-field-draggableviews.png

If you had any other fields in your display, you can probably remove all of them but the Content: Title fields, and the two that you just added. When sorting the list, you don’t need it to be cluttered.

Next, you need to add the sorting. Click Add under Sort Criteria. Choose Draggableviews: Weight. Change it to be for this page (overridden). If you had other sort criteria, move Draggableviews to the top.

Depending on your needs, and how you want to sort, you may want to turn off the pager, and choose to Display all Items, for this display. I find it makes sorting a lot easier, and gives you a broader view of the list, especially if it’s a few pages.

There are a few more optional things you might want to do to help with User Experience. You can change the Display names to help you remember which is your actual display, and which is your sorting page. You can change the title of the sorting display. And you could add a link in the header of your sorting display, linking back to your main listing page.

The final step for the sorting view is to set a path for the page. Set it to whatever makes sense for you. If the list I’m sorting is already a page, I will usually just use that with /sort appended to the end. Once you’ve set your path, save your view.

Now that we’ve got the sorting set up. It’s time to get your original display to use it. On your original display, under Sort Criteria, click Add. Choose Draggableviews: Weight (just like with our sorting view). When configuring the settings, you will see the field Display sort as - this just sets which sorting data to use.

draggableviews-configure-sort.png

And you should only have option in that list right now. If you ever set up multiple displays with multiple sorting displays, this is where you’d link up each one to its proper sorting page. Now as before, if you had previous sorting, move the Draggableviews: Content field to the top of the list.

Save your view, and then test it out.

It should look something like this.

draggableviews-sorting-page.png

And then like this.

draggableviews-listing-page-sorted.png

Jun 17 2016
Jun 17

As an html/css purist at heart, my school of thought has always been having your representational layer separated from your markup. Sites like CSS Zen Garden taught us that you should never have to mix your design styles inside your markup with the idea being that well structured html will never have to change even on a complete re-design.

Bootstrap

2 years ago, I was forced to use a css framework for one of my project. Being the control freak that I am, I was reluctant to try new things and bloat my beautiful handmade custom css.

It took me a little over a year for me to embrace using a css framework and rely on existing css to style my markup, but I’ve learned so much by doing so from people a lot smaller than I am. And I’ve reduced more than half the need to write custom css as well as lowered production time.

Disclaimer: Some of these new classes will only work on the current alpha-2 release of bootstrap 4 and might change in the future since it’s still in heavy development. Use at your own risk.

Responsive Floats

Responsive floats are great for header elements among other things. I often come across designs that have search box right aligned on desktop, but are left aligned on tablet. Or main navigation that are floated to the left but move to the right and collapse on mobile.

Responsive floats works by using the pull-<breakpoint>-<direction> pattern.

<header>

  <form class=”pull-xs-left pull-md-right”>

     <input type="text" placeholder="Search">

  </form>

</header>

The above code will float the search bar left until the screen width reaches the “md” breakpoint, floating it to the right.

In conjunction with other components from the framework like navbar, spacing and setting your own variables in sass, we can easily come very close to the original design mockups without writing a single line of custom css. Like I said earlier, it took me a while to develop using these concepts but it opened my mind to write my code in a more modular fashion and reuse these components on every site I work on.

Responsive Text Alignments

This one I use often for content. On Desktop, the design’s text is aligned center inside articles but on mobile this makes for a weird looking effect and we’de much rather have it left aligned.

Bootstrap v4 introduces new responsive text alignment classes like this:

<article class=”text-md-center”>

 <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit ex, semper quis eros sed,</p>

</article>

This will leave the text at its default left alignment on smaller breakpoints, but will align the text center on the medium breakpoint and up, removing the need to write a media query in your css.

If you prefer to have your text centered on all breakpoints you simply need to use text-xs-center

Conclusion

This is just the tip of the iceberg for new features that ships with the Bootstrap 4. Some other things that I’m really loving is the new card component and contextual colors and backgrounds creating custom ones is as easy as using the “bg-variant($parent, $color)” mixin.

If you haven’t already, I urge you to look at the documentation , but whatever css framework you chose to use, make sure you really dig in the documentation and use all the tools that are available to you. The investment will save you time in the long run.

Jun 16 2016
Jun 16

This is one of the blogs that I was really thrilled to write because I got to document my first ever installation of the production version of Drupal 8.  And boy, was I excited!  As you know, Drupal has made some significant changes under the hood in this version. I am not going to go over those changes in this feature, but I thought, I would give an overview of some of the superficial changes that it has undergone.  More than anything, as a developer, I was really interested to see how much it has changed in terms of the UI and operability.

Setting Up

I setup Drupal 8 on my Windows 10 machine running Acquia Dev Desktop (yes, you read that right!).  The installation was pretty straight forward and appeared to be somewhat quicker than all the versions I have tried before.  Once I got it setup, the front page looked extremely familiar, with it running Bartik as the default theme.  But right off the bat, I noticed the nice admin toolbar across the top of the page with pretty much the same menu links that we're accustomed to.  The one new change, 'Modules' is now called 'Extend'.

The Modules Page

Going to the modules page, we see that we have a module filter by default, making module searches a lot easier when our list starts building up. As we scroll down the list, we notice a couple of inclusions that are finally getting their dues, as you might already know, Views and Views UI are in Core!  The Views UI pretty much looks the same but the one thing I really liked is the ability to now clone a View display type as any other display type. To elaborate, in D7, if we wanted to clone a Page display, we were only allowed to clone to the same display type, ‘Page’.  However, the Views in D8, now allows us to clone a display type like Page, as any other display type like ‘Block’, ‘Entity Reference’, ‘Feed’, ‘Attachment’, etc (views.png). This is one change I’m really happy about because there has been one too many instances where I’ve had to fiddle with code after cloning a display to transform it to another display type.

More welcomed goodies in Core

The other noticeable changes: we've got CKEditor, Contextual Links, Quick Edit, and Configuration Manager all enabled and running as part of Core.  They've also added multilingual capabilities, and web services as part of the release.  These are definitely welcomed additions and makes Drupal much more relevant and powerful from the get-go.  One additional change that I noticed, the removal of the PHP Filter module.  It has now moved to a contributed module at http://drupal.org/project/php.

Display Modes with More Juice

Moving along, Drupal 8 now incorporates some of the functionality of Display Suite and offers us more control over the way nodes, user profiles, comments, taxonomies and blocks are displayed.  There is a new admin section under 'Structure' called 'Display Modes' from where we can add more display modes to control the look and feel of content as well as forms.  So not only can we easily manage the display that the end-user sees, but we can also modify the look of forms while data is inputted.

In-Place Content Editing

One of the other features that is in Core now is the ability to edit content in-place. In Drupal 7, this task was accomplished by contributed modules.  With the inclusion of it in Core now, it just makes life a lot easier for us, especially when we’ve got tons of stuff to edit and test.  There’s an ‘Edit’ button at the top of the toolbar and that displays all the places on the page that we can edit in-place.  Editing and displaying of the updated content is now a cinch.

Configurations made easier

As I began to delve further into the configuration section, the one thing that caught my eye was the new 'Configuration synchronization' section under Development.  I briefly played around with the feature  and my initial reaction is, it's a mild-dose of the Features module. Basically, this new feature allows us to export all the configuration changes made on a site into a nice little tar.gz file.  In the scenario above, I just created a new user role called 'Super User' and immediately exported my configurations. Once you extract the file, you can see that there are quite a few .yml format text files Configurations, and among them is a file called, 'user.role.super_user.yml', which is the config for my new role.  Basically, I can take this and import it into my Staging or Production site, provided they're the same site and share the same UUID.  As the Features modules allows us to bundle related configurations and re-use it on ANY site, Drupal's core configuration feature allows us to keep configuration consistent between different environments of the SAME site.  As you can see, it won't replace the Features module just yet, but it does offer a great starting step towards a cleaner and more reliable way to transfer and transport configuration among different environments and sites.

In conclusion

In a nutshell, my first encounter with Drupal 8 has been extremely positive. The guys at Drupal have taken stock of what users really need and have tried to incorporate those changes into this new version.  I've got lots of roads to traverse with Drupal 8 and I hope to share with you some of those experiences during my future trails.

Visit our Why Drupal 8? site!

Jun 16 2016
Jun 16

Prerequisites:

  • RequireJS (and some knowledge of how to use it)
  • IntentionJS
  • A brain
  • Bananas

There are plenty of reasons you shouldn’t HAVE to use IntentionJS, but it’s just so good when you NEED your fix, of DOM manipulation.

Normally a responsive website should be designed so that when you expand or collapse the viewport (effective screen), the DOM elements flow naturally from left to right, and top to bottom. The order is preserved, and it was designed so that those elements follow that flow in terms of importance and usability.

Admittedly, this does limit us at times, and we need elements to be in completely different placements in the DOM, depending on the device used. Sure we can mess with duplicated content by hiding and showing the right elements based on the screen size [please don’t, it’s bad], or doing some fancy schmancy css floating and absolute positioning, but then you start to get other fun issues, that go beyond the scope of this banana log.

So, we’re left with manually moving the elements around. You could start using the append() and after() functions say, from jQuery, but that also gets complicated.. setting screen widths, window resize, or using Modernizr.mq (media query), etc. All messy in some form or another.

We like clean, even though we like poo, we still like clean.

Our Hero, IntentionJS

From the mouths of the intentionJS magicians: (http://intentionjs.com/)

“Intention.js offers a light-weight and clear way to dynamically restructure HTML in a responsive manner.”

Good right? riiight.

Okay, so we all have our own methods for including JS, and writing libraries and code. Here’s what we monkeys do.

Starting with RequireJS

We like using requireJS. A lot. In fact I get a banana every time I do. So in the main.js file loaded by require we have:

requirejs.config({
paths: {
// vendor
'intention': 'vendor/intention',
'underscore': 'vendor/underscore-min',
'viewportsize': 'vendor/viewportSize-min',
// custom
'jquery': 'modules/jquery-global',
'intentcontext': 'modules/intentcontext',
'homepage': 'modules/homepage',
'initintent': 'modules/initintent'
},
});

Here we are just telling require where to find all our ‘required’ files when we ‘require’ them. Yeah.. there is probably a better way of saying that. *puts on deal with it glasses*

Intention requires underscore, so we’re including that. Also, we’re using a little library called ‘viewportsize’. Why? well because different browsers report different viewport sizes, based on whether or not it’s showing the scroll bar. That’s a problem, this fixes that problem. (https://github.com/tysonmatanich/viewportSize)

Then we include jQuery, cause we need it. Then comes some magical code with unicorns.. and monkeys.

require([
'jquery',
'underscore',
'intentcontext',
], function ($, _, IntentContext) {
'use strict';
// DOM ready
$(function() {
// js loaded only on homepage
if ($('body').hasClass('front')) {
require(['homepage']);
}
if ($('html').length > 0) {
require(['initintent']);
}
}); // DOM ready
});

So here, we’re just including the needed libraries for the site in general, and then checking if we’re on the homepage, if so, include the homepage module. Then the very last that we include in the initialization of the intent. Think of it, as intentions’s big red “go” button. We’ll get to these a bit later. For now, just know, that we are making sure that the initinent file is included last, since we’re doing all ‘intention’ setup first. Since require loads these in ORDER, of the code inclusion, we’re able to do all the setup first, then lastly initialize it.

IntentContext.js

This is where we setup our ‘contexts’. A context is basically a ‘switch point’ - a point a which stuff is supposed to happen. Each ‘context’ is associated to a screen size (these values should match your CSS media queries for major layout changes)..

IntentContext.bp_desktop = 1025;
IntentContext.bp_tabletlandscape = 769;
IntentContext.bp_tablet = 641;
IntentContext.bp_mobilelandscape = 321;
IntentContext.bp_mobile = 0;

These are the breakpoints were major layout changes happen (for the purpose of this blog). Yours would match that of your CSS breakpoint values.

Next up, making our contexts. As you will see, each context has a name, and I’m setting the “min” value to the breakpoint value that I set in the above code. So basically, the ‘desktop’ context will get triggered every time the browser hits the “1025 pixel” viewport width or above. (It won’t keep re-triggering events though, as you increase viewport width above that, which is nice.) All the other ‘contexts’ will get triggered at their respective screen width values.

IntentContext.horizontal_axis = IntentContext.intent.responsive({
ID: 'width',
contexts: [{
name: 'desktop',
min: IntentContext.bp_desktop
}, {
name: 'tabletlandscape',
min: IntentContext.bp_tabletlandscape
}, {
name: 'tablet',
min: IntentContext.bp_tablet
}, {
name: 'mobilelandscape',
min: IntentContext.bp_mobilelandscape
}, {
name: 'mobile',
min: IntentContext.bp_mobile
}],
matcher: function (measure, context) {
return measure >= context.min;
},
measure: function () {
IntentContext.v_width = viewportSize.getWidth();
return IntentContext.v_width;
}
});

So, there is a thing. It’s thing you may need. Normally intention won’t activate the context on first page load, which you may need. We will get to that. (This is what that initintent.js file is for).

Homepage.js

Now we need to tell which elements where to be placed in the dom, according to whatever ‘context’ is triggered. You can either go directly in the HTML and add all the special intention attributes to the elements, or do it via JS. I like doing it in the JS, i find it cleaner.

So in our Homepage.prototype.intent = function () function:

var footer = $('.l-footer');
footer.attr('intent', '');
footer.attr('in-desktop-after', '.l-header');
footer.attr('in-tabletlandscape-after', '.l-main');
footer.attr('in-tablet-after', '.l-main');
footer.attr('in-mobilelandscape-after', '.l-header');
footer.attr('in-mobile-after', '.l-header');
IntentContext.intent.on('desktop', function() {
footer.attr('style', 'border: 4px solid red;');
});
IntentContext.intent.on('tabletlandscape', function() {
});
IntentContext.intent.on('tablet', function() {
});
IntentContext.intent.on('mobilelandscape', function() {
footer.attr('style', 'border: 4px solid white;');
});
IntentContext.intent.on('mobile', function() {
footer.attr('style', 'border: 4px solid blue;');
});

First line we just get the element we want to target. The next lines are key.

I’m now manually adding all the required contexts on that elements, so for each ‘breakpoint’ context, we know where to place the footer. The syntax is as follows

footer.attr(‘in-[your-breakpoint-name]-[move-function], ‘[dom element]’)’

‘your-breakpoint-name’ is just the name you associated to the breakpoint, up in the IntentContext.js file.

‘move-function’ is the method in which you want to place that element. They work just like jQuery’s manipulation functions [append(), before(), after(), prepend()]

‘dom-element’ is just the element you are specifying to be “moved to”.

So in this case, when the browser hits the ‘desktop’ layout screen width, we are putting the ‘.l-footer’ element just after the ‘.l-header’ element in the DOM. The next lines all work the same and specify where the element needs to go, for whichever context (screen size).

Then, we have some more magical code.

IntentContext.intent.on('desktop', function() {
footer.attr('style', 'border: 4px solid red;');
});
IntentContext.intent.on('tabletlandscape', function() {
footer.attr('style', '');
});

So, for each context, we can run some custom code of any kind. In this case, every time we hit the ‘desktop’ context, we are going to add a border to the footer element. Everytime we hit the ‘tabletlandscape’ context, we make sure remove any lingering styles. Etc..

I normally like to use these methods to ‘reset’ certain things that may have been triggered on an alternate layout.

Lastly, the Initilization of Intent. This will allow us to use those .on() [in above code] functions on page load as well.

Know that all this will only happen on the homepage though. If you need this to happen on all pages, you can create a separate module that can handle site wide context changes, and just include it in the main.js require section.

InitIntent.js

IntentContext.horizontal_axis.respond();
IntentContext.intent.elements(document);
$(window).on('resize', IntentContext.horizontal_axis.respond);

So these 3 lines just get everything going. Check out the intention.js website for further detail, but suffice to know, they get intention up and running.

That should be it to have it all working nicely and being able to do some sexy DOM manipulation without to much pain.

Jun 02 2016
Jun 02

The Design Factor

DrupalCon was an amazing sight to behold in person. Since I was fortunate enough to be on the New Orleans DrupalCon design team, it was actually uber cool to see all of the Drupal Association’s (DA's) and Chris Arlidge’s (our creative director and lead designer) hard work in action.

Everything my eyes fell on was our design. That was honestly the neatest thing for me, as it represented many, many months of collaborative work with the DA (I may have taken a thousand photos). The feedback on the conference designs was enthusiastic and very positive, which gave me the “warm fuzzies” right from the start of the con.

Entrance to DrupalCon 2016 (New Orleans) - design by Cheeky Monkey Media's Creative Director Chris Arlidge

So Happy Together

It also blew my mind to see such a large conference so well organized. My hat goes off to the entire DA team & all of the volunteers who made attending this event so seamless. For someone like me who deals with a ton of my company's “logistics”, I was very impressed with how the DA handled over 3000 people. Well done.

Another noteworthy experience was getting to shake hands and speak with my Drupal peers. There is nothing like actually feeling a huge room full of passionate, like-minded, fun DrupalCon’ers! I had heard about how awesome the Con’s are, but experiencing it first hand was a whole different ballpark. The tech vibe was amazing (some of which I understood - ha!)

Treena and Amanda at DrupalCon

Representing

The booths and swag were off the chart. There were so many unique ways to showcase each company’s brand and message. I in particular loved the fact that so many of my peers were willing to share thoughts and ideas, whether pertaining to the representation of their booth/company, or just on improving the Drupal community in general. Awesome.

While maintaining/sponsoring a booth at DrupalCon is a lot of work, I really enjoyed getting to meet and greet so many attendees from around the world. I met people from all over the United States, Europe and even Africa (plus many other Canadians which was cool). I was truly amazed at how much I learned from this conference just from chatting at our booth.

Rick with his monkey had at DrupalCon 2016

The monkey booth at DrupalCon 2016 New Orleans

Learning Curves

There were many sessions available to every skill level of attendee. If you want to learn more about anything Drupal and all things associated, this is the conference to attend. My crew got the chance to sit in on a few sessions which they deemed very worthy, and I plan on hitting some sessions for my next con in Baltimore.

One of the sessions at DrupalCon 2016

Get them to the Geek

I am a social creature to be sure, so I loved the networking parties. After all, we were in New Orleans! The venues for the post day gatherings were so interesting. The architecture in the Crescent city is stunning - the wrought iron (part inspiration for the conference logo design), the huge shutters, the history - it all added to the ambiance of the parties. The jazz bands were unreal (I love, love the washboard). I also discovered that ‘geeks’ are very enthusiastic dancers and some of the moves I saw will be burned into my memory for forever. Again, awesome!

The Pantheon Party at DurpalCon 2016

Trivia Night in the National War Museum, DrupalCon 2016 - New Orleans

Final Thoughts

To sum everything up, I was totally enamored with DrupalCon. Even though I had heard everything there is to know about the Cons for years, being there was an unique experience that I will hopefully get to do again. GO BALTIMORE 2017!

DrupalCon 2017 - Blatimore Logo

Feb 01 2016
Feb 01

In order to import some json data, you first need theses modules installed and enabled.

First to import content from another site, you need to create the content type so the data can be saved on your website. The fields from the JSON source should be the same as your content type on your site depending your needs. for exemple if the JSON data array looks like this:

{
 "name": “Johny John”,
 “date_joined”: 02/12/1988
 "title": “Teacher",
 "department": “Astrophysics",
 "email": [email protected],
}

The fields in your content type should look something like this:

  • name - Text field
  • date_joined - Date field
  • title: - Text field
  • department - Text field
  • email - Email field

Depending on where you download the data, there could be just a few or hundreds and thousands of arrays. There is also a great tool to get a view of your JSON file, its called "REST Console” for chrome. (There are similar apps for all other browsers). REST Console will help you fetch the JSON data and display it on front of you.(See image below) This is valuable get to the data field names and context for configuring the JSON Feeds Import.

Rest Console

Now that the Content Type is created, configuring the Feeds Importers is all thats left.

The first configuration page in feeds in the Basic settings.

  • Name & description : Self-explanatory, simply the name of what you are importing.
  • Attach to content type:
  • If standalone form is selected, use this link: http://sitename.com/import to import data.
  • If a content type is selected, you must create a node of that content type to import data.
  • Periodic Import: Run the import on regular basis, by using cron.

The Second is the Fetcher settings.

“Where should I get the data from?” is what the fetcher is saying. In the Fetcher page there is a menu of selection that you can choose from depending your demand. the two most common are “File Upload” or “HTTP Fetcher”(URL).

The Third is the Parser settings.

“How should i read and interpret this data?” is what the parser is saying. This part is important because its where you say to the website that its going to be a JSONPath parser. (see image below)

Now before going in and configuring the JSONPath parser settings, you first need to create the feed mapping.

For the source always select jsonpath_parser. The numbers will increment automatically like in the picture below. Do this for all your content type fields.

Once the mapping is done. Go to the JSONPath parser settings. You should see something like the picture below.

In this picture above you should see all the content type fields in order just like in the mapping page. In the text box you need enter the JSONPath field by referencing the JSON key like in the first picture. As for the context text box this variable depends on how your JSONPath output is constructed. For this example its pretty simple, there is only one context so you put

 “ $.[] “ 

Here is a page where you could find more info about the Context : https://www.drupal.org/node/1059152 .

Finally you should be ready to import JSONPath Feeds. Go to the import page and add the import file or add the feed URL just like below.

Once the import is done you should see your new nodes created in your content page.

Dec 30 2015
yan
Dec 30

Recently I migrated a drupal site that uses ms sql server to mysql.

One of the conversions required me to convert all the tables from latin1_swedish_ci to utf8_general_ci character set.

If you only want to convert a few tables, just execute the following sql statement.

ALTER TABLE tableName CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

We all know a typical drupal site can have100+ tables.

In my case, the database I needed to convert had 350+ tables, so doing it manually was simply not an option.

So I am sharing a simple script I used to do all the conversions.

// Change the following setting as needed.
$host = "localhost";
$db_name = 'dbname';
$db_username = "root";
$db_password = "root";
$convert_to = "utf8_general_ci";

try {
 $conn = new PDO("mysql:host=$host;dbname=$db_name", $db_username, $db_password);
 // set the PDO error mode to exception
 $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

 $sql = "SHOW TABLES";

 print "Following SQL Statements have been executed. 

"; foreach ($conn->query($sql) as $row) { $table_name = $row['Tables_in_' . $db_name]; $sql = 'ALTER TABLE ' . $table_name . ' CONVERT TO CHARACTER SET utf8 COLLATE ' . $convert_to; $output = $sql . '
'; print $output; $conn->query($sql); } } catch(PDOException $e) { echo "Connection failed: " . $e->getMessage(); }

Good luck and I hope this helps!

Download Code

Dec 17 2015
Dec 17

When working on larger projects, software architects and tech leads inevitably come across a few big hurdles in the project requirements for some not so “out of the box” functionality. They start asking themselves questions about the best way to approach these tasks:

  • Can I find a contrib module that I can leverage enough to accomplish this?
  • Will that extra work be less effort, and less of a headache to maintain than just building exactly what I need?
  • Should I just build a custom module that does exactly what I need?

Like all good Drupal lovers, we tend to roll the dice on the contrib module route because there are so many that are solidly built, and that provide a solid base if you do need to extend upon it.

Let me share a brief summary of one of my last projects, and sadly, my struggles with leveraging contrib modules.

Over the majority of the last year, I’ve been working on a project here at Cheeky Monkey Media that required a custom search tool. Once you have searched, you would see a breakdown of the totals of your search, and have the option to download the full datasets. The dataset was quite large, 650,000+ records with 30+ fields per record. Over the course of the project, we constructed, then reworked this process multiple times in order to increase speed, and decrease our memory footprint. Our search needed to look at two content types with a parent/child relationship between the two.

Our first, less successful approach, utilized Search API, with Apache SOLR and mysql database backends, as well as a more direct integration with Apache SOLR. When we did our initial build and testing, we were using a small subset of the data. We needed to migrate their old data, and were working on the search tasks in parallel with the migration tasks. Everything worked great on our subset, and everyone felt like when we switched over to the fully migrated database, our speeds would still be in acceptable levels.

Unfortunately, we were wrong. Although, after a little tweaking, our initial search results and breakdown was returned in a timely manner; none of these implementations allowed us to generate the full results, both quickly and without generating huge memory footprints which could crash the file generation process. The results were offered in downloadable PDF and Excel files, and with working with these contrib modules; finding a balance between the memory footprint of loading in the data needed to write the files with the ever increasing file size of the download with generating the files in an acceptable time frame just could never be met.

Our final solution ended up utilizing a custom database queries against two search index tables, one for each content type. This allowed us to streamline our whole approach, eliminating some extra steps added from how we could interface with the contrib modules. And with being a custom solution, we were able to analyze our queries and set up indexes on the tables, to further optimize as needed. We were also able to make more minor adjustments to the how we generated our initial total breakdowns - creating very precise queries instead of having to use a combination of multiple queries and record iteration to compile our needed breakdowns.

In the end, the choice to go with the contrib modules ended up biting us in the ass. Even though they were pretty solid modules, there was just too much “extra”, too much rigidity added from the contribs. Being a smaller dev shop, most of our projects are on the smaller size. We sometimes forget how sloppy, inefficient, or even superfluous code, whether from a contrib module you’ve extended upon, or even your own custom code, can become a giant pain when scaled up, even just 2-3 times. And all that extra space around that square peg in the round hole is no longer just negligible, it’s now made things unusable.

In the end, I’m not trying to say that when you scale things up, a contrib module that needs a little extra work is going to kill your processes, or that contrib modules just don’t scale. I’m hoping to remind everyone to keep in mind there are tradeoffs of choosing a slightly imperfect solution, or slopping together a makeshift solution. That even when working on smaller projects, when the few extra milliseconds here and there doesn't really matter, we become better architects and programmers by remembering they do add up. That we can always be honing our skills and staying sharp for when they are quite noticeable.

Nov 03 2015
Nov 03

A while ago, our creative director asked me to implement a custom 404 page on our corporate website. We were tired of the generic drupal 404 page and wanted to give it our own “cheeky” touch.

Of course with drupal, there are a few different ways to accomplish this. So I decided to use a custom preprocessor and php template for our application.

Basically, what we are going to do is create a new php template called page--404.tpl.php and modify the code to suit our needs. But before we can get started, we first need to tell drupal about this new template.

This is where all the magic happens. Add the following preprocessor to template.php in your custom theme. This will be located at: sites/all/themes/themename/template.php

/**
* Implements template_preprocess_page().
*/

function themename_preprocess_page(&$vars) {
 // Adds a Custom 404 page
 $header = drupal_get_http_header("status");
 if($header == "404 Not Found") {    
   $vars['theme_hook_suggestions'][] = 'page__404';
 }
}

Note: Replace themename with your custom theme name. Underscores are converted to dashes.

This will create the necessary theme hook suggestion and tell drupal to use page--404.tpl.php if it returns a 404 page.

Now that drupal knows about the new page template, we can completely customize the look and feel of our 404 page. For most people, you can just copy the code from page.php into page--404.tpl and customize it appropriately. However we took this one step further and gave this page its own unique layout and css.

Have a look at the finished product http://cheekymonkeymedia.ca/404 and click the “Panic” button to see what happens!

Let us know what you think of our custom 404 page or vote for it on Best404.net

Sep 22 2015
yan
Sep 22

This tutorial is written for new drupal developers or php developers who want to learn drupal. You can find the part 1 of the tutorial here: tutorial part 1

Last time, we created a simple recipe module with save and load functionality. The user interface is not very friendly yet, and users have to enter a recipe id in the url to load it.

Today, we are going to improve the usability of the module by adding some UI element to it. By the end of the tutorial, you will be able to add, and list recipes. Editing, deleting, enable/disable recipes will be covered in the next tutorial.

Here is the topic we are going to cover today:

  1. Use theme function to create a table
  2. Use Devel tools

Step 1: Getting the tools.

First, let's get the devel module to help us out.

Install the devel module by the following drush command:

drush en devel -y

You can also download the module manually from drupal.

If you install it manually, make sure you enable the devel module after the installation, otherwise you will get a white screen by calling an undefined function.

Step 2: Getting the data from the database

Modify the simple_recipe.module file located at sites/all/modules/custom/simple_recipe

To add a new function, simple_recipe_get_recipes($uid, $status), we are going to have two parameters for this; A drupal user id, and receipt status.

/**
* Load recipes from given user.
*
* @param int $uid
*  User id.
*/
function simple_recipe_get_recipes($uid, $status = 2) {
 $query = db_select('simple_recipe', 'sr')
 ->fields('sr')
 ->condition('sr.uid', $uid);

 // Decide what to load.
 switch($status) {
     case 0:
       // Disabled recipes.
       $query->condition('sr.status', 0);
       break;

     case 1:
       // Enabled recipes.
       $query->condition('sr.status', 1);
       break;

     default:
       // Load every recipes.
       break;
 }

 $result = $query->execute()
 ->fetchAll();

 return $result;
}

Step 3: Register a path for the recipe listing page

Now we are going to create a new page to list all the data. We will need to register a path for this page, so lets modify the simple_recipe_menu(),

/**
* Implements hook_menu().
*/
function simple_recipe_menu() {
 $items = array();

 $items['user/%user/simple_recipe'] = array(
        'title' => 'Simple Recipe',
        'description' => 'The recipe form',
        'page callback' => '_simple_recipe_list_recipes',
        'page arguments' => array(1),
        'access callback' => '_simple_recipe_access_check',
        'access arguments' => array(1),
        'type' => MENU_LOCAL_TASK,
 );

 $items['user/%user/simple_recipe/add'] = array(
        'title' => 'Simple Recipe',
        'description' => 'The recipe form',
        'page callback' => 'drupal_get_form',
        'page arguments' => array('simple_recipe_form'),
        'access callback' => '_simple_recipe_access_check',
        'access arguments' => array(1),
        'type' => MENU_LOCAL_TASK,
 );

 return $items;
}

As you can see, we are going to use the user/%user/simple_recipe path for listing all the recipes. user/%user/simple_recipe/add for inserting a new recipe.

Step 4: Populate the recipe listing page

It’s now time to add another function _simple_recipe_list_recipes()

/**
* List all the recipes from a given user.
* @param User Obj $account
* @return string
*/
function _simple_recipe_list_recipes($account) {
 $recipes = simple_recipe_get_recipes($account->uid);
 dsm($recipes);

 return ' ';
}

Note:

dsm() is a function from the devel module, you pass a variable that you want to inspect as the argument. It will generate a human friendly version of the variable for you.

Now, lets visit user/1/simple_recipe

If you(admin) have previously entered any recipes,  you should be able to see them in the krumo output.

Now that we have the recipes loaded, it’s time to create a table to hold them.

  • create an array to hold table’s header
  • create an array to hold table’s row
  • loop through each recipe and fill rows array
  • call theme function to create the html table

The _simple_recipe_list_recipes function should looks similar to this one:

/**
* List all the recipes from a given user.
* @param User Obj $account
* @return string
*/
function _simple_recipe_list_recipes($account) {
 // Lets change the page title.
 drupal_set_title(t('Recipes'));

 // Declare table header.
 $header = array(
        t('Name'),
        t('Date Saved'),
        t('Options'),
 );

 // Declare table rows.
 $rows = array();

 // Load all saved recipes.
 $recipes = simple_recipe_get_recipes($account->uid);

 // Added each recipe as a table row.
 foreach ($recipes as $recipe) {
        $operation = $recipe->status ? 'Disable' : 'Enable';

        // Unserialize the data, so we can actually get its value.
        $recipe_values = unserialize($recipe->form_values);

        // Add a table row.
        $rows[] = array(
        l(t($recipe_values['name']), "user/$account->uid/simple_recipe/edit/$recipe->rid"),
        format_date($recipe->timestamp, 'medium'),
        l(t('Edit'), "user/$account->uid/simple_recipe/edit/$recipe->rid") . ' | ' .
        l(t('Delete'), "user/$account->uid/simple_recipe/delete/$recipe->rid") . ' | ' .
        l(t($operation), "user/$account->uid/simple_recipe/statue/$recipe->rid"),
        );
 }

 // Create a button to create recipe.
 $create_btn = l(t('Create Recipe'), "user/$account->uid/simple_recipe/add", array("attributes" => array("class" => array('button'))));

 if (!empty($rows)) {
        return $create_btn . theme('table', array('header' => $header, 'rows' => $rows));
 }
 else {
        return '
' . t('You don\'t have any recipe saved yet.') . '
' . $create_btn . '
'; } }

Your end result should look like this:

Custom Recipe Module

That’s all for this tutorial, I hope you enjoy reading it.

Oh, here is the source code:

Download Source Code

Sep 15 2015
Sep 15

Welcome back. If you just found this, you might want to start with Part 1 before reading on.

Okay, now we’re going into our custom theme folder (that’s based off the STARTER foundation sub-theme. Check out Justin’s Blog post, on how to set that up.

So, now that you’ve got your custom sub-theme folder and files setup, we be changing some things, and adding MOAR files.

Drupal -- showing it some love.

File: [drupal-root-folder]/sites/all/themes/[themename]/[themename].info 

First your .info file. If you’re using foundation, it should have these lines:

; Theme scripts (minified).
; Grunt will compress any custom theme scripts matching the _*.js naming convention
; into app.min.js.
scripts[] = js/app.min.js 

Problem (not really, but it’s not using our workflow).. The issue here is that foundation does a good thing, and compresses all your custom JS into an “app.min.js” file. But, we can’t use require with that, and our require will uglify and compress our custom code anyway. SO, lets comment that out. Put a “;” infront of that “scripts[] = js/app.min.js” line.

Now the template php file.

File: [drupal-root-folder]/sites/all/themes/[themename]/template.php

In your custom theme folder, load up the ‘template.php’ file. Add this line to the top under the <php:

include ('theme-functions.php'); 

Now that theme-functions.php file, that will help Drupal determine if we’re using a ‘development’ environment, or ‘production’.

File: [drupal-root-folder]/sites/all/themes/[themename]/theme-functions.php
/**
* debug switch for debug mode
*/
function cmm_is_dev_mode () {
if ( preg_match('/dev$/', $_SERVER['HTTP_HOST']) ) {
return true;
} else {
return false;
}
}

So, this the function that helps us define wether or not we are in a ‘development’ environment or a ‘production’ one. Since I like to have all my ‘dev’ environments end in a .dev domain suffix, it works. But you can tailor it to whatever you use for your local dev environment. In the case of this article, I’m using “drupaltest.dev”. Production would presummably be “drupaltest.com”.

/**
* Path to theme.
*/
function cmm_path_to_theme() {
return drupal_get_path('theme', 'drupaltest');
}

Pretty obvious what this one does. Gets the path to your custom sub-theme.

/**
* Helper functions for Require JS include
*/
function cmm_rjs_rev() {
return cmm_path_to_theme() ? time() : hashDirectory( drupal_realpath(cmm_path_to_theme() . '/js/src') );
}
function cmm_path_to_rjs_main() {
return '/' . cmm_path_to_theme() . (cmm_is_dev_mode() ? '/js/src' : '/js/dist') . '/main.js?rev=' . cmm_rjs_rev();
}
function cmm_path_to_rjs() {
return '/' . cmm_path_to_theme() . (cmm_is_dev_mode() ? '/js/src' : '/js/dist') . '/vendor/require.js?rev=' . cmm_rjs_rev();
}

Okay, first method just returns a random hash string, that we’ll need for cache busting for requireJS.

Second method there, just returns the proper path to the main.js file, based on if we are on a ‘production’ environment, or ‘development’ environment.

Third method does the same thing, except to the require.js library file itself.

The last method hasDirectory() is what creates that hash string.. Not bothering printing it out here, since… you’ll have it.. you downloaded the source didn’t you.

Change up some template files.

File: [drupal-root-folder]/sites/all/themes/[themename]/templates/html.php.tpl 

I just copied the file from the supplied zurb-foundation templates. And we’re just going to add one line.

<script id="requirejs" data-rev="<?php print cmm_rjs_rev(); ?>" data-main="<?php print cmm_path_to_rjs_main(); ?>" src="https://cheekymonkeymedia.ca/blog/require-js-grunt-bower-foundation-and-drupal-part-2/<?php print cmm_path_to_rjs(); ?>"></script>

That should look familiar. You can see those methods hard at work, printing out the correct paths, to the require.js file, and your main js file that will hold all your custom code. Put that line in the <head>...</head> area.

We’re almost here. Stuff should be loading up and working in drupal now, but lets just take this one step further, and try an example out.

File: [drupal-root-folder]/sites/all/themes/[themename]/js/src/main.js 

So in this file we do one more thing to help get rid of that caching that require js does, when we don’t want it, for development.

var __getrev = function () {
'use strict';
var rev = document.getElementById('requirejs').getAttribute('data-rev');
return rev || (new Date()).getTime();
};
requirejs.config({
urlArgs: 'rev=' + __getrev()
});

Finally, we can get to our regular scheduled programming, and load up the dependencies, and JS files. In this example, I just load the the ‘homepage’ dependency only IF we are on drupal’s ‘front’ page.

require([
'jquery',
'underscore',
'intentcontext',
], function ($, _, IntentContext) {
'use strict';
// DOM ready
$(function() {
// init the DOM elements with intentionJS
IntentContext.intent.elements(document);
IntentContext.intent.on('desktop', function () { });
IntentContext.intent.on('tablet', function () { });
IntentContext.intent.on('mobile', function () { });
// js loaded only on homepage
if ($('body').hasClass('front')) {
require(['homepage']);
}
}); // DOM ready
});

And in our homepage.js file.

File: [drupal-root-folder]/sites/all/themes/[themename]/js/src/modules/homepage.js
define([
'jquery',
], function ($) {
'use strict';
/**
* object constructor
*/
var Homepage = function() {
this.init();
};
/**
* init homepage module
*/
Homepage.prototype.init = function() {
var self = this;
console.log("Homepage JS Init", self)
};
/**
* DOM ready
*/
$(function () {
var home = new Homepage();
});
});

So this file, requires ‘jquery’. We then create a new instance, and run it in the .init method -- I also console.log the object, just to see it. You don’t have to follow this same prototyping style of JS programming. But, it find it to be a very scaleable / clean way to work with JS.

Hope it wasn’t too painful, happy coding!

*cuddles*

Download the code from GitHub

Sep 03 2015
Sep 03

In depth, but not too deep

Okay, so you want to use RequireJS to manage and organize your JS and all the dependencies, in a modular way. You also don’t want deal with RequireJS caching the heck out of your JS changes during development, otherwise...Derpal..  but, you do if you’re ready for production.

Also...  Compiling with Grunt (compass), component package management with Bower, and having it not interfere with Drupal. (.info files… we’ll get to that).

And finally, I’m not a fan of installing ruby gems and all that globally on your machine. We want this specific to the project, and keeping the versions in sync, with that Gemlock file that gets generated after the “bundle install”, which installs those ruby gems.

What we’re gonna do:

  1. Set up our files and structure for front-end development, and having it work with foundation, but not interfere with other theme related stuff.
  2. Set Up some PHP to have drupal differentiate between a ‘dev’ environment and production, as well as getting a form of cache busting in there for Require.
  3. Setup RequireJS, and make use of that cache busting.
  4. Get a sample Require JS module running, that will only load the needed JS files related to the homepage.

First thing’s first.

From what I’ve seen, it’s been common practice to have all your FE (front-end) related files in the theme folder, including your gruntfile.js, package.json, Gemfile.. etc.. Problems can arise from this.  Some bower or node packages contain .info files that aren’t Drupal standard .info files.

Drupal unfortunately recursively scans all your sub folders, and if it finds additional .info files (which would be installed along with node or bower packages) it will read them and derp out.  You can expect to find very weird problems, like not being able to install drupal or the theme properly, or unexplainable php errors.

Below is a link to a thread where people are proposing solutions.. But we’re doing things differently, so we won’t run into the issue at all.

https://www.drupal.org/node/2329453

Our Solution.  -- Don’t use the theme folder for all your setup and compiling related files.

Instead, I simply like to use a custom subfolder off of Drupal’s root folder.  Since everything is “user interface” related, it makes sense to call the folder “UI”.

So we have: [drupal-root-folder]/UI

Alright, now we can begin to put all of our front-end compiling related files in there.

Let’s start with our Node Modules, we’ll need a bunch, to get all this working.  We first need a ‘package.json’ file that will contain a list of all the node modules and their version.

File: [drupal-root-folder]/UI/package.json

{
"name": "cmmdrupalboiler",
"version": "0.1.0",
"private": true,
"config": {
"unsafe-perm": true
},
"scripts": {
"install": "bundle install --path ruby_gems && bower install"
},
"devDependencies": {
"load-grunt-tasks": "~0.3.0",
"grunt": "~0.4.5",
"grunt-contrib-watch": "~0.6.1",
"grunt-contrib-compass": "~1.0.3",
"grunt-contrib-cssmin": "~0.8.0",
"grunt-contrib-jshint": "~0.8.0",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-requirejs": "~0.4.4",
"grunt-contrib-uglify": "~0.3.3",
"grunt-contrib-copy": "~0.8.0",
"node-bourbon": "~1.2.3"
}
}

Looks like a pretty standard package file. You may have noticed the ‘scripts’ section.  It just allows us to simply only run “npm install” and it will also install all the required bower modules and ruby gems, we’ll talk about those later in the grunt file.

I’ve also included ‘node-bourbon’ since that comes from foundation. So we’ll need it. (Unless you don’t plan on using it of course).

Okay, so we got node packages listed out, now lets do some bower stuff.  We’ll need the ‘bower.json’ file for this.

File: [drupal-root-folder]/UI/bower.json

{
"name": "cmmdrupalboiler",
"private": "true",
"dependencies": {
"intentionjs": "0.9.9",
"underscore": "1.7.0",
"viewportsize": "latest",
"requirejs": "latest"
}
}

Just some bower components, so we can use them.. talk to them, tease them, snuggle them. We’re including requireJS through bower here as well.

Next up, your Gems. (Gemfile)

File: [drupal-root-folder]/UI/Gemfile

source 'http://rubygems.org'
gem 'sass', '3.4.5'
gem 'compass', '~> 1.0.3'

Okay now that we’ve got all our resources setup, we need to install them. So, do:

npm install

And then magical unicorns will install all those packages for ya.

Grunt!

Well, now that we’ve got our packages installed, we can setup our gruntfile.  This one is a bit of a doozy, but bare with me.. we can snuggle later.

Im going to go through the file bit by bit. Follow along with the downloaded code.

File: [drupal-root-folder]/UI/Gruntfile.js

/*
* Base Gruntfile Module
*/
module.exports = function (grunt) {
'use strict';
return this.registerTask('default', ['build']);
};

First part is just standard syntax for starting a grunt file. And we just register the default task, which is our ‘build’ task. -- We’ll add that actual task later. This is just the opening and closing of the function, obviously there’s a lot more in it, I’m just being syntactically correct.

Next:

/*
* load grunt tasks automatically
*/
require('load-grunt-tasks')(grunt);
var bourbon = require('node-bourbon').includePaths;
/*
* setup paths
*/
var path_vars = {
theme_path: '../sites/all/themes/cmmdrupalboiler',
foundation_path: '../sites/all/themes/zurb_foundation',
compile_path: '../UI',
bower_path: '<%= path_vars.compile_path %>/bower_components',
gem_path: '<%= path_vars.compile_path %>/ruby_gems',
js_base_path: '<%= path_vars.theme_path %>/js',
js_src_path: '<%= path_vars.theme_path %>/js/src',
js_bld_path: '<%= path_vars.theme_path %>/js/dist'
};
/*
* foundation - additional libraries
*/
var foundation_libs = [
'<%= path_vars.foundation_path %>/js/vendor/placeholder.js',
'<%= path_vars.foundation_path %>/js/vendor/fastclick.js'
];
/*
* foundation - core JS
*/
var foundation_js = [
'<%= path_vars.foundation_path %>/js/foundation/foundation.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.abide.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.accordion.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.alert.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.clearing.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.dropdown.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.equalizer.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.interchange.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.joyride.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.magellan.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.offcanvas.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.orbit.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.reveal.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.slider.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.tab.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.tooltip.js',
'<%= path_vars.foundation_path %>/js/foundation/foundation.topbar.js'
];

So here we just setup all the variables, and paths to everything. We also include all the paths to the JS files that are needed by foundation. The foundation stuff was taken right out of the gruntfile, from it’s “zurb_foundation” theme folder.

So now for the tasks.

/*
* grunt tasks config
*/
grunt.initConfig({
path_vars: path_vars,
pkg: this.file.readJSON('package.json'),
/*
* grunt clean
*/
clean: {
css: ['<%= path_vars.theme_path %>/css'],
js: ['<%= path_vars.theme_path %>/js/dist'],
options: {
force: true
}
},
...

We need a ‘clean’ task that will clear out all the old CSS files, and the all old JS files, so we don’t run into problems with old versions, or orphaned files making things messy.

/*
* grunt copy
*/
copy: {
main: {
files: [{
expand: true,
src: [
'<%= path_vars.bower_path %>/underscore/underscore-min.js',
'<%= path_vars.bower_path %>/intentionjs/intention.js',
'<%= path_vars.bower_path %>/viewportsize/viewportSize-min.js',
'<%= path_vars.bower_path %>/requirejs/require.js',
],
dest: '<%= path_vars.js_src_path %>/vendor',
filter: 'isFile',
flatten: true
}]
}
},
...

Okay, so here’s some more interesting stuff.  I like bower, but I don’t like having all the files that come with each bower component. It makes things messy, and you don’t need all that on your server, or say your GIT repo.

I’ve setup a ‘copy’ task, that will copy all the desired JS files, from their specific locations (from the bower install), to the one specified location, to where they will actually be used, by either drupal, or in this case RequireJS.  We’ll get to that. Let’s keep moving on through the Gruntfile.js

/*
* grunt compass
*/
compass: {
clean: {
options: {
clean: true
}
},
dev: {
options: {
basePath: '<%= path_vars.theme_path %>',
sassDir: 'scss',
cssDir: 'css',
imagesDir: 'images',
importPath: [
'<%= path_vars.foundation_path %>/scss/'
].concat(bourbon),
bundleExec: true
},
},
build: {
options: {
basePath: '<%= path_vars.theme_path %>',
sassDir: 'scss',
cssDir: 'css',
imagesDir: 'images',
importPath: [
'<%= path_vars.foundation_path %>/scss/'
].concat(bourbon),
outputStyle: 'compressed',
noLineComments: true,
environment: 'production',
bundleExec: true,
}
}
},

We now have two different build options for compass. A ‘dev’ version that compiles all your sass (or scss), leaving in comments and line comments and all that good stuff.  Then a build version, where all that is striped out, and the css is compressed.

Right, compass, not sass.  I like the way compass outputs it’s line comments for debugging and some of the other options it has.  The gruntfile that comes with foundation is using a compiled version of sass, which is fast, but.. doesn’t have all the nice options. At this point, it’s your choice what ya like to use.

MOAR!

/*
* grunt jshint
*/
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'<%= path_vars.js_src_path %>/main.js',
'<%= path_vars.js_src_path %>/modules/*.js',
'!<%= path_vars.js_src_path %>/vendor/**/*.js'
]
},

A little hint hurt no body. This will just help us keep our JS clean.  The .jshintrc file is included in the code, but that’s beyond the scope of this.  For now, you can see that we are just keeping the gruntfile, main.js file (requirejs main file), everything in our custom modules folder, but nothing in the vendor folder.. since that’s all 3rd party js code.

/*
* grunt uglify
*/
uglify: {
options: {
sourceMap: false
},
dist: {
files: {
'<%= path_vars.js_base_path %>/libs.min.js': [foundation_libs],
'<%= path_vars.js_base_path %>/foundation.min.js': [foundation_js]
}
}
},

We’re just using uglify manually here, to uglify foundation’s JS code.  This is also pulled from foundations default gruntfile.  So, keeping foundation in mind, whispering sweet little nothings and giving snuggles here and there. Making sure it feels the love.   Onto the homestretch for our little gruntfile.

/*
* grunt requirejs
*/
requirejs: {
compile: {
options: {
baseUrl: '.',
appDir: '<%= path_vars.js_src_path %>',
dir: '<%= path_vars.js_bld_path %>',
mainConfigFile: '<%= path_vars.theme_path %>/js/src/main.js',
optimize: 'uglify',
preserveLicenseComments: false,
useStrict: true,
wrap: true,
removeCombined: true
}
}
},

There’s our friend require.  We’re telling require to move all our require related JS code into the ‘dist’ folder, and then uglifying it there for compression.  This task only runs when we do a ‘grunt build’, and not on “grunt dev”.  WHY?, cause you’ll see, stop whining. *arnold voice*

/*
* grunt watch
*/
watch: {
grunt: { files: ['Gruntfile.js'] },
compass: {
files: ['<%= path_vars.theme_path %>/scss/**/*.scss'],
tasks: ['compass:dev']
},
js: {
files: ['<%= jshint.all %>'],
tasks: ['jshint', 'uglify']
}
}

And last but not least our watch task.  We’re wanting to watch for any changes to the gruntfile itself, the scss source files, or any of the JS files, which are defined in the jshint task.

Okay, last part.

/*
* register 'dev' task
* : for development compilation
*/
grunt.registerTask('dev', [
'copy',
'clean',
'compass:dev',
'uglify',
'watch'
]);
/*
* register 'build' task
* : for production compilation
*/
grunt.registerTask('build', [
'copy',
'clean',
'compass:build',
'uglify',
'requirejs'
]);

We’ve got two different running tasks.  The dev one being for when we want to work on the project. It first runs ‘copy’ to copy over all the bower related files we need to use. Then ‘clean’ to clean up our files. Then “compass:dev” to get some freshly compiled css out there and ready for development/debugging. Then ‘uglify’ (for foundation JS), Then ‘watch’ to watch for any changes.

The other task is reserved for production use.  When we’re happy with our code, and got everything figured out, we’ll run the ‘grunt build’ task. (Or just ‘grunt’ since that’s our default). The same ‘copy’, ‘clean’ tasks run.  But now we’re running compass:build, that will compress everything and remove needless comments and such.  Then ‘uglify’ (for foundation JS), Then require task will run, and move all the JS to the dist folder, and uglify it all. 

So at this point, you might be wondering what’s the point of the dist folder, how are we going to tell require to use everything in the ‘dist’ folder, and not ‘src’ for production.  This is where we do some PHP fun.  But before we do that, we do that snuggling we were talking about, and grab a coffee.

Continue With Part 2

Download the code from GitHub

Jul 30 2015
Jul 30

Have you ever been working on a site, and had your QA department, or your client come back with issues because when logged in, the local tabs (view, edit, etc) distort the page layout? Or maybe there are a lot of pages that contain a lot of content, and it has become frustrating for site admins to have to scroll all the way back up to edit the page? Wouldn’t it be great to still have easy access to the local tabs and not have them add extra bulk to the page layout and content?

We have began using a few different tweaks to add in the local tabs into the shortcuts menu area of a few of our main administration menu modules. So far, we’ve added this to toolbar, admin_menu, and nav_bar.

The first step, is to remove the rendering of the tabs in your page.tpl.php file(s). In most themes, you’ll find the following code renders out the tabs.


Simply delete or comment out those lines.

The second step is to add the local menu tabs and local actions to the shortcuts menu. All three modules have a preprocess or an alter hook to that allows us to add some extra menu items to the shortcuts menu area in each one. I’ll showcase the code we use for adding extras to admin_menu’s shortcuts area, but will also provide an example custom module which has examples for all three.

For admin_menu, we’ll take utilize hook_admin_menu_output_alter() to make our alterations.

function admin_menu_shortcuts_admin_menu_output_alter(&$build) {
 $path = drupal_get_path('module', 'admin_menu_shortcuts') . '/admin_menu_shortcuts.css';
 drupal_add_css($path);

 // Ensure our additions render last.
 $build['shortcut']['shortcuts']['toolbar'] = array(
    '#weight' => 99,
 );
 $build['shortcut']['shortcuts']['toolbar']['menu_local_tabs'] = menu_local_tabs();
 $build['shortcut']['shortcuts']['toolbar']['menu_local_tabs']['#primary'][] = menu_local_actions();

 // Add workbench moderation menu if needed.
 if (module_exists('workbench_moderation')) {
   $build['shortcut']['shortcuts']['toolbar']['workbench'] = array(
     '#prefix' => '
',
   );
 }
}

As you can see, there really isn’t much to it, once you know the structure you’re adding it to. However, with admin_menu, just adding the alter function doesn’t get us all the way there. With admin_menu, there are two caching options which will nullify our new addition, since it will cache for one page, and won’t be contextual to the page you are on. However, if you set the following to variables to FALSE, admin_menu_cache_client and admin_menu_cache_server. This will disable the caching, and let your users enjoy the easier to use links.

And, as you’ve probably noticed, we have included a css file. In an effort to avoid conflicts with front-end and admin theme styling, we have created a custom overriding stylesheet to apply the module’s shortcuts menu styling to the new links to have a nice uniform look and feel everywhere across the site.

Another item to note, is that our examples are using a module. Which means, the changes will apply to both front-end and admin themes. We realize that with admin themes, having the tabs show is more practical and useful, so not everyone will want the tabs in the shortcuts menu with both themes. We like to be consistent, so we use the module option most often, but you can also add all of these hooks to your custom theme’s template.php file to have them be front-end only.

Now, as promised, here is the full example module.

Pages

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web