Feb 20 2018
Feb 20

Drupal is really good at allowing the user (developer) manipulate its data.

It’s very common to override templates for nodes and views in D7, but in Drupal 8, it’s been made even easier to override templates at every level.  I found I was writing a lot less pre-processors on a D8 project versus D7. 

On a recent project, and I’m sure the majority of projects, Node and View templates will need to be overridden.  For nodes, it’s pretty much the same as before and very easy to find documentation.  Simply copy the base template and create a new file with this pattern:

               node--[type|nodeid]--[viewmode].html.twig

It’s really useful when you have multiple view modes.  For example, my recent project used the default view mode for a full page and a custom “Card” view mode for Views.

David Drupal Blog_0.JPG

On Views (D7), I use to output data with fields and override the View template at the row level for theming. 

D8, I found it more efficient to output data as Content then select the view mode.  For this approach, I reuse the node “Card” display and only worry about the wrapping DIVs from the view.  At most I would be adding some classes to the View’s row template, everything else about the content itself comes from the node card template.

               Container - views-view--[viewname].html.twig

               Row - views-view-unformatted--[viewname]--[displayname].html.twig

I also found I’ve used field template overrides more often than before.  It was useful when adding Bootstrap classes to fields for positioning or implementing other components such as tabs or carousels.  

Drupal.org has a list of twig naming conventions here for all entities that can be customized here

[https://www.drupal.org/docs/8/theming/twig/twig-template-naming-conventi....

The best way to find all the layers of template suggestions is to enable debug mode.  There’s a great step-by-step on Drupal.org that outlines how to enable twig debug mode as well as disable caching while you develop

[https://www.drupal.org/node/2598914]

Once this is enabled, inspect your page and you’ll find that every level of HTML will have a block of comments.  If you’re looking at a View, you’ll find all the suggestions for each level (container, row, node, field). 

In my opinion, this has made development a lot easier and efficient, minimizing the need to write code that will only be used in specific scenarios.  Hope this helps anyone that’s looking to start a new project!

Feb 20 2018
Feb 20

DrupalCamp London is coming around the corner! If you have the chance to go, I highly recommend it. The organizers put on a top-notch event. Last year I had the privilege of giving my first keynote at the conference. I firmly believe that open source is a creator of opportunity. There is no such thing as free software. In open source, we donate our time to provide software that has no monetary cost. This lowers the barrier to entry by removing a layer economic limitations. This is why I love working in open source, and Drupal.

I realized I never wrote up my keynote or shared it beyond the recording. A year later it seems like a great reflection point.

Thumbnail

I had been playing with code since middle school. I learned PHP because our Battle.net and Counter-Strike teams wanted websites, somewhere we could post news and stuff. Thanks to XTemplate and (I think?) PHPNuke. I then met some friends who played Ultima Online and began writing C# so we could hack on RunUO and have our own shard. For the record, C# is probably my favorite to work with and is one reason I'm glad to see OOP in Drupal 8.

What is open source?

The term "open source" refers to something people can modify and share because its design is publicly accessible.

This definition is from opensource.com. I like it because it is not limited to code. Having ideas open, shareable, and hackable leads to opportunities that would not be found in a locked down environment.

This is what allowed me to grow my hobby. It was a career possibility back then. It was just something fun I could do. I got to learn how to code by reading open source software and sandboxing around. I wrote a C# desktop client that communicated with our PHP website - security holes and glaringly bad code included.

Thumbnail

Fast forward some years and I still wrote code as a hobby. I built a CMS for a World of Warcraft guild so we could manage raid times and membership. But I had met my wife and needed to get a real job that didn't involve making sandwiches and provided insurance. So I got a job at the local beer distributed and eventually became a driver, throwing kegs of beer around for thirsty college students.

Sometimes I think things happen for a reason. It was November of 2012 and I slipped going down some stairs with my dolly and two barrels. I hurt my back and had a doctors note that I could not work for a few days. At the same time, a local marketing agency had opened a job posting for a web developer. So I took the chance. I knew I had some skill, but I didn't think enough. But I went for it.

The job interview was to take a Photoshop mockup and convert it into a WordPress theme. I had worked with WordPress once or twice before, but not much. I had always opted to hack things on my own so I could fiddle around.

Thanks to open source...

I could review and learn.

I was able to review other existing themes and WordPress documentation to accomplish my task. I firmly believe you gauge someone's skill by the ability to solve problems. Not by how well they have memorized a process.

No training or formal education

I have a bachelors in Software Engineering, now. At that time I had an Associates degree in IT Networking. All of my code writing had been self-taught and learning by examples. 

I was as knowledgeable as I chose to be.

Working with open source, my only limitation was my willingness to debug and reach the Google nethers for an answer.

Thumbnail Photo by Heymo_V: https://flic.kr/p/G5RzEC

Roughly 5 years ago, now, I started my first Drupal site. With Commerce Kickstart 2. I installed the demo store. I had to rebuild the site because you cannot uninstall the demo. It was a fun first ride. While we all of our sites on WordPress, we had a large eCommerce project. WooCommerce was in its infancy and there were many half-baked WordPress solutions. Through research, I found Drupal via Commerce Kickstart.

Why did I get hooked?

I got hooked, initially, out of the fact it was free and was stable compared to my other options. Magento felt too closed and heavy, requiring too much of an ask on hosting requirements. 

Drupal had centralized issue queues, an active IRC channel and a free spirit of help. With basic research, I felt I could take on this task by just experiencing the static parts of the Drupal community.

The Community.

There is something special about the people we work and connect with through Drupal. It still feels special today as it did those first few stressful weeks of figuring out what the hell I was doing while using Drupal. The code did not give me all the answers. Reading hook documentation only takes you so far when you're new. 

  • StackExchange question and answers came from people.
  • Documentation on Drupal.org and blogs came from people
  • IRC (now Slack, too) is full of people willing to donate some time and answer questions.

This community had sold me on Drupal, and it was from just the tip of the iceberg experience I had. 

Thumbnail

What makes the community?

At its basis, I think a community is made of people who share ideas. Is that not how open source projects start? Someone shares an idea or code. Someone else thinks it is a great idea or has a similar idea. These individuals work together to create more ideas and code. Now there is a project attracting more individuals and it becomes a community, regardless if anyone has ever met.

However, a community does not get far that way. What makes Drupal special is the friendship that seems to span all these individuals in different timezones, nations, and cultures. We make these friendships and bonds at user groups meetings and conferences (Drupal Camps for the win!)

Drupal & the community brought new opportunities

So, I got hooked on Drupal because of Drupal Commerce. We shifted away from using WordPress to using Drupal. Drupal's features allowed us to handle custom content models customers wanted, with less code to maintain. Community support made it easier to solve hard problems. Working with Drupal you feel like you have a support team behind you. It may not be immediate, but there are community members who will go above and beyond to help you solve problems (if you're polite!)

Drupal helped me land my first freelance gig!

In the past, I had done some freelance here and there. Nothing big, unless you count the two lost Bitcoin from when they were worth $5. Oops.

I had started contributing patches to some of the modules we were using. Specifically the USPS and UPS modules, just to help improve them. We were using them at work and I wanted to give something back in exchange. My activity in the queue turned into freelance work from the module maintainer, helping me pay down some bills.

DrupalCamp Atlanta 2013!

Thumbnail

Andy Giles, said maintainer of the USPS and UPS modules, offered to fly me down to attend DrupalCamp Atlanta. I accepted the offer, with my mind yet again blown that this opportunity was happening. It's the career-defining moment of my life. I was shell-shocked by the openness of the community and the discussions being made. This was before Weather.com had officially launched on Drupal, and people were discussing those challenges. I couldn't believe it.

Thanks to Mike Anello, Ryan Szrama, and many others I spoke to at the conference

  • I offered to co-maintain Commerce Reports and opened the 7.x-4.x branch to overhaul it
  • I created a local Drupal user group
  • I chipped away at my imposter syndrome
  • I realize I could make a career out of Drupal
Thumbnail

Networking and meeting similar individuals

Drupal Camps and local user group meetings introduced me to people from all over the world. This networking allows us to continue to share ideas, work on our projects, and introduce and nurture new members. I love the fact that the handful of times I needed to go to New York for a client that I could attend the NYC Drupal meet up.

Provides a way to show skillset and interact with others

I had horrible imposter syndrome. It is why I never pursued a career until I realized I was going to break my body down if I continued to throw barrels of beer around. The community allowed me beat back that imposter syndrome and realize we're all normal folk.

Creates demand for skills and people with those skills

If Dries has never released Drupal, hundreds of thousands of us would not have jobs. If those other individuals had not gathered around Drupal, those same hundreds and thousands of us would not have jobs. Even consider Drupal Commerce. If Ryan had not made Ubercart, ventured to Commerce Guys and built Drupal Commerce... I would not be where I am today. Everything I have today rests on a foundation laid by the Drupal community and the open source software we build.

Thumbnail

As a community, we contribute Support, Inspiration, and Jobs. These are my motivators. For example

  • If we build a better Drupal Commerce, we build a product people can sell
  • If we build a better Drupal Commerce, more code samples and bug fixes in Drupal
Thumbnail

The Driesnote at DrupalCon Dublin really resonated with me. I highly recommend reading his Drupal's collective purpose blog post. As open source users and contributors, we are making an impact on peoples lives. We are creating opportunities for people and lowering barriers. We may not be solving world problems, but we are doing something a little bit bigger than ourselves.

Some days I miss my CDL and driving a truck. Shooting the breeze with bar owners. But I also don't miss getting my truck ready at 5:30 AM and stacking barrels in a basement. So, thanks, Drupal and everyone who makes it!

Thumbnail
Feb 20 2018
Feb 20

Drupal is the most flexible general purpose Content Management System on the market today—Open Source or not. Using Drupal enables us to provide a cost effective and flexible platform for our clients, while contributing to Drupal allows us to ensure it remains the most flexible general purpose Content Management System. As contributing to Drupal is the job of the Drupal Community, it’s essential that Drupal advocates and aficionados convene to teach and learn from each other. What better way to do that than at DrupalCon?

What is DrupalCon?

DrupalCon is a conference where the Drupal Community can meet each other and exchange information in real life. The North American DrupalCon bounces around the Continental US, yet DrupalCon also happens in Europe, Asia, and South America.

The conference spans multiple days starting with paid training. Throughout the week there are community contributed sessions,  a vendor exposition hall, and it all ends in community-driven project sprints.

Why go to DrupalCon?

At its core, DrupalCon is a technology conference, so a big part of going to DrupalCon is keeping up with the current trends in technology. These may not be just be specific to Drupal, but may feature trends within the php programming language and technology as a whole.

Besides having structured, focused sessions, simple hallway conversations are a great way to keep up with current trends. I missed quite a few session while hanging out in the halls talking to people, yet this isn't a source of stress because all of the DrupalCon sessions are posted to YouTube by the association. Additionally, much of their information can be learned from reading blog posts online, attending local DUGs (Drupal User Groups), or conversations on Drupal's IRC channels, but it's important to get fully immersed by congregating for a few days with community members that are not local. The point of attending the conference is the people, the networking, and those conversations in the hallway.

Open Source Contribution

A large part of getting together is working together. Much of the work on an open source project happens remotely. This is difficult with many core maintainers being spread all over the globe in different timezones. At DrupalCon, we have the remarkable ability to be in the same room. This allows for many opportunities for collaboration. Code sprints occur all week with Friday being reserved as a sprint day. There are no sessions or talks on Friday, leaving the whole day for contribution, typically in a room with round tables organized by topic: migration, twig, install-systems, etc. This is also a good place to work on contributed modules. While at the Baltimore DrupalCon, I wrote the Drupal 8 version of the Speedboxes module.

Exploring and getting familiar with Drupal 8

Any software project that is under active development will be a moving target, and as users of this software, it is important to stay on top of the latest versions. In an effort to do this, I submitted a session for Baltimore DrupalCon about exploring and evaluating Drupal 8 by re-architecting a Custom Learning Management System we had built for New Perspectives Online. By doing this session, I was able to both get more experience with a new product without having to learn on a high-stakes client project, and I also had the opportunity to share those experiences with others in the Drupal Community. Below is a video of my presentation.

[embedded content]

Contribution isn't always about code. Contribution is possible regardless of skillset. Everything including bug reports, documentation, design, code, or even just attending DrupalCon is a worthwhile contribution.

Feb 19 2018
Feb 19
When I walk along with two others, from at least one I will be able to learn. 
 – Confucius

Drupal development as a career is usually also a commitment to constant learning through ongoing professional development.  Whether you make it a point to read blog posts or watch screencasts, sign up for some type of live-instructor training, or partake in co-working and meet-ups, on-going learning is a critical piece to being a professional Drupal  developer. Years ago, when DrupalEasy was presenting our Drupal Career Technical Education program exclusively in-person (now Drupal Career Online), the lab-portion (where we met in a less formal way than classroom sessions) became so popular with students, that we decided to continue to host them after graduation for anyone who had taken the class.

Six years later, these "office hours"are still going strong, now online and attended by people weekly from all over the country. It’s amazing to see the developers who first learned how to spell Drupal years ago in our riverside classroom in Cocoa, Florida; now the veterans assisting and connecting with those from recent sessions. People from former sessions, even those who attend at different times, also support each other beyond the labs, which has all contributed to the development of, what we think, is a pretty cool DrupalEasy Learning Community.

Weekly on Thursday afternoons U.S. Eastern Time, you can find DrupalEasy’s Mike Anello leading Go-To-Meeting ofice hours sessions, which are open to anyone who is enrolled in, or has taken any long-form DrupalEasy training courses. It’s a loose session devoted to helping anyone overcome issues, figure out how to approach something, share insights on particular modules and also talk Drupal. Learning experts call this collaborative learning, and it has even more advantages than we realized, which explains why it is so popular and seemingly effective as both an initial learning strategy and ongoing professional development tool. Everyone learns (Even Mike).

The Cornell University Center for Teaching Innovation explains that  “Collaborative learning is based on the view that knowledge is a social construct.”  (Wow, that relates to Drupal and open source projects on so many levels!)  They also explain that there are four principles to the ways collaborative learning happens, including that those who are learning are the primary focus, it is important to “do” and not just listen, working in groups is key, and the group should be learning by developing solutions to real problems.  

DrupalEasy’s learning community organically grew and developed all of these principles over the years, which is a pretty good confirmation that from both learning and solutions perspectives, we are on the right track. At the onset of each week’s office hours session, we say our hellos and figure out the first problem someone is having, or had, and the group works together to come up with a solution. There is of course also a bit of Nerd banter that keeps things fun and allows us to get to know each other a bit more. Cornell’s experts also confirm that group learning contributes to developing a lot of the soft skills (oral communication, leadership,etc.) that can help make a good developer great. We agree!

We also especially appreciate the value of the problem-solving approach to teaching, and also use it in our structured training. Cornell again has some great insight into the types and characteristics of problem solving as a mode of teaching that really resonates with us. They go in pretty broad and deep with references and explanations, so let’s pull the one element they cite that we feel we can attribute a good part of the success of our programs: “The problem is what drives the motivation and the learning.” (Boom!)  

So, knowledge is a social construct and problems motivate us to learn and figure out solutions. Working together as a community to overcome problems and build viable solutions. It’s all very Drupal-y, don’t you think?

The next session of Drupal Career Online begins March 26th. Two no-cost Taste-of-Drupal information sessions about the course are coming up at 1:30pm EST on February 28 and March 14.  Sign up!

Feb 19 2018
Feb 19

It took a while before I could write a new edition, I was just busy with the production of customer projects. Here again with a brand new version, what struck me in module updates in the past month:

1. D8 Editor Advanced link

A popular module that extends the standard editor in Drupal 8 with additional options for managing links. You can now add the following attributes:

  • title
  • class
  • id
  • target
  • rel

2. Password strength

Default password checks are stupid and annoying for the user: they can check the entered password meets certain rules, such as the number of characters and varying types herein (symbols, numbers, capital letters etc.).

This is a stupid way of checking because the password ‘Welcome123’ is accepted, while it is easy to guess.

This module enables a secure password policy by “pattern-matching” and “entropy calculation”. Almost every type of password is accepted, as long as it has sufficient entropy.

Source

How it works

Instead of checking strict rules, this module calculates the expected time a brute force attack needs to retrieve the password. This is calculated based on underlying patterns:

  • Words that appear in a standard dictionary, common first and surnames and other default passwords.
  • Words from a dictionary, but written in Leet / 1337. For example, where the “e” is written as a three and “a” like an @.
  • A standard sequence of letters like “abcdef”, “qwerty” or “123456”
  • Dates or years.

This module has been around since 2007, I wonder why I only encounter this now :) It is currently available in alpha for Drupal 8 and stable for Drupal 7 available — it is supported by Acquia and Card.

So if you want people to not have to bother to look for a password such as “one special character, 1 upper case and at least 8 characters’, then this module offers a solution.

3. Better Field Descriptions

In order to give content managers issues, it is possible to write an explanation of all content fields that they import. But the standard explanation in a field in the backend of Drupal are often irrelevant, to not apply these generic texts in the implemented *user story* of the installation concerned.

After installing this module you can:

  • Content managers have their own explanation text per field.
  • Set where it stands: above or below the field.
  • The explanatory style that you like.

4. Better login

Want to make the standard Drupal login screen better? Then install this module and you are good to go: through template overrides you can then do the required further tuning of the layout of the login screen.

5. Ridiculously Responsive Social Sharing Buttons

Another social sharing module, but as you see in the title: these are terribly responsive. The icons are SVG based and you need no external services such as AddThis.

Advantage: you’re less dependent and have your data in hand, downside: you have less functionality- such as comprehensive statistics.

6. Flush Cache

If you are not using Drush or Drupal console works then you can Drupal caches flush via “the ‘Flush all caches” button in the Drupal backend. But in a production environment, you will almost never flush all caches, it can cause severe performance problems.

This module solves that problem: install it and you have more control over the caches you want to flush.

7. Multiple Selects

Have your Drupal content management easier with ‘multiple selects’ administration, this image seems to me to speak for itself:

8. Neutral paths

If you are running a multilingual Drupal website, visitors can see the content in one language: the currently active language. Sometimes you would like to see pages in another language. In addition: content managers / Drupal administrators usually want English and not the backend *default language*, in our case, often Dutch.

Issue tracking for example, much easier if the backend is in English: Drupal documentation and support in English is much more available than in Dutch.

This module ensures that you can visit other pages in another language than the default. And can navigate the backend in English, while frontend is in another language.

9. Password Reset Landing Page (PRLR)

Drupal core includes a ‘password’ function: If you have forgotten your password then you can request a one-time login link that is automatically mailed to you.

If you click on the login link, you will see a screen with a login button. Once you click the ‘login’ button you are logged in and you are redirected to your profile page — that’s it.

You are in this situation where your password is lost / forgotten. You are not required to change your password. This is not usually done, so people often endlessly request login links.

This module solves this: the screen where you end up after clicking on the login link not only contains a login button, but also a function to change your password immediately.

10. Auto Purge Users

The user list in Drupal is usually not or hardly ever administered. If people have long been inactive or have not completed their registration, the account can usually be removed to avoid overhead and security issues.

This module does it for you automatically, it checks inactivity below a point and blocks users if they meet:

  • Certain time inactive.
  • Account never activated after registration.
  • Not been logged in for a period of time.

Not a popular module, but in the case of an example Drupal social intranet it can come in handy.

11. Vertical Tabs Config

Want to influence the order of the Drupal tabs? Or do you want some tabs to not show all of your content manager? To keep tabs simple and usable you can install this module: select which tabs to show and in what order.

Modules with similar functions: Simplify and Hide vertical tabs.

12. Custom Search

The default Drupal search is fine, but really standard: you have few options to tune the engine. After installing this module, changes that you can then include are:

  • Change the default label in the search box.
  • Set a default text in the search box.
  • Tune ‘Advanced Search’.
  • Change the text on the “submit button”.

And much more, see module page:

13. Persistent Login

Drupal 8 core does not have a ‘remember password’ function when you log in. You can remain automatically logged for some time, but that is based on a PHP session. This module does not, you can also:

  • How long users can stay logged in.
  • How many places a person can be logged in at once.
  • Select certain pages that the user must log in again at. These are usually pages where more sensitive information is available.
  • Allow the user to delete all his logins themself.

14. Realistic Dummy Content

Wisdom

Using the Devel module you can automatically generate content so you can see if your modules / themes work well. But it gives an unrealistic picture of the end result, this module generates more realistic images and texts.

15. Password Policy

Although I am a fan of the aforementioned ‘Password strength’ module, this can also be useful if you want to make a specific password policy on your Drupal website.

16. Mass Password Reset

This module, we often use to implement Drupal social intranet: previously, all users and content created by an administrator on a test environment, without it people were informed through e-mail.

Once the social intranet went live, we sent all users at once an email with a login link via this module; the system was live!

Wrap Up

So far that’s what I noticed last month in Drupal modules, stay tuned for more fat Drupal content!

Source header image

Feb 19 2018
Feb 19

React for DrupalThe interest in creating decoupled/headless/API-first Drupal sites has been growing for a while. As the interest grows, and more sites are implementing this architecture, there is a growing list of articles and discussions about it. Essentially, with a decoupled site you have a backend that provides an editorial interface for creating and storing content, and an API for retrieving it. This is combined with one or more frontend clients that can display that content where and how you would like. Drupal is a great backend for these kinds of sites, and React is the most popular JavaScript framework being used for frontends. While Drupal and React are both well-established technologies with a wealth of documentation, the interaction between the two, and best practices around that interaction, are still developing.

There has also been a push for Drupal core to adopt a modern JavaScript framework with the end goal of improving Drupal's user experience (UX). At this time React is the current leader in this initiative. So it's not a bad idea for any Drupal developer to at least be familiar with what React is and why it has been taking the web by storm.

Lullabot Education (the company that runs Drupalize.Me) has been exploring the world of JavaScript in general, and React specifically, and we've been pulling together resources. As part of this process, we've put together a new site, React for Drupal, that curates the best of our findings. If decoupled Drupal and/or React are topics you want to learn more about and keep current with, this is a great place to start. We'll also be keeping the site up-to-date as best practices emerge or change and we'll be working to help fill gaps in the current knowledge and documentation.

We hope this is a useful resource to both the Drupal and React communities. If you have any suggestions or comments about what we're covering and what's missing, please let us know! Check out React for Drupal to sign up for regular updates in the future.

Feb 19 2018
Feb 19
Download and install Drupal 8.5 and try umami.

By Jesus Manuel OlivasHead of Products | February 19, 2018

By Jesus Manuel OlivasHead of Products | February 19, 2018

If you are following the upcoming release of Drupal 8.5 you might be aware of the umami profile. This installation profile is part of the Out of The Box experience initiative. The goal of this profile is to add sample content presented in a well-designed theme, displayed as a food magazine. Using recipes and feature articles this example site will make Drupal look much better right from the start and help evaluators explore core Drupal concepts like content types, fields, blocks, views, taxonomy, etc.

This profile is committed to the 8.5 branch of the Drupal project repository which makes it a little complicated to try out. To facilitate this I wrote a chain command.

You may think this looks cool but wait ... what this YAML means and what is a chain command?

A chain command is a custom command that helps you automate multiple command execution, allowing you to define and read an external YAML file containing the definition name, options, and arguments of multiple commands and execute that list based on the sequence defined in the file.

For more information about chain commands refer to the Drupal Console documentation.

How do I try this chain command?

In order to try this chain command it is required to have installed on your local system:

What do I need to do?

Copy the content of this gist file to a new file and name it as ~/.console/chain/try-umami-sqlite.yml

How do I execute the new command?

After adding the new file, the `try:umami:sqlite` command will be listed when running the list command. Then you have to execute the command on your local machine

Executing using the interactive mode and answering the interactive question:

drupal try:umami:sqlite

Enter the value for "directory" placeholder:

> /path/to/install/umami/

Executing the command inline and entering the directory where Drupal will be cloned and installed.

drupal try:umami:sqlite --directory=/path/to/install/umami/

Can I use another database as MariaDB, MySQL or other?

Yes, you can. But modifying the downloaded chain file will be required as updating the db-type='mysql' and passing the required options. To review all of the available options for the "site:install" command you can read the DrupalConsole documentation.

Feb 18 2018
Roy
Feb 18
Notes user interface: a text area, a published checkbox and a Save button

Tweet-sized notes posted as content on yoroy.com that get pushed to Twitter via RSS and Zapier.

My previous post inspired Joeri to some improvements on his site. Nice!

I built another step towards POSSE this weekend: tweet-sized notes posted as content on yoroy.com that get pushed to Twitter via RSS and Zapier. Here’s how:

Create a new content type “Note”. This one needs to only have a text area. And here we run into Drupal always requiring a title. We can’t create entities without giving it a title. The title itself is always a text field, so not ideal for writing 280 char bits of text. Two contrib modules to work around this:

  • Auto entity label to define an automatic pattern for the title of these Notes. I set it to use a simple timestamp.
  • Exclude node title to actually hide the title field on the Note creation form and on display.

Next I defined a new text format that does not use CKEditor but allows tags and automatically transforms URLs into links. I set this to be the default text format for the text area on the Note using the Better Formats module (sadly currently only available as an old development release). This step is optional, it helps remove user interface clutter. This gives me a content creation form with just a single plain text text area, a “published” checkbox and a Save button.

I updated the views that list blog content on this site to also include content of type “Note” and configured a Notes RSS feed as well. I use this feed as an input on Zapier where the Notes body is extracted and posted as a tweet.

18 Feb 2018

Feb 17 2018
Feb 17

Five years ago I went to my second Drupal Camp and first Drupal Camp that I presented at. It has been four years, but I am finally going back to Florida Drupal Camp. I am pretty excited, as a lot has changed since then.

My first Drupal event was DrupalCamp Atlanta in 2013. Thanks for making it a possibility, Andy Giles! I met some amazing people there and fell in love with the Drupal community. In fact, it's where, after talking to Ryan Szrama for a brief moment I decided to opt in and offer a co-maintainer of Commerce Reports. I met some amazing people from the Southeast community. One of them was Mike Herchel.

I cannot remember how it exactly came about, but he said I should propose a session for Florida DrupalCamp. I had no idea what I could talk about, or why it would even make sense for someone from Wisconsin to propose a session for a conference in Drupal. But I did, and I am so happy I took that chance.

I decided to propose a session on how I was using Panels as my workplace. I worked at a marketing agency who focused on great content that would be well received on any device. I found Panels to be our solution - Rockin` Responsive Content with Panels. In fact, the sample code I wrote is still available on my GitHub.

My session got accepted. Thanks, Mike. I'm sure you played a big part in making that happen. But, I had to figure out how to go there. The idea still seemed ludicrous to me. I was a novice at my trade, going to conferences was a new concept. The fact I had just been to a conference in Atalanta blew my mind. But, then things lined up.

Short interjection: I want to give a huge shout out to my wife who supported me on these adventures and continues to.

I believe you need to think big and strive to achieve above and beyond what is currently available to you. Otherwise, you miss chances. And that is exactly what allowed me to make my first visit to Florida Drupal Camp.

My employer did a lot of work for several local chapters of a national non-profit. There just so happened to be invited to a conference the group was hosting -- in Florida. The conference was before Florida Drupal Camp, but they saw value in attending, especially since they would be down there. If I had not taken the risk, decided "why not, what can I lose?" I doubt the dots would have connected for us to attend Florida Drupal Camp, leaving me at home in the Wisconsin post-winter slush.

Just as Drupal Camp Atlanta was an eye-opening experience, so was Florida Drupal Camp. After my session, I got to learn that Derek "Hawkeye Tenderwolf" DeRaps and Kendall Totten were working on Classy Panel Styles to give more power to the content editor who was working in panels. I got to experience my first true community collaboration.

Back at Atlanta, my mind was merely blown by the community's willing ability to share and help. Now I got to witness first-hand collaboration and idea sharing. I was being exposed to my ability to make an impact with some other effort.

People also liked my session! This blew away the layers of imposter syndrome I had sitting on my shoulders. By this time I had been improving Commerce Reports - but that was still in my bubble. I had gotten the ability to open a new Git branch and make fixes which made our client happy. I still had a lingering feeling that I wasn't successful.

I also wanted to get to Florida so I could tell Mike Anello I started a Drupal user group. Back in Atlanta, at dinner after the conference, he told me I should "plant a flag" for Drupal and just start a Drupal user group. Which, I did and ran for almost a year.

So I'm pretty happy and nostalgic as I am on this flight to Orlando (well, now in a hotel room editing and posting.) Florida Drupal Camp 2014 made a major impact in my career. It opened my eyes to new opportunities and careers choices available. It broke down my imposter syndrome to show we all are awesome at some things and equally horrible at others. But that's okay; this is how people work.

I want to give credit to those who made such an impact that caused a jumpstart to my career and deep dive into the Drupal community

  • Andy Giles
  • Mike Herchel
  • Mike Anello
  • Every single attendee that I have talked to in Atlanta and Florida.

Making an impact in someone's journey is not always done in big statements. It is the little things.

Feb 17 2018
Feb 17

What even is "Site Building"?

At DrupalDownunder some years back, the wonderful Erica Bramham named her talk "All node, no code". Nodes were the fundamental building blocks in Drupal, they were like single drops of content. These days though, it's all about entities.

But hang on a minute, I'm using lots of buzz words, and worse, I'm using words that mean different things in different contexts. Jargon is one of the first hurdles you need to jump to understand the diverse worlds of the web. People who grow up multi-lingual learn that the meanings of words is somewhat arbitrary. They learn the same thing has different names. This is true for the web too. So the first thing to know about Site Building, is it means different things to different people. 

To me, it means being able to build a website with out knowing how to code. I also believe it means I can build a website without having to set up my own development environment. I know people who vehemently disagree with me about this. But that's ok. This is my blog, and these are my rules.

So - this is a post about site building, using SimplyTest.Me and Drupal 8 out of the box.

1. Go to https://simplytest.me

2. Type Drupal Core in the search field, and select "Drupal core" from the list

3. Choose the latest development branch, right at the bottom of the list.

For me, right now, that's 8.6.x, and here's a screenshot of what that looks like.

SimplyTest Me Screenshot, showing drop down fields described in the text.

4. Click "Launch sandbox".

Now wait.

In a few moments, you should see a fresh shiny Drupal 8 site, ready for you to explore.

For me today, it looks like this.  

Drupal 8.6.x front page screenshot

In the top right of the window, you should see a "Log in" link.

Click that, and enter admin/admin to login. 

You're now ready to practice some site building!

A guide to what's next

Follow the Drupal User guide to start building your site!

If you want to start at the beginning, you'll get a great overview of Drupal, and some important info on how to plan your site. But if you want to roll up your sleeves and get building, you can skip the chapter on site installation and jump straight to chapter 4, and dive into basic site configuration.

Experiment

You have 24 hours to experiment with the simplytest.me sandbox - after that it disappears.

Get in touch

If you want something more permanent, you might want to "try drupal" or contact us at catalyst-au.net to discuss our Drupal services.

Feb 16 2018
Feb 16

Hello everybody! You might've experienced some changes of the project settings interface already - here’s the broad summary of what makes Drop Guard more efficient and more powerful now: composer package manager mode, speeding up the setup of update type behaviors (with a short mode option) and live site monitoring.

 

1.Why we made the Drop Guard module installation of the life module expendable #composer

First of all - no worries! You can still set up your Drop Guard projects with installing the Drop Guard live site module. Especially if you have a Drupal project, which doesn’t work with a composer package manager (such as nearly all Drupal 7 projects do), you will need to install the Drop Guard module on your Drupal live site, so it can check out your activated modules and update them.

But if your Drupal project DOES work based on a composer package manager, you will benefit from our new optimization.

No module installation needed.

You don’t need to touch your Drupal website to let Drop Guard work for you. You inserted your Git URL (as usual) in the first Basic setup step and then on the Site config you can decide how to proceed:

You can select between 3 options of your Git settings now.

Option 1: You can select the composer package manager setting to let Drop Guard check your composer files within 3 clicks. And of course it will respect your version constraints if you like.

Option 2: You can still install the Drop Guard module on the live site of your project.

Option 3: No composer package manager? No live site installation? But all your modules are inside your git? Well, just let Drop Guard check your Git repo directly.

 

2. Time reduced update behavior setup: 1 section for 4 update types

This is the regular view of the update behaviors setting page:

Regular view of the update behaviors page: You have to adjust the settings of every single update type.

Most of our users handle the updates from “Critical” to “Not Critical” Security updates in just the same way with no individual setting. So - why wasting time here? Enjoy the short mode!

Under “Update behaviors”, you’ll find the SHORT mode option:

You can elect the SHORT mode now to handle 4 update types as one single group.

Step 1: Set up one update type behavior of the middle section (f.e. you set up “Critical” update type just the way you want that all types from “Moderately Critical” to “Not Critical” work and don’t waste time on setting up these 3 types).

Step 2: Select SHORT mode at the bottom of the update type section.

Step 3: Choose “Critical” settings as the basic settings of the short mode.

Step 4: Done.

Quick update type handling with the new SHORT mode option.

 

3. Your Drupal site was down and you haven’t realized it immediately?

Let Drop Guard monitor your live site and inform you about down times. Just watch out for the “Extra settings” on the “Site config” tab and insert your live site URL.

Drop Guard checks your live site and recognizes if the site is unreachable. In that case, you’ll be informed via email. If the site is up and running again, you will get a second mail. No spam, just 2 mails for every incident.

That’s it for now! What comes next?

Stay tuned for our next improvements, which will include our highlight “time scheduling of Drop Guard actions" - predictable update handling.

Contact us for more information: [email protected]

Feb 16 2018
Feb 16
My website plan

In an effort to reclaim my blog as my thought space and take back control over my data, I want to share how I plan to evolve my website. Given the incredible feedback on my previous blog posts, I want to continue to conversation and ask for feedback.

First, I need to find a way to combine longer blog posts and status updates on one site:

  1. Update my site navigation menu to include sections for "Blog" and "Notes". The "Notes" section would resemble a Twitter or Facebook livestream that catalogs short status updates, replies, interesting links, photos and more. Instead of posting these on third-party social media sites, I want to post them on my site first (POSSE). The "Blog" section would continue to feature longer, more in-depth blog posts. The front page of my website will combine both blog posts and notes in one stream.
  2. Add support for Webmention, a web standard for tracking comments, likes, reposts and other rich interactions across the web. This way, when users retweet a post on Twitter or cite a blog post, mentions are tracked on my own website.
  3. Automatically syndicate to 3rd party services, such as syndicating photo posts to Facebook and Instagram or syndicating quick Drupal updates to Twitter. To start, I can do this manually, but it would be nice to automate this process over time.
  4. Streamline the ability to post updates from my phone. Sharing photos or updates in real-time only becomes a habit if you can publish something in 30 seconds or less. It's why I use Facebook and Twitter often. I'd like to explore building a simple iOS application to remove any friction from posting updates on the go.
  5. Streamline the ability to share other people's content. I'd like to create a browser extension to share interesting links along with some commentary. I'm a small investor in Buffer, a social media management platform, and I use their tool often. Buffer makes it incredibly easy to share interesting articles on social media, without having to actually open any social media sites. I'd like to be able to share articles on my blog that way.

Second, as I begin to introduce a larger variety of content to my site, I'd like to find a way for readers to filter content:

  1. Expand the site navigation so readers can filter by topic. If you want to read about Drupal, click "Drupal". If you just want to see some of my photos, click "Photos".
  2. Allow people to subscribe by interests. Drupal 8 make it easy to offer an RSS feed by topic. However, it doesn't look nearly as easy to allow email subscribers to receive updates by interest. Mailchimp's RSS-to-email feature, my current mailing list solution, doesn't seem to support this and neither do the obvious alternatives.

Implementing this plan is going to take me some time, especially because it's hard to prioritize this over other things. Some of the steps I've outlined are easy to implement thanks to the fact that I use Drupal. For example, creating new content types for the "Notes" section, adding new RSS feeds and integrating "Blogs" and "Notes" into one stream on my homepage are all easy – I should be able to get those done my next free evening. Other steps, like building an iPhone application, building a browser extension, or figuring out how to filter email subscriptions by topics are going to take more time. Setting up my POSSE system is a nice personal challenge for 2018. I'll keep you posted on my progress – much of that might happen via short status updates, rather than on the main blog. ;)

Feb 16 2018
Feb 16

Chances are that you already use Travis or another cool CI to execute your tests, and everyone politely waits for the CI checks before even thinking about merging, right? More likely, waiting your turn becomes a pain and you click on the merge: it’s a trivial change and you need it now. If this happens often, then it’s the responsibility of those who worked on those scripts that Travis crunches to make some changes. There are some trivial and not so trivial options to make the team always be willing to wait for the completion.

This blog post is for you if you have a project with Travis integration, and you’d like to maintain and optimize it, or just curious what’s possible. Users of other CI tools, keep reading, many areas may apply in your case too.

Unlike other performance optimization areas, doing before-after benchmarks is not so crucial, as Travis mostly collects the data, you just have to make sure to do the math and present the numbers proudly.

Caching

To start, if your .travis.yml lacks the cache: directive, then you might start in the easiest place: caching dependencies. For a Drupal-based project, it’s a good idea to think about caching all the modules and libraries that must be downloaded to build the project (it uses a buildsystem, doesn’t it?). So even a variant of:

cache:
  directories:
    - $HOME/.composer/cache/files

or for Drush

cache:
  directories:
    - $HOME/.drush/cache

It’s explained well in the verbose documentation at Travis-ci.com. Before your script is executed, Travis populates the cache directories automatically from a successful previous build. If your project has only a few packages, it won’t help much, and actually it can make things even slower. What’s critical is that we need to cache slow-to-generate, easy-to-download materials. Caching a large ZIP file would not make sense for example, caching many small ones from multiple origin servers would be more beneficial.

From this point, you could just read the standard documentation instead of this blog post, but we also have icing on the cake for you. A Drupal installation can take several minutes, initializing all the modules, executing the logic of the install profile and so on. Travis is kind enough to provide a bird’s-eye view on what eats up build time:

Execution speed measurements built in the log

Mind the bottleneck when making a decision on what to cache and how.

For us, it means cache of the installed, initialized Drupal database and the full document root. Cache invalidation is hard, we can’t change that, but it turned out to be a good compromise between complexity and execution speed gain, check our examples:

Do your homework and cache what’s the most resource-consuming to generate, SQL database, built source code or compiled binary, Travis is here to assist with that.

Software Versions

There are two reasons to pay attention to software versions.

Use Pre-installed Versions

Travis uses containers of different distributions, let’s say you use trusty, the default one these days, then if you choose PHP 7.0.7, it’s pre-installled, in case of 7.1, it’s needed to fetch separately and that takes time for every single build. When you have production constraints, that’s almost certainly more important to match, but in some cases, using the pre-installed version can speed things up.

And moreover, let’s say you prefer MariaDB over MySQL, then do not sudo and start to install it with the package manager, as there is the add-on system to make it available. The same goes for Google Chrome, and so on. Stick to what’s inside the image already if you can. Exploit that possibility of what Travis can fetch via the YML definition!

Use the Latest and (or) Greatest

If you ever read an article about the performance gain from migrating to PHP 7, you sense the importance of selecting the versions carefully. If your build is PHP-execution heavy, fetching PHP 7.2 (it’s another leap, but mind the backward incompatibilities) could totally make sense and it’s as easy as can be after making your code compatible:

language: php
php:
  - '7.2'

Almost certainly, a similar thing could be written about Node.js, or relational databases, etc. If you know what’s the bottleneck in your build and find the best performing versions – newer or older – it will improve your speed. Does that conflict with the previous point about pre-installed versions? Not really, just measure which one helps your build the most!

Make it Parallel

When a Travis job is running, 2 cores and 4 GBytes of RAM is available – that’s something to rely on! Downloading packages should happen in parallel. drush make, gulp and other tools like that might use it out of the box: check your parameters and configfiles. However, on the higher level, let’s say you’d like to execute a unit test and a browser-based test, as well. You can ask Travis to spin up two (or more) containers concurrently. In the first, you can install the unit testing dependencies and execute it; then the second one can take care of only the functional test. We have a fine-grained example of this approach in our Drupal-Elm Starter, where 7 containers are used for various testing and linting. In addition to the great execution speed reduction, the benefit is that the result is also more fine-grained, instead of having a single boolean value, just by checking the build, you have an overview what can be broken.

All in all, it’s a warm fuzzy feeling that Travis is happy to create so many containers for your humble project:

If it's independent, no need to serialize the execution

Utilize RAM

The available memory is currently between 4 and 7.5 GBytes , depending on the configuration, and it should be used as much as possible. One example could be to move the database main working directory to a memory-based filesystem. For many simpler projects, that’s absolutely doable and at least for Drupal, a solid speedup. Needless to say, we have an example and on client projects, we saw 15-30% improvement at SimpleTest execution. For traditional RMDBS, you can give it a try. If your DB cannot fit in memory, you can still ask InnoDB to fill memory.

Think about your use case – even moving the whole document root there could be legitimate. Also if you need to compile a source code, doing it there makes sense as well.

Build Your Own Docker Image

If your project is really exotic or a legacy one, it potentially makes sense to maintain your own Docker image and then download and execute it in Travis. We did it in the past and then converted. Maintaining your image means recurring effort, fighting with outdated versions, unavailable dependencies, that’s what to expect. Still, even it could be a type of performance optimization if you have lots of software dependencies that are hard to install on the current Travis container images.

+1 - Debug with Ease

To work on various improvements in the Travis integration for your projects, it’s a must to spot issues quickly. What worked on localhost, might or might not work on Travis – and you should know the root cause quickly.

In the past, we propagated video recording, now I’d recommend something else. You have a web application, for all the backend errors, there’s a tool to access the logs, at Drupal, you can use Drush. But what about the frontend? Headless Chrome is neat, it has built-in debugging capability, the best of which is that you can break out of the box using Ngrok. Without any X11 forwarding (which is not available) or a local hack to try to mimic Travis, you can play with your app running in the Travis environment. All you need to do is to execute a Debug build, execute the installation part (travis_run_before_install, travis_run_install, travis_run_before_script), start Headless Chrome (google-chrome --headless --remote-debugging-port=9222), download Ngrok, start a tunnel (ngrok http 9222), visit the exposed URL from your local Chrome and have fun with inspection, debugger console, and more.

Takeaway

Working on such improvements has benefits of many kinds. The entire development team can enjoy the shorter queues and faster merges, and you can go ahead and apply part of the enhancements to your local environment, especially if you dig deep into database performance optimization and make the things parallel. And even more, clients love to hear that you are going to speed up their sites, as this mindset should be also used at production.

Feb 16 2018
Ana
Feb 16

When is the right time to let it go and move forward? Yes, we are talking about migrating to Drupal 8 version. Drupal 8 was released in November 2015, so it has been more than two years now. No matter what kind of website you have, whether you have an online shop, small brochure website or an extensive and complex website, if its build on Drupal 6, it's almost urgent you move forward and upgrade it to Drupal 8. Why? The Drupal community no longer (officially) supports Drupal 6 since three months after Drupal 8 came out. That means that bugs are no longer getting fixed. Drupal 6 is simply long gone, finito, end of story. 

 

So why go with Drupal 8?

Drupal 8 has so many benefits. But it is a little bit different than you been use to so far. For example, you need to learn PHP framework called Symfony. PHP engine is replaced with engine “Twig”. But Drupal has many improvements, like better integration with services, mobile design, better user experience for admins etc. 

computer

 

Is it upgrade or migrate?

If you are hoping that your new Drupal 8 site is going to be the same as your site on Drupal 6, that may not happen. With all the improved features, your site is going to get different, but better. For example, all contributed modules that you are using on Drupal 6 might not have an automatic upgrade path ready (yet). Hence you need to sift through the migration results. You might also settle that it will be simpler to manually copy-paste the content from your old website to your new Drupal 8 installation or going with a custom migration approach.

Drupal 6 sites can be migrated directly to Drupal 8 or if you think you will benefit from Drupal 7 vast choice of contrib modules. Drupal 7 will stay fully supported until Drupal 9 will be released. That gives you a chance to choose if you rather migrate your Drupal 6 site to Drupal 7 or 8. 

 

A new approach to upgrading

Upgrading your website from Drupal 6 to Drupal 8 uses very different approach than going from Drupal 6 to Drupal 7. When Drupal 6 site is upgraded to Drupal 7, the same database is upgraded from Drupal 6 structure to Drupal 7 structure. Now, if you want to upgrade a Drupal 6 site to Drupal 8, you first need to install a clean Drupal 8 site. You will then need to migrate your site configuration and site content to your new Drupal 8 site. This means, your existing Drupal 6 site remains wholly unaltered and intact.


Unfortunately, upgrading from Drupal 6 to Drupal 8 is not a matter of clicking a button. Depending on the complexity of the built, we can even say it's a migration rather than upgrade. Nevertheless, I encourage you to look ahead and embrace the novelties Drupal 8 brings and upgrade your website.
 

Feb 15 2018
Feb 15

In part one and two of this Acro Media Tech Talk video series, we covered how you set up a new product attribute and used rendered fields, in Drupal Commerce 2. Parts three and four then to set up a product variation type and a product type, both with custom fields. This completes our new product configuration.

In part five, the last of this series, we'll finally get to try out the new product! We'll add a product to the store as if we are a store administrators (end user) who is creating content. We'll try out all of the fields and properties we've configured, make a product, and view it on the site. Afterwards, we'll cover how an administrator can then go in and edit the product to make content changes.

This entire video series, parts one through five, show you how to set up a new product in Drupal Commerce 2, from start to finish. The video is captured using our Urban Hipster Commerce 2 demo site.

Its important to note that this video was recorded before the official 2.0 release of Drupal Commerce and so you may see a few small differences between this video and the official release now available.

Urban Hipster Commerce 2 Demo site

This video was created using the Urban Hipster Commerce 2 demo site. We've built this site to show the adaptability of the Drupal 8, Commerce 2 platform. Most of what you see is out-of-the-box functionality combined with expert configuration and theming.

Visit Our Drupal Commerce 2 Demo Site

More from Acro Media
Drupal modules used in this video

Contact us and learn more about our custom ecommerce solutions

Feb 15 2018
Feb 15

Last fall at BADCamp it was exciting to see that a component-driven approach to building Drupal 8 themes is becoming the standard. Many people are doing great things to advance this approach, including reducing duplication and simplifying data structures. In the day-long front end summit, and in many sessions and BOFs during BADCamp, great tips were shared for making the most of helper modules, such as the UI Patterns module, as well as techniques that make the most of Pattern Lab, KSS, and other front end systems.

While Drupalers are rejoicing at these exciting advances allowing newfound front end freedoms, there are still a few hoops to be aware of in order to make the most of Drupal, especially for a newcomer who might be eager to shove aside a lot of what Drupal provides. Some of these things, like contextual links, are nice-to-haves that can make life easier for content administrators. However, other things that are easily dismissed in a component-driven approach, like letting Drupal fully render fields, can cause headaches further on if they’re ignored, and make life difficult when it comes to keeping your front end forward-compatible with Drupal.
 

A Quick Recap of the Component-Driven Approach

At its basic level, the component-driven approach to Drupal theming means:

  1. Breaking your site’s interface down into independent components.
  2. Organizing those components into a system of reusable parts (i.e., the Atomic Design philosophy).
  3. Build out those parts however you see fit in a standalone presentation platform that supports twig (i.e., a KSS, or Pattern Lab style guide), with the pieces of those components that can change set up as variables in the twig files.

These component twig files that you use to build your system of reusable parts essentially serve as replacements for the templates in your Drupal theme (field.html.twig, block.html.twig, node.html.twig, etc.) You’ll still need the Drupal templates -- for now, see the UI Patterns module note at the end -- but they only serve as the “presenter” that helps map values from Drupal to the appropriate variables in your component template. The biggest payoffs with this approach are:

  1. Build things how you like them! You’re in control of the markup, and don’t necessarily have to be a seasoned Drupal developer to dive in.
  2. Back end setup, and front end build out can happen at the same time.
  3. A more organized, and structured presentation layer that’s not strictly tied to Drupal, and could potentially be repurposed for other platforms.

For a deeper dive into the components-driven approach, be sure to check out Mario Hernandez’s blog post series on integrating components into Drupal: Part 1, Part 2, and Part 3.

So if you’re not following a component-driven approach already, I’m sure you can see why it’s becoming popular. However, before diving in, here are a few things to consider to help you keep your approach forward-compatible with Drupal, and hopefully avoid headaches.
 

When It Comes To Fields, Let Drupal Do Its Thing

As we know, the default field markup in Drupal 8 is abstracted to account for field labels, and multiple values. This means that by default in Drupal even a simple, single value text field is going to render with multiple layers of <div>s wrapping the value of the field. However, let’s say you have a callout component in your style guide that includes an optional subtitle field. You’d probably mark that up with just a single, semantic element, like this:
 

{% if subtitle %}
 <h3 class=”callout__subtitle”>{{ subtitle }}</h3>
{% endif %}

And let’s say on the Drupal side of things you’re going use a custom block type for adding callout components to your site. Therefore, in the block--callout.html.twig template that serves as the “presenter” for mapping Drupal values to the component template, you’d have something like this:
 

{% include ‘@custom_theme/callout/callout.twig’ with {
  ...
  ‘subtitle’: content.field_subtitle
  ...
} %}

Since we’re letting Drupal render the subtitle field in our block template, we’d end up with all the default field markup inside our <h3>, which isn’t what we want at all.

While the quickest solution may be to pull out the value of the subtitle field from the render array for the field, and pass that to the component template...
 

‘subtitle’: content.field_subtitle.0['#context].value 

...this can come back to bite you later because of the way Drupal 8 handles caching. One option that’s more cache-friendly is to use the Twig Field Value module. This module gives you custom filters that help you safely pluck the value you need from the render array for the field:
 

‘subtitle’: content.field_subtitle|field_value

This is better, but we’re still shoving aside how Drupal adds attributes to the field markup. We’d only have our custom class on the <h3> for the subtitle, with no way for modules in the Drupal ecosystem to inject their classes or other attributes. As some of the “Outside-In” initiatives in Drupal start to mature this will become increasingly important if you want to take advantage of them. What follows are some options for how you can make your components more “loyally” accommodate Drupal.
 

Follow Drupal’s Lead For Field Markup

First, you could markup your component templates with additional wrappers that include only your classes, which would apply styling to the semantic element included in the variable output of your component template. Understandably, this could lead to a bit more bloated styling and markup, plus require you to include markup in the sample data that your style guide uses. Example:

Component markup:

{% if subtitle %}
  <div class=”callout__subtitle-wrapper”>
    {{ subtitle }}
  </div>
{% endif %}

Component placeholder data in the style guide:

{
  “subtitle”: “<h3 class=\”callout__subtitle\”>Subtitle Text</h3>”
}

In this case, when the component is implemented on the Drupal side of things, you would create a custom field template for the subtitle field, where you would change the markup to use only a single <h3>, plus add the “callout__subtitle” class via the Drupal addClass() function.

Drupal field template for the subtitle field in our “callout” custom block type:
 

<h3{{ attributes.addClass(‘callout__subtitle’) }}>
  {%- for item in items -%}
    {{ item.content }}
  {%- endfor -%}
</h3>

But Wait, I Want Control Of My Markup!

The previous option somewhat defeats the purpose of the markup freedom you get with a component driven approach, so you may want to instead consider leaving the component markup nice and lean, and just use a <span> tag for the subtitle field where the Drupal-specific attributes can be applied.

Component markup:

{% if subtitle %}
  <h3 class=”callout__subtitle”>
    {{ subtitle }}
  </h3>
{% endif %}

Component placeholder data in the style guide:

{
  “subtitle”: “Subtitle Text”
}

Drupal field template for the subtitle field in our “callout” custom block type:

<span{{ attributes }}>
  {%- for item in items -%}
    {{ item.content }}
  {%- endfor -%}
</span>

This works pretty nicely, but you may find that those Drupal attributes really need to be output where they were intended: the main wrapper for the field.
 

Twig Embed To The Rescue

A good middle ground for keeping your markup lean, but still loyally accommodating Drupal attributes, is to use twig embed blocks in your component template. This means you could put whatever you want inside the embed block declaration for the subtitle field in the component template, and on the Drupal side when the callout component is integrated via a twig embed, we simply swap that subtitle block with something else. Example:

Component markup:

{% block callout_subtitle %}
{% if subtitle %}
  <h3 class=”callout__subtitle”>
    {{ subtitle }}
  </h3>
{% endif %}
{% endblock %}

Component placeholder data in the style guide:

{
  “subtitle”: “Subtitle Text”
}

Drupal block template for integrating a callout component:

{% embed ‘@custom_theme/callout/callout.twig’ with {
  ...
  ‘subtitle’: content.field_subtitle
  ...
} %}
  {% block callout_subtitle %}
    {{ subtitle }}
  {% endblock %}
{% endembed %}

Drupal field template for the subtitle field in our “callout” custom block type:

<h3{{ attributes.addClass(‘callout__subtitle’) }}>
  {%- for item in items -%}
    {{ item.content }}
  {%- endfor -%}
</h3>

Accommodate Attributes All The Way Up

Now that we’ve established some options for accommodating Drupal at the field level, let’s take a look at how to accommodate Drupal in the block template for our callout component example.

One key Drupal feature that’s extremely helpful for content administrators is contextual links. To make these work in our callout component example we’ll need to accommodate the Drupal attributes variable on the main wrapper of the component template, plus include the title_prefix/title_suffix variables. These are what Drupal needs to inject the contextual links into a template.

Since the attributes variable can include class, id, and data attributes in one variable, we need to make sure we only combine Drupal’s classes with ours, and let the other attributes render without Drupal classes. This can be accomplished on the main wrapper of our callout component template:

<div class=”callout {{ attributes ? attributes.class }}”{{ attributes ? attributes|without(‘class’) }}>

Note that the ‘without’ twig filter in this example is a Drupal-specific filter, so for your style guide you’ll want to make sure you’re using one that supports Drupal’s custom filters (both KSS node, and Pattern Lab have configuration options that support Drupal twig filters.)

The other thing you’ll want to include to make sure contextual links get injected are the title_prefix/title_suffix variables. You typically will want to include this around the markup for the main title of the component:

{{ title_prefix }}
<h3 class=”callout__title”>
  {{ title }}
</h3>
{{ title_suffix }}

Make Sure Empty Means Empty

You may recall when first discussing the subtitle for our callout component it was mentioned that it would be an optional field, and in our component template we include an ‘if’ statement to check for a populated subtitle before outputting its related markup. One thing to keep in mind when letting Drupal fully render fields is that even though no content may have been entered for the subtitle on the Drupal side, your component may still read the value of the rendered field as not being empty, and proceed with outputting the markup inside the if statement. This is especially problematic when you have twig debug turned on in your theme.

A reliable way to avoid false positives when checking for empty fields is to check the results of a field after applying the render and trim filters. Example:

‘subtitle’ = content.field_subtitle|render|trim is not empty ? content.field_subtitle

Leave No Content Unrendered

Finally, one last step we’ll want to take in our “presenter” template, is to make sure we allow Drupal to go ahead and do its render thing on the main content variable of the block, even though we’re only interested passing specific field values to our component template. This is again is to help avoid headaches with how caching is handled (read more about this here: https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays). We also need to make sure that we exclude the fields we passed over to our component template since we don’t want them to actually be output in the Drupal template. Example:

{{ content|without(‘field_title’, ‘field_subtitle’, ‘body’) }}

What The Future Holds

As mentioned in the beginning there is also UI Patterns module that many are embracing for a component-driven approach to Drupal site building. The benefit of this module is that it eliminates the need for the “presenter” template when integrating your components.

For now, though, if you find yourself in a position where your Drupal templates are having to serve as the presenter for your components, make sure to consider these ways of keeping things as forward-compatible as possible with Drupal, so that you can take advantage of new Drupal initiatives as their rolled out, and save yourself some headaches later on.

Additional Resources
5 Advantages of Component Driven Theming | Video
Building Components: Breaking it Down | Blog
5 Aspects of Component Driven Back End Development with Drupal 7 | VIdeo

Feb 15 2018
Feb 15

In the past I’ve struggled with the decision of whether or not to start a new Drupal project with a distribution. Since Drupal 8 has evolved I’ve noticed the decision has shifted from whether or not to use one, to which one is the right fit. Two things that are fairly new to distributions are sub-profiles and build tools, both of which have influenced the way I approach a new Drupal project.

Sub-profiles

Sub-profiles are a relatively new thing. While there is still some work to be done in how to manage dependencies and deal with more complex inheritance, inheriting a profile is now possible and in many cases recommended. One example is Acquia's Lightning distribution. Lightning does a good job highlighting the wheels you should not be re-inventing, while also serving as an example of a parent and sub-profile to the well known OpenEDU distribution.

Acquia's article about sub-profiles covers a helpful list of questions to start with such as: Does your new Drupal 8 site need media support? Does it need layout support? As the project develops and matures, are you ready to support the changes that will happen in Drupal core with media and layout, or anything else? As of version 8.3, things like media and layout were only stable enough in contrib, and in 8.4 were only partially moved into core. As of 8.5 and 8.6, workflow, media and layout are planned to be moved into core and stable and will considerably change your site's architecture and implementation. So, with a sub-profile, the specifications for which modules to use and how to use them are now inherited, and not the responsibility of the sub-profile.

Build tools

The next thing to consider is how, or who, is actually building your profile. If you're not thinking about SaaS, (if you are, see Dries's article about making distributions commercially interesting), then you're really targeting developers. Since Drupal 8 development is now entirely composer based, you might want to checkout what profiles are already doing with composer. Here are some examples of composer.json configurations as well as open source tools that you can integrate with composer:

  • Composer scripts - https://github.com/acquia/lightning/blob/8.x-3.x/composer.json - script hooks, (like post-install, pre-install), auto class loading, dependency management, etc.
  • Robo task runner - https://github.com/consolidation/Robo - defines tasks in an auto-loaded PHP class RoboFile
  • Phing build tool - https://www.phing.info - define tasks with a build.xml
  • Testing - PHPUnit test helper methods and classes, as well as addon Behat features and commands
  • Starter content - this currently is just a hook_install script that installs a view with a header, but worth trying out and building on
  • TravisCI integration - with only a few modifications to an existing .travis.yml file you can setup continuous integration for your profile. The existing configuration already handles setting up your server, installing composer and configuring PHP, installing a local browser for testing, headless browser for testing (see composer hooks), installing and re-installing Drupal (see robo), running tests (see behat, phpunit), and development tools for moving files around in your local development environment.

Using a combination of sub-profiles with these build tools have made starting my new Drupal projects more efficient. There is a lot of helpful material out there to learn from, contribute to, and build on. Hopefully this gives you a great start to focusing your new Drupal projects as well.

Feb 15 2018
Feb 15

Thanks again to everyone who has participated in my survey about agile practices in our industry. In this final piece, I would like to share some of my key observations and provide an overview of what has been covered in the previous nine blog posts.

The 30 survey participants provided in-depth answers in 10 different sections with a set of multiple-choice questions and freeform answers. The survey aimed to get a better understanding of how agile practices are established and live in agencies related to the Drupal community.

Survey results overview

  • Part 1 - Initial Observations provides an overview of popular methodologies, project team sizes, iteration length, team integration, how teams stay connected, splitting up the work, client communication and delivery practices.

  • Part 2 - Process Insights gives a deeper understanding of how strictly teams follow the process and which adaptations they have applied.

  • Part 3 - Teams analyses the average team size, where teams work and how teams and projects are paired.

  • Part 4 - Discovery & Planning examines the balancing features and functionality against providing value when talking about work increments and when teams make the discovery.

  • Part 5 - Team Communication & Process is about how teams communicate, how much time they spend in meetings and how client work is balanced against internal or non-billable work.

  • Part 6 - Defining Work analyses the different phases in the ticket process and who is involved in defining work, as well as which tools are essential for organising the work.

  • Part 7 - Estimations provides insights into how teams estimate and by whom estimations are executed.

  • Part 8 - Client Interactions highlights how regularly teams meet with the client and how communication between the team and the client is handled.

  • Part 9 - Practices gives a rundown of how often teams deploy code and compares usage of the various agile practices teams apply to their work.

Key survey takeaways

Having spent some time looking at the data, and processing chunks of the results into the individual blog posts I have mentioned before, was a rewarding task. Even though the number of survey participants was not very high, I believe that the results are appropriate and representable. Apart from the quantitative analysis, I was happy to have asked for freeform answers which provided me with the diversity to allow the survey to be representative.

There is not a single truth to how agile works. In some cases, you'll be able to collaborate closely with the client on a daily basis, in other cases, you will be lucky if you can meet the client every second week. While some agencies have fewer long-term projects, the majority have a mix of smaller and bigger projects regarding size and duration.

Some teams prefer to work integrated across disciplines. Others prefer to have separate teams based on their expertise. From my point of view, active collaboration and communication between teams and clients are essential to create a better product. The way in which this is organised always depends on what works best for the participating individuals and organisations.

An example, where implementing a rigid process can make sense, would be, that we can help the team not to take on too much work. On the other hand, if the process starts getting in the way of everything, we need to remind ourselves of the principle «Individuals and interactions over processes and tools» of the agile manifesto. The process is there to help the team collaborate with the client to produce working software and responding to change as we move forward in the project. The process must be well understood by all role players so that it helps instead of limit our work.

Feel free to dig into the results raw data and please make sure to look at the freeform answers. I tried to summarise some highlights as parts of the series, but there is a lot more to be found from reading them yourself.

That’s it for the agile agency survey results. Thanks again to all the participants and let us know if you have any thoughts on the survey about agile practices.

Feb 15 2018
Feb 15

by Elliot Christenson on February 15, 2018 - 7:01am

We're Drupalers who only recently started digging deep into CiviCRM and we're finding some really cool things! This series of videos is meant to share those secrets with other Drupalers, in case they come across a project that could use them. :-)

In the screencast below, I'll demonstrate how to create a publicly accessible CiviCRM "lead" form. This form will add a contact into your CRM database. In this example, I'll be creating a "Corporate Sponsor Lead" type of form. This is the sort of form you might put into a newsletter email or just have easily accessible by volunteers.

Watch the screencast to see if I run into any issues with the instructions:

Video of CiviCRM secrets for Drupalers: Screencast of Roundearth CiviCRM Profile Forms

Some highlights from the video:

  • Create a CiviCRM Profile with a "Corporate Sponsor Lead" Form
  • Create a ACL to allow this Profile Form to be public

Please leave a comment below!

Feb 15 2018
Feb 15

In an effort to better understand each team member’s unique contribution to iterate, we have begun monthly sessions where each team member gives a 5 minute presentation educating the rest of the team about a specific aspect of their work. It is a great opportunity to not only work on our presentation skills, but it also allows us to learn from each other. We don't take ourselves too seriously so the presentations were fun and informative. Below is a brief overview explaining what each team member spoke about last month.

To kick off 2018 we had our first round of these 5 minute presentations in January. We learned about Why Typography Matters, competing at SEO, Drupal 8 templates, Mental Fitness for Business, and When to Apologise.

Mark started off the presentations with a look at why typography matters. The goal of the presentation was to introduce the team to the basics of typography by discussing the characteristics of different type classifications. We took a look at the anatomy of letterforms in order to be able to identify and discuss different fonts. We also looked at how we read type by looking at negative space, line length and saccadic eye movement. If you didn’t know and we sure didn’t, saccades are rapid, ballistic movements of the eyes that abruptly change the point of fixation. We finished with some practical tips on web typography and advanced typesetting options in text editor tools.

Next, Dale gave us a live demonstration of a Drupal 8 template and discussed the pros and cons of using a template as a basis for a development project. As a company who has spent years discussing the downfalls of using templates, this was an eye opener!

Colin gave us a brief overview of how to compete at SEO. We looked at the consideration to bid on competitor branded keywords in adwords and at related searches to help identify competitor keywords. He also analysed the nature of keywords or phrases and how they can indicate where a searcher may be in their purchase and if they are someone that should be targeted. Lastly, he spoke about crafting content that delivers a superior experience.

Lyndsey and Karen had just come back from a seminar with Neil O’Brien who spoke about the importance of Mental Fitness, specifically when its applied to business performance. Their presentation detailed the three factors that contribute to Mental Fitness:

  • Mood
  • Self Discipline and Habit
  • Resilience and Recovery

While they discussed the details and insights involved with all three of these contributing factors to mental fitness, in the end the steps and exercises taken to improve on each ultimately lead to this conclusion:

“The key to your mental fitness is the ability to do what you don’t want to do when you don’t want to do it”

and the understanding that your potential is on the edge of your comfort zone and that is where mental fitness is. A follow up post will go into this in more detail.

Finally, Gary spoke about the importance of apologising and specifically, knowing when and how to apologise. And on that note, we’re sorry that it’s been so long since we wrote a blog post… we’ve been very busy working on client projects! FYI, you’re not meant to make excuses after you apologise but we're still learning.

Feb 15 2018
Feb 15

Omar Alahmed is a Technical Team Lead at Vardot with more than 10 years experience in web development, specializing in PHP and Drupal. Omar has worked with Drupal since 2007 starting with Drupal 5 and has continued along mastering 6, 7, and Drupal 8.

Omar had multiple motivations to earn certifications, which serve to establish his credibility and expertise. He has achieved Zend Certified PHP Engineer in Sep 2013, Oracle Certified Professional (OCP) MySQL 5.6 Developer in May 2014, Acquia Certified Developer - Drupal 7 in Dec 2014, and most recently, Acquia Certified Developer - Drupal 8 in Jan 2018 and Acquia Certified Back End Specialist - Drupal 8 in Feb 2018.

More importantly, is the added benefit of the time spent reviewing and studying all of the relevant topics and materials that these qualifications are built upon. His deep study of computer science concepts allowed him to step beyond surface-level theory and apply his learnings directly in his application of the code.

We interview Omar about what excites him most working with enterprise Drupal implementations at Vardot.

 

What are the tasks you find most exciting?

I started as a full-stack developer and I always feel that it is the best role for a new web developer. This is because it will introduce you to the broadest view of the web development life-cycle process. Taking this approach will give you exposure and the opportunity to examine what is needed in each phase. However, after getting the needed experience, some tasks may distract you from the deeper technical items. Therefore, I currently prefer to work on more custom tasks, such as using APIs and custom module development.

 

At Vardot, we follow the Agile methodology in our project development life-cycle. This usually begins with a Work Breakdown Structure (WBS), dividing the project deliverables into small chunks, and then assigning them to project’s team members. I prefer to work on the more customized tasks, either on the backend or frontend and to guide and train other team members when needed. For our team, this helps us deliver the tasks in a formalized practice and ensures projects to follow the Drupal best-practices, thus contributing to the Drupal project more often in each project.

 

How did you prepare for the exams? What background knowledge does one need to get Acquia Drupal 8 Developer & Acquia Back End Specialist Certified?

When I received the Acquia Certified Developer - Drupal 7 certification, I realized that the exam truly validates a Drupal developer experience in mastering a Drupal website in a professional and standardized way. It is not a theoretical exam and cannot be passed simply by reading a study guide. Practical experience in developing web applications, like the work I do at Vardot, is required to succeed.

 

At Vardot we always strive to follow and endorse the best practices in development and apply it to different types of projects. Given this experience, I didn't find any difficulties during the preparation for the exam. I made sure to review the study guide links that were provided by Acquia and found ways to programmatically apply the topics that I had not worked with before. This allowed me to apply these topics in action instead of only reading about them.

 

Anyone pursuing this certification would probably agree that programming is an experimental science. In order to obtain the reusable knowledge at hand, you must write code and repeatedly practice. This method will help you expose problems that you may not be been introduced to before. I found that the published Acquia documentation is a good start for module development, as well as the Drupal API documentation.

Particularly:

Coding Standards: https://www.drupal.org/docs/develop/standards

Block API: https://www.drupal.org/docs/8/api/block-api

Form API: https://www.drupal.org/docs/8/api/form-api

Cache API: https://www.drupal.org/docs/8/api/cache-api/cache-api

Routing API: https://www.drupal.org/docs/8/api/routing-system

Theming API: https://www.drupal.org/docs/8/theming

Don't panic if you don't have an enjoyable experience in the Drupal API or module development resources. The key takeaway is to get an overview of the topics and then apply as much as you can.

 

Preparing using the above material is very important for both the Developer and Back End Specialist exams. The Developer exam covers advanced topics, but it also encompasses site building skills, such as working with content types, blocks, taxonomies, and views.

 

The Back End Specialist exam touches everything about Drupal API, performance, security, contributing to the community, and how to apply these techniques in real tasks by giving real scenarios or problems and asking to resolve them in the best way. So make sure to understand Drupal 8 core’s structure, and to do more hands-on practices before taking the exam, especially if you are not familiar with the latest PHP and OOP development techniques such as design patterns.

For further information about the content of the exams, you can check out the study guides for Acquia certification exams and an overview of Acquia Certification Program.

 

What are some tips you would give other developers working on Drupal 8?

As a Drupal 8 developer, you have probably observed that the Drupal community is the most important factor that places Drupal as the top web development platform. Therefore, I would say to try to interact with the community members; don’t work alone, don’t repeat yourself, and be cooperative as much as possible. If you find a bug or need a new feature, feel free to create a new issue in the project. You can also resolve, test and patch it to enable all Drupalers around the world to benefit along with you.

 

You’re probably aware that Drupal 8 is built on top of many Symfony2 components, like DependencyInjection, EventDispatcher, and Routing, with some customizations to be suitable for Drupal needs. With that in mind, it's a good idea for you to traverse how the core uses these components in order to facilitate and speed up your Drupal development. It’s important to always use the Drupal core code as an example if you need to write custom code because it will illustrate the best way to proceed and enlighten you what APIs are available for use. This helps you learn by example.

Summary

Omar Alahmed gives us a great example of what it takes to demonstrate success as a specialized developer in the Drupal community. Through his exhibited certifications, we can assume Omar's background required many dedicated hours of hard work and study. But we can also see that he was preparing for more than just certifications. Omar shows a passion for web development community at large, offering his advice as a team lead on what it takes to be a successful team player. His method of approaching problems and finding new ways to create solutions using industry best practices and established patterns makes Omar an invaluable member of our development team at Vardot.

Feb 15 2018
Feb 15

Omar Alahmed is a Technical Team Lead at Vardot with more than 10 years experience in web development, specializing in PHP and Drupal. Omar has worked with Drupal since 2007 starting with Drupal 5 and has continued along mastering 6, 7, and Drupal 8.

Omar had multiple motivations to earn certifications, which serve to establish his credibility and expertise. He has achieved Zend Certified PHP Engineer in Sep 2013, Oracle Certified Professional (OCP) MySQL 5.6 Developer in May 2014, Acquia Certified Developer - Drupal 7 in Dec 2014, and most recently, Acquia Certified Developer - Drupal 8 in Jan 2018 and Acquia Certified Back End Specialist - Drupal 8 in Feb 2018.

More importantly, is the added benefit of the time spent reviewing and studying all of the relevant topics and materials that these qualifications are built upon. His deep study of computer science concepts allowed him to step beyond surface-level theory and apply his learnings directly in his application of the code.

We interview Omar about what excites him most working with enterprise Drupal implementations at Vardot.

 

What are the tasks you find most exciting?

I started as a full-stack developer and I always feel that it is the best role for a new web developer. This is because it will introduce you to the broadest view of the web development life-cycle process. Taking this approach will give you exposure and the opportunity to examine what is needed in each phase. However, after getting the needed experience, some tasks may distract you from the deeper technical items. Therefore, I currently prefer to work on more custom tasks, such as using APIs and custom module development.

At Vardot, we follow the Agile methodology in our project development life-cycle. This usually begins with a Work Breakdown Structure (WBS), dividing the project deliverables into small chunks, and then assigning them to project’s team members. I prefer to work on the more customized tasks, either on the backend or frontend and to guide and train other team members when needed. For our team, this helps us deliver the tasks in a formalized practice and ensures projects to follow the Drupal best-practices, thus contributing to the Drupal project more often in each project.

 

How did you prepare for the exams? What background knowledge does one need to get Acquia Drupal 8 Developer & Acquia Back End Specialist Certified?

When I received the Acquia Certified Developer - Drupal 7 certification, I realized that the exam truly validates a Drupal developer experience in mastering a Drupal website in a professional and standardized way. It is not a theoretical exam and cannot be passed simply by reading a study guide. Practical experience in developing web applications, like the work I do at Vardot, is required to succeed.

At Vardot we always strive to follow and endorse the best practices in development and apply it to different types of projects. Given this experience, I didn't find any difficulties during the preparation for the exam. I made sure to review the study guide links that were provided by Acquia and found ways to programmatically apply the topics that I had not worked with before. This allowed me to apply these topics in action instead of only reading about them.

Anyone pursuing this certification would probably agree that programming is an experimental science. In order to obtain the reusable knowledge at hand, you must write code and repeatedly practice. This method will help you expose problems that you may not be been introduced to before. I found that the published Acquia documentation is a good start for module development, as well as the Drupal API documentation.

Particularly:

Don't panic if you don't have an enjoyable experience in the Drupal API or module development resources. The key takeaway is to get an overview of the topics and then apply as much as you can.

Preparing using the above material is very important for both the Developer and Back End Specialist exams. The Developer exam covers advanced topics, but it also encompasses site building skills, such as working with content types, blocks, taxonomies, and views.

The Back End Specialist exam touches everything about Drupal API, performance, security, contributing to the community, and how to apply these techniques in real tasks by giving real scenarios or problems and asking to resolve them in the best way. So make sure to understand Drupal 8 core’s structure, and to do more hands-on practices before taking the exam, especially if you are not familiar with the latest PHP and OOP development techniques such as design patterns.

For further information about the content of the exams, you can check out the study guides for Acquia certification exams and an overview of Acquia Certification Program.

 

What are some tips you would give other developers working on Drupal 8?

As a Drupal 8 developer, you have probably observed that the Drupal community is the most important factor that places Drupal as the top web development platform. Therefore, I would say to try to interact with the community members; don’t work alone, don’t repeat yourself, and be cooperative as much as possible. If you find a bug or need a new feature, feel free to create a new issue in the project. You can also resolve, test and patch it to enable all Drupalers around the world to benefit along with you.

You’re probably aware that Drupal 8 is built on top of many Symfony2 components, like DependencyInjection, EventDispatcher, and Routing, with some customizations to be suitable for Drupal needs. With that in mind, it's a good idea for you to traverse how the core uses these components in order to facilitate and speed up your Drupal development. It’s important to always use the Drupal core code as an example if you need to write custom code because it will illustrate the best way to proceed and enlighten you what APIs are available for use. This helps you learn by example.

Summary

Omar Alahmed gives us a great example of what it takes to demonstrate success as a specialized developer in the Drupal community. Through his exhibited certifications, we can assume Omar's background required many dedicated hours of hard work and study. But we can also see that he was preparing for more than just certifications. Omar shows a passion for web development community at large, offering his advice as a team lead on what it takes to be a successful team player. His method of approaching problems and finding new ways to create solutions using industry best practices and established patterns makes Omar an invaluable member of our development team at Vardot.

Feb 15 2018
Feb 15

This is an export of my session from DrupalCon Baltimore 2017. This is here for posterity. The least effor possible was put into trascribing it from presentation format to a web page.

In case you are wondering

You are here in the galaxy

Hello My Name Is Frank

I am a Christian, Father, and Technology Enthusiast.

Clarity Innovations Logo

Clarity Innovations is a professional services firm based in Portland, Oregon focused on providing K-12 and higher education technology consulting to non-profits, schools, and corporations.

We develop solutions for our clients including strategic consulting, professional development and content creation, and engineering solutions such as apps, web apps, and websites to help improve the process and practice of teaching and learning.

One such site is a custom LMS for our clien New Perspectives Online.

New Perspectives Online Screenshot

Why do [Drupal 8 Exparamentation]?

  • The big question is D8 or D7, this is a question that I have to ask myself every time I am asked to do an estimate.
  • How do we pick which version of Drupal to use?
  • Let me GET THIS OUT THE WAY I will not be going over hard numbers for building with one version over the other. I will give you the only answer that I can give knowing what I know about your project's requirements. IT DEPENDS.

Bottom line

  • I create with Drupal 7.
  • I want to create with Drupal 8.
  • I want to know the differences between creating with Drupal 7 vs 8.
  • I would like to know how I can leverage the new features of Drupal 8 in complicated information systems.

Lets go from:

Frame from LOTR - I will take the ring to Mordor

To:

Frame from the movie the hobbit - I am going on an adventure

Custom LMS Architecture

Learning Management System

An LMS is software that allows for the organization and delivery of courses or training programs.

LMS Architecture

Need to deal with some prerequisite information so we all understand the goals of the project that I used as my test bed.

  • What is an LMS? An LMS is a Learning Management System.

It is software that allows for the organization and delivery of courses or training programs. If you have used buildamodule.com or drupalize.me then you have used a LMS.

Traditional LMS

Our custom LMS is structured

Basic Drupal Architecture

Forced tutorial

In order to make sure we are all on the same page moving forward I need to talk about some basic Drupal Architecture. If this is review for some of you, I am sorry for the unskippable tutorial level.

Basic Drupal Content Architecture

Don't worry I will mostly just be talking about Entities, Fields, and Variables.

Entities

Entities are things in Drupal; things do not have to be nodes.

  • Entities are things in Drupal, starting in drupal 7 we got content entities.
  • In Drupal 6 custom things where typically nodes or totally custom
  • In Drupal 7 the entity-field system brought the CCK into core without making everything a node
  • Drupal 8 has a fully fledged entity api which is derived from the capabilities of the contrib entity api module for drupal 7.
  • Users, Taxonomy Terms, and Nodes, are all Entities

Bundles and Fields

  • A bundle is a collection of fields instances on an Entity
  • A field instance is a place for complex data in a Entity Bundle
  • A property is simple storage for Entity level data

An Entity can have Bundles to allow for multiple collections of fields instances on a single type of entity. - Field instances are unique to that bundle. - An Entity has properties which span all bundles. - created date - node status - who created are all properties - A field instance is a place for complex data in a Entity Bundle - A property is simple storage for Entity level data

Properties

Properties are linked to an Entity, such as Node. Fields are linked to the Bundle, such as Content Type.

Properties are stored on the entity's table and fields are stored in their own table.

Variables

Variables are what Drupal 7 provides for configuration --when it isn't a custom table.

LMS Features

Support Backwards Design philosophy

  • Site Features
  • Traditional LMS
    • Collection of Curriculum or Lesson plans
      • Collection of Unit or Module
        • Collection of Lesson/Project/Assessment/Mini-lessons
  • Curriculum Designer will often use a Backwards Design philosophy
  • Starts Standards/Topical they with to teach

Goals of lesson planning

Using the 5 e's as the goals of lesson planning.

  • Engage
  • Explore
  • Explain
  • Elaborate
  • Evaluate

LMS Lesson Goals

  • Teaching
  • Application
  • Assessment

Thus Goals for Lesson Plan Features.

  • Activate Prior knowledge
  • Modeling or Teaching
  • Practice
  • Application
  • Assessment

Our custom LMS is structured as

-   module -> menu
    -   segments -> nodes
        -   components -> paragraphs items

Drupal 7 Modules Used

Frank's list of modern site building tools

I gave a talk on modern Drupal 7 development at a meetup in Portland last year, and I am not going to go into great detail here. I wrote a blog post about it and if you would like more details I suggest you look there.

  • I will go over the modules that this site used (in its core functionality), what they do.
  • Later I will go over how they relate to Drupal 8.
  • Remember when building a site that the output that drupal give us is always a suggestion. The important part of site building is giving the content team everything they need, you can leave it up to the developers and themers to make sure that the content gets displayed properly.

Paragraphs

Paragraphs allows us to create collections of fields. Each collection type is its own bundle and can have its own fields.

  • Paragraphs -- If you are familiar with field collection then this module functions very similarly, with the main exception of the user being able to pick the bundle or paragraph type when creating content.

Entity Form

Named eForm in Drupal 8. Allows the use of the field api to create webform and have the submissions be entities.

  • Entity Form -- In Drupal 8 this module was renamed to eform. The cool part of this module is that it allows us to use the field api to create webforms. Unlike the webform module, the form submissions are entities. This gives us flexibility use in views or displaying them with multiple view modes.

Eva

Solves the problem of putting views into entities as pseudo-fields.

  • EVA -- Entity View Attachment. Allows us to embed views into fields. Handy for things like Taxonomy term views or anywhere an ID can be used as an argument in a view.

Flag

This module allow users to flag things. Largest use is probably the "Flag this as inappropriate" functionality.

  • Flags -- This module allow users to flag entities. Largest use is probably the "Flag this as inappropriate" functionality.
  • The last two modules don't have much to do with this site per-se but they are fantastic modules that will really help a site-builder.

Coffee

Coffee works like Unity for Ubuntu or Spotlight search for Mac, or the Start Menu in Windows. Just start typing and a list of options will be presented. Pick the option and it will take you there.

  • Coffee -- Speed up your Drupal navigation by typing where you want to go. Much like unity for Ubuntu or Spotlight for Mac or Start for Windows, this module allows us to zip around our site's admin interface with ease.

Speedboxes

Check more than one box with a click and drag mechanic.

  • Speedboxes -- Allows us to check multiple checkboxes at the same time. Super useful for setting up permissions.

A word on Blocks

Bean

Bean is an acronym that stands for:

Block Entities Aren't Nodes.

  • This is not a block heavy site
  • It works mostly as an app with the blocks only really being used to place active menus on the screen.
  • This is mainly because there are not many reusable pieces to the site. If it isn't a page level thing then it really isn't a part of this site.
  • This site doesn't use blocks, but when I use blocks I build them with BEAN.
  • Bean gives us all the functionality of building content types with nodes except with blocks instead.
  • I normally add a content view for beans at /admin/content/blocks and I disable the default drupal block management stuff, with the exception of block placement. because that is still necessary.
  • But again, this site didn't make heavy use of blocks.

I don't always use blocks, but when I do I use the bean module

I don't always use blocks, but when I do I use the bean module

LMS Content Strategy

Arguably, the most important part of a site.

  • Content Strategy
  • Now thats out of the way we can talk about the site's content strategy.

13 paragraphs types and 1 content type

In the end our site had 13 paragraphs item bundles for 1 content type and three where interactive.

  • Text response
  • Checkbox list
  • Drag and Drop
Text response

Checkbox list

Drag and Drop

The rest are multimedia/content.

Everything can be combined to form larger whole components.

  • Four where used for custom inter and intra module navigation
  • The rest where videos, image, and text.
  • all can be combined to form larger whole components.

Linking the EntityForm Submission to the Paragraph item

Entity | Machine Name ----------------- |---------------- Paragraph Type | text_response EntityForm Type | text_response

Linking the EntityForm Submission to the Paragraph item, each interactive paragraphs item had a corresponding entity form with an entity reference back to the paragraphs item that displayed the form. We used the paragraphs item's bundle machine name to pick the bundle of the EntityForm to display.

We put this all together, using Drupal's ingenious render array system that doesn't care if it is displaying a form, or content, or anything themable, we where able to HULK smash the entityforms into the paragraphs item displays and save any users response and know what they where responding to and who was responding to it.

Evaluation

Sharing via Flags on the paragraphs items

We also had to allow for self evaluation. Our client wanted users to be able to share their responses and learn from the responses of others. So we used flags that let the users share their responses, in turn if they share their response then they see their peer's responses and then they can edit their old response and save a new one.

Our initial expectation was that we would have to build out all the content in a spreadsheet and at one point I was building a migration to import all the content from a CSV. Choosing the Paragraphs module gave our content editors an interface that allowed them to build the content in the site as we where adding functionality.

Custom Development

The meat of how we are putting this together is in the hook_entity_view_alter implementation and the hook_form_alter implementation.

Pass the build to custom function

<?php
        if (!empty($build['#bundle'])) {
          $bundle = $build['#bundle'];
          if (function_exists("_component_{$bundle}_alter")) {
            // We need to pass build in an array in order to trick call user func
            // into passing the build by reference.
            call_user_func("_component_{$bundle}_alter", array(&$build));
          }
        }

Remember we used the bundle type machine names to add the correct entity form types? We do that with call_user_func which calls a function based on the name we give it. We check beforehand if the function exists, this way it is extensible without having to modify too much existing code. So if we want to add another interactive element we can do so without modifying anything to do with our current interactive elements.

Text response callback

<?php
    /**
     * Implements custom _component_TYPE_alter().
     */
    function _component_text_response_alter(&$build) {
      if (isset($build[0]['#entity']) && !empty($build[0]['#entity']->item_id)) {
        module_load_include('inc', 'entityform', 'entityform.admin');
        $entity_form_name = 'text_submissions';
        $component_id = $build[0]['#entity']->item_id;
        $entity = $build[0]['#entity'];
        $form = _get_entityform(entityform_empty_load($entity_form_name), array('component_id' => $component_id, 'entity' => $entity));
        $form['field_component_submission']['#attributes']['class'][] = 'element-invisible';
        // ... Other Stuff ...
        $form['field_text_response_submission']['#attributes']['class'][] = 'component-input-no-label';
        $form_rendered = drupal_render($form);
        $build[0][] = array(
          '#type' => 'markup',
          '#markup' => $form_rendered,
          '#prefix' => '<div class="component-text-response">',
          "#suffix" => '</div>',
          "#weight" => 100,
        );
      }
    }

In the case of the text response this checks for a valid callback and runs this code to include the entity form.

Then in the form_alter we change the actual form options or the text area label to use the correct text.

Things get complicated at this point, because ajax. We have to ajaxify each of the paragraph items. I'm not going to go into code here because that would just be boring, and it is better documented elsewhere.

An interesting thing about saving a response is, only after it is saved can we make the paragraphs item sharable. Then after it is shared only then can we make show the shared responses. All of these things required heavy development for Drupal 7, and will likely also require lots of custom work for Drupal 8 too.

Considerations Building a LMS with Drupal 8

  • Architectural differences
  • UI Changes
  • Module availability
  • Specifically What needs to change
    • Architecture
      • Custom Development
        • Content strategy

General Drupal 8 Considerations

  • devel kint debugging DO NOT USE KUMO it doesn't work on real objects
  • no longer cache clear now cache rebuilding
  • No more module disable, uninstall or die
  • Enable developer mode
  • Nice thing is that there is lots of information available already for Drupal8 the problem is that there is lots of bad information available for Drupal 8. Check your sources and do not expect everything you read to actually work. Even d.o documentation can be out of date. poll module example.

Architectural Differences

I am not going to give you an exhaustive list of new Drupal 8 features and in the end I will just give you a list of things to google.

Configuration Entities

I am not going into detail about them other than to say generally that the configuration management initiative changed so much with regard to developing and deploying Drupal. All for the better. If you are committed to stick with the db-sync workflow, it still works with Drupal 8 but really learn as much as you can about configuration entities and what you can do with them. Really this could be a talk or two on this, and I don't have the time in this talk to do them justice.

I will say that configuration entities gives drupal a place other than a random variable to store configuration and keeps developers from having to manage a bunch of tables if they needed something more complex than a simple variable could offer.

Blocks

Blocks now function much like nodes insofar as they are full fledged entities with bundles and fields.

Blocks still have an Achilles heel in that they are both content and configuration. The content lives in the database and isn't easy to export and sync and the placement of the block is configuration and is easy to sync. This can lead to embarrassing deployment gaffs. Where the placement of a block that doesn't exist is possible. Here is a good article about avoiding that.

Display Modes

Content View Modes

If you used the entity view modes modules or display suite to provide view modes for content types and such, then you should already be familiar with this. If you don't know what view modes are, they are ways for providing different ways to display the same content. So for a node we could have a teaser or a full view mode or a grid view mode. Basically anything that the design called for. These existed for content in Drupal 7 but they required a contrib module such as entity view modes or the display suite module to configure them without code. Drupal 8 gave a full fledged UI to work with.

Form View Modes

All that stuff I said about being able to display content in different configurable ways now also applies to forms with Drupal 8. So, as an example, let say you have a very complicated user registration form because your client wants to collect a bunch of information about the user, but none of it is required. Now you can create a new simplified form for adding users. You can do this in the UI in Drupal 8.

Things to google (many have been backported to Drupal 7)

  • Composer support
  • Toolbar update (Navbar in Drupal 7)
  • Responsive Image Styles (Picture Module in Drupal 7)
  • File Entities
  • RESTful api
  • Experimental Core Modules
  • Content Moderation
  • etc...

UI Changes

Good News! Not much has changed significantly in the UI. I guess that could be bad new too.

  • This is going to be brief, mainly because the UI changes are minimal.

Operations

New Drop down thingy for selecting what we are doing to a thing. One change is Operations now go in a drop down with the maybe most common one first? Really I don't know how that was chosen so if someone here does know please tell me afterward.

Form Display Settings

Multiple entity form settings on the Manage form display page, this includes field widget settings.

Another change you will find between D7 and D8 I have already hinted at with the Form View. If you have a alternate node form then you will find the option for editing that form view in "Manage Form Display" section. This also means that controls for the form widgets are configured on the form view display settings and not the "Manage Fields" page. Mange Fields is now entirely about the field and its storage.

Good news about learning curves

The Drupal learning curve

Good news, there are fewer changes for site builders who are coming from Drupal 7 to worry about. Bad news is for someone coming from not Drupal the perceived Drupal learning curve could be intimidating.

Module Availability

elephant in the room

Big problem with my re-architecture exercise.

EntityForm is not supported on Drupal 8.There is a discussion about whither or not this module is necessary. I of corse believe the module is necessary. However, this doesn't make the module stable today. The module works well enough for this experiment, but if this where a full client project we would have to explore some options.

  • Find an alternative

    • Custom Entities are an option
    • Comment module
    • Contact module extras
    • Relation module

    Didn't bring this module up in the modules used because we didn't use it, but this is a really cool module. This module has the ability to supplant the functionality of flag and organic groups. It adds the concept of entity endpoints which allow us to make fieldable relations between entities. In the example of this LMS that entity would have all the fields for the response, an endpoint for the paragraphs item (renamed paragraph revision for Drupal 8), and an endpoint for the user.

    I have used this module for saving user state in js apps and for keeping track of users completion status for resources in custom Professional Development portals. - Fund the development of a stable release.

    While I do encourage finding alternatives, at this state in Drupal 8 development I would encourage us to choose the final option because, frankly, aside from the comment module none of the above options are any more stable than eform and more importantly Drupal 8 needs more stability in contrib.

Second problem - Paragraphs doesn't want me to reference paragraphs - It is possible, but requires use of the EXPERIMENTAL field widget. The main reason this is EXPERIMENTAL is that the paragraphs modules is not mean to be used to reuse content, that is more of a function of blocks. I spent more time on this than I would have liked, due to some of Drupal 8's UI changes that I didn't fully understand. But it turned out to be a non-problem. - In this case the problem wasn't the module but my own unfamiliarity and over confidence. The answer was staring me in the face.

Baby Elephant

So we do have an elephant, but it is just a baby elephant.

Specifically What needs to change

Not Much

  • This site works more like a an app than a traditional site, this means we have slightly different expectations when choosing a Framework.
  • Drupal was chosen for its scaleability, strong user centric or permissions based content model, high quality contrib space, and familiarity. As I said before I have been doing drupal professionally for close to 10 years, so I am very familiar with the project, community, and workflow. However, I am constantly looking into other technology and I have built things with other tech when Drupal isn't the best choice, so this isn't a statement coming from the island.
  • Drupal 8 has lots of new Features but the biggest advances have been in underlying architecture (with the content/config entity system) and development workflow (with the switch to Semantic Versioning).

Architecture & Content Strategy

Mostly the same

Custom Development

Biggest Changes

  • The largest change is the addition of developing a stable release for whatever we use for the response saving.

Custom Development

This is where the largest changes where made.

  • Custom development
  • This is where the largest changes where made, but maybe not where it was expected.

Not Much

  • We still use hook_entity_view_alter
  • We still use hook_form_alter

  • In Drupal 7 we accomplished the HULK SMASH part, where we smash the form from the entity form into the display of the paragraphs item, with a hook_entity_view_alter implementation coupled with a hook_form_alter implementation. In Drupal 8 with its Object Oriented Architecture I was able to accomplish it in the exact same way.

Incoming Transmission

  • "But Wait" you say, "Drupal 8 is OOP we aren't supposed to put stuff into the .module file anymore. That is just there for decoration!"
  • Oh no, the joy of modifying aspects of the program with hooks is not gone in D8. Hooks are good things, and even though Drupal is want to change things with new version and add modern development practices to Drupal, Drupal also isn't going to ditch what is likely the most flexible pattern of php development just because it stepped in some OOP.

Okay, really lots

But all good!

  • The Object Oriented Architecture is designed to make common things easier.
  • For example.
  • When building this with Drupal 7, we had to reimplement parts of the form builder from the entity forms module in order to display entity forms programatically. This was likely due to the incomplete nature of the entity api in Drupal 7.
  • In Drupal 8 the entity api is far more flushed out. We still use Entity Field Queries to get the EntityForm Submission for the current user and the current paragraph revision, but this time Drupal has an api for creating the empty EntityForm submission object if the user has never submitted. And it has an interface for building forms for Entities, new or old. Thus we can get a form for a new entity in the same way we get the form for the old entity, with all the right fields filled in.

Drupal 8 version:

<php
    // This creates a new eform submission.
    $eform_submission = \Drupal::entityTypeManager()
      ->getStorage('eform_submission')
      ->create(['type' => 'multiple_choice_question']);
    // This loads an existing eform submission.
    $submitted_eform = \Drupal::entityTypeManager()
      ->getStorage('eform_submission')->load(2);
    // Either way we build the form with a call to the entity.form_builder service.
    $form = \Drupal::service('entity.form_builder')
      ->getForm($submitted_eform);
    // Then we append it to the render array.
    $build[] = $form;

  • To build a new entity, this could be a node, eform_submission, or comment, We user the Drupal::entityTypeManager class and call the create method or to load an existing one we use the same class with the load method and the entity id.
  • Then we user the entity form builder service to build the form for the entity. I tested this with nodes as well. It is the same generic interface for all content entities.

  • No more Drupal 7 non-existent entity api

  • Drupal 8 has intelligent use of OOP that makes site building easier

  • Over 100 lines of code is reduced to under 10

Incoming Rainbow

  • No more Drupal 7 non-existent entity api
  • Drupal 8 has intelligent use of OOP that makes site building easier
  • Over 100 lines of code is reduced to under 10
  • Mind Blown

The End

Don't take things so seriously

When are sprints?

April 24-27: Sprint Lounge at Baltimore Convention Center

April 28: Sprint Day - General Sprints, Mentored Core Sprint, First-Time Sprinter Workshop at Baltimore Convention Center

We also provide a 24-hour Sprinter Lounge that opens on April 24th at 7:00pm and will close on Thursday, April 27th at midnight. The Sprinter Lounge will be located at the Hilton Baltimore (401 West Pratt Street) in room Peale A-C.

Based on community feedback and input from the Sprint Leads, we understand the need for 'shorter sprints with greater support', and as a result will not be hosting Extended Weekend Sprints at this DrupalCon.

Feb 14 2018
Feb 14

by David Snopek on February 14, 2018 - 4:57pm

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

Today, there is a Moderately Critical security release for the Custom Permissions module to fix an Access Bypass vulnerability.

This module enables the user to set custom permissions per path.

The module doesn't perform sufficient checks on paths with dynamic arguments (like "node/1" or "user/2"), thereby allowing the site administrator to save custom permissions for paths that won't be protected. This could lead to an access bypass vulnerability if the site is relying on the Custom Permissions module to protect those paths.

After applying this patch, go to the "Site Configuration Permissions" page and click "Save". If the form saves without errors, your site isn't vulnerable. If you get an error, delete the permission or correct the patch per the information in the error.

See the security advisory for Drupal 7 for more information.

Here you can download the Drupal 6 patch.

If you have a Drupal 6 site using the Custom Permissions module, we recommend you update immediately! We have already deployed the patch for all of our Drupal 6 Long-Term Support clients. :-)

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

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

Feb 14 2018
Roy
Feb 14
Screenshot of the google hangout for the UX meeting.

Some links that might help sketch the outlines of what a “Drupal admin UI revamp” might involve.

At Drupalcon Vienna there was a lot of interest and preparation work done around modernizing the Drupal administrative interface. I wrote up a high level summary here. As a result this initial issue was posted.

My previous post with a small concept for the editor UX triggered some interesting discussion on Twitter.

We also discussed this topic during yesterdays UX meeting.

As a result, ckrina now proposes an initial round of research to learn and get inspiration from other systems. Mind you, this is the woman that brought us the redesigned status report page and is a member of the team that made the Umami demo that’s now in core. Good things can come from this!

Your help in researching these topics is very welcome. Have a look.

14 Feb 2018

Feb 14 2018
Feb 14

Sometimes you need to make custom modifications to a composer package. Assuming that your modification is a bug fix, the best approach is to file an issue with the package's issue queue and submit the fix as a pull request (or a patch file when dealing with Drupal projects). Then you can use the composer-patches plugin to include the change in your project.

However this doesn't always work. I had a need to modify the composer.json file of a package that my project used. I tried creating a patch to modify it as I mentioned above, but composer didn't use the patched changes to composer.json. I imagine this is because a package's composer.json file is parsed before composer-patches has a change to modify it.

So the next best thing is to fork the package you need to modify to make the changes you need. The package I was modifying was already hosted on GitHub, so I forked it, made my change in a new branch, and pushed it up to my fork.

From there, I just had to change my project's composer.json file to add my fork to the list of package repositories to scan when looking for project dependencies. This is described in composer's documentation. I changed the version to "dev-my-branch-name" as instructed.

But for some reason, composer was still refusing to use my version of the repo. After more digging, it turns out that's because composer looks at the default branch of the forked repo to "discover" what package it is. Turns out my fork was really old, and the default branch was an older branch. This old branch of code used a different name for the package in it's composer.json file! The package name needs to match exactly what you have in your project's requirements list. To fix this, all I had to do was sync the default branch of my fork with the upstream.

Feb 14 2018
Feb 14

drupal-console

05812d0 [console] Tag 1.6.0 release. (#3782)
3f64cc1 Add form element for the status and make name field required (#3775)
b596bfe Replace invalid commands service with console container (#3759)
5306d69 [site:install] Load commands after site installation. (#3776)
2e7e1b3 Small bugfix for update:execute, removing extra unneeded parameter from runUpdates. (#3757)
7273643 [console] Add new option for generate ajax commmand. (#3755)
dfbca67 [site:install] Fix dbHostQuestion ask null. (#3754)
b386af7 [license] Update version GPL-2.0+ is deprecated. (#3752)
85766ba "[console] Pass DrupalFinder to DrupalConsoleCore." (#3751)
76f005b [console] Show message only on list command. (#3750)
a8a6aa1 3729 role improvements (#3745)
dcc986f [locale:language:add] Add multiple languages as arguments (#3738)
4573260 A new format output for adding new fields (#3747)
0b6f4c4 (origin/master, origin/HEAD, drupal/master) Adding ArrayInput trait. Add spaces for contantination. Fix the bug with missing default_code (#3743)
281b4e8 Fix parameter class. (#3742)
f68bcf9 [generate:module] Fix parameter name. (#3741)
7d827bd [console] Add DrupalFinder as service. (#3740)
e98a6f7 [generate:help] Fix duplicated use statement. (#3739)
40ec43d Implementation of GeneratorInterface (#3737)
4b480ce [generate] Implement GeneratorInterface fixes. (#3735)
52c9638 3515 form trait input multi values (#3734)
bac0de0 [theme] Refactor theme commands. Fix #3696 (#3703)
0ee42c6 [console] Apply PSR-2 code style. (#3732)
e203274 Implementation of generator interface (#3731)
b0a14a8 Replace default value and update handling of Enter input from the user (#3730)
c1c7deb [generate:command] Replace null with empty string as default value on choiceNoList. (#3728)
6523926 Add symfony/thanks Composer plugin (#3727)
f24306f [user:create] Remove email default value. (#3726)
b48099c [console] Remove un-usued createGenerator legacy method. (#3725)
82df098 [user:create] Set email default as empty string. (#3723)
fe34f5f [user:create] Remove email default null value. (#3724)
46c6303 Add support of multiple values for breakpoints option, when we use inline options (#3713)
7f8a6eb [generate:controller] Add default value. Fix #3719. (#3722)
0fb1b34 [console] Remove useless traits and death code. Fix #3716 (#3717)
c9d2e62 [generate:ajax:command] Update Generator to implement GeneratorInterface. (#3721)
edd12a9 [generate:command] Add generator option. (#3720)
723d580 Add new trait ArrayInputTrait, which will parse nested data. Switch muti value options to array to handle them properly, when receive params through the options (#3712)
ca88d11 Fix cs for AuthenticationProviderCommand (#3709)
d9cce58 Fix cs for AjaxCommand (#3708)
c3a8b53 [generate:ajax:command] Change command extend Command not ContainerAwareCommand. (#3706)
80cde77 [generate:command] Add initialize option. (#3704)
cfd8ad6 Remove unused variables (#3702)
dea5fee [console] Remove unused vars in feature trait. Fix #3686. (#3692)
5fa51d1 Fix translation for generate ajax command. (#3690)
02acda8 Remove Drupal core code drupal_set_message in theme install and uninstall commands. Fix the message for theme install command when dependencies are not met (#3697)
4a8746c [generate:module] Fix issues with .info template. (#3689)
dd25b2a Add extension annotation to views command. (#3688)
2bf3d00 [console] Replace DrupalStyle object usage. Fix #3685 (#3691)

drupal-console-core

f998ed7 [console] Rename method getDrupalMessages to addDrupalMessages. (#316)
6abeb9e [console] Propagate Drupal messages to Drupal Console (#307)
d9b655d [console] Remove extra directory separators. (#315)
094c050 [console] Return empty array if no config directories found. (#314)
cce0dbe [console] Validate file exists when phar is running. (#313)
483b8c6 [generate:site:alias] Validate no sites found. (#312)
63b8424 [debug:sites] Change invalid sites error as warning message. (#311)
97b9a31 [debug:chain] Add warning message when no chain files found. (#310)
6862cba [console] Pass default value when calling invalid_commands. (#309)
4c7962a Replace direct access to sites with getSites (#305)
4d59986 Add Console container class replace call of invalid commands (#304)
7bbdebd [console] Relocate command registration to loadCommands method. (#308)
a80391b (tag: 1.6.0) [console] Tag 1.6.0 release. (#303)
d7bd067 [console] Add DrupalFinder as constructor argument. (#302)
b018bdf [license] Update version GPL-2.0+ is deprecated. (#301)
a299179 [chain] Update example chain command name. (#300)
7c27d70 [console] Rollback Generator implement interface. (#299)
8abd821 Generator interface implementation (#294)
d4f12a4 [console] Add showBy to messageManager. (#298)
3b4d66f [chain] Improve chain discovery strategy. (#297)
a75d712 [console] Change warning message background color. (#238)
cae7eed [list] Remove messages when format is not txt. (#296)
fe4ea26 Remove aliases crr and mod (#295)
62164ee [console] Remove use operators. (#293)
51ddcb2 [console] Add validator parameter to askEmpty method. (#292)
413fd78 [generate:site:alias] Use correct template path. (#291)
230f94a [console] Add docblock to generate method. (#290)
8c0ded0 Replace DrupalStyle object with getIo (#285)
54b28d8 [generate:site:alias] Add new command. (#282)
0c4e7f6 [console] Add drush mappings and aliases (#281)
72833b3 [help] Improve options display. (#280)
07a5aa8 [chain] Add support to parse twig. (#279)

drupal-console-en

5f072c7 [debug:chain] Add no-files translation. (#174)
db5372d Add question mark for questions (#152)
8532f0f Fixed syntax found in error message (#171)
34cc14f [console] Fix debug namespace references. (#170)
cbe2cd0 [console] Update generic generated lines message. (#169)
3236088 Fix placeholders quotes (#167)
57dbd26 (translation-fixes) Update translations for generate ajax command. (#166)
ed009cc Wrap %s with double quotes (#164)
b918d3e [site] Update language keys. (#165)
3e4673e [license] Update version GPL-2.0+ is deprecated. (#163)
a4f3009 [chain] Update legacy message translations. (#162)
7188a3a [chain] Add legacy message translations. (#161)
62bb837 Generate theme update examples (#157)
8b1fb83 Update: show proper messages when we have multiple or one language (#158)
8f2d46b Generic confirmation (#159)
3bf92a5 New format for adding fields (#160)
f5f36ae [generate:command] Add translations for new generator option. (#156)
97fba81 [generate:site:alias] Add translations for command. (#155)
c5aebe3 Add translations for commands.generate.command.options.initialize, commands.generate.command.questions.initialize (#154)
be82842 Remove already, because the phrase not already sounds wierd (#153)
ae47930 Fix translation for no-depencies string in module.dependency.install.yml file (#151)

Feb 14 2018
Feb 14

By default, Drupal Commerce 2 provides an activity log on the life of each order: the add to cart event, the checkout entry, the order placed, its possible shipment and its conlusion.

Each status of the command corresponds to an entry in a log that is generated. This provides a complete history for each order.

Default order activity

Having needed to customize this activity log, to allow managers of the online store to enter in this log various comments related to the management of the order, I discovered on this occasion the small module, used to generate this log, developed by the maintainers of Drupal Commerce 2. A small but extremely powerful module, titled Commerce log. My favorite modules.

We will discover how to use this module to insert additional log entries. These entries can be generated automatically as well as correspond to an user input.

The Commerce log module

This module declares 2 Plugin types : LogCategory and LogTemplate. The first allows us to declare log categories, while the second allows us to create log templates, which we will assign to previously created categories. Its operation is extremely similar to State Machine: no GUI (hence also less code, and therefore maintenance), and thus creation / declaration of the plugins using YAML configuration files.

But because a good example is sometimes better than a long speech, let's get right to the point right away. We will allow order managers to leave comments in this activity log.

A customized activity journal

Let's create a small MYMODULE module and declare our Log template right away.

The structure of our module will look like this

├── MYMODULE.commerce_log_categories.yml
├── MYMODULE.commerce_log_templates.yml
├── MYMODULE.info.yml
├── MYMODULE.install
├── MYMODULE.module
 

The category of a Log allows us to specify for which entity type the Log will be generated. Here we declare the MYMODULE_order category which will concern the Drupal Commerce Orders entities:

MYMODULE_order:
  label: Order comment
  entity_type: commerce_order

Then we declare our template, here order_comment that we assign to our category. Here we could have used the category already created by the commerce log module.

order_comment:
  category: cerema_commerce_order
  label: 'Comment'
  template: "<p><b>{{ 'Comment'|t }} :</b> {{ comment }}</p>"

The key information of the LogTemplate Plugin is its template that is declared. It's actually a simple Twig inline template. Here we declare our inline template which will use a variable comment.

And it's done !

Well almost. It only remains to generate our log entries at the right time. Since we want to record comments from the online store managers input, we will intervene before the order is saved.

We take care to create beforehand a simple text field, for example field_order_note, on the order entity type, and polish a little the order edit form to obtain this result.

Order form comment

Then we implement hook_entity_presave(), to intervene before saving an order. We will simply check if this field is filled in, and if necessary we will generate the corresponding log entry.

/**
 * Implements hook_entity_presave().
 */
function MYMODULE_entity_presave(EntityInterface $entity) {
  if ($entity instanceof OrderInterface) {
    if ($entity->hasField('field_order_note')) {
      if (!$entity->get('field_order_note')->isEmpty()) {
        // Get the comment, clear it from the order, and log it.
        $comment = $entity->get('field_order_note')->value;
        $entity->set('field_order_note', '');
        /** @var \Drupal\commerce_log\LogStorageInterface $logStorage */
        $logStorage = \Drupal::entityTypeManager()->getStorage('commerce_log');
        $logStorage->generate($entity, 'order_comment', ['comment' => $comment])->save();
      }
    }
  }
}

The key method here for generating the log entry is the generate() method from the LogStorage class.

This method expects as arguments, the entity itself, the identifier of the template to use, and finally an array of parameters to pass to the Twig inline template. We can therefore pass as many parameters as necessary to the Twig template to generate the log entry.

And then we can from the edit form, enter a comment.

un commentaire sur une commande

And we now find this note in the order activity log.

Un commentaire dans le journal de la commande

To go further with Commerce Log

Commerce log is used to generate the Drupal Commerce Order Activity Log. But its design allows us to generate logs for any entity type of Drupal 8. For example generate activity logs for some users, depending on some actions performed on the contents of a project, according to conditions based for example on user roles and / or common taxonomy terms. As well, the Message stack covers this need, but if you already have Drupal Commerce 2 on the project, it may not be useful to install these other modules for this. Give a try with commerce log. You will be surprised. But this will be the subject of another ticket.

Feb 14 2018
Feb 14

A quick run-through of one the many exciting new features that Twig brings to Drupal 8: extendable, easily-overridden templates.

One of the many good things about Drupal 8 is the introduction of Twig. It's a lovely templating engine that, in my opinion, is far superior to PHPTemplate. For us frontenders, it has a much nicer user syntax that's more akin to handlebars or other JS templating engines.

Imagine this scenario (I'm sure many developers have encountered this before):  you're building a site and some of your page templates need to be full-width, while others have a width-restricted content section. Furthermore on some pages you want to add a class to change your nav's styling.

The Drupal 7 way went something like this:

  • Take page.tpl.php and duplicate it, e.g. page--featured-content.tpl.php
  • Add the new wrapper to the new template
  • Clear the cache
  • Job done

This is fine, but is definitely WET rather than DRY. What happens when the markup for say the footer, or the header, needs to change? The answer is a mass find / replace, leaving you open to missed pages, etc.

Thanks to Twig we have a much cleaner solution for this. Twig brings to the table the concept of blocks (not to be confused with Drupal blocks!). You can define a named section in a template that can be overridden by a sub template. What this means is rather than copying / pasting the whole file and changing one line, you simply override that one block in your new file.

Let's start with the wrapper example from above…

First we create a named block to hold the content we want to override:

{% block header %}
  {% set alt_header = FALSE %}
  {# Header code #}
{% endblock %}

{% block wrapper %}
  {% block content %}
    {# Content code #}
  {% endblock %}

  {% block footer %}
    {# Footer code #}
  {% endblock %}
{% endblock %}


Now for our page--featured-content.html.twig we can just do:

{% extends 'page.html.twig' %}
{% block wrapper %}
  <div class="container">
    {{ parent() }}
  </div>
{% endblock %}


That first line just tells Twig which template to use as a base. The new content block will be used in place of the base template, and the rest will stay the same.

The parent() line is pretty cool: it tells Twig to just whack the content of the 'master' block in the new block, so you don't have to retype the whole thing. If you have nested blocks (as in this example), it doesn't matter, you just say "this in here, thanks".

What about variables?

In the example of our dark nav, our Twig template has this:

{% set dark_nav = FALSE %}
{% block header %}
  {% set nav_class = '' %}
  {% if dark_nav %}
    {% set nav_class = 'header--dark-nav' %}
    <header class="header {{ nav_class }}">
      {# header markup here #}
    </header>
  {% endif %}
{% endblock %}

We simply declare the variable outside of the block, and then in the new block redefine it, e.g.: 

{% block header %}
  {% set dark_nav = TRUE %}
  {{ parent() }}
{% endblock %}


So there we have it, in a nutshell. All our new templates can inherit all the defaults from one base, and only have the customisations we need in the sub templates.

Life is better, and updating blocks is just a case of directly editing one place. Happy days!

Feb 14 2018
Feb 14

Drupal 8 User Guide

We've just released a new free guide on our site, Drupal 8 User Guide in order to help our members--and anyone--with minimal existing knowledge of Drupal get started building something quickly. It's a re-publication of the one already available on Drupal.org, with the addition of embedded videos.

I want to share a little bit about why we choose to republish existing content instead of creating new materials, why we've opted to add video to the user guide, and why we're giving it all away for free.

What is the User Guide project?

The Drupal 8 User Guide project consists of about 100 pages of written content that provides an introduction to Drupal for newcomers.

From the guide's preface:

This guide was written mainly for people with minimal knowledge of the Drupal content management system. The topics will help them become skilled at installing, administering, site building, and/or maintaining the content of a Drupal-based website. The guide is also aimed at people who already have some experience with a current or past version of Drupal, and want to expand the range of their skills and knowledge or update them to the current version.

Its content is written and maintained by the Drupal community. It is published and freely available on Drupal.org and it's licensed Creative Commons CCbySA 2.0.

When it came time for us to start planning for the intro-level content we wanted to include on our site we opted to make use of this existing resource. Drupalize.Me has a long history of involvement with the project. I put forth the initial proposal at DrupalCon LA, helped to subsequently refine it into the current version, and am one of the current maintainers. Amber Matz helped with some of the editorial process, and we created the graphics used in the example site, licensed under Creative Commons for use in the guide.

Why republish the user guide?

  • "A good introduction to Drupal 8" is one of the more common requests we get from our members.
  • The text is already written and licensed Creative Commons. So it's a great head start for us and allows us to complete things faster without also essentially duplicating quality content that is already available elsewhere.
  • It's really high quality. Given our involvement with the project since the beginning, we already know that it's as good or better than anything we might write ourselves.
  • We can do double-duty with our time, and benefit both our site and help improve the official user guide project at the same time.
  • The content of the guide is already organized in a way that is similar to how to we like to break things up. Short concept tutorials that introduce a new idea followed by one or more task tutorials that demonstrate the new concepts in use. So it fits well into our existing architecture.
  • Our site has some unique features that our members appreciate that Drupal.org doesn't currently have. For example, tracking which tutorials you've already read so you can more easily pick up where you left off last time or adding things to your queue for future watching or reading.

We're super excited about this and feel like it's a big win for Drupalize.Me, our members, and the Drupal community as a whole.

Adding Video to the User Guide

One thing that we feel the current iteration of the user guide project is missing is video, and we want to help fix that. So we recorded video for all of the task tutorials in the guide, are making them available under the Creative Commons license, and publishing them all on both our site and our YouTube channel.

Why video?

  • Different people learn in different ways, some are more visual learners, and having the ability to watch as someone else navigates the steps required to complete a task is more helpful than either reading instructions, or looking at screenshots.
  • Video can also be beneficial for auditory learners.
  • Video allows the user to see important elements of the UI that may not be covered by screenshots.
  • Some people prefer watching a video over reading a page of text.

The downside of video is that it's harder than text to produce and requires some specialized knowledge that can make it harder for volunteers to create and maintain--something we've gotten really good at over the years. We know first-hand the difficulty of producing and updating high-quality video content. When talking about our own content and the work we do on a daily basis we often state that, "It's easier to patch a text file than a video."

Additionally, we've learned from experience that when it comes to video, people tend to expect a highly polished and consistent format. It can be jarring to switch frequently from one presenter to another, or distract from the learning experience when different screen-casters are using different browser or a different configuration in their terminal. This is by no means impossible for a volunteer team to accomplish, but it's absolutely easier for a team with experience and relevant resources to do.

For these reasons, and because we're firm believers that when Drupal does better we all do better, we're working to contribute all the videos we created back to the original Drupal 8 User Guide project. Our hope is that by contributing them back to the community more people can get the chance to learn from them. And, that by also using them on Drupalize.Me we can continue to help keep them up-to-date and accurate for future versions of Drupal.

If you've got thoughts about how, or if, these videos should be included in the guide see this issue on Drupal.org.

What's next?

Going forward we would like to create and contribute videos to accompany the concept tutorials in the user guide. Although, we don't yet have a timeline for that work. Additionally, with this baseline information in place, we'll begin working on expanding the Drupalize.Me tutorial library to go more in-depth into topics like content types, views, and user management that the user guide introduces.

Get started learning Drupal 8 today with the Drupal 8 User Guide, now with videos!

Feb 14 2018
Feb 14

Have you ever been in a situation where you were required to generate PDF of HTML code? Recently, I came across a similar situation. In Drupal 8, there are several PHP libraries that allow you to generate PDF. However, out of curiosity, I thought of finding better alternatives. After some research, I found an interesting library, called mPDF, that converts HTML code to PDF without changing the structure.

mPDF is a smart library that considers the CSS attached to the HTML. Not only CSS, it takes care of almost all the HTML tags like form tags, tables, images, lists etc.

Generating PDF of HTML in custom module

Requirements

mPDF 7.0 requires PHP ^5.6 || ~7.0.0 || ~7.1.0 || ~7.2.0. PHP mbstring and gd extensions

Installation

Step 1 Download mPDF via composer and its packageist package mpdf/mpdf.

Step 2 Run the following command in the Drupal root directory: 

$ composer requires mpdf/mpdf

Step 3 Once the mPDF libraries install generate the pdf in the custom module.

Step 4 In custom module, create a controller with routing path(/pdf-download)

Step 5 Now hit the URL (/pdf-download) to download pdf

Whenever you hit the URL, pdf will automatically get downloaded. Further, the HTML which we wish to print can be passed dynamically too. For example, by passing the node contents, we can download the node contents in a pdf file.

Hope you can now generate PDF from encoded HTML in the custom module. If you have any suggestions or queries please comment down let me try to answer.
 

Feb 14 2018
Ana
Feb 14

You have already seen what Drupal blogs we trending in the previous month, and now it is time to look at all our blog post we wrote. Here are the blog topics we covered in January.

The first blog post in January was 2017 in review. In this blog post, our Commercial director Iztok looked back in the year 2017 and summarized what differences we made as a company, which Drupal events we have visited, how much fun we had and how do we contributed back to the community in 2017. 

The second was Who will get the control of personal data after GDPR? by Ales Kohek. He talked about new set of rules that EU is imposing in the form of General Data Protection Regulation (GDPR), what changes are the new rules bringing and what does that mean for Internet users. 

snowman

Let's continue with blog post An ever-expanding field of opportunities for Drupal. Ales has searched the opportunities in Industry 4.0 and how can we provide valuable digital experience. He is also answering a question what new regulations on data protection and privacy are bringing us. 

The fourth blog post an interview with our Development manager Igor, who tells us about his beginnings with AGILEDROP,  how did his career path developed and what are his responsibilities now.

winter

Fifth in a row is Drupal events in 1st quarter of the year. We checked out which Drupal events can we attend, where they take place and what are what makes this event special.

The last one is The quality of life and the effect it has on work performance. How our needs changed through time and where does the remote work come in? Ales tells us what remote working means to him personally. 

Those were our blog post from January. Looking forward to having you as readers in 2018!

Feb 14 2018
Feb 14

Florida DrupalCamp 2018 finally arrives this weekend, February 16-18! Commerce Guys is a Gold sponsor this year, and I will be heading down to the conference to talk about Reporting in Drupal Commerce.

With Drupal Commerce 2.4 out the door (see yesterday's release notes), our focus is shifting back to the contributed module ecosystem. As Bojan highlighted in our year in review blog post, we have now ported many essential modules and pushed for them to achieve stable releases. With 55 payment gateways, shipping support, and work on recurring payments in progress, we've identified reporting as our next major initiative.

Reporting is obviously essential to eCommerce. Merchants need to know which products are selling, if a marketing campaign is producing new sales, how much sales tax to remit, and more. Each new type of report brings unique challenges related to understanding, querying, and visualizing the underlying data.

At Florida DrupalCamp, I will discuss the requirements and challenges we've identified in reporting within Drupal Commerce and the solutions available to our users in the Commerce Reports and Commerce Google Analytics modules. Finally, I will also unveil Commerce Guys’ newest product, Lean Commerce Reports.

Lean Commerce Reports dashboard

Lean Commerce Reports, which we first showed off at DrupalCon Baltimore, is finally production ready. Over 80 stores use Lean Commerce Reports to add a plug and play sales dashboard to the back end of Drupal Commerce. The dashboard gives store owners immediate visibility into their sales trends, traffic by channel, conversion rate, and top selling products over time. Furthermore, each summary report on the dashboard links to a full report you can further explore, refine, export, etc.

Jonathan and I have worked really hard these last few months to get Lean Commerce Reports to where it is now, and I can't wait to show it off in Orlando. If you miss me there, come find us at DrupalCon Nashville or get in touch if you'd like to try it out while it's still in private beta.

Feb 14 2018
Feb 14

Yes, a blog post about Drupal 7!

I recently worked on an enhancement for a large multi-site Drupal 7 platform to allow its users to import news articles from RSS feeds. Pretty simple request, and given the maturity of the Drupal 7 contrib module ecosystem, it wasn't too difficult to implement.

One somewhat interesting requirement was that images from the RSS feed be imported to an image field on the news article content type. RSS doesn't have direct support for an image element, but it has indirect support via the enclosure element. According to the RSS spec:

It has three required attributes. url says where the enclosure is located, length says how big it is in bytes, and type says what its type is, a standard MIME type.

RSS feeds will often use the enclosure element to provide an image for each item in the feed.

Despite being in a beta release still, the Drupal 7 Feeds module is considered quite stable and mature, with it's most recent release in September 2017. It has a robust interface that suited my use case quite well, allowing me to map RSS elements to fields on the news article content type. However, it doesn't support pulling data out of enclosure elements in the source. But alas, in there's an 8 year old issue containing a very small patch that adds the ability.

With that patch installed, the final step is to find the proper "target" to map it's data to. It's not immediately clear how this should work. Feeds needs to be smart enough to accept the URL to the image, download it, create a file entity from it, and assign the appropriate data to the image field on the node. Feeds exposes 4 different targets for an image field:

Feeds image field targets

Selecting the "URI" target is the proper choice. Feeds will recognize that you're trying to import a remote image and download it.

Feb 14 2018
Feb 14

In one of our recent projects, our client made a request to use LinkIt module to insert file links to content from the group module.  However, with the added distinction of making sure that only content that is in the same group as the content they are editing is suggested in the matches.

Here’s how we did it.

The LinkIt module

First, let me give you a quick overview of the LinkIt module.

LinkIt is a tool that is commonly used to link internal or external artifacts. One of the main advantages of using it is because LinkIt maintains links by uuid which means no occurrence for broken links. And it can link any type of entity varying from core entities like nodes, users, taxonomy terms, files, comments and to custom entities created by developers.

Once you install the module, you need to set a Linkit profile which consists of information about which plugins to use. To set the profiles use /admin/config/content/linkit path. And the final step will be to enable the Linkit plugin on the text format you want to use. Formats are found at admin/config/content/formats. And you should see the link icon when editing content item.

Once you click on the LinkIt icon it will prompt a modal as shown below.

By default LinkIt ships with a UI to maintain profiles that enables you to manage matchers.

Matchers

Matchers are responsible for managing the autoload suggestion criteria for a particular LinkIt field. It provides bundle restrictions and bundle grouping settings

Proposed resolution

To solve the issue; we started off by creating a matcher for our particular entity type. Linkit has an EntityMatcher plugin that uses Drupal's Plugin Derivatives API to expose one plugin for each entity type. We started by adding the matcher that linkit module exposed for our custom group content entity type.

We left the bundle restrictions and bundle grouping sections un-ticked so that all existing bundles are allowed so the content of those bundles will be displayed.

Now that the content is ready we have to let the matcher know that we only need to load content that belongs to the particular group for which the user is editing or creating the page.

Using the deriver

In order to do that we have to create a new class in /modules/custom/your_plugin_name/src/Plugin/Linkit/Matcher/YourClassNameMatcher.php by extending existing EntityMatcher class which derives at /modules/contrib/linkit/src/Plugin/Linkit/Matcher/EntityMatcher.php.

Because Linkit module's plugin deriver exposes each entity-type plugin with and ID for the form entity:{entity_type_id} we simply need to create a new plugin with an ID that matches our entity type ID. This then takes precedence over the default derivative based plugin provided by Linkit module. We can then modify the logic in either the ::execute() or ::buildEntityQuery method.

Using LinkIt autocomplete request

But here comes the challenge, in that content edit page the LinkIt modal doesn’t know about the group of the content being edited, therefore we cannot easily filter the suggestions based on the content being edited. We need to take some fairly extreme measures to make that group ID available for our new class to filter the content once the modal is loaded and user starts typing in the field.

In this case the group id is available from the page uri.

So in order to pass this along, we can make use of the fact that the linkit autocomplete widget has a data attribute 'data-autocomplete-path' which is used by its JavaScript to perform the autocomplete request. We can add a process callback to the LinkIt element to extract the current page uri and pass it as a query parameter in the autocomplete path.

The code

To do so we need to implement hook_element_info_alter in our custom module. Here we will add a new process callback and in that callback we can add the current browser url as a query parameter to the data-autocomplete-path attribute of the modal.

\Drupal\linkit\Element\Linkit is as follows;

public function getInfo() {
 $class = get_class($this);
 return [
  '#input' => TRUE,
  '#size' => 60,
  '#process' => [
    [$class, 'processLinkitAutocomplete'],
    [$class, 'processGroup'],
  ],
  '#pre_render' => [
    [$class, 'preRenderLinkitElement'],
    [$class, 'preRenderGroup'],
  ],
  '#theme' => 'input__textfield',
  '#theme_wrappers' => ['form_element'],
 ];
}

Below is the code to add the process callback and alter the data-autocomplete-path element. We rely on the HTTP Referer header which Drupal sends in its AJAX request that is used to display the LinkIt modal, which in turn builds the LinkIt element

/**
* Implements hook_element_info_alter().
*/

function your_module_name_element_info_alter(array &$info) {
  $info['linkit']['#process'][] = 'your_module_name_linkit_process';
}

/**
* Process callback.
*/
function your_module_name_linkit_process($element) {
 // Get the HTTP referrer (current page URL)
 $url = \Drupal::request()->server->get('HTTP_REFERER');

 // Parse out just the path.
 $path = parse_url($url, PHP_URL_PATH);

 // Append it as a query parameter to the autocomplete path.
 $element['#attributes']['data-autocomplete-path'] .= '?uri=' . urlencode($path);
 return $element;
}

Once this is done we can now proceed to create the new plugin class extending EntityMatcher class. Notice the highlighted areas.

namespace Drupal\your_module\Plugin\Linkit\Matcher;

use Drupal\linkit\Plugin\Linkit\Matcher\EntityMatcher;
use Drupal\linkit\Suggestion\EntitySuggestion;
use Drupal\linkit\Suggestion\SuggestionCollection;


/**
* Provides specific LinkIt matchers for our custom entity type.
*
* @Matcher(
*   id = "entity:your_content_entity_type",
*   label = @Translation("Your custom content entity"),
*   target_entity = "your_content_entity_type",
*   provider = "your_module"
* )
*/

class YourContentEntityMatcher extends EntityMatcher {

/**
 * {@inheritdoc}
 */
public function execute($string) {
  $suggestions = new SuggestionCollection();
  $query = $this->buildEntityQuery($string);
  $query_result = $query->execute();
  $url_results = $this->findEntityIdByUrl($string);
  $result = array_merge($query_result, $url_results);

  if (empty($result)) {
    return $suggestions;
  }

  $entities = $this->entityTypeManager->getStorage($this->targetType)->loadMultiple($result);

  $group_id = FALSE;
  // Extract the Group ID from the uri query parameter.
  if (\Drupal::request()->query->has('uri')) {
    $uri = \Drupal::Request()->query->get('uri');
    list(, , $group_id) = explode('/', $uri);
  }

  foreach ($entities as $entity) {
    // Check the access against the defined entity access handler.
    /** @var \Drupal\Core\Access\AccessResultInterface $access */
    $access = $entity->access('view', $this->currentUser, TRUE);
    if (!$access->isAllowed()) {
      continue;
    }

    // Exclude content that is from a different group
    if ($group_id && $group_id != $entity->getGroup()->id()) {
      continue;
    }

    $entity = $this->entityRepository->getTranslationFromContext($entity);
    $suggestion = new EntitySuggestion();
    $suggestion->setLabel($this->buildLabel($entity))
      ->setGroup($this->buildGroup($entity))
      ->setDescription($this->buildDescription($entity))
      ->setEntityUuid($entity->uuid())
      ->setEntityTypeId($entity->getEntityTypeId())
      ->setSubstitutionId($this->configuration['substitution_type'])
      ->setPath($this->buildPath($entity));
    $suggestions->addSuggestion($suggestion);
  }

  return $suggestions;
 }
}

Conclusion

And we are done.

By re-implementing the execute() method of EntityMatcher class we are now able to make the LinkIt field to display only content from the same group as the content the user is editing/creating.

So next challenge here is to create some test coverage for this, as we're relying on a few random pieces of code - a plugin, some JavaScript in the LinkIt module, an element info alter hook and a process callback - any of which could change and render all of this non-functional. But that's a story for another post.

Photo of Pasan Gamage

Posted by Pasan Gamage
Drupal Developer

Dated 14 February 2018

Add new comment

Feb 13 2018
Feb 13

In part one and two of this Acro Media Tech Talk video series, we covered how you set up a new product attribute and used rendered fields, in Drupal Commerce 2. In part three we set up a product variation type with custom fields. 

In part four of this series, we'll complete our overall product configuration by setting up a product type. The product type defines the type of product that you're creating (i.e. hat, shirt, shoe). This is what your store administrators will see when they add a new product to their catalog. By default, a product type will consist of a title, body, and variation type. We'll add some additional custom fields for things like taxonomy reference (for categorization), short description, specifications, product review, etc. 

This entire video series, when complete, will show you how to set up a new product in Drupal Commerce 2, from start to finish. The video is captured using our Urban Hipster Commerce 2 demo site.

Next week we'll post part 5: How to Add and Modify Product Content

Its important to note that this video was recorded before the official 2.0 release of Drupal Commerce and so you may see a few small differences between this video and the official release now available.

Urban Hipster Commerce 2 Demo site

This video was created using the Urban Hipster Commerce 2 demo site. We've built this site to show the adaptability of the Drupal 8, Commerce 2 platform. Most of what you see is out-of-the-box functionality combined with expert configuration and theming.

Visit Our Drupal Commerce 2 Demo Site

More from Acro Media
Drupal modules used in this video

Contact us and learn more about our custom ecommerce solutions

Feb 13 2018
Feb 13

In this post, we’ll begin to talk about the development considerations of actual website code migration and other technological details. In these exercises, we’re assuming that you’re moving from Drupal 6 or 7 to Drupal 8. In a later post, I will examine ways to move other source formats into Drupal 8 - including CSV files, non-Drupal content management systems, or database dumps from weird or proprietary frameworks.

Migration: A Primer

Before we get too deep into the actual tech here, we should probably take a minute to define some terms and explain what’s actually happening under the hood when we run a migration, or the rest of this won’t make much sense.

When we run a migration, what happens is that the Web Server loads the content from the old site, converts it to a Drupal 8 format, and saves it in the new site.  Sounds simple, right?

Actually, it pretty much is that simple. At least, conceptually. So, try to keep those three steps in mind as we go through the hard stuff later. Everything we do is designed to make one of those three steps work.

Key Phrases

  • Migration: The process of moving content from one site to another. ‘A migration’ typically refers to all the content of a single content or entity type (in other words, one node type, one taxonomy, and so on).

  • Migration Group: A collection of Migrations with common traits

  • Source: The Drupal 6 or 7 database from which you’re drawing your content (or other weird source of data, if applicable)

  • Process: The stuff that Drupal code does to the data after it’s been loaded, in order to digest it into a format that Drupal 8 can work with

  • Destination: The Drupal 8 site

Interestingly, each of those key phrases above corresponds directly to a code file that’s required for migration. Each Migration has a configuration (.yml) file, and each is individually tailored for the content of that entity. As config files, each of these is pretty independant and not reusable. However, we can also assign them to Migration Groups. Groups are also configuration (.yml) files. They allow us to declare common configurations once, and reuse them in each migration that belongs to that group.

The Source Plugin code is responsible for doing queries to the Source database, retrieving the data, and formatting it into PHP objects that can be worked on. The Process Plugin takes that data, does stuff to it, and passes it to the next step. The Destination Plugin then saves it in Drupal 8 format.  Rinse, repeat.

On a Drupal-to-Drupal migration, around 75% of your time will be spent working in the Migration or Migration Group config, declaring the different Process Plugins to use. You may wind up writing one or more Process Plugins as part of your migration development, but a lot of really useful ones are included in Drupal core migration code and are documented here. A few more are included with Migrate Plus.

Drupal 8 core has Source Plugins for all standard Drupal 6 and Drupal 7 entity types (node, taxonomy, user, etc.). The only time you’ll ever need to write a Source plugin is for a migration from a source other than Drupal 6 or 7, and many of these are already available as Contrib modules.

Also included in Drupal core are Destination Plugins for all of the core entity types. Unless you’re using a custom entity in Drupal 8, and migrating data into that entity, you’ll probably never write a Destination Plugin.

Development Foundations

There are a few key requirements you need to have in place before you can begin development.  First, and probably foremost, you need to have both your Drupal 6/7 and Drupal 8 sites - the former full of all your valuable content, and the latter empty of everything but structure.

An important note: though the completed migration will be run on your production server, you should be using development environments for this work. At Phase2, we use Outrigger to simplify and standardize our dev and production environments.

For migration purposes, we only actually need the Drupal 7 site’s database itself, in a place that’s accessible to the destination site.  I usually take an SQL dump from production, and install it as an additional database on the same server as the destination, to avoid network latency and complicated authentication requirements. Obviously, unless you freeze content for the duration of the migration development, you’ll have to repeat this process for final content migration on production.

I’d like to reiterate some advice from my last post: I strongly recommend sanitizing user accounts and email addresses on your development databases.  Use drush sql-sanitize and avoid any possibly embarrassing and unprofessional gaffes.

On your Drupal 8 site, you should already have completed the creation of the new content types, based on information you discovered and documented in your first steps.  This should also encompass the creation of taxonomy vocabularies, and any fields on your user entities.

In your Drupal 8 settings.php file, add a second database config array pointed at the Drupal 7 source database.

sites/default/settings.php




  1. $databases['migration_source_db']['default'] = array(

  2.   'database' => 'example_source',

  3. 'username' => 'username',

  4. 'password' => 'password',

  5. 'prefix' => '',

  6. 'host' => 'db',

  7. 'port' => '',

  8. 'namespace' => 'Drupal\Core\Database\Driver\mysql',

  9. 'driver' => 'mysql',

  10. );


Finally, you’ll need to add the migration module suite to your site.  The baseline for migrations is migrate, migrate_drupal, migrate_plus, and migrate_tools.  The Migrate and Migrate Drupal modules are core code. Migrate provides the basic functionality required to take content and put it into Drupal 8.  Migrate Drupal provides code that understands the structure of Drupal 6 and 7 content, and makes it much more straightforward to move content forward within the Drupal ecosystem.

Both Migrate Plus and Migrate Tools are contributed modules available at drupal.org. Migrate Plus, as the name implies, adds some new features, most importantly migration groups. Migrate Tools provides the drush integration we will use to run and rollback migrations.

Drupal 8 core code also provides migrate_drupal_ui, but I recommend against using it. By using Migrate Tools, we can make use of drush, which is more efficient, can be incorporated into shell scripts, and has more clear error messages.

Framing the House

We’ve done the planning and laid the foundations, so now it’s time to start building this house!

We start with a new, custom module.  This can be pretty bare-bones, to start with.

example_migrate/example_migrate.info.yml




  1. type: module

  2. name: 'Example Migrate'

  3. description: 'Example custom migrations'

  4. package: 'Example Migrate'

  5. core: '8.x'

  6. dependencies:

  7. - drupal:migrate

  8. - drupal:migrate_plus

  9. - drupal:migrate_tools

  10. - drupal:migrate_drupal


Within our module folder, we need a config/install directory. This is where all our config files will go.

Migration Groups

The first thing we should make is a general migration group. While it’s possible to put all the configuration into each and every migration you write, I’m a strong believer in DRY programming (Don’t Repeat Yourself).  Migrate Plus gives us the ability to put common configuration into a single file and use it for multiple migrations, so let’s take advantage of that power!

Note the filename we’re using here. This naming convention gives Migrate Plus the ability to find and parse this configuration, and marks it as a migration group.

example_migrate/config/install/migrate_plus.migrate_group.example_general.yml




  1. # The machine name of the group, by which it is referenced in individual migrations.

  2. id: example_general

  3. # A human-friendly label for the group.

  4. label: General Imports

  5. # More information about the group.

  6. description: Common configuration for simple migrations.

  7. # Short description of the type of source, e.g. "Drupal 6" or "WordPress".

  8. source_type: Drupal 7 Site

  9. # Here we add any default configuration settings to be shared among all

  10. # migrations in the group.

  11. shared_configuration:

  12. source:

  13. key: migration_source_db

  14. # We add dependencies just to make sure everything we need will be available

  15. dependencies:

  16. enforced:

  17. module:

  18. - example_migrate

  19. - migrate_drupal

  20. - migrate_tools


This is a very simple group that will use for migrations of simple content . Most of the stuff in here is self-descriptive.  However, source is a critical config - it uses the key of the database configuration we added earlier, to give migrate access to that database.  We’ll examine a more complicated migration group another time.

User Migration

In Drupal, users pretty much have their fingers in every pie.  They are listed as authors on content, they are creators of files… you get the picture.  That’s why it’s usually the first migration to get run.

Note again the filename convention here, which allows Migrate Plus to find it, and marks it as a migration (as opposed to a group).

example_migrate/config/install/migrate_plus.migration.example_user.yml




  1. # Migration for user accounts.

  2. id: example_user

  3. label: User Migration

  4. migration_group: example_general

  5. source:

  6. plugin: d7_user

  7. destination:

  8. plugin: entity:user

  9. process:

  10. mail:

  11. plugin: get

  12. source: mail

  13. status: status

  14. name:

  15. -

  16. plugin: get

  17. source: name

  18. -

  19. plugin: dedupe_entity

  20. entity_type: user

  21. field: name

  22. roles:

  23. plugin: static_map

  24. source: roles

  25. map:

  26. 2: authenticated

  27. 3: administrator

  28. 4: author

  29. 5: guest_author

  30. 6: content_approver

  31. created: created

  32. changed: changed

  33. migration_dependencies:

  34. required: { }

  35. dependencies:

  36. enforced:

  37. module:

  38. - example_migrate


Wow! There’s lots of stuff going on here.  Let’s try and break it down a bit.




  1. id: example_user

  2. label: User Migration

  3. migration_group: example_general


The id designation is a standard machine name for this migration.  We will call this with drush to run the migration. Label is a standard human-readable name.  The migration_group should be obvious - it connects this migration to the group we designed above, which means we are now importing all the config in there.  Notably, that connects us to the D7 database.




  1. source:

  2. plugin: d7_user

  3. destination:

  4. plugin: entity:user


Here are two key items.  The source plugin defines where we are getting our data, and what format it’s going to come in.  In this case, we are using Drupal core’s d7_user plugin.

The destination plugin defines what we’re making out of that data, and the format it ends up in.  In this case, we’re using Drupal core’s entity:user plugin.




  1. process:

  2. mail:

  3. plugin: get

  4. source: mail

  5. status: status

  6. name:

  7. -

  8. plugin: get

  9. source: name

  10. -

  11. plugin: dedupe_entity

  12. entity_type: user

  13. field: name

  14. roles:

  15. plugin: static_map

  16. source: roles

  17. map:

  18. 2: authenticated

  19. 3: administrator

  20. 4: author

  21. 5: guest_author

  22. 6: content_approver

  23. created: created

  24. changed: changed


Now we get into the real meat of a migration - the Process section. Each field you’re going to migrate has to be defined here. They are keyed by their field machine name in Drupal 8.  

Each field assigns a plugin parameter, which defines the Process Plugin to use on the data. Each of these process plugins will take a source parameter, and then possibly others.  The source parameter defines the field in the data array provided by the source plugin.  (Yeah, like I’ve said before, naming things clearly isn’t Drupal’s strong suit).

Our first example is mail. Here we are assigning it the get process plugin. This is the easiest process to understand, as it literally takes the data from the old site and gives it to the new site without transforming it in any way. Since email addresses don’t have any formatting changes or necessary transformations, we just move them.

In fact, the get process plugin is Drupal’s default, and our next example shows a shortcut to use it. The status field is getting its data from the old status field. Since get is our default, we don’t even need to actually specify the plugin, and the source is simply implied. See the documentation on drupal.org for more detail.

Name is a slightly more complicated matter.  While usernames don’t change much in their format, we want to make absolutely sure that they are unique.  This leads us to Plugin Chaining, an interesting option that allows us to pass data from one plugin to another, before saving it. The YML array syntax, as demonstrated above, allows us to define more than one plugin for a single field.

We start off by defining the get plugin, which just gets the data from a source field. (You can’t use the default shortcut when you’re chaining, incidentally.)

We then pass it off to the next plugin in the chain, dedupe_entity. This plugin ensures that each record is absolutely certain to be unique.  It has the additional parameters entity_type and field. These define the entity type to check against for uniqueness, and the field in which to look on that entity. See the documentation for more detail.

Note that this usage of dedupe_entity does not specify a source parameter.  That’s because plugin chaining hands off the data from the first plugin in line to the next, becoming, in effect, the source.  It’s very similar to method chaining in jQuery or OOP PHP.  You can chain together as many process plugins as you need, though if you start getting up above four it might be time to re-evaluate what you’re doing, and possibly write a custom processor.

Our final example to examine is roles. User roles in Drupal 7 were keyed numerically, but in Drupal 8 they are based on machine names.  The static_map plugin takes the old numbers, and assigns them to a machine name, which becomes the new value.

The last two process items are changed and created. Like status, they are using the get process plugin, and being designated in the shortcut default syntax.




  1. migration_dependencies:

  2. required: { }

  3. dependencies:

  4. enforced:

  5. module:

  6. - example_migrate


The last two configs are pretty straightforward.  Migration Dependencies are used when a migration requires data from other migrations (we’ll get into that more another time). Dependencies are used when a migration requires a specific additional module to be enabled. In my opinion it’s pretty redundant with the dependencies declared in the module itself, so I don’t use it much.

In the next post, we’ll cover taxonomy migrations and simple node migrations. We’ll also share a really useful tool for migration development.  Thanks for reading!

Feb 13 2018
Feb 13

On a recent project, I had to create a custom page which displays content by the logged in user, think of it as a “My articles” or “My blogs” page. I knew how to do it by writing code but I thought I’d try it with Views and see how far I could get without writing any custom code. Long story short, I was able to do it all by using just the Views module.

In this tutorial, you’ll learn how to create a page which will appear as a tab (local task) on the user profile page.

Getting Started

For once there are no extra modules to download and install. In Drupal 8, Views ships with core and will be automatically installed if you installed Drupal using the Standard installation profile.

If it’s not already installed, go to Extend and install Views and “Views UI”.

Create User Profile Page

The first bit of work we need to do is create an actual Views page.

This page will display a table of articles which is owned by the user, we’ll call it “My articles” and the URI to the page will be /user/{user}/my-articles the {user} argument will be the user ID which will be used by the contextual filter.

The owner of the content is defined by the user added to the “Authored by” field on the content edit page.

1. Go to Structure, Views and click on “Add view”.

2. Fill in the “Add view” form with the values defined in Table 1.0.

Table 1.0: Add view

Option Value View name My Articles Machine name my_articles Show Content (default) Of Type Article Create a page Checked Page title My Articles Path user/{user}/my-articles Display format Table

3. If you go to /user/{user}/my-articles replace {user} with any number, it should return a table of articles.

Create Contextual Filter

The {user} argument getting passed through the URI is not being used at this point. Let’s now add a contextual filter which will use the argument and only display articles which are authored by the user ID.

1. While on the Views edit page, click on Advanced then Add next to Contextual filters.

2. Search for “Authored by” in the Content category and click on Add.

3. Select the “Provide default value” radio button and choose “Raw value from URL”, and 2 from “Path component”.

This will tell the filter to get the 2nd path component, which is the user ID and pass that into the view.

4. Further down the page:

  1. Check “Specify validation criteria”.
  2. Select “User ID” from Validator.
  3. Check “Validate user has access to the User”.
  4. Under “Access operation to check” select Edit.

5. Click on Apply to save the contextual filter, then click on Save to save the view.

Now if you go to the page, /user/{user}/my-articles make sure you change {user} with an actual user ID, you should only see their articles.

Page Access Control

Please make sure you’ve checked “Validate user has access to the User” and have chosen Edit under “Access operation to check”.

This means that only users who have edit access can access the page. This would be users accessing their own accounts or site administrators who can edit other user accounts.

If you do not then any user who knows the URI /user/{user}/my-articles could go directly to it and see which articles are owned by the user.

Display Page as Tab (Local Task)

At this point, we’ve created the page and added a contextual filter to only display articles owned by the user.

Now let’s create a menu for the page so it’s accessible via a tab on the user profile page.

1. While on the views edit page, click on “No menu” link in the “Page settings” section.

2. In the “Page: Menu item entry” window, complete the following:

  1. Select “Menu tab” from Type.
  2. Add “My articles” to “Menu link title”.
  3. Select “<User account menu>” from Parent. This is important if you don’t do this then the tab won’t appear.
  4. Add 5 to weight.

3. Now if you go to the “My articles” page it should go from this:

To this:

If you can’t see the tabs but have configured it properly then try rebuilding the site cache. Go to Configuration, Performance and click on “Clear all caches”.

Summary

The ability to create these types of pages is where Views really shines. Often a client will ask for a content specific page such as a “My blog” or “My articles” page and Views makes it very easy to create these types of pages.

FAQs

Q: “My Articles” tab is not appearing.

First, make sure you’ve chosen “<User account menu>” from the Parent drop-down. Second, try rebuilding the site cache (go to Configuration, Performance and click on “Clear all caches”) and see if that fixes it.

Ivan Zugec

About Ivan Zugec

Ivan is the founder of Web Wash and spends most of his time consulting and writing about Drupal. He's been working with Drupal for 10 years and has successfully completed several large Drupal projects in Australia.

Feb 13 2018
Feb 13

We are in an era where we see a lots of third party integrations being done in projects. In Drupal based projects, cookie management is done via Drupal itself to maintain session, whether it be a pure Drupal project or decoupled Drupal project,.

But what when we have a scenario where user’s information is being managed by a third party service and no user information is being saved on Drupal? And when the authentication is done via some other third party services? How can we manage cookie in this case to run our site session and also keep it secure?

One is way is to set and maintain cookie on our own. In this case, our user’s will be anonymous to Drupal. So, we keep session running based on cookies! The user information will be stored in cookie itself, which then can be validated when a request is made to Drupal.

We have a php function to set cookie called setCookie() , which we can use to create and destroy cookie. So, the flow will be that a user login request which is made to website is verified via a third party service and then we call setCookie function which sets the cookie containing user information. But, securing the cookie is must, so how do we do that?

For this, let’s refer to Bakery module to see how it does it. It contains functions for encrypting cookie, setting it and validating it.

To achieve this in Drupal 8, we will write a helper class let’s say “UserCookie.php” and place it in ‘{modulename}/src/Helper/’. Our cookie helper class will contain static methods for setting cookie and validating cookie. Static methods so that we will be able to call them from anywhere.

We will have to encrypt cookie before setting it so we will use openssl_encrypt() php function in following manner:

/**
* Encrypts given cookie data.
*
* @param string $cookieData
*   Serialized Cookie data for encryption.
*
* @return string
*   Encrypted cookie.
*/
private static function encryptCookie($cookieData) {

 // Create a key using a string data.
 $key = openssl_digest(Settings::get('SOME_COOKIE_KEY'), 'sha256');

 // Create an initialization vector to be used for encryption.
 $iv = openssl_random_pseudo_bytes(16);

 // Encrypt cookie data along with initialization vector so that initialization
 // vector can be used for decryption of this cookie.
 $encryptedCookie = openssl_encrypt($iv . $cookieData, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);

 // Add a signature to cookie.
 $signature = hash_hmac('sha256', $encryptedCookie, $key);

 // Encode signature and cookie.
 return base64_encode($signature . $encryptedCookie);
}

  1. String parameter in openssl_digest can be replaced with any string you feel like that can be used as key. You can keep simple keyword too.
  2. Key used should be same while decryption of data.
  3. Same initialization vector will be needed while decrypting the data, so to retrieve it back we append this along with cookie data string.
  4. We also add a signature which is generate used the same key used above. We will verify this key while validating cookie.
  5. Finally, we encode both signature and encrypted cookie data together.

For setting cookie:
 

/**
* Set cookie using user data.
*
* @param string $name
*   Name of cookie to store.
* @param mixed $data
*   Data to store in cookie.
*/
public static function setCookie($name, $data) {
$data = (is_array($data)) ? json_encode($data) : $data;
$data = self::encrypt($data);
 setcookie($name, $cookieData,Settings::get('SOME_DEFAULT_COOKIE_EXPIRE_TIME'), '/');
}

Note: You can keep 'SOME_COOKIE_KEY' and 'SOME_DEFAULT_COOKIE_EXPIRE_TIME' in your settings.php. Settings::get() will fetch that for you.
Tip: You can also append and save expiration time of cookie in encrypted data itself so that you can also verify that at time of decryption. This will stop anyone from extending the session by setting cookie timing manually.

Congrats! We have successfully encrypted the user data and set it into a cookie.

Now let’s see how we can decrypt and validate the same cookie.

To decrypt cookie:

/**
* Decrypts the given cookie data.
*
* @param string $cookieData
*   Encrypted cookie data.
*
* @return bool|mixed
*   False if retrieved signature doesn't matches
*   or data.
*/
public static function decryptCookie($cookieData) {

 // Create a key using a string data used while encryption.
 $key = openssl_digest(Settings::get('SOME_COOKIE_KEY'), 'sha256');

 // Reverse base64 encryption of $cookieData.
 $cookieData = base64_decode($cookieData);

 // Extract signature from cookie data.
 $signature = substr($cookieData, 0, 64);

 // Extract data without signature.
 $encryptedData = substr($cookieData, 64);

 // Signature should match for verification of data.
 if ($signature !== hash_hmac('sha256', $encryptedData, $key)) {
   return FALSE;
 }

 // Extract initialization vector from data appended while encryption.
 $iv = substr($string, 64, 16);

 // Extract main encrypted string data which contains profile details.
 $encrypted = substr($string, 80);

 // Decrypt the data using key and
 // initialization vector extracted above.
 return openssl_decrypt($encrypted, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
}

  1. We generate the same key using same string parameter given while encryption.
  2. Then we reverse base64 encoding as we need extract signature to verify it.
  3. We generate same signature again as we have used the same key which was used to creating signature while encryption. If doesn’t signatures doesn’t matches, validation fails!
  4. Else, we extract initialization vector from the encrypted data and use to decrypt the data return to be utilized.
/**
* Validates cookie.
*
* @param string $cookie
*   Name of cookie.
*
* @return boolean
*   True or False based on cookie validation.
*/
public static function validateCookie($cookie) {
 if (self::decryptCookie($cookieData)) {
   return TRUE;
 }
 return FALSE;
}

We can verify cookie on requests made to website to maintain our session. You can implement function for expiring cookie for simulating user logout. We can also use decrypted user data out of cookie for serving user related pages.

Feb 13 2018
Feb 13

Using Cockpit CMS

In my previous post, I presented some Headless CMS solutions and suggested using Drupal mostly due to the content editorial capabilities and flexibility. Drupal can be leveraged as a vanilla solution or in a distro flavor (e.g. Contenta, Reservoir). I also approached Cockpit CMS, because it's a pure Headless CMS that is open-source, simple, with a great UI and provides the basis for starting a Headless website.

So the purpose of this post is to give you an overview of Cockpit, in terms of installation, configuration,  the core concepts and how to retrieve contents. In my next post of that series, I'll provide the last piece in form of a simple website implemented in React and that can consume dynamically the contents available on Cockpit.

Cockpit CMS

Cockpit comes in two flavors, Official Release, the most stable or Preview, also known as Next. All examples I am providing here are based on the Next branch.

Requirements

Humm! Quite simple, right? Yes, as you can see, no generation or build scripts, or heavyweight PHP libraries or dependencies. It means that Cockpit can run with low resources.

Installation

The installation is a straightforward process, just extract to your docroot folder and point the browser to http://<yourdomain>/install, no configurations are required during the installation, you are redirected to the login page and can login using admin/admin (better to change the password after the first login).

A docker compose file is also provided, so if you want to try the docker version just run:

docker-compose up -d

Usage and Core concepts

Cockpit is based on the below main concepts:

  • Collections

  • Regions

  • Forms

  • API

  • Webhooks

  • Collections

  • Addons

Collections

Collections are probably the most important, they can be compared with content types on Drupal, a collection can define any piece of information (e.g. Page, a Product, etc..) so as a node in Drupal, a collection contains fields. Cockpit provides already a complete set of field types:

Asset, Boolean, Code, Color, Color Tag, Date, File, Gallery, HTML, image, Layout, Layout Grid, Location, Markdown, Multiple Select, Object, Password, Rating, Repeater, Select, Set, Tags, Text, Textarea, Time, wysiwyg (html editor), Collection Link

Above list is probably more than enough for most of the business cases to define a content type, however, if you require something different you can extend them by providing your own field types.

Something that can seem a bit weird is that the definition of the field attributes is a plain JSON object! Yes, it is, however, I don't see it as a big problem, in fact for me it worked better I was able to define all the attributes of a field quicker than using a step based UI. Something that helps is to have the docs in hand (https://getcockpit.com/documentation/reference/fieldtypes), so you can copy paste the JSON object directly from the template and do the modifications you need.

http://take.ms/MEStO


Defining the fields as JSON objects is something that I consider valuable, as it permits to update the fields easily if required.

Resuming, collections are the core of Cockpit in terms of structuring information, they can virtually represent any piece of information and Cockpit interface is powerful enough for developers and simple enough for non-technical users, the perfect wedding.

I will return further below in the article to collections as I pretend to demonstrate it's power by providing some examples.

Regions

Regions are editable contents and code snippets that can be re-used, for example, if we need a block of content for contacts that will display a list of contacts (e.g. phone number, e-mail, address) we can build a region named Contacts and access it using the API. One major difference to collections is that we can define templates for regions, however, I believe that by doing that we are corrupting the main headless concept, so I suggest to use them without templates.

Forms

Forms are available on the Next branch, however, they are not yet functional and no documentation is available. They look to seem a kind of special collection to be exposed as typical forms, a bit similar concept of webforms in Drupal.

API

The API is the core of the headless CMS, is the bridge between the client (application) and the contents. Cockpit provides a security layer based on API tokens, it's possible to define full access tokens, custom tokens that can interact with specific collections only or can only retrieve and not save data, or tokens that are user based.

Retrieving collections using the API and Javascript can be performed with one command:

fetch('/api/collections/get/basicpage?token=xxtokenxx', {
   method: 'post',
   headers: { 'Content-Type': 'application/json' },
   body: JSON.stringify({
       filter: {published:true},
       limit: 10,
       sort: {_created:-1}
   })
})
.then(res=>res.json())
.then(res => console.log(res));

On the above example we are retrieving the last 10 contents of type "basicpage" that have the field published = true.

Webhooks

Webhooks are reactive actions that can interact with 3rd party applications/services when something happens (e.g. after or before a collection is saved or a collection is removed). Let's imagine that we have a newsletter collection that collects an email and a name and we want to store that data in a google sheets document. We can create a webhook with a 3rd party service like Zappier (as it can interact easily with Google sheets) that is triggered every time that the subscription collection is saved. When triggered it will invoke the Zappier service with the saved data and Zappier will create a new entry in the configured Google sheet.

Addons

Like Drupal or other CMS, Cockpit can be extended by the installation of add-ons, basically, we need to follow a simple structure. An addon is a folder that should contain a bootstrap.php file where depending on the Addon functionality (e.g. It will provide Admin functionality or a REST endpoint) we need to provide the correct code to initialize it.

An addon implementation may require the understanding of Riot.js (http://riotjs.com) if it provides admin functionality and the Lime php micro framework (https://github.com/agentejo/lime) for example to handle events.


After playing a bit with Cockpit I implemented two new add-ons:

Conclusion and Next Steps

For me, the most interesting part of Cockpit is not on the features that are available but in the way they are, and mostly on the quickness of creating/updating collections. So taking that into consideration my next step is to build something usable and see how it really works to build a headless experience. To prepare that exercise I will be using React.js in the frontend as a consumer for Cockpit contents.

My simple exercise consists of a typical website that needs to provide:

  1. Creation of Basic Pages using a "componentized" approach, so instead of having a typical bunch of static fields like summary, body, etc, I have instead different components:

  • Banner

  • Text

  • Block of text with a CTA

  • FAQ section

  • Quote section

  • etc..

  1. Have a main menu and the ability to define the pages that should be visible in the main menu

  2. Responsive

  3. Easy to change the UI without touching Cockpit

Using a "Componentized" approach permits easily to have a relationship between the Collection and a React component, for example, if you pick The Quote section it can be described in Cockpit with two fields, one for the quoted text and other for the quote author, for the quoted text we can use a Markdown field and for the author we can use a simple text field. When retrieving the collection it will be represented in JSON as below structure:

[
   {
       "author": "Some Author",
       "name": "Quote - Homepage",
       "content": "Quo usque tandem abutere, Catilina, patientia nostra?",
       "_mby": "5a61396e7640edoc1261186187",
       "_by": "5a61396e7640edoc1261186187",
       "_modified": 1517826090,
       "_created": 1517347771,
       "_id": "5a70e3bb09cdddoc1719074663",
       "_link": "quote"
   }
]


On the client side, we can build a Quote stateless component, that has two props, the quoted text, and the author and finally render the markup. The below workflow represents the build of the component from the Cockpit collection until is rendered on React:

Pretty simple right! The same approach is applied to all other components, we have in Cockpit the content structure and in React we build the corresponding component, depending on the functionality of each and interaction with the user the React components can be stateful or stateless.

In my next post  the third and final part of this series, I’ll detail the React implementation, and will provide a full working example in React and Cockpit.

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