Planet Drupal

Syndicate content
Drupal.org - aggregated feeds in category Planet Drupal
Updated: 59 min 12 sec ago

Drupal core announcements: Coding standards proposals for final discussion

Fri, 01/22/2016 - 22:20
pThe a href=https://drupal.org/project/drupal_twgTWG/a a href=https://drupal.org/project/coding_standardscoding standards committee/a is announcing two coding standards changes for final discussion. These appear to have reached a point close enough to consensus for final completion. The new process for proposing and ratifying changes is documented on the coding standards project page./p pThe two issues being proposed are:/p ullia href=https://www.drupal.org/node/2304909Please relax requirement for @file when using OO Class or Interface per file: 'ERROR | Missing file doc comment'/a/li lia href=https://www.drupal.org/node/181955[policy, then patch] Consistent .install file layout/a/li /ulpThese proposals will be re-evaluated during the next coding standards meeting currently scheduled for February 5th. At that point the discussion may be extended, or the policy may be dismissed or ratified and moved to the ‘update documentation’ step./p

roomify.us: Building a JIRA team planning app with BAT for Drupal

Fri, 01/22/2016 - 18:19
Last week we released BAT - our Bookings and Availability Management toolkit as well as a Drupal module for BAT.  We are using BAT to build the new version of our Rooms module as well as other products. However, BAT is much more than an engine for nightly bookings. It also allows us to build any sort of booking / resource management tool. So we asked: What would it take to build a resource management tool to manage ourselves?. We have previously used a tool called ResourceGuru, and while it is a wonderful tool, we wanted to build something that integrated tightly with our project planning and issue tracking tool, Jira. The result actually impressed us. We thought it would be a useful exercise, but we didn't anticipate getting a tool that we could use daily this early in the game. Read on for some of the details of what we did.

Acquia Developer Center Blog: Acquia U: Jump in and own it. Kickstart your career. - meet Amy Parker

Fri, 01/22/2016 - 18:05
div class=field field-name-field-podcast-image field-type-image field-label-abovediv class=field-labelImage:nbsp;/divdiv class=field-itemsdiv class=field-item evenimg typeof=foaf:Image src=https://dev.acquia.com/sites/default/files/podcast/images/amy_parker_acquia_u_0_post.png width=2392 height=1458 alt= //div/div/divdiv class=field field-name-body field-type-text-with-summary field-label-abovediv class=field-labelBody:nbsp;/divdiv class=field-itemsdiv class=field-item even property=content:encodedpAmy Parker, the Director of Acquia University--aka Acquia U--and I sat down in Acquia's downtown Boston headquarters to talk about Acquia's technology boot camp. The course covers much more than Drupal; the curriculum is designed to produce people able to work in tech companies: Besides a whole lot of Drupal and related technologies, it includes agile methodologies, project management tools, troubleshooting tickets, presentation skills, and more. Listen to our whole conversation to learn more./p blockquotepIf you think about it, the very senior-level, highly skilled Drupalists are already employed and there isn't a succession plan and there isn't a talent pipeline. This program is really not just about Acquia's ability to hire internally; it's about partnering with our community to be able to offer an opportunity to ramp up their teams./p/blockquote h2What is Acquia U?/h2 pAmy: Acquia U is a 14-week, hands-on, intensive, technical boot camp to take people who have a strong interest in web technology and bring them into the world of Drupal. [At the end of the course], depending on their skills coming in, they're prepared to become people who can build websites using Drupal and integrate it into a larger digital platform and a digital strategy ... Entry level Drupalists!/p pDrupal is unknown to people entering into the career market in web technologies. The problem that we find from an education perspective is that it's not taught in a lot of high schools or universities, even among computer science majors./p h2Interview video - 25 min./h2 piframe frameborder=0 height=360 src=https://www.youtube.com/embed/2KzFOd1EaNo width=640/iframe/p h2Origin story/h2 pA need arose in 2011--Amy mistakenly says 2001 in the recording--to hire more people faster and Acquia U was launched as an internal initiative, taught by Acquians. It was very successful. They had nine people in the program. Eight completed the program. Eight were hired here at Acquia. And many are still at Acquia, while others have moved on to careers outside the company. I don't consider that a loss, because those are Drupal evangelists out in other technology fields./p h2Mission/h2 pAcquia U's mission is to help make Drupal better known overall, help create more interest and Drupalists, and connect people with careers in Drupal. It also has the ambition to try to fill the gap Amy describes thus: There's no way that we can't not give back talent into the organisation. Acquia is struggling to hire. All Drupal companies are struggling to hire. If you think about it, the very senior-level, highly skilled Drupalists are already employed and there isn't a succession plan and there isn't a talent pipeline. This program is really not just about Acquia's ability to hire internally; it's about partnering with our community to be able to offer an opportunity to ramp up their teams./p pIn the next year to two years, I would like to see this program filling the void of junior-level talent in a lot of different spaces: whether it's in a non-profit, at a partner company, a client company, at another digital, Drupal shop./p h2The ideal candidate/h2 pFor me, it's about finding people who might not otherwise get a job here ... so I look in other places. If I think about it, somebody who's looking for a position at Acquia U may not know how to navigate a Drupal career path, so I go to places they may not have looked before. Going to the places where you might not think to traditionally find Drupalists is the place to go to find new Drupalists./p pI have a strong interest, as does Acquia, in hiring people in underserved populations: women ... veterans ... different age groups. My vision of the ideal candidate has nothing to do with age or background. The foundation of being successful here is potential. I define potential on:/p ullistrongWhat's motivating them:/strong If I'm motivated by giving to the community or participating in something larger than myself, that's awesome./li listrongCuriosity:/strong One of my favorite questions [to ask] is 'What's the last creative thing that you did? What's the last thing that you did that was really interesting?'/li listrongWe look for people that are motivated by their sense of integrity and wanting to learn./strong/li /ulpA good candidate, the people that are successful and come through the program ... are the people that demonstrate strong interest in something innovative, creative, fast-paced. They're looking for not just a job./p div class=column-border margin-bottom h2 style=margin-bottom: 0px;More Amy and Acquia U on the web!/h2 olliAcquia Podcast with Keith Donaldson, Acquia U graduate, 2015: a href=https://dev.acquia.com/podcast/drupal-fastest-way-idea-mvp-meet-keith-donaldsonDrupal, the fastest way from idea to MVP/a/li liAmy spoke with Brian Lewis in 2015 on a href=https://modulesunraveled.com/podcast/132-how-and-why-acquia-training-drupal-talent-they-hire-them-amy-parker-modules-unraveledModules Unravelled Podcast 132, AcquiaU/a (a href=https://www.youtube.com/watch?v=Lgm6ynNqDhohere's the video/a of their conversation)./li liAmy was a guest on a href=http://drupaleasy.com/podcast/2014/11/drupaleasy-podcast-141-or-without-l-amy-parker-acquia-uDrupalEasy podcast 141/a in 2014./li /ol/div h2Guest dossier/h2 ulliName: Amy Parker/li liWork affiliation: Director, a href=http://u.acquia.com/Acquia University/a/li liDrupal.org: a href=https://www.drupal.org/u/amyjparkeramyjparker/a/li liTwitter: a href=https://twitter.com/blueoceanview@blueoceanview/a/li liLinkedIn: a href=https://www.linkedin.com/in/amyjparkerAmy Parker/a/li liBlog/Website: a href=http://site.comhttp://site.com/a/li /ul/div/div/divdiv class=field field-name-field-podcast-audio field-type-file field-label-hiddendiv class=field-itemsdiv class=field-item evenaudio controls=controlssource src=https://dev.acquia.com/sites/default/files/podcast-audio/amy_parker_acquia_u_0.mp3 type=audio/mpeg //audio/div/div/divdiv class=field field-name-field-blog-workflow field-type-workflow field-label-abovediv class=field-labelWorkflow:nbsp;/divdiv class=field-itemsdiv class=field-item evenPending/div/div/divdiv class=field field-name-field-node-rate field-type-number-integer field-label-abovediv class=field-labelNode rate:nbsp;/divdiv class=field-itemsdiv class=field-item even0/div/div/divdiv class=field field-name-field-featured-podcast field-type-list-boolean field-label-abovediv class=field-labelMake this a featured podcast:nbsp;/divdiv class=field-itemsdiv class=field-item even/div/div/divdiv class=field field-name-field-author-logo field-type-image field-label-abovediv class=field-labelAuthor Logo:nbsp;/divdiv class=field-itemsdiv class=field-item evenimg typeof=foaf:Image src=https://dev.acquia.com/sites/default/files/podcast/author_logo/blumo_square.jpg width=1073 height=1073 alt= //div/div/div

Drupal Commerce: Commerce 2.0 alpha2 released

Fri, 01/22/2016 - 16:43
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even property=content:encodedpThe holidays are a distant memory, and Drupal 8 contrib work is happening in full force. Time for another 2.x alpha. The past three weeks have seen bug fixes, test work, and many internal cleanups. But let's focus on the bigger changes./p pbReminder:/b Commerce 2.x alphas are NOT production ready. No upgrade path is provided between alphas, a full reinstall is needed each time./p pa href=https://drupalcommerce.org/blog/43978/commerce-20-alpha2-releasedRead on to find out what's new.../a/p /div/div/div

Acquia Developer Center Blog: Drupal 8 Module of the Week: BigPipe

Fri, 01/22/2016 - 16:42
div class=field field-name-field-author field-type-entityreference field-label-hiddendiv class=field-itemsdiv class=field-item evenJeffrey A. quot;jamquot; McGuire/div/div/divdiv class=field field-name-field-blog-image field-type-image field-label-hiddendiv class=field-itemsdiv class=field-item evenimg typeof=foaf:Image src=https://dev.acquia.com/sites/default/files/styles/blog__190_x110_/public/blog/drupal_8_logo_isolated_cmyk_72_2_0.png?itok=hygXR1Wz width=140 height=85 alt=Drupal 8 logo title=Drupal 8 logo //divdiv class=field-item oddimg typeof=foaf:Image src=https://dev.acquia.com/sites/default/files/styles/blog__190_x110_/public/blog/fortunatedecisivekillifish_0.gif?itok=XhNhfrFU width=140 height=85 alt=BigPipe page loading model, animated title=BigPipe page loading model, animated //div/div/divdiv class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even property=content:encodedpEach day, more Drupal 7 modules are being migrated over to Drupal 8 and new ones are being created for the Drupal community’s latest major release. In this series, the Acquia Developer Center is profiling some of the most prominent, useful modules available for Drupal 8. This week: a href=https://www.drupal.org/project/big_pipeBigPipe/a./p /div/div/divdiv class=field field-name-field-blog-tags field-type-taxonomy-term-reference field-label-inline clearfixdiv class=field-labelTags:nbsp;/divdiv class=field-itemsdiv class=field-item evena href=/tags/acquia-drupal-planet typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=acquia drupal planet/a/divdiv class=field-item odda href=/tags/bigpipe typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=bigpipe/a/divdiv class=field-item evena href=/tags/drupal-8 typeof=skos:Concept property=rdfs:label skos:prefLabel datatype=drupal 8/a/div/div/div

Pronovix: Announcing EmbedHelp: a Javascript widget for support resources

Fri, 01/22/2016 - 15:10
pWe’ve developed EmbedHelp, a Javascript widget that makes it really easy to embed any kind of online help resource into a webpage or web application. We plan to extend this with an open source Drupal module that can be used to curate and manage the content that gets embedded into a web application. We believe it could become a valuable extension for Drupal based documentation systems./p

Mediacurrent: DrupalCamp Atlanta 2015: A First Look at Behavior Driven Development with Behat in Drupal

Fri, 01/22/2016 - 15:07
img typeof=foaf:Image src=http://d1l4od7sxc8nwf.cloudfront.net/sites/default/files/styles/thumb_blog_spotlight/public/drupalcamp_atlanta_blog_image_1.png?itok=d9KdEUNb width=200 height=152 alt=Drupalcamp Atlanta 2015 title=Drupalcamp Atlanta 2015 / pEngineers and developers tend to be passionate about building something great, and Drupal is the ideal foundation./p pIn this presentation from DrupalCamp Atlanta 2015, I explain why testing is the best way to ensure sustainable quality in what you build. While Drupal already uses some great tools for this (simpletest, php code sniffer, php unit) I like to talk about another option: Behat, and the Behavior Driven Development paradigm that it encourages./p

Tim Millwood: Composer dependencies in Drupal contrib

Fri, 01/22/2016 - 12:51
Drupal 8 is out, Drupal 8.1 will be out before we know it, but it seems contrib is still catching...

DrupalCon News: Application Period Open for Grants and Scholarships to DrupalCon

Fri, 01/22/2016 - 10:07
div class=field field--name-body field--type-text-with-summary field--label-hiddendiv class=field__itemsdiv class=field__item evenpFor individuals in the Drupal community who want to attend DrupalCon but are unable to do so due to financial considerations, the Drupal Association is pleased to offer scholarships and grants. Whether you need Drupal or Drupal needs you, we're here to help qualified individuals make their dreams of attending DrupalCon a reality./p pSo, how does it work? There's a bit of a difference between scholarships and grants, which were introduced for DrupalCon Prague. The difference can be summarized in the two following phrases:/p/div/div/div

Craig Aschbrenner: packagist.drupal-composer.org file could not be downloaded

Fri, 01/22/2016 - 06:44
div class=field field-name-body field-type-text-with-summary field-label-hiddendiv class=field-itemsdiv class=field-item even pI'm excited to be starting a new Drupal 8 project. I get to try new and shiny things. Only this time I'm breaking things along the way as I figure out what some of our new processes will be with Drupal 8./p pPart of what I've been looking into is how to go about providing local environments to team members, building out the code-base, etc. With Drupal 7 I was pretty comfortable using .make files, install profiles and distributions.  I wanted to give Drupal Composer a try.  There are several other articles that discuss Drupal Composer and more specifically Drupal Project (Composer template for Drupal projects).  I'll leave it up to you to read through those other articles./p pI wanted to keep this short and sweet and point out an issue I ran into and what the work-around is in case anyone else runs into similar issues./p pWhile running strongcomposer install/strong I started to get the following error./p pstrong[Composer\Downloader\TransportException]br /br / The a href=https://packagist.drupal-composer.org/p/provider-archived%241a0102814c28eb08a6c5ce0781872a6cf26fe1229c357943aceaedbdf0af0948.jsonhttps://packagist.drupal-composer.org/p/provider-archived%241a0102814c28.../a file could not be downloaded (HTTP/1.1 404 Not Found)/strong/p pA good couple of hours was spent trying to track down what I may have done to break the process.  I went to a href=https://packagist.drupal-composer.orghttps://packagist.drupal-composer.org/a and at first inspection the site looked up.  Then I started browsing for packages and noticed that when trying to view a package the server was returning a 500 error.  This was the likely culprit of the 404 issue I was receiving.  /p pNow that I know it's most likely not an issue with my composer.json file, my next task was figuring out how to work-around packagist.drupal-composer.org being essentially offline.  I needed to get some work done./p pOn the off chance that packagist.drupal-composer.org was just another domain for packagist.org, I modified my composer.json file changing:/p pstrongurl: a href=https://packagist.drupal-composer.orghttps://packagist.drupal-composer.org/a/strong/p pto:/p pstrongurl: a href=https://packagist.orghttps://packagist.org/a/strong/p pBingo!!!/p pWhile I can't use strongsudo composer create-project drupal-composer/drupal-project:~8.0 drupal --stability dev --no-interaction/strong mentioned in the articles linked to above, I was able to simply download the project template and then run strongcomposer install/strong.  All of the packages downloaded without issue and things are starting to get back on track./p pHopefully this is just a random server down issue but in case anyone else runs into the same issue, maybe this will be helpful./p /div/div/div ul class=field field-name-field-tags field-type-taxonomy-term-reference field-label-hidden i class=icon icon-tags/i li a href=/tags/drupal-planetdrupal-planet/a /li li a href=/tags/composercomposer/a /li li a href=/tags/d8d8/a /li /ul

Chromatic: Drupal 8 Deployments with Jenkins, GitHub Slack

Fri, 01/22/2016 - 03:16
pWe recently launched our first Drupal 8 site--actually it’s this very site that you’re reading! While this wasn’t our first time using or developing for Drupal 8, it was our first full site build and launch on the new platform. As such, it was the first time we needed to handle Drupal 8 code deployments. While I’ve a href=http://chromatichq.com/blog/automated-servers-and-deployments-ansible-jenkinspreviously covered the benefits /a of using Jenkins, this post will take you through the steps to create a proper Drupal 8 deployment and how to integrate GitHub and Slack along the way. In other words, you’ll see our current recipe for deploying code automatically, consistently and transparently./p h2First Things First: Some Assumptions/h2 pThis post assumes you already have a Jenkins server up and running with the following plugins installed:/p ul lipa href=https://wiki.jenkins-ci.org/display/JENKINS/Github+PluginGitHub Plugin/a (has a handful of dependencies)/p/li lipa href=https://wiki.jenkins-ci.org/display/JENKINS/Slack+PluginSlack Notification Plugin/a/p/li /ul pIf you don’t yet have these things ready to go, getting a Jenkins server setup is a href=https://wiki.jenkins-ci.org/display/JENKINS/Installing+Jenkinswell documented here/a. As is a href=https://wiki.jenkins-ci.org/display/JENKINS/Plugins#Plugins-Howtoinstallpluginshow to install Jenkins plugins/a. For us, we typically use a Linode instance running Ubuntu LTS for our Jenkins servers. This post also assumes that the external environment you’re trying to deploy to already has a href=http://docs.drush.org/en/master/install/Drush for Drupal 8/a installed./p h2Example Deployment Script with Drush/h2 pBefore we dive into setting up the Jenkins job to facilitate code deployments, I’d like to take a look at what exactly we’re trying to automate or delegate to our good friend Jenkins. At the heart of virtually any of our Drupal deployments (be them Drupal 7, 8 or otherwise) is a simple bash script that executes Drush command in succession. At a macro level, this typically means doing the following, regardless of version:/p ol liSSH to the server/li liChange directory to repository docroot/li liPull down latest code on the codemaster/code branch/li liClear Drush cache/li liRun database updates/li liUpdate production configuration/li liClear Drupal caches/li /ol pIn Drupal 7, where we relied heavily on Features to deploy configuration, we would typically do something like this:/p pre code echo echo Switching to project docroot. cd /var/www/drupal-7-project/docroot echo echo Pulling down latest code. git pull origin master echo echo Clearing drush cache drush cc drush echo echo Run database updates. drush updb -y echo echo Reverting features modules. drush fra -y echo echo Clearing caches. echo drush cc all echo echo Deployment complete. /code /pre pIn Drupal 8, we have the magical unicorn that is the a href=https://www.drupal.org/documentation/administer/configConfiguration Management System/a, so our deployments scripts now look something like this:/p pemIf you’re familiar with creating Jenkins jobs already and are just looking for a Drupal 8 deploy script, these next lines are for you./em/p pre code echo echo Switching to project docroot. cd /var/www/chromatichq.com/docroot echo echo Pulling down the latest code. git pull origin master echo echo Clearing drush caches. drush cache-clear drush echo echo Running database updates. drush updb -y echo echo Importing configuration. drush config-import -y echo echo Clearing caches. drush cr echo echo Deployment complete. /code /pre pSeriously, configuration management in Drupal 8 is amazing. Hat tip to all of those who worked on it. Bravo./p pAnother notable difference is that with Drupal 8, clearing caches uses the codecache-rebuild/code Drush command or codedrush cr/code for short. codedrush cc all/code has been deprecated. R.I.P. little buddy. ⚰/p pIf you have a site that needs to be put into Maintenance mode during deployments, you can handle that in Drupal 8 with codedrush sset system.maintenance_mode 1/code to enable and codedrush sset system.maintenance_mode 0/code to disable./p h2Creating our Jenkins Slave amp; Job/h2 pNow that we’ve covered what it is we want Jenkins to handle automatically for us, let’s quickly run down the punch list of things we want to accomplish with our deployment before we dive into the actual how-to:/p ol liAutomatically kickoff our deployment script when merges to the master branch occur in GitHub/li liRun our deployment script from above (deploys latest code, imports config, clears caches, etc.)/li liReport deployment results back to Slack (success, failure, etc.)/li /ol h3Create Your Jenkins Slave/h3 pFor Jenkins to orchestrate anything on a remote box, it first needs to know about said box. In Jenkins parlance, this is known as a node. In our case, since we’re connecting to a remote machine, we’ll use a “Dumb Slave”. Navigate to strongemManage Jenkins Manage Nodes New Node/em/strong/p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-00.jpg alt=Creating a Jenkins node //p /div pAt Chromatic our naming convention matches whatever we’ve named the machine in Ansible. For the purposes of this article, you can just name this something that makes sense to you. Example:** Drupal-Prod-01**/p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-slave-creation.jpg alt=Creating a Jenkins node //p /div pAs part of the creation of this node, you’ll need to specify the strongHost/strong and the strongCredentials/strong Jenkins should use to access the box remotely. If you don’t yet have credentials added to Jenkins, you can do so at strongemJenkins Credentials Global credentials (unrestricted)/em/strong. From there things are pretty self-explanatory./p h3Setup the Basics for our Jenkins Job/h3 pNow that we have a way for Jenkins to target a specific server (our slave node) we can start building our deployment job from scratch. Start by navigating to: strongemJenkins New Item Freestyle Project/em/strong./p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-01.jpg alt=Creating a freestyle project screenshot //p /div pFrom there press OK and move on to setting up some basic information about your job, including Project Name, Description and the URL to your GitHub repository. Pro tip: take the time to add as much detail here, especially in the Description field as you can. You’ll thank yourself later when you have loads of jobs./p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-02.jpg alt=Basic job information screenshot //p /div h3Configure Slack Notification Settings (optional)/h3 pAssuming you’re interested in tying your deployment status messages to Slack and you’ve installed the a href=https://wiki.jenkins-ci.org/display/JENKINS/Slack+PluginSlack Notification Plugin/a, the next step is to tell Jenkins how/where to report to Slack. You do this under the strongSlack Notifications/strong options area. As far as notifications go, we prefer to use only the Notify Failure, “Notify Success” and “Notify Back To Normal” options. This is the right mix of useful information without becoming noisy. To allow Jenkins to connect to your Slack channels, you’ll need to a href=https://my.slack.com/services/new/jenkins-cifollow these steps/a for adding a Jenkins integration. Then just fill in your Slack domain, the integration token from Slack and the channel you’d like to post to. These settings are hidden under “Advanced…”./p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-03.jpg alt=Slack notifiation settings //p /div h3Configure Where this Job Can Run/h3 pThis is where we instruct Jenkins on which nodes the job is allowed to run. In this case, we’ll limit our job to the slave we created in step one: strongDrupal-8-Prod-01/strong. This ensures that the job can’t run, even accidentally, on any other nodes that Jenkins knows about. Jenkins allows this to be one node, multiple nodes, or a group./p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-04.jpg alt=Restricting where the job can run settings screenshot //p /div h3Configure GitHub Repository Integration/h3 pUnder Source Code Management we’ll specify our version control system, where are repository lives, the credentials used to access the repo and the branches to “listen” to. In our example, the settings look like this:/p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-05.jpg alt=Version control settings screenshot //p /div pHere we’re using a codejenkins/code system user on our servers that has read access on our GitHub repositories. You’ll want to configure credentials that make sense for your architecture. Our Branch Specifier (code*/master/code) tells Jenkins to look for changes on the codemaster/code branch or any remote name by using the wildcard, “*”./p h3Configure Your Build Triggers/h3 pThis is where the rubber meets the road in terms automation. At Chromatic, we typically opt for smaller, more frequent deployments instead of larger releases where there is a higher probability of regressions. Since we rely heavily on the GitHub pull request model, we often have many merges to codemaster/code on any given day of development for an active project. So we configure our deployments to coincide with these merges. The following setup (provided via the GitHub Jenkins Plugin) allows us to automate this by selecting emBuild when a change is pushed to GitHub/em./p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-06.jpg alt=Building the job automatically //p /div h3Setup Your Deployment Script/h3 pHere’s where we’ll implement the example deployment script I wrote about earlier in the post. This is the meat and potatoes of our job, or simply put, this is what Jenkins is going to do now that it finally knows how/when to do it./p pUnder Build choose “Add build step” and select “Execute shell”. Depending on your installed plugins, your list of options might vary./p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-07.jpg alt=Adding the shell execution step //p /div pThen add your deployment script to the textarea that Jenkins exposed to you. If you want somewhere to start, a href=https://gist.github.com/chrisfree/78996998f7a66e8c3ecehere is a gist/a of my job from above. When you’ve added your script it should look something like this:/p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-08.jpg alt=Creating the deployment script //p /div h3Last Step! Enable Slack Notifications/h3 pAlthough earlier in the job we configured our Slack integration, we still need to tell Jenkins to send any/all notifications back to Slack when a build is complete. You do this sort of thing under the Add post-build action menu. Select “Slack Notifications” and you’re good to go./p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-09.jpg alt=Adding Slack Notifications //p /div pOur deployment job for Drupal 8 is now complete! Click Save and you should be able to start testing your deployments. To test the job itself, you can simply press “Build Now” on the following screen OR you can test your GitHub integration by making any change on the codemaster/code branch (or whichever branch you configured). With the setup I’ve covered here, Jenkins will respond automatically to merges and hot-fix style commits to codemaster/code. That is to say, when a PR is merged or when someone commits directly to codemaster/code. Of course no one on your team would ever commit directly to codemaster/code, would they?!/p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupal-8-deployments/jenkins-10.jpg alt=Pointing out the build now button //p /div h3Wrapping Up/h3 pAssuming everything is setup properly, you should now have a robust automatic deployment system for your Drupal 8 project! Having your deployments automated in this way keeps them consistent and adds transparency to your entire team./p

Chromatic: The Anatomy of a Good Ticket

Fri, 01/22/2016 - 03:16
pWe previously wrote about a href=http://chromatichq.com/blog/how-write-great-commit-messagehow to write a great commit message/a, but before that commit message is ever written, there was (hopefully) a great ticket that was the impetus for the change. Whether or not a ticket is great is subjective, and it is often how well thought out the details are that makes the difference. The ticket might have everything a developer needs to complete the task, but not provide any insight into how to test the final product. Conversely, it might provide all the details the QA team needs to verify, but not provide any insight into the technical requirements for implementation./p pBefore we examine the specific things that make up a great ticket let’s first examine some of the best practices that further enhance communication and efficiency:/p ul lipHaving all stakeholders using the ticket management system and not allowing any communication of requirements via email or other communication tools that silo information./p/li lipEnsuring that requirements which are discussed one-on-one or during a meeting are added back into the ticket so nothing is lost or forgotten./p/li lipHaving any message conversations in open channels that allow visibility into the decisions for others working on related issues./p/li lipContinuously keeping tickets updated with the current status so the whole team is aware of where everyone else is with their tasks./p/li lipEnsure everyone is familiar with the internal jargon and acronyms used, or ensure they are provided with the tools to decipher the terms./p/li /ul pWith some ground rules established, let’s investigate the factors that make for a great ticket./p h3A User Story/h3 pA user story provides a high-level description of functionality from a user’s perspective, such as, when a user logs in they should be able to see a list of past purchases. Great tickets often start with a user story that answers what is needed and why at a high level./p h3Clearly Defined Goals amp; Scope/h3 pClearly stated goals from the business allows the ticket to be resourced correctly. Also, a full understanding of the requested change’s scope will inform what brands, sites, regions, pages, etc. a new feature or change will affect, and is crucial to planning a proper implementation./p h3Accurate Estimates/h3 pA well thought through estimation of the level of effort from developers and other stakeholders will make sprint planning/resourcing much more accurate and sprint reviews/evaluations more insightful./p h3Understanding of Priority/h3 pA clear understanding of the business priorities will ensure timely completion and allow the team to plan ahead, avoiding late nights and weekends./p h3Knowledge of Blockers/h3 pExposing any potential barriers or blockers during the estimating of the ticket will allow them to be accounted for and even potentially solved before development starts./p h3Screenshots/h3 pProviding screenshots and adding arrows and text for clear communication that makes it very apparent what this and “that” are, thus avoiding pronoun trouble./p h3Documented Designs/h3 pProviding detailed requirements with exact values, sizes, states, etc. with considerations for edge cases will make any developer forever grateful. Style guides with documented font names, sizes, weights, etc. are another tool that will improve design workflow efficiency. Additionally, designs can provide:/p ul lipWhere every piece of information comes from./p/li lipHow items should appear if a given field or other information source is empty./p/li lipHow long or short variants of a given data point are handled and what logic controls programmatic truncation if applicable./p/li /ul h3Contact Information/h3 pProviding the names and contact information for other team members who may hold key pieces of information that didn’t make it onto the ticket will prevent blockers and help new developers learn which team members have expertise in other areas. Additionally, providing contact information for external parties when working on third-party integrations will prevent communication gaps and middlemen. Sending a quick introduction when rolling a new person into the mix will get you bonus points./p h3Code Context/h3 pTaking the first step is the hardest part, but often a lead developer will know right where and how to proceed. Providing other developers with the names of functions or files to look for from someone with deeper knowledge of the codebase can save an immense amount of time up front and avoids potential refactoring down the road. It also reduces guesswork and more importantly, might reinforce a best practice when there are multiple approaches that would technically work. Examples of previous implementations or before-and-after code samples are also great things to consider providing./p h3Reliable Information/h3 pUp-to-date acceptance criteria that is verified as accurate and updated if/when requirements changed, and the ability for a developer to have 100% confidence in this information makes everyone’s life better./p h3Complete Logical Requirements/h3 pThinking through default values or fallback values/logic if a given piece of data is empty by default, instead of treating it as an edge case, allows for cleaner code and reduces emergencies and bugs down the road./p h3Component Driven Separation/h3 pGiving everyone on the team discrete chunks of work that can be documented, developed, tested, and completed will allow everyone to feel much better about the progress of the project. Providing clearly defined subtasks that allow chunks of the work to be checked off and delineated clearly when working on larger tickets will help with this. Another key to success is having properly managed dependencies for blocking work so effort is not wasted until all blockers are resolved./p pThis can be accomplished by separating tickets by components, not pages. For example, social share bar and comment widget tickets that probably appear on every content type rather than a article page ticket that includes building and styling all of those components before it can be considered complete./p h3Exact URLs/h3 pWhen possible, always provide the exact URLs of pages where the offending bug can be found or the new functionality should be placed. This keeps anyone from making assumptions and when properly paired with a nice screenshot, it really takes the guesswork out of recreating bugs or finding where new features should live./p h3Reproducible Steps/h3 pIn addition to exact URLs, a thorough lists of steps to reproduce the bug, the expected result, and the actual result will all help a developer quickly pinpoint and understand a problem. It is just as important for developers to provide QA and business stakeholders with steps to test functionality that is not intuitive or simple to test./p h3Assumptions amp; Changes/h3 pFinally, not all developers are the same. If you ask two developers to solve the same problem, you might get very different solutions, but the more details you provide them, the better the chance of a successful outcome. Additionally, a developer with a wealth of institutional knowledge might need significantly less information to have a clear picture of what needs to be done, while a new hire, internal transfer or external contractor will likely need more information./p pHowever, I would argue that regardless of the expected assignee’s knowledge, the extra time spent to write a good ticket is rarely wasted. Tickets often get passed around as people take vacations, flat tires happen, and children get sick. When these things inevitably occur, we don’t want to rely upon assumptions, which, no matter how good, only need to be wrong once to cause potentially large amounts of wasted time, embarrassment, liability, etc./p h3Ways to Work This Into Your Project/h3 ul lipCreate a blocked status for your Agile or Kanban boards and utilize it liberally to ensure high visibility into the unknowns and show others how much time is lost due to blockers./p/li lipLoop project managers into conversations with the person who filed the initial ticket so they see first hand the level of effort required to track down answers./p/li lipTalk through the issues during sprint review and review what did and did not go well./p/li lipAllow developers to review and estimate issues before they are included in a sprint and require clear requirements before accepting a ticket./p/li lipDon’t just complain; be a part of the solution. Educate stakeholders on the structure you want to see for requirements and provide them with tools to help communicate more clearly such as logic maps, data flow diagramming tools, etc./p/li /ul h3What Now?/h3 pI encourage you to think of a good ticket not just as a means to an end; be that a fixed bug, a new feature, or new design. Instead, treat it as an opportunity to show respect to each of the many professionals that will touch the ticket through its lifecycle by providing them the information and tools they need to perform their job to the best of their abilities. This respect goes in all directions, from ensuring good requirements for developers, to writing good testing instructions for QA, writing quality code for a great product and providing stable hosting infrastructure. This all culminates in a well-built project that shows respect to what this is ultimately all about: the user./p

Chromatic: Unloading jQuery in Drupal 8

Fri, 01/22/2016 - 03:16
pIn the process of redesigning our site, we decided to axe jQuery early on. Analytics informed us that cross-browser compatibility wouldn’t be an issue, so we took the easy performance gain and stuck it out with vanilla JavaScript./p pBeginning in version 8, Drupal does not load jQuery by default. Great - no issues for us! However, the long, shadowy spectre of jQuery haunted development./p h2Even if you’re not using jQuery, it can still load for anonymous users./h2 pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/unloading-jquery/spray.jpg alt=Contrib jQuery dependency //p pYou have your libraries.yml file free of any dependencies, and you’re deep into development when you notice jQuery is still loading. Why? Contrib modules can still require jQuery./p pFor us, the culprit was the a href=https://www.drupal.org/project/google_analyticsGoogle Analytics module/a. It’s a great contributed module, but because of the overhead it brought, we decided to create a custom module and attach our tracking code separately./p h2More to come./h2 pI’m sure there will be other gotchas as D8 proliferates in the wild, but hopefully these two will save you some time in case you find yourself wondering, much like I was, why jQuery still cast its shadow. Now get back to it, and build something awesome./p h3Correction/h3 pPreviously, this post stated that Drupal behaviors are dependent on drupal.js, which is in turn dependent on jQuery. This is incorrect and drupal.js in D8 is not dependent on jQuery. After running into some errors, a href=https://www.drupal.org/node/2269515this post on the JavaScript API/a led me to that conclusion. Apologies and thanks to a href=https://twitter.com/nod_@nod_/a for his tweet and sending me down the right path!/p

Chromatic: Creating Links Within Twig Templates Using path() and url()

Fri, 01/22/2016 - 03:16
pDrupal 8 comes packed with loads of great new features, APIs and developer tools. There are sweeping changes aplenty. Not the least of which is a brand new templating system called a href=http://twig.sensiolabs.org/Twig/a. Twig is the bee's knees and a welcome improvement over the much maligned PHPTemplate. However, many front-end developers who've grown accustomed to the templating ways of old might feel a bit lost as they enter the strange, new world of Drupal 8: Twig and a href=/blog/badcamp-2015-transitioning-theme-and-theme-functions-render-arrays-and-templatesrender arrays/a. Furthermore, the Drupal community is still learning, documentation is still being written, etc./p pAs we approach the completion of our first official Drupal 8 project here at Chromatic, I thought it would be helpful to start sharing a bit of what I've learned along the way, starting with some examples on linking from within Twig templates./p pIf you want to just see how the hell you link to things from within Twig templates, a href=#examplesskip these next bits/a on context./p h2Some Context/h2 pIn Drupal 7 and versions prior, we used paths to define destinations for our content, APIs, etc. In Drupal 8, these are abstracted into routes. Where in Drupal 7 you would define a custom page via codehook_menu()/code, like so:/p precodelt;?php function chromatic_conact_menu() { $items['contact'] = array( 'title' =gt; 'Chromatic Contact', 'page callback' =gt; 'contact_page', 'access arguments' =gt; array('access content'), 'type' =gt; MENU_SUGGESTED_ITEM, ); return $items; } ?gt; /code/pre pIn Drupal 8, you define this in a special coderouting/code file that follows this naming convention: codemodule_name.routing.yml/code. Here's a similar example, where codechromatic_contact_contact/code is our route name and codecontact/code is the internal path where it can be accessed./p precodechromatic_contact_contact: path: 'contact' defaults: _form: '\Drupal\chromatic_contact\Form\ChromaticContactForm' _title: 'Contact Us!' requirements: _permission: 'access content' /code/pre pHere's how Drupal 8 sets up the route for node type creation:/p precodenode.type_add: path: '/admin/structure/types/add' defaults: _entity_form: 'node_type.add' _title: 'Add content type' requirements: _permission: 'administer content types' /code/pre h2Got it. Routes are the new hotness in D8. Now why does this matter to me? I'm a front-ender./h2 pGlad you asked. Routes matter because if you want to generate URLs to custom pages from your templates and you want to do it properly, you need to understand routes. The old methods of using paths are a href=https://www.drupal.org/node/2073811dead in Drupal 8/a./p pThe codeurl()/code and codepath()/code functions are how we handle this type of linking in D8. These functions don't expect an internal path like you're probably familiar with in prior versions of Drupal. Instead, they expect proper system routes. The type of thing you now see in codemodule_name.routing.yml/code./p h3So what's the difference?/h3 ul licodepath()/code - Generates a [relative] URL path given a route name and parameters./li licodeurl()/code - Generates an absolute URL given a route name and parameters./li /ul h2Examples/h2 pa name=examples/a/p precode// Link to the default frontpage content listing view: lt;a href={{ path('view.frontpage') }}gt;{{ 'View all content'|t }}lt;/agt; // Link to a specific node page: lt;a href={{ path('entity.node.canonical', {'node': node.id}) }}gt;{{ 'Read more'|t }}lt;/agt; // Link to a specific user profile page: lt;a href={{ path('entity.user.canonical', {'user': user.id}) }}gt;{{ 'View user profile'|t }}lt;/agt; // Link to a view, and throw in some additional query string parameters: lt;a href={{ path('view.articles.page_1', {'page': 2}) }}gt;{{ 'Go to page 2'|t }}lt;/agt; // Link to a view and pass in some arguments to the view: lt;a href={{ path('view.recent_articles_by_author.page_1', {'arg_0': user.field_display_name.value|drupal_escape }) }}gt;{{ 'See all the articles written by'|t }} {{ user.field_display_name.value }}lt;/agt; /code/pre pThe source code for the codepath()/code and codeurl()/code Twig extensions can be found here within Drupal 8 core: code/core/lib/Drupal/Core/Template/TwigExtension.php/code./p pIf you're curious about how all of this came to pass, here's the D.O issue on which the work occurred: a href=https://www.drupal.org/node/2073811https://www.drupal.org/node/2073811/a. It's long. emReally long/em. The strongtldr;/strong is basically a lot of back and forth over how routes are a barrier to entry for beginners and that there should still be an easy way to use paths. I honestly see both sides, but in the end, routes won out in the name of consistency and compatibility. The original patch contained a codeurlFromPath()/code function but it has a href=https://www.drupal.org/node/2556847since been removed/a. :-/. Beginner or not, you should now understand how to generate URLs within your templates. Now go! Commence Twigging!/p h3One more thing!/h3 pThe Drupal.org a href=https://www.drupal.org/node/2486991documentation page/a that explained these Twig functions (and others) was marked as incomplete, so I took this opportunity to a href=https://www.drupal.org/node/2486991/revisions/view/9074124/9181186finish it up/a. If you have other examples to share, please do so there!/p

Chromatic: Drupal Camp Chattanooga 2015

Fri, 01/22/2016 - 03:16
pA few weekends ago I was fortunate enough to attend my first Drupal Camp ever. What was even more fortunate for me was that it was located near where I grew up in Chattanooga, TN. I’ve been to several leadership/business conferences in my life, but this is the first one that I’ve been to where it felt like everyone was genuinely glad to be there, even on a rainy fall day. In the spirit of open source, it wouldn’t feel right to keep all of the helpful info I learned to myself, so I wanted to take a moment and share some of my key take-aways./p h3Selling Drupal/h3 pa href=https://www.drupal.org/u/bsnodgrassBob Snodgrass/a from a href=http://www.net2community.com/net2Community/a gave a great seminar on sales. He started his a href=https://prezi.com/slaicndcji3q/selling-drupal/presentation/a on selling Drupal by stating Don’t sell Drupal, sell results! So many times we become entrenched in the technology that we use and sell, and that’s ok!, but we have to remember that clients are more interested in the results we can provide, instead of the medium we use to get there. A good example given was a donut in a donut box. People rarely care about what box it comes in, they just want the donut!/p pBob also brought attention to how each team member contributes to selling, whether they realize it or not. The interactions, work and relationships that we manage on a daily basis help clients decide if they will continue to work with us or recommend us to their work colleagues./p h3Becoming a PM Ninja/h3 pa href=https://www.drupal.org/u/thejustinrhodesJustin Rhodes/a from a href=https://commerceguys.com/Commerce Guys/a led a a href=https://www.drupalcampchattanooga.com/session/becoming-pm-ninjagood discussion/a on increasing efficiencies as a Project Manager. One of the first things we discussed was a href=https://en.wikipedia.org/wiki/Parkinson%27s_lawParkingson’s/aa href=https://en.wikipedia.org/wiki/Parkinson%27s_law Law/a: tasks will swell or shrink according to the amount of time given to them. If you use this law to your advantage, you can create small window deadlines to create efficiencies in your development process./p pWhen it comes to planning and estimating phases for a project, Justin shared the success he has had doing this by using relativity to help the team give input. For example, rather than trying to nail down hours for each process step right way, you can tell everyone to estimate the size of the task by using shirt sizes (S, M, L, XL) to align everyone by using relative sizes. This can give the resource planner a clear visual of which parts of the project are going to take the longest. Of course, there are no complete replacements for old fashioned hourly estimates. The key to success on estimates is to check the team’s accuracy by comparing estimates against actual spend./p h3Contributing to Open Source/h3 pOur keynote speaker was a href=https://www.drupal.org/u/ultimikeMike Anello/a from a href=http://drupaleasy.com/Drupal Easy/a. He gave a a href=https://www.drupalcampchattanooga.com/article/community-contributions-boost-your-bottom-linegreat talk/a on why we should be contributing back to the Drupal community. It wasn’t the typical, do it because it is the right thing to do, lecture. Mike made the case that not only does contributing back to the community grow your network and visibility, but it has a very real probability of increasing your bottom line. It is easy to say that we are going to contribute, but unless you deliberately set aside time, it probably isn’t going to happen. One way to make contributing a priority is to work it into your marketing budget. Switching your perspective on contributing from a way to get karma points to a powerful marketing tool, will change your priorities around where it fits into the company’s strategy./p pThe last take away I got from Mike’s talk was that even those of us who are nontechnical team members can contribute back to the Drupal community. Reaching out to module owners and asking how you can help, cleaning up ticket queues on modules, confirming bugs and assisting in documentation, are all ways to help move the ball forward (and I’m told they are greatly appreciated). Don’t forget that Drupal events don’t just happen by themselves. There is always a need for folks to help with the planning and coordination of meetups, camps and conventions./p h3Final Thoughts/h3 pAlthough I was unable to attend the pre and post party, I have no doubt that the enthusiasm of the group spilled into every conversation that was had. Who knows where I will be living next year (the benefits of working for a distributed company), but if I am able to, I’ll be returning to DrupalCamp Chattanooga!/p div class=structure__article structure__article--image pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/drupalcamp-chattanooga-2015/chattanooga-2015.png alt=image alt text //p /div p(photo credit goes to a href=https://twitter.com/DrupalNooga/status/663136147862888448/photo/1@DrupalNooga/a)/p

Chromatic: TheaterMania: Lessons Learned on Localization

Fri, 01/22/2016 - 03:16
pWe recently launched a new site for an existing client, a href=http://www.theatermania.com/TheaterMania/a. We helped launch and currently maintain and develop a href=https://www.theaterclub.com/nyThe Gold Club/a, which is a subscription-based discount theater club in New York City. The new site is the same thing, but in London - same language, same codebase, new database, different servers. We only had to migrate users, which were already exported for us, so nothing exceptional there. Shouldn't be a big deal, right? We learned that's not always the case./p h2Architectural Decisions/h2 pOne of our first problems, besides the obvious localization issues (currency, date formats, language), was to decide what we were shipping. Were we just building another site? Were we packaging software? There will most likely be more sites in other cities in the future - how far did we want to go in terms of making this a product that we could ship? In the end, we wound up going somewhere in the middle. We had to decide initially if we would use a href=https://www.drupal.org/project/ogOrganic Groups/a to have one site with multiple clubs, one Drupal multisite installation, or multiple Drupal installations. The final decision was to combine the latter two choices - we created multisite-style directories so that if we need to take the site in a multi-site direction, we can easily do that. The sites each have a site-specific settings file, full of various configuration variables./p pNow that the site has been launched, we're not sure if this list of variables will be developer-friendly moving forward, and have been keeping in mind that we may want a more elegant solution for this. The best part about this setup is that we have one codebase, one master branch, and each site is configured to use the appropriate settings. The most important thing is that this is all very thoroughly documented, both in the code, README files, and the repo wiki./p h3Currency amp; Recurly: Easier than Expected/h3 pOne of the issues I thought would be very problematic was currency, but that wasn't actually an issue. All of the existing transactions are set up in cents - ie, code100/code instead of code1.00/code for a dollar, and that translates perfectly from dollars to pounds. We use a href=http://chromaticsites.com/blog/integrating-recurly-and-drupalRecurly/a, an external payment and subscription processor, so we didn't have to worry about any localization issues on that front. Most of the currency abstractions I did were to remove any hard-coded references to the dollar sign, and create functions and variables to get the appropriate currency symbol./p h3Dealing with Dates; Ugh./h3 pDate formats were something I expected to be easy, but that wound up being more complex. I discovered codehook#95;date#95;combo#95;process#95;alter()/code to change the display of the date in calendar popup fields. This made what I’d thought was going to be a difficult series of view handlers really simple. We have several fields using the date combo box on both content types and entities, and this function took care of them./p pre code /** * Implements hook_date_combo_process_alter(). * * Changes the date format. */ function gc_display_date_combo_process_alter($element, $form_state, $context) { if (isset($element['#entity']-type)) { switch ($element['#entity']-type) { case 'event': $element['value']['#date_format'] = variable_get('date_format_short'); break; case 'partner': $element['value']['#date_format'] = variable_get('date_format_short'); $element['value2']['#date_format'] = variable_get('date_format_short'); break; case 'promo_offer': $element['value']['#date_format'] = variable_get('date_format_short'); $element['value2']['#date_format'] = variable_get('date_format_short'); break; default: break; } } elseif (isset($element['#entity']-field_name)) { if ($element['value']['#instance']['widget']['type'] == 'date_popup' $element['#entity']-field_name == 'field_user_csr_notes') { $element['value']['#date_format'] = variable_get('date_format_short'); } } }/code /pre pI took the dozen or so existing date formats from Drupal, altered some of them to meet our needs, and added a few more. My head also started spinning when testing because I'm so used to M/D/Y formats that D/M/Y formats look really strange after a while, especially because code changes needed to be tested on the US and UK sites, so I had to be really careful when visually testing a page to make sure that a US page was showing 9/1/15 and the UK page was showing 1/9/15. In the future, I’d definitely advocate for a testing suite on a project like this. Overall, making sure all of the dates were changed was somewhat tedious, but not difficult. It required a lot of attention to detail and familiarity with PHP date formats, and vigorous testing by the whole team to make sure nothing had been missed./p h3Proper Use of t() Early == Wins Later/h3 pThis project made me extremely grateful for the codet()/code function. Since both sites were in English, we didn't have a need for site-wide translation, but we did need to localize a handful of strings, both for language issues (words like 'personalize' vs 'personalise'), and the general language preference of the stakeholders. It was easy enough to find the strings and list them in codelocale#95;custom#95;strings#95;en/code to switch them out. One gotcha we came across that I wasn't familiar with - you cannot use codet()/code in your settings files. The function isn't available at that point in the bootstrapping. You can use codeget#95;t()/code, but we opted to remove the translation strings from any variables and make sure that codet()/code was used when the variable was called. This wasn't something I had run into before, and it caused some problems before we figured it out./p h3Miscellany/h3 pA few tricky miscellaneous problems cropped up, too. There was a a href=https://www.drupal.org/node/2540838geolocation function/a enabled in Recurly, which was defaulting to the US and we were unable to change the settings - we also didn't realize this when testing in the US, and we scratched our heads when the London team told us the field was defaulting to US until we came across the culprit. We were able to fix it, and put in a patch for the library causing the issue./p pI also realized how many various settings default to the US when working on this project - a lot of the location-related work was just abstracting out country defaults. Something to keep in mind if you're working on a project with locations. Don't make more work for developers who live or work on projects outside of the US. Plan for the future! Assume nothing!/p h3Looking Back/h3 pI'm really glad that I worked on this project, because it's made me develop with a better eye for abstraction of all kinds, and making sure that it's easy for developers or users to work with my code anywhere. In the future, I’d put more thought into managing our configurations from the start, as well as automating the testing process, both for time-saving and better QA./p pIf you’ve ever worked on a site with challenges like these, I’d love to hear how you handled them! emWhat are your best practices for managing custom locale strings and other site-specific variables? To what extent do you abstract things like dates and currency when developing a site, even when you don’t know if those will ever change?/em/p

Chromatic: BADCamp 2015: Transitioning From theme() and Theme Functions to Render Arrays and Templates

Fri, 01/22/2016 - 03:16
pI was fortunate to attend and speak at a href=https://2015.badcamp.net/BADCamp/a for the first time this year. BADCamp is the Bay Area Drupal Camp, held annually in Berkeley, CA. I don't know the official numbers, but I believe over 1,000 were in attendance, giving it the feel of a smaller DrupalCon. The camp was well organized, the sessions were high quality, and I met and got to know quite a few great people./p pAnyone who wasn't able to attend can watch my session, ema href=https://2015.badcamp.net/session/7-8-transitioning-theme-and-theme-functions-render-arrays-and-templates7 to 8: Transitioning From theme() and Theme Functions to Render Arrays and Templates/a/em, here:/p div class=embedded-video iframe width=100% height=100% src=https://www.youtube.com/embed/f7esUy-1c7E frameborder=0 allowfullscreen/iframe /div pa href=http://blog-media.chromaticsites.com.s3.amazonaws.com/badcamp-2015/badcamp-render-arrays-templates-guschilds-chromatic.pdfMy slides are also available online/a. The video and slides include in-depth examples, but for the TL;DW crowd more interested in the key takeaways:/p h2Render Arrays theme()/h2 pThe a href=https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme/7codetheme()/code function/a no longer exists in Drupal 8. Instead, render markup by passing render arrays to the template. Start using render arrays instead of codetheme()/code in Drupal 7 right now. Not only will it make the code easier to port to Drupal 8, but there are other advantages./p pUsing render arrays allows for the data to remain an array until the template renders it into markup. Waiting to render markup allows other modules or themes to intercept and alter the data before it is rendered. This is typically done with preprocess hooks./p h2Templates Theme Functions/h2 pWhen Drupal 7 goes to render markup, it does so with either a theme function, such as codetheme_image()/code, or a template. Theme functions contain a lot of logic and are a tough way to write and alter markup. Overriding theme functions also involves copying a significant amount of code to make changes./p pInstead of writing theme functions, write templates. Keep the logic in preprocess and process functions. This separation will make altering the logic and markup much easier. Other modules or themes can easily use preprocess hooks or override templates as needed./p pDrupal 8 has taken this approach. While theme functions can still exist in Drupal 8, all core theme functions were converted to templates./p h2More information/h2 pFor more on this topic, check out these resources on drupal.org:/p ul lia href=https://www.drupal.org/node/1920746Twig best practices - preprocess functions and templates/a/li lia href=https://www.drupal.org/node/930760Render Arrays in Drupal 7/a/li lia href=https://www.drupal.org/node/223430Setting up variables for use in a template (preprocess and process functions)/a/li lia href=https://www.drupal.org/documentation/themeTheming Guide/a/li /ul pThere were also a number of other sessions at BADCamp related to this topic. They included:/p ul lia href=https://www.youtube.com/watch?v=V0_US_YZSxUDrupal 8 Theming: A Crash Course/a/li lia href=https://www.youtube.com/watch?v=KDZE7TO5FG8Drupal 8 Theming - No More div-itis/a /li lia href=https://2015.badcamp.net/session/drupal-8-backend-frontendDrupal 8 The Back-end of Front-end/a/li /ul pThanks again to the BADCamp organizers. I hope to see everyone again next year!/p

Chromatic: Drupal 8 Configuration Management - Solving the Configuration Conundrum

Fri, 01/22/2016 - 03:16
pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-hero.jpg alt=Drupal 8 Configuration Management //p pA common difficulty in web development is keeping configuration consistent between environments. Drupal keeps most configuration settings in the database and it can be a pain to keep databases across environments synchronized. Solving this conundrum was one of Drupal 8's goals and the focus of D8's Configuration Management Initiative (CMI). All site configuration is saved in YAML files (hooray for version control!) and can be shared between site environments./p h2The Way We Were/h2 pLet's take a classic example from before D8, using the beloved Views module. When you build a great new view on your local machine you still need to get it onto the production site. You could repeat what you did on your local machine and build the View by hand on prod, but that's just repeating all the work you have already completed, not to mention, prone to user error. Most developers are too lazy to do that anyways, so they depend on Drupal's a href=https://www.drupal.org/project/featuresFeatures module/a. The Features module works by exporting db configuration settings into Drupal module code which can be shared amongst environments. It usually works pretty well, but it turns out the Features module was not built for handling deployment and configuration. These tasks have fallen into its lap because, until now, it was the only game in town./p h2The Way We're Going/h2 pWith every Drupal 8 installation, the configuration system creates a configuration directory*, codesync/code, to hold the aforementioned YAML configuration files. The directory is actually created as a sub-directory in codesites/default/files/code, into a folder with a long, random hash as its name, prefaced by codeconfig_/code. em(Including a random hash makes it near impossible for bad guys to guess the configuration folder name.)/em/p pem* At the time of writing the default installation actually created two directories: codeactive/code and codestaging/code, but that was changed to just one, the codestaging/code directory which subsequently was changed to codesync/code. The blog post has been updated to reflect this./em/p pstrongIn picture form...a folder with a really, really long, random name/strong/p pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-sync-folder.png alt=sync_folder //p pSo in the above screenshot the configuration directory's name is/p pcodeconfig_Z1fHk5YnKXiTdJl9lAfz_dqGmrMTzqT9lNnbUF6z4kwKxglnC8srJZBTcI1dIMSCOmOwvEMZ5g/code/p pand the full path of the codesync/code directory is:/p pcodesites/default/files/config_Z1fHk5YnKXiTdJl9lAfz_dqGmrMTzqT9lNnbUF6z4kwKxglnC8srJZBTcI1dIMSCOmOwvEMZ5g/sync/code/p pSo that's where the site configuration files live, but by default, for reasons of a href=https://www.drupal.org/node/2241059speed and security/a, the actual configuration settings are saved in the database. So all the configuration from those YAML files actually gets imported into the database./p pThe configuration management system provides a UI for uploading and double-checking changes before applying them to the live site. (Of course, there are Drush commands, codedrush config-export/code and codedrush config-import/code that allow you to import/export through the command line too.)/p h2How do you Feel About Clones?/h2 pNow hold on, you can't upload one site's configuration to any old site; you can only synchronize configuration settings between cloned instances of a site. This restriction was a a href=https://www.youtube.com/watch?t=1130amp;v=O6K4UxOk9oAconscious decision/a made by the Drupal CMI team. So you need to start with one environment and then clone it. If you don't do this, Drupal simply will not allow configuration settings to be imported./p h3Steps for cloning a site:/h3 ol lipDo a db dump of the original database and import it into an empty database for your new clone environment./p/li lipAssuming you are using git, (you are using git, right?) you can run codegit clone/code to clone the original site files into the clone environment./p/li lipCheck folder permissions (Did .htaccess come across? Does codesites/default/files/code have sufficient permissions?)./p/li lipChange codesettings.php/code in cloned site to point to the fresh db from step 1./p/li /ol pAssuming your cloned site is working, you are ready to import settings from one environment to another. In my case, I created a new view called embookshelf/em that needs to get to prod. Below are screenshots of what the process looks like./p h2Export and Download from Dev/h2 pIn this screenshot, I have just exported and downloaded my dev environment's configuration tar.gz file./p pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-export.png alt=d8-config-export //p h2Upload into Prod/h2 pHaving switched to my prod environment, I select the downloaded tar.gz file and upload it./p pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-import.png alt=d8-config-import //p h2Successful Upload/h2 pAfter a successful upload you can see that there are changes. Note that my new embookshelf/em view is there. I can click the emView differences/em button to compare the changes./p pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-success.png alt=d8-config-view-bookshelf //p h2Vive la Difference/h2 pHaving clicked the emView differences/em button, I see the changes that are about to be made./p pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-diff.png alt=d8-config-bookshelf-diff //p h2Import All/h2 pSatisfied with what I see, I can click emImport all/em to apply the changes./p pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-import-all.png alt=d8-config-bookshelf-import-all //p h2Import Progress/h2 pA progress bar displays as Drupal imports the settings./p pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-import-progress.png alt=d8-config-bookshelf-progress //p h2A Site With a View/h2 pVoilà, the new view is on my prod site./p pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/d8-config-management/config-view.png alt=d8-config-view-is-there //p pWhew, so there were a bunch of steps to get things set up, but once you have your environments in place, it's easy to move settings between them. Of course, in a full-on, professional development environment you would harness the power of Drush and use scripts to do all the dirty work. But that's a tutorial for another time./p

Chromatic: Programatically Creating and Storing WordPress Migrate Migrations in Drupal

Fri, 01/22/2016 - 03:16
pMigrations are never glamorous, but doing them right and verifying their integrity is essential to their success. The a href=https://www.drupal.org/project/wordpress_migrateWordPress Migrate/a module gives you an easy turnkey solution to migrating content into Drupal from WordPress. It allows you to create each migration through an interactive admin form, allowing you to configure your migration entirely through the UI. This is great, but it does not make creating or storing the resulting migrations easy to manage across multiple environments, since the migrations are not defined in code like a typical a href=https://www.drupal.org/project/migrateMigrate class/a. Short of copying database tables or re-entering the configuration through the admin forms, developers are stuck with the migrations stored in a single database and thus it is not easy to move to other environments for testing or further development./p pCopying data tables is almost always the wrong solution and manually re-entering all of the migrations would be way too time consuming, so our solution was to create the migrations programmatically. To do this, we hooked into the existing a href=https://www.drupal.org/project/wordpress_migrateWordPress Migrate/a codebase and used its logic to build programmatically, what it builds from data input to its admin forms. Then we are able to define all of our migration sources in code and instantly create all of our migrations in a new environment, or recreate them after something fails during development./p pAs mentioned, this solution relies upon programmatically submitting admin forms, which is often not an ideal scenario. Additionally, there is the almost inevitable request to add additional customizations beyond what Wordpress Migrate supports out of the box. Sometimes this makes WordPress Migrate more of a hinderance than a help. So why not just create a custom Migrate class from the outset and avoid all of these issues? Here are some factors to consider:/p ul liWriting a custom Migrate class for your WordPress content always sounds more appealing until you run into problems and realize WordPress Migrate already solved those issues./li liThe WordPress Migrate module offers a lot of functionality, including file transfer, author migration, embedded video processing, internal link rewriting, comment migration, etc./li liYou might not need much custom code and just tweaking the WordPress Migrate functionality by extending one of its classes will easily do the trick./li liYou might not have the resources (time, knowledge, etc.) to write a custom Migrate class./li liRunning and testing the migrations on multiple environments might not be in your workflow, although I would argue it should be./li liYou might only have one or two WordPress sites to migrate content from, so manually re-creating them is not an issue./li /ul pIf after weighing all of the factors, you decide using the WordPress Migrate module is in your best interest and manually recreating the migrations is not an option, then follow along as we walk you through our approach to creating and storing WordPress Migrate migrations programmatically./p h3Our Solution/h3 pFirst we need to define the list of source blogs. The keys of each item in this array can be added to as needed to override the default values we assign later./p pre code /** * Define the WordPress blogs to be imported. */ function example_wordpress_migrate_wordpress_blogs() { // Any key not set here will default to the values set in the // $blog_default_settings variable in the drush command. $blogs = array( array( 'domain' = 'www.example.com/site-one/', ), array( 'domain' = 'www.example.com/site-two/', ), array( 'domain' = 'www.test.com/', ), ); return $blogs; } /code /pre pNext we'll create a custom drush command so that we can easily trigger the creation of our migrations from the command line./p pre code /** * Implements hook_drush_command(). */ function example_wordpress_migrate_drush_command() { $items = array(); // Creates WordPress migrations. $items['example-migrate-create-wordpress-migrations'] = array( 'description' = 'Creates the WordPress migrations.', 'aliases' = array('mcwm'), ); return $items; } /code /pre pBe sure to note the codeexample_migrate_wordpress_password/code variable below, as you will need to ensure you set that in codesettings.php/code before creating the migrations. The WordPress Migrate code needs to be able to login to your site to download the source XML file, and a password is paramount to the success of that operation!/p pre code /** * Callback for WordPress migration creation drush command. */ function drush_example_wordpress_migrate_create_wordpress_migrations() { // Reset the file_get_stream_wrappers static cache so the 'wordpress' stream // wrapper created by the wordpress_migrate module is available. $wrappers_storage = drupal_static('file_get_stream_wrappers', NULL, TRUE); // The wordpress_migrate module's UI is a multi-step form that collects all // configuration needed to migrate a given blog. As this form's steps are // submitted and validated, an export file is downloaded for each blog and its // contents are migrated. There is no easy way to export these settings or use // code to provide that configuration and then trigger a migration, so the best // bet is simulate the submission of those form steps with the needed data. module_load_include('inc', 'migrate_ui', 'migrate_ui.wizard'); // Get a list of blogs to migrate. $blogs = example_migrate_wordpress_blogs(); $blog_default_settings = array( 'source_select' = '1', 'domain' = '', 'username' = 'admin', 'password' = variable_get('example_migrate_wordpress_password', ''), 'wxr_file' = NULL, 'do_migration' = 0, 'default_author' = 'admin', 'page_type' = '', 'blog_post_type' = 'story', 'path_action' = 1, 'tag_field' = '', 'category_field' = '', 'attachment_field' = '', 'text_format' = 'filtered_html', 'text_format_comment' = 'filtered_html', ); // Import each of the blogs. foreach ($blogs as $blog_settings) { // Combine the default settings and the custom per blog settings. $blog_settings = array_merge($blog_default_settings, $blog_settings); // Skip the import if no username or password was found. if (empty($blog_settings['username']) || empty($blog_settings['password'])) { $message = t('The :site-name migration was not created since no username and/or password could be found. Verify that the example_migrate_wordpress_password variable has been set.'); $replacements = array( :site-name = $blog_settings['domain'], ); drupal_set_message(t($message, $replacements), 'warning'); continue; } // Set the form state values. $form_state['values'] = $blog_settings; // Store the values so we can use them again since $form_state is // a reference variable. $form_state_values = $form_state['values']; // Build the import form. $form = drupal_get_form('migrate_ui_wizard', 'WordPressMigrateWizard'); $form = migrate_ui_wizard($form, $form_state, 'WordPressMigrateWizard'); // Create a Migrate Wizard object. $form_state['wizard'] = new WordPressMigrateWizard(); // Set the number of steps in the form. $form_steps = 6; // Go through all of the steps. foreach (range(1, $form_steps) as $step) { // Validate the form data. $form_state['wizard']-formValidate($form_state); // Submit the form page. migrate_ui_wizard_next_submit($form, $form_state); // Put any values removed from the array back in for the next step. $form_state['values'] = array_merge($form_state_values, $form_state['values']); } // Submit the form. drupal_form_submit('migrate_ui_wizard', $form_state); // Save the settings into the wizard object. $form_state['wizard']-formSaveSettings(); // Notify the user that the migration was created successfully. $replacements = array( '@site-name' = $blog_settings['domain'], ); $message = t('The @site-name migration was successfully created.', $replacements); drupal_set_message($message, 'success'); } } /code /pre pWith all of this in place, the source WordPress sites and the configuration needed to import them are now fully defined in code along with a custom Drush command to create the required migrations. No longer will each individual site need to be re-entered through the UI introducing opportunities for mistakes and wasted time./p pNow when you are in a new environment or after you reset your migrations, you can simply run codedrush mcwm/code./p pimg src=http://chromaticsites.com/sites/default/files/migration%20creation.png alt=output of the drush mcwm command //p pFollowing its successful completion, the following are done for you:/p ul liA new Migrate group is created for each individual blog./li liThe actual Migrate classes within each group that migrate, authors, content, terms, and attachments are created and configured as defined in the code./li liThe source WordPress XML file is downloaded for each site and stored in codewordpress:///code./li /ul pThen simply run codedrush ms/code to verify everything was created successfully, and you are ready to migrate some content!/p pimg src=http://chromaticsites.com/sites/default/files/migration%20status.png alt=output of the drush ms command //p pNow that you have the tools and knowledge to evaluate your unique migration needs, you can make a well informed decision if this approach is right for you. However, we think that more often than not, all of the incredible functionality you get pre-built with the WordPress Migrate module will outweigh the issues that arise from not being able to fully build and store your migrations in code, especially when you add the functionality outlined above that gets you the best of both worlds. So have your cake and eat it too, and define your migrations in code and utilize the WordPress Migrate module while you are at it!/p pIf you decide to go this route, all of the code referenced here is available in this a href=https://gist.github.com/adamzimmermann/9d5d265c6b224e9f3387gist/a. Please note that this was all built for a href=https://www.drupal.org/node/2443061WordPress Migrate 7.x-2.3/a, so future updates to the module could break this functionality./p

Chromatic: Presenting at DrupalCamp Asheville 2015

Fri, 01/22/2016 - 03:16
pimg src=http://blog-media.chromaticsites.com.s3.amazonaws.com/presenting-drupal-asheville-2015/ashDC.jpg alt=Photo by Hunter Ward https://www.flickr.com/photos/124911585@N08/15377004489/in/photostream/ / Last weekend I enjoyed the awesomeness of a href=https://drupalasheville.com/DrupalCamp Asheville/a. The Asheville Drupal User Group did an amazing job once again. It was a great camp filled with positive people and smart sessions. This time around I was lucky enough to deliver my own presentation, a href=https://github.com/ryanhagerty/svg-hotSVG: How To Have Fun Making Your Site Look Hot!/a./p pThe session was filled with a great mix of people of all skill levels - from having little SVG exposure to people who employ it in all their projects. The talk catered to both as we reviewed everything from the basics of understanding SVG and getting it displayed on your site to more advanced topics like line-stroke animations and SVG filters./p pThis was my first presentation at a DrupalCamp, and it was very rewarding. I think everyone learned something, and it felt great to give back to a community that shares so much information on a daily basis./p pOverall, the presentations were on point. A few sessions I attended that stood out were Bayo Fodeke and Mark Shropshire’s a href=https://drupalasheville.com/drupal-camp-asheville-2015/sessions/decoupled-drupal-meteorDecoupled Drupal with Meteor/a, Chris Russo’s a href=https://drupalasheville.com/drupal-camp-asheville-2015/sessions/personal-git-workflow-everyonePersonal git workflow, for everyone!/a and Matt Davis’ a href=https://drupalasheville.com/drupal-camp-asheville-2015/sessions/headless-challenges-answered-weathercoms-presentation-frameworkHeadless Challenges Answered: Weather.com's Presentation Framework/a./p pBesides being a great camp, it’s located in Asheville, which is a true gem of the East Coast with vibrant arts, food and beer scenes. If you get the chance, you should definitely try to attend next year's camp. Whether you’ve never attended a camp or you’re a grizzled veteran, you’ll love the setting, the sessions, and best of all, the awesome people you’ll meet. strongSee you in 2016!/strong/p