How to Add WooCommerce Compatibility to Your WordPress Theme

In this beginner’s tutorial I will show you the right way to add WooCommerce compatibility to your WordPress theme. You’ll also learn how to extend it in an unobtrusive way, without editing the plugin’s core files. We’ll cover these logical steps:

  1. Getting Started
  2. Using Hooks and Actions
  3. WooCommerce Extensions

1. Declare WooCommerce Support

Let’s imagine we’re developing a WordPress theme. We’d like to leverage some of WooCommerce’s superb functionality, and we’d like to customize some of that functionality too. There are two ways we could extend WooCommerce without editing the plugin core files:

  1. Using hooks (for intermediate theme developers)
  2. Using the catch-all woocommerce_content() function inside our theme

I find that a combination of these options works best to produce reliable results. So first let’s declare WooCommerce support in our theme’s “functions.php” file and disable WooCommerce’s default styling; we will style WooCommerce with our own theme design.

This will hide the “Your theme does not declare WooCommerce support” message.

To disable WooCommerce’s default styling, we add the following:

With the class_exists() function, we check if the WooCommerce plugin is installed and active. Once it is active, we disable its default styling. Later in the tutorial, we’ll add some actions and hooks configurations within this if statement.

2. Create a New Page Template

For now, duplicate the theme’s “page.php” file, and name it “woocommerce.php”. This file should be located as follows: wp-content/themes/YOURTHEME/woocommerce.php.

Open up your newly created file in a text editor or the code editor of your choice. Next you need to find the loop, which usually starts with:

and usually ends with:

This varies between themes. Once you have found the loop, delete it. In its place, put:

Our woocommerce.php template now uses WooCommerce’s loop instead. woocommerce_content() loads the products list on the shop main page, product category pages, products search page and single product content when viewing the single product page.

3. Adding Things to woocommerce.php

As woocommerce.php is now part of your theme, you can customize it along with your other files. For example, I always add the page title section and breadcrumbs, as my regular pages usually contain those things. Neither of these things affects the woocommerce_content(). At this stage, you can also add other things using conditional tags from WooCommerce and WordPress.

For example, let’s add the single product pagination function, like this:

4. Using WooCommerce Hooks and Actions

The complete list of WooCommerce actions, hooks, and filters can be found in the WooCommerce documentation.

If you are new to WordPress actions, hooks, and filters, I highly recommend checking out these resources:

For a better understanding of hook locations, I recommend reading Business Bloomer’s Visual Hook Series.

For a slightly more complex, but even deeper understanding of how WooCommerce logic works, I recommend you examine the plugin core files (woocommerce > templates).

For example, let’s see what we can do in the shop page. To modify the layout of the shop page with hooks, you have two options:

  • Extend the existing action without removing it.
  • Remove/unhook the existing action and replace it with your custom one.

Which method is better depends on your task. For example, imagine you want to remove the product ordering option from your shop page:

This is all that you need to add to your functions.php file inside the if class exists statement. WooCommerce now understands that you don’t need that functionality.

And imagine we want to add a search widget instead of the product ordering. After the remove action, add this code:

Further still, imagine you want to remove the rating from products on the shop page. Paste the following code into your functions.php file:

Altering Execution Priority

You’ll have noticed that each action has a number as the last parameter. This is the priority that’s used to specify the order in which the functions associated with a particular action are executed. Lower numbers result in earlier execution, and functions with the same priority are executed in the order in which they were added to the action.

This is very important in situations where several functions are applied to the same action hook. For example, I might want to wrap product details (title, rating, price, add to cart button) with a div.

First, we add the opening wrapper div tag:

Then, we add a closing tag:

Playing with the action hook priority can make our work much easier.

The same principle is applied to a single product page. And here you should be very careful, as changes you make with action hooks for products in the loop/archive/shop page are ignored for the single product page. Here you should modify the single product layout separately, but the main principle is the same.

Knowing how to work with WooCommerce actions extends your theme to the next level. Here are some examples of what I do in my themes when it comes to WooCommerce compatibility:

  • Custom image loading for products
  • Custom image placeholder for products
  • Custom image gallery for products
  • Custom label system display for products (Like Hot!, Most Popular! Recommended!)
  • AJAX Quick look
  • Custom add to cart text and button
  • Custom sale label
  • Custom image slider and lightbox effect for single product page
  • AJAX Wishlist
  • Single product custom tabs
  • Single product reviews 
  • Gravatar custom size
  • Custom related/cross-sells/up-sells products
  • Custom AJAX navigation for products

5. WooCommerce Extensions

If you want to add to your theme with WooCommerce extensions, the principle is almost the same. Always support high-quality official extensions, as they will have integration guidelines and a support team. For example, I extend my themes’ shop with these two plugins:

As they are WooCommerce extensions, first you will need to make sure WooCommerce is installed and active, so any hooks, actions, or filters within the extension that you will use should be placed in the if (class_exists()) statement that we wrote at the beginning. And of course, you should make sure that your extensions are also installed and active by checking the plugin class, function, or constant name. As an example from my theme code:

To find out what class, function, or constant to check, examine the main file.php of the extension.

Conclusion

WooCommerce is an awesome eCommerce plugin and, to be completely frank, any new premium theme should support it. Always follow WooCommerce’s integration guides. Doing so will guarantee that your theme passes the review process and won’t break the structure and logic of WooCommerce. 

After any development work of this kind, you should always test both WordPress and WooCommerce. Enable WordPress’s WP_DEBUG, and test your theme using WordPress’s Theme Unitest and WooCommerce’s dummy content test

Useful Resources


Source: Webdesign Tuts+

Art Directing For The Web With CSS Grid Template Areas

Art Directing For The Web With CSS Grid Template Areas

Art Directing For The Web With CSS Grid Template Areas

Andrew Clarke

2018-04-09T11:00:23+02:00
2018-04-10T14:53:40+00:00

(This article is kindly sponsored by CoffeeCup Software.) Alright, I’m going to get straight to the point. CSS Grid is important, really important, too important to be one of those “I’ll use it when all browsers support it” properties. That’s because, with CSS Grid, we can now be as creative with layout on the web as we can in print, without compromising accessibility, responsiveness, or usability.

If you’re at all serious about web design or development, you need to be serious about learning and using CSS Grid too. In this article I’m going to explain how to use one aspect, grid-template areas, a way of arranging elements that even a big, dumb mug like me can understand, and one that doesn’t get enough attention.

Now, you want to see some action and some code, I know that, but hold on one Goddam minute. Before you learn “how,” I want to teach you “why” it’s important to make the kind of layouts we’ve seen in other media for decades, but have mostly been absent from the web.

Feeling Frustrated

I guess you’ve seen those “which one of these two layouts are you designing today?” tweets, lamenting the current state of design on the web. Even I’ve spoken about how web design’s lost its “soul.” I bet you’ve also seen people use CSS Grid to recreate posters or pages from magazines. These technical demonstrations are cool, and they show how easy implementing complex layouts with CSS Grid can be when compared to other methods, but they don’t get to the bottom of why doing this stuff matters.

So what’s the reason? Why’s layout such an important part of design? Well, it all boils down to one thing, and that’s communication.

For what seems like forever, web designers have created templates, then filled them, with little consideration of the relationship between content and layout. I suppose that’s inevitable, given considerations for content management systems, our need to make designs responsive, and the limitations of the CSS properties we’ve used until now. Sure, we’ve made designs that are flexible, usable, but we’ve been missing a key piece of the puzzle, the role that layout plays in delivering a message.

If you’ve been around the block a few times, you’ll know the role color plays in setting the right tone for a design. I don’t need to tell you that type plays its part too. Pick the wrong typeface, and you run the risk of communicating ineffectively and leaving people feeling differently to how you intended.

Layout — closely linked to aspects of typography like the ’measure’ — plays an equally important role. Symmetry and asymmetry, harmony and tension. These principles draw people to your content, guide them, and help them understand it more easily. That’s why crafting the right layout is as important as choosing the most appropriate typeface. Print designers have known this for years.

Telling Stories Through Art Direction

Art direction matters as much on the web as it does in other media, including print, and what I’m going to cover applies as much to promoting digital products as it does to telling stories.

What do you think of when you hear the term ’art direction?’ Do you think about responsive images, presenting alternative crops, sizes or orientations to several screen sizes using the <picture> element or ’sizes’ in HTML? They’ve become useful responsive design and art direction tools, but there’s more to web design than tools.

Do you think of those designers like Jason Santa Maria and Trent Walton who sometimes art direct their writing by giving an entry its own, distinctive image, layout and typography. This gets us closer to understanding art direction, but images, layout, and typography are only the result of art direction, not the meaning of it.

So if art direction isn’t exactly those things, what exactly is it? In a sentence, it’s the art of distilling an essential, precise meaning or purpose from a piece of content — be that magazine article or a list of reasons why to use the coolest app from the hottest start-up — and conveying that meaning or purpose better by using design. We don’t hear much about art direction on the web, but it’s well established in another medium, perhaps the most memorable being magazines and to some extent newspapers.

I’m not old enough to remember first hand Alexey Brodovitch’s work on Harpers Bazaar magazine from 1934 to 1958.


designs by Brodovitch

Fig.1. What I love about these designs — particularly his pencil sketches — is how Brodovitch placed his content to perfectly reflect the image that accompanies it.

I do remember Neville Brody’s artistic art direction for the Face magazine and I’m still inspired by it every day.


Brody’s pages from The Face magazine

Fig.2. Even twenty five years after he created them, Brody’s pages from The Face magazine are still remarkable designs.

Art direction is so rarely discussed in relation to the web that you could be forgiven for thinking that it’s not relevant. Perhaps you see art direction as an activity that’s more suited to the print world than it is to the web? Some people might think of art direction as elitist in some way.

I don’t think that any of that’s true. Stories are stories, no matter where they’re told or through what medium. They may be thought-provoking like the ones published on ProPublica, or they might be the story of your company and why people should do business with you. There’s the story of how your charity supports a good cause and why people should donate to it. Then there’s the story of your start-up’s new app and why someone should download it. With all of these stories, there’s a deeper message beyond just telling the facts about what you do or sell.

Art direction is about understanding those messages and deciding how best to communicate them through the organization and presentation of words and visuals. Is art direction relevant for the web? Of course. Art directors use design to help people better understand the significance of a piece of content, and that’s as important on the web as it is in print. In fact, the basic principles of art direction haven’t changed between print and digital.

I’d go further, by saying that art direction is essential to creating cohesive experiences across multiple channels, so that the meaning of a story isn’t lost in the gaps between devices and screen sizes.

David Hillman, formerly of The Guardian and New Statesman and designer of many other publications said:

“In its best form, (art direction) involves the art director having a full and in-depth understanding of what the magazine says, and through design, influencing how it is said.”

My friend Mark Porter, coincidentally the former Creative Director at The Guardian also said:

“Design is being in charge of the distribution of elements in space.”

CSS Grid makes being in charge of the distribution of elements more possible than ever before.

Art Directing A Hardboiled Story

I guess now is the time to get down to it, so I’m going to tell you how to put some of this to work in a series of Hardboiled examples. I’ll shine a flashlight on layout and how it helps storytelling and then give you the low down on how to develop one of these designs using CSS Grid.


several ’shots’ of a story in a Hardboiled book

Fig.3. When I conceived the covers for my Hardboiled books, I wanted the story to continue across several ’shots.’ (Left: Cover illustrations by Kevin Cornell. Right: Cover illustrations by Natalie Smith.) (Copyright: Stuff & Nonsense)

First, the backstory. On the cover of my 2010 edition of Hardboiled Web Design (1), a mystery woman in a red dress (there’s always a woman in a red dress) is pointing a gun at our private dick. (Sheesh, I know that feeling.) By the Fifth Anniversary Edition in 2015 (2), the story’s moved on and a shadow moves ominously across the door of our detective’s office. The door flies open, two villains burst in (3), and a fist fight ensues (4). Our mystery woman sure knows how to throw a punch and before you can say “kiss me, deadly” one villain’s tied to a chair and ready to spill the beans (5).

Chapter Three

I’ll start telling that story at the explosive moment when those two villains bust open the door. Now, if you’ve read Scott McCloud’s book ‘Understanding Comics’ you’ll know that panel size affects how long people spend looking at an area, so I want to make the image of our bad guys as large as possible to maximise its impact (1). What the hoods don’t know is that our woman is waiting for them. I use layout to add tension by connecting their eye lines, (2) at the same time drawing a reader’s eyes to where the content starts.


Adding tension by connecting eye lines and maximise impact through large images.

Fig.4. Add tension by connecting eye lines and maximise impact through large images. (View project files on CodePen) (Copyright: Stuff & Nonsense)

Chapter Four

As the first villain bursts onto the scene, I use the left edge of the page, without margins, to represent the open door (1). As most of the action takes place on the right, I create a large spacial zone using the majority of the height and width of the page (2).

Now, when fists fly in all directions, our layout needs to do the same, so my content comes from the top — where whitespace draws the eye down to the bold paragraph (3) — and from the left with the enormous headline (4). You might be wondering why I haven’t mentioned that smaller image in the top-right, but I’ll get to that in a minute.


When fists fly, a layout needs to do the same.

Fig.5. When fists fly, a layout needs to do the same. (View project files on CodePen) (Copyright: Stuff & Nonsense)

Chapter Five

The fight’s over, and our detective is back in control, so on this final page I use a more structured layout to reflect the order that’s returned. Solid columns of justified text (1) with plenty of whitespace around them add to the feeling of calm. At the same time, the right aligned caption (2) feels edgy and uncomfortable, like the gunpoint interrogation that’s taking place.


using layout to create order as well as disorder

Fig.6. We can use layout to create order as well as disorder. (View project files on CodePen) (Copyright: Stuff & Nonsense)

Getting My Dands Dirty

It’s time for a confession. I’m not going to teach you everything you need to know about developing layouts using CSS Grid as there are plenty of smarter people who’ve done that before:

Instead, I’ll show you the inspiration for one grid, how I translated it into a (large screen) layout using columns and rows in CSS Grid, and then placed elements into the spacial zones created using the grid-template areas property. Finally, I’ll deconstruct and alter the design for smaller screen sizes.

The Perfect Beat

My inspiration for the layout I use came from this 1983 design by Neville Brody for The Face Magazine. I was drawn to how Brody cleverly created both horizontal and vertical axis and the large space occupied by the main image.


layout by Neville Brody for The Face Magazine

Fig.7. This layout by Neville Brody for The Face Magazine felt like the perfect starting point for my design. Look closely at Brody’s grid, and you should spot that he used five columns of equal width.

I did the same by applying the following CSS Grid properties to the margin-less <body> element of my page, where columns one fraction unit wide repeat five times with a 2vw gap between them:

body { 
margin: 0;
padding : 0;
display: grid;
grid-column-gap : 2vw;
grid-template-columns: repeat(5, 1fr); }

combining five equal width columns

Fig.8. I combine five equal width columns in different ways to create spacial zones.

In CSS Grid we define a grid module by giving it a name, then we place an element into either a single module or multiple adjacent modules — known as spacial zones — with the grid-template-areas property. Sounds complicated huh? No, not really. It’s one of the easiest and most obvious ways of using CSS Grid, so let’s get to work.

First things, first. I have five elements to position, and they are my “Kiss Me, Deadly” title, the largest ’banner’ image, main content, aside paragraph and two images, fig-1 and fig-2. My HTML looks like this:

<body>
<picture role="banner">…</picture>
<h1 class="title">…</h1>
<main>…</main>
<aside>…</aside>
<img class="fig-1">
<img class="fig-2">
</body>

I wrote that markup in the order that makes most sense, just as I would when constructing a narrative. It reads like a dream on small screens and even without styles. I give each element a grid-area value that in a moment I’ll use to place it on my grid:

[role="banner"] { grid-area: banner; }
.title { grid-area: title; }
main { grid-area: main; }
aside { grid-area: aside; }
.fig-1 { grid-area: fig-1; }
.fig-2 { grid-area: fig-2; }

Your grid area values don’t necessarily need to reflect your element types. In fact, you can use any values, even single letters like a, b, c, or d.

Back with the grid, I add three rows to the columns I created earlier. The height of each row is automatically defined by the height of the content inside it:

body {
grid-template-rows: repeat(3, auto); }

Here’s where the magic happens. I literally draw the grid in CSS using the grid-template-areas property, where each period (.) represents one empty module:

body {
grid-template-areas:
".  .  .  .  ."
".  .  .  .  ."
".  .  .  .  ."; }

Now it’s time to position elements on that grid using the grid-area values I created earlier. I place each elements’ value into a module on the grid and if I repeat that value across multiple adjacent modules — either across columns or row, that element will expand across them to create a spacial zone. Leaving a period (.) will create an empty space:

body {
grid-template-areas:
".  aside  .  fig-2  fig-2"
"title  title  banner  banner  banner"
"fig-2  main  banner  banner  banner"; }

One more small detail before I finish the layout CSS. I want the content of the aside element to sit at the bottom — close to the title and leaving ample white space above it to draw someone’s eye down — so I use an align-self property that might be familiar from learning Flexbox, but with a new value of ’end.‘

aside { 
align-self: end; }

CSS Grid layout for larger screens

Fig.9. That’s it, my CSS Grid layout for larger screens is done. (Copyright: Stuff & Nonsense)

All that remains is to add a few other styles to bring the design to life, including a striking inverse color scheme and a bright, red accent that ties the word “Deadly” in the title to the color of our woman’s dress:

<h1 class="title">Kiss Me, <em>Deadly</em></h1>

.title em {
font-style: normal;
color : #fe3d6b; }

Going Up In Smoke

Now, I know you’ve been wondering about that smaller fight image, and I need to admit something. Natalie Smith made only one finished fists flying illustration for my Hardboiled Shot covers, but her sketches were too good to waste. I used CSS Grid to position an inverted version of one pencil sketch above the gun and rotated it with a CSS transform to form a cloud of smoke.


CSS Grid and transforms turn this sketch into a cloud of smoke.

Fig.10. CSS Grid and transforms turn this sketch into a cloud of smoke. (Copyright: Stuff & Nonsense)

Breaking It Down

In this article, I’ve shown how to create a layout for large screens, but in reality, I start with a small one and then work up, using breakpoints to add or change styles. With CSS Grid, adapting a layout to various screen sizes is as easy as positioning elements into different grid-template areas. There are two ways that I can do this, first by changing the grid itself:

body { 
grid-template-columns: 50px repeat(2, 1fr); }

@media screen and (min-width : 48em) {
body { 
grid-template-columns: repeat(5, 1fr); }
}

The second, by positioning elements into different grid-template areas on the same grid:

body { 
grid-template-areas:
"fig-1  aside  aside  aside  aside"
"fig-1  title  title  title  title"
"banner  banner  banner  banner  banner"
"....  main  main  main  main"; }

@media screen and (min-width : 64em) {
body {
grid-template-areas:
"....  aside  ....  fig-2  fig-2"
"title  title  banner  banner  banner"
"fig-1  main  banner  banner  banner"; }
}

adapting layout to various screen sizes

Fig.11. Adapting my layout to various screen sizes is as easy as positioning elements into different grid-template areas. Small screen (left) Medium screen (right). (Copyright: Stuff & Nonsense)

Using CSS Grid Builder

Grid template areas make developing art directed layouts so easy that even a flat-foot like me can do it, but if you’re the type that likes tools to do the dirty work, CSS Grid Builder from CoffeeCup Software might be just the thing for you. You may have used WYSIWYG editors before, so you might be remembering how lousy the code they spat out was. Let me stop you there. CSS Grid Builder outputs clean CSS and accessible markup. Maybe not as clean as you write yourself, but pretty damn close, and the small team who developed it plan to make it even better. My handwritten HTML looks like this:

<picture role="banner">
    <source srcset="banner.png" media="(min-width: 64em)">
    <img src="banner-small.png" alt="Kiss Me, Deadly">
</picture>

The CSS Grid Builder <picture> element comes wrapped in an extra division, with a few other elements thrown in for good measure:

<div class="responsive-picture banner" role="banner">
    <picture>
    <!--[if IE 9]><video style="display: none;"><![endif]-->
    <source srcset="banner.png" media="(min-width: 64em)">
    <!--[if IE 9]></video><![endif]-->
    <img alt="Kiss Me, Deadly" src="banner-small.png">
    </picture>
</div>

Like I said, close enough, and if you don’t believe me, download a set of exported files from my Hardboiled example. Maybe that’ll convince you.

Browsers’ developer tools are getting better at inspecting grids, but CSS Grid Builder helps you build them. Obviously. At its core, CSS Grid Builder is a Chromium-based browser wrapped in a user-interface, and it runs on macOS and Windows. That means that if the browser can render it, the UI tools can write it, with one or two notable exceptions including CSS Shapes.

In fact, CSS Grid Builder builds more than grids, and you can use it to create styles for backgrounds — including gradients, which is very handy — borders, and typography. It even handles Flexbox and multi-column layouts, but you’re here because you want to learn about CSS Grid.

Looking Around The Interface

The interface in CSS Grid Builder, is pretty much as you’d expect it, with a wide area for the design you’re making on the left and controls over on the right. Those controls include common elements; text, images, interactive buttons and form controls, and layout containers. If you need one of those elements, drag and drop it into your work area.


Drag and drop common elements including text, images, and layout containers.

Drag and drop common elements including text, images, and layout containers.

Press to reveal the Styles tab, and you’ll find controls for naming class and ID attributes, applying styles at specific breakpoints and in particular states. All very useful, but it’s the layout section — somewhat inconveniently tucked away at the bottom of the pane — that’s the most interesting.


Styles layout section contains grid controls.

Styles layout section contains grid controls.

In this section you can design a grid. Setting up columns and rows to form a layout without visual representation can be one of the hardest parts of learning how ‘grid’ works. The app’s ability to visually define the grid structure is a handy feature, especially when you’re new to CSS Grid. This is the section I’m going to explain.


The Grid Editor contains tools for building a grid visually.

The Grid Editor contains tools for building a grid visually.

Using CSS Grid Builder I added a container division. When selecting that in the work area, I get access to the Grid Editor. Activate that, and all the tools needed to visually build a grid are there:

  • Add columns and rows
  • Align and justify content and items within each module
  • Size columns and rows using every type of unit including fr and minmax
  • Specify gaps
  • Name grid-template-areas
  • Specify breakpoints

When I’m happy with those settings, “OK” the changes and they’re applied to the design in the work area. Back there, use sliders to preview the results at various breakpoints, and if you’re one of those people who’s worried about the shrinking percentage of people using incapable browsers, CSS Grid Builder also offers settings where you can figure fallbacks. Then just copy and paste CSS styles to somewhere else in your project or export the whole kit and caboodle.


preview results at various breakpoints

Preview results at various breakpoints, save the project to edit later or export the files.

CSS Grid Builder is currently free while CoffeeCup develops it and if you like what they’re doing, you can throw a few dollars their way to help fund its development.

Cleaning Up

I’m finding it hard to contain my excitement about CSS Grid. Yes, I know I should get out more, but I really do think that it offers us the best chance yet of learning lessons from other media to make the websites we create better at communicating what we aim to convey to our audiences. Whether we make websites for businesses who want to sell more, charities who need to raise more money through donations to good causes, or news outlets who want to tell stories more effectively, CSS Grid plus thoughtful, art directed content makes that all possible.

Now that’s Hardboiled.

I hope you enjoyed this article, now view the project files on CodePen or download the example files.

Art Direction for the Web‘Art Direction for the Web’ by Andy Clarke, the first Hardboiled Web Design ‘shot.’ Shots are a series of short books on ‘Art Directing for the web, ’ ‘Designing with a Browser,’ and ‘Selling Creative Ideas’ to be published throughout 2018.

Smashing Editorial(ms, ra, il)


Source: Smashing Magazine

Hit The Ground Running With Vue.js And Firestore

Hit The Ground Running With Vue.js And Firestore

Hit The Ground Running With Vue.js And Firestore

Lukas van Driel

2018-04-06T13:30:33+02:00
2018-04-10T14:53:40+00:00

Google Firebase has a new data storage possibility called ‘Firestore’ (currently in beta stage) which builds on the success of the Firebase Realtime Database but adds some nifty features. In this article, we’ll set up the basics of a web app using Vue.js and Firestore.

Let’s say you have this great idea for a new product (e.g. the next Twitter, Facebook, or Instagram, because we can never have too much social, right?). To start off, you want to make a prototype or Minimum Viable Product (MVP) of this product. The goal is to build the core of the app as fast as possible so you can show it to users and get feedback and analyze usage. The emphasis is heavily on development speed and quick iterating.

But before we start building, our amazing product needs a name. Let’s call it “Amazeballs.” It’s going to be legen — wait for it — dary!

Here’s a shot of how I envision it:


Screenshot of Amazeballs app

The legendary Amazeballs app

Our Amazeballs app is — of course — all about sharing cheesy tidbits of your personal life with friends, in so-called Balls. At the top is a form for posting Balls, below that are your friends’ Balls.

When building an MVP, you’ll need tooling that gives you the power to quickly implement the key features as well as the flexibility to quickly add and change features later on. My choice falls on Vue.js as it’s a Javascript-rendering framework, backed by the Firebase suite (by Google) and its new real-time database called Firestore.

Firestore can directly be accessed using normal HTTP methods which makes it a full backend-as-a-service solution in which you don’t have to manage any of your own servers but still store data online.

Sounds powerful and daunting, but no sweat, I’ll guide you through the steps of creating and hosting this new web app. Notice how big the scrollbar is on this page; there’s not a huge amount of steps to it. Also, if you want to know where to put each of the code snippets in a code repository, you can see a fully running version of Amazeballs on github.

Let’s Start

We’re starting out with Vue.js. It’s great for Javascript beginners, as you start out with HTML and gradually add logic to it. But don’t underestimate; it packs a lot of powerful features. This combination makes it my first choice for a front-end framework.

Vue.js has a command-line interface (CLI) for scaffolding projects. We’ll use that to get the bare-bones set-up quickly. First, install the CLI, then use it to create a new project based on the “webpack-simple” template.

npm install -g vue-cli

vue init webpack-simple amazeballs

If you follow the steps on the screen (npm install and npm run dev) a browser will open with a big Vue.js logo.

Congrats! That was easy.

Next up, we need to create a Firebase project. Head on over to https://console.firebase.google.com/ and create a project. A project starts out in the free Spark plan, which gives you a limited database (1 GB data, 50K reads per day) and 1 GB of hosting. This is more than enough for our MVP, and easily upgradable when the app gains traction.

Click on the ‘Add Firebase to your web app’ to display the config that you need. We’ll use this config in our application, but in a nice Vue.js manner using shared state.

First npm install firebase, then create a file called src/store.js. This is the spot that we’re going to put the shared state in so that each Vue.js component can access it independently of the component tree. Below is the content of the file. The state only contains some placeholders for now.

import Vue from 'vue';
import firebase from 'firebase/app';
import 'firebase/firestore';

// Initialize Firebase, copy this from the cloud console
// Or use mine :)
var config = {
  apiKey: "AIzaSyDlRxHKYbuCOW25uCEN2mnAAgnholag8tU",
  authDomain: "amazeballs-by-q42.firebaseapp.com",
  databaseURL: "https://amazeballs-by-q42.firebaseio.com",
  projectId: "amazeballs-by-q42",
  storageBucket: "amazeballs-by-q42.appspot.com",
  messagingSenderId: "972553621573"
};
firebase.initializeApp(config);

// The shared state object that any vue component can get access to. 
// Has some placeholders that we’ll use further on!
export const store = {
  ballsInFeed: null,
  currentUser: null,
  writeBall: (message) => console.log(message)
};

Now we’ll add the Firebase parts. One piece of code to get the data from the Firestore:

// a reference to the Balls collection
const ballsCollection = firebase.firestore()
  .collection('balls');

// onSnapshot is executed every time the data
// in the underlying firestore collection changes
// It will get passed an array of references to 
// the documents that match your query
ballsCollection
  .onSnapshot((ballsRef) => {
    const balls = [];
    ballsRef.forEach((doc) => {
      const ball = doc.data();
      ball.id = doc.id;
      balls.push(ball);
    });
    store.ballsInFeed = balls;
  });

And then replace the writeBall function with one that actually executes a write:

writeBall: (message) => ballsCollection.add({
  createdOn: new Date(),
  author: store.currentUser,
  message
})

Notice how the two are completely decoupled. When you insert into a collection, the onSnapshot is triggered because you’ve inserted an item. This makes state management a lot easier.

Now you have a shared state object that any Vue.js component can easily get access to. Let’s put it to good use.

Post Stuff!

First, let’s find out who the current user is.

Firebase has authentication APIs that help you with the grunt of the work of getting to know your user. Enable the appropriate ones on the Firebase Console in AuthenticationSign In Method. For now, I’m going to use Google Login — with a very non-fancy button.


Screenshot of login page with Google authentication

Authentication with Google Login

Firebase doesn’t give you any interface help, so you’ll have to create your own “Login with Google/Facebook/Twitter” buttons, and/or username/password input fields. Your login component will probably look a bit like this:

<template>
  <div>
    <button @click.prevent="signInWithGoogle">Log in with Google</button>
  </div>
</template>

<script>
import firebase from 'firebase/app';
import 'firebase/auth';

export default {
  methods: {
    signInWithGoogle() {
      var provider = new firebase.auth.GoogleAuthProvider();
      firebase.auth().signInWithPopup(provider);
    }
  }
}
</script>

Now there’s one more piece of the login puzzle, and that’s getting the currentUser variable in the store. Add these lines to your store.js:

// When a user logs in or out, save that in the store
firebase.auth().onAuthStateChanged((user) => {
  store.currentUser = user;
});

Due to these three lines, every time the currently-logged-in user changes (logs in or out), store.currentUser also changes. Let’s post some Balls!


Screenshot of logout option

Login state is stored in the store.js file

The input form is a separate Vue.js component that is hooked up to the writeBall function in our store, like this:

<template>
  <form @submit.prevent="formPost">
    <textarea v-model="message" />
    <input type="submit" value="DUNK!" />
  </form>
</template>

<script>
import { store } from './store';

export default {
  data() {
    return {
      message: null,
    };
  },
  methods: {
    formPost() {
      store.writeBall(this.message);
    }
  },
}
</script>

Awesome! Now people can log in and start posting Balls. But wait, we’re missing authorization. We want you to only be able to post Balls yourself, and that’s where Firestore Rules come in. They’re made up of Javascript-ish code that defines access privileges to the database. You can enter them via the Firestore console, but you can also use the Firebase CLI to install them from a file on disk. Install and run it like this:

npm install -g firebase-tools
firebase login
firebase init firestore

You’ll get a file named firestore.rules where you can add authorization for your app. We want every user to be able to insert their own balls, but not to insert or edit someone else’s. The below example do nicely. It allows everyone to read all documents in the database, but you can only insert if you’re logged in, and the inserted resource has a field “author” that is the same as the currently logged in user.

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read: if true;
      allow create: if request.auth.uid != null && request.auth.uid == request.resource.data.author;
    }
  }
}

It looks like just a few lines of code, but it’s very powerful and can get complex very quickly. Firebase is working on better tooling around this part, but for now, it’s trial-and-error until it behaves the way you want.

If you run firebase deploy, the Firestore rules will be deployed and securing your production data in seconds.

Adding Server Logic

On your homepage, you want to see a timeline with your friends’ Balls. Depending on how you want to determine which Balls a user sees, performing this query directly on the database could be a performance bottleneck. An alternative is to create a Firebase Cloud Function that activates on every posted Ball and appends it to the walls of all the author’s friends. This way it’s asynchronous, non-blocking and eventually consistent. Or in other words, it’ll get there.

To keep the examples simple, I’ll do a small demo of listening to created Balls and modifying their message. Not because this is particularly useful, but to show you how easy it is to get cloud functions up-and-running.

const functions = require('firebase-functions');

exports.createBall = functions.firestore
  .document('balls/{ballId}')
  .onCreate(event => {
    var createdMessage = event.data.get('message');
    return event.data.ref.set({
      message: createdMessage + ', yo!'
    }, {merge: true});
});

Oh, wait, I forgot to tell you where to write this code.

firebase init functions

This creates the functions directory with an index.js. That’s the file you can write your own Cloud Functions in. Or copy-paste mine if you’re very impressed by it.

Cloud Functions give you a nice spot to decouple different parts of your application and have them asynchronously communicate. Or, in architectural drawing style:


Server logic architectural diagram of Cloud Functions

Asynchronous communication between the different components of your application

Last Step: Deployment

Firebase has its Hosting option available for this, and you can use it via the Firebase CLI.

firebase init hosting

Choose distas a public directory, and then ‘Yes’ to rewrite all URLs to index.html. This last option allows you to use vue-router to manage pretty URLs within your app.

Now there’s a small hurdle: the dist folder doesn’t contain an index.html file that points to the right build of your code. To fix this, add an npm script to your package.json:

{
  "scripts": {
    "deploy": "npm run build && mkdir dist/dist && mv dist/*.* dist/dist/ && cp index.html dist/ && firebase deploy"
  }
}

Now just run npm deploy, and the Firebase CLI will show you the URL of your hosted code!

When To Use This Architecture

This setup is perfect for an MVP. By the third time you’ve done this, you’ll have a working web app in minutes — backed by a scalable database that is hosted for free. You can immediately start building features.

Also, there’s a lot of space to grow. If Cloud Functions aren’t powerful enough, you can fall back to a traditional API running on docker in Google Cloud for instance. Also, you can upgrade your Vue.js architecture with vue-router and vuex, and use the power of webpack that’s included in the vue-cli template.

It’s not all rainbows and unicorns, though. The most notorious caveat is the fact that your clients are immediately talking to your database. There’s no middleware layer that you can use to transform the raw data into a format that’s easier for the client. So, you have to store it in a client-friendly way. Whenever your clients request change, you’re going to find it pretty difficult to run data migrations on Firebase. For that, you’ll need to write a custom Firestore client that reads every record, transforms it, and writes it back.

Take time to decide on your data model. If you need to change your data model later on, data migration is your only option.

So what are examples of projects using these tools? Amongst the big names that use Vue.js are Laravel, GitLab and (for the Dutch) nu.nl. Firestore is still in beta, so not a lot of active users there yet, but the Firebase suite is already being used by National Public Radio, Shazam, and others. I’ve seen colleagues implement Firebase for the Unity-based game Road Warriors that was downloaded over a million times in the first five days. It can take quite some load, and it’s very versatile with clients for web, native mobile, Unity, and so on.

Where Do I Sign Up?!

If you want to learn more, consider the following resources:

Happy coding!

Smashing Editorial(da, ra, hj, il)


Source: Smashing Magazine

The Rise Of Intelligent Conversational UI

The Rise Of Intelligent Conversational UI

The Rise Of Intelligent Conversational UI

Burke Holland

2018-04-05T13:00:48+02:00
2018-04-10T14:53:40+00:00

For a long time, we’ve thought of interfaces strictly in a visual sense: buttons, dropdown lists, sliders, carousels (please no more carousels). But now we are staring into a future composed not just of visual interfaces, but of conversational ones as well. Microsoft alone reports that three thousand new bots are built every week on their bot framework. Every. Week.

The importance of Conversational UI cannot be understated, even if some of us wish it wasn’t happening.

The most important advancement in Conversational UI has been Natural Language Processing (NLP). This is the field of computing that deals not with deciphering the exact words that a user said, but with parsing out of it their actual intent. If the bot is the interface, NLP is the brain. In this article, we’re going to take a look at why NLP is so important, and how you (yes, you!) can build your own.

Speech Recognition vs. NLP

Most people will be familiar with Amazon Echo, Cortana, Siri or Google Home, all of which have an interface that is primarily conversational. They are also all using NLP.


Large preview

Aside from these intelligent assistants, most Conversational UIs have nothing to do with voice at all. They are text driven. These are the bots we chat with in Slack, Facebook Messenger or over SMS. They deliver high quality gifs in our chats, watch our build processes and even manage our pull requests.


Large preview

Conversational UIs built on text are nice because there is no speech recognition component. The text is already parsed.

When it comes to a verbal interaction, the fundamental problem is not recognizing the speech. We’ve mostly got that one down.

OK, so maybe it’s not perfect. I still get voicemails every day like a game of Mad Libs that I never asked to play. iOS just sticks a blank line in whenever they don’t know what exactly was said.


Large preview

Google, on the other hand, just tries to guess. Like this one from my father. I have absolutely no idea what this message is actually trying to say other than “Be Safe” which honestly sounds like my mom, and not my dad. I have a hard time believing he ever said that. I don’t trust the computer.


Large preview

I’m picking on voice mail transcriptions here, which might be the hardest speech recognition to do given how degraded the audio quality is.

Nevertheless, speech recognition is largely a solved problem. It’s even built right into Chrome and it works remarkably well.


Large preview

After we solved the problem of speech recognition, we started to use it everywhere. That was unfortunate because speech recognition on it’s own doesn’t do us a whole lot of good. Interfaces that rely soley on speech recognition require the user to state things a precise way and they can only state the limited number of exact words or phrases that the interface knows about. This is not natural. This is not how a conversation works.

Without NLP, Conversational UI can be true nightmare.

Conversational UI Without NLP

We’re probably all familiar with automated phone menus. These are known as Interactive Voice Response systems — or IVRs for short. They are designed to take the place of the traditional operator and automatically transfer callers to the right place without having to talk to a human. On the surface, this seems like a good idea. In practice, it’s mostly just you waiting while a recorded voice reads out a list of menu items that “may have changed.”


Large preview

A 2011 study from New York University found that 83% of people feel IVR systems “provide either no benefit at all, or only a cost savings benefit to the company.” They also noted that IVR systems “score lower than any other service option.” People would literally rather do anything else than use an automated phone menu.

NLP has changed the IVR market rather significantly in the past few years. NLP can pick a user’s intent out of anything they say, so it’s better to just let them say it and then determine if you support the action.

Check out how AT&T does it.

AT&T has a truly intelligent Conversational UI. It uses NLP to let me just state my intent. Also, notice that I don’t have to know what to say. I can fumble all around and it still picks out my intent.

AT&T also uses information that it already has (my phone number) and then leverages text messaging to send me a link to a traditional visual UI, which is probably a much better UX for making a payment. NLP drives the whole experience here. Without it, the rest of the interaction would not be nearly as smooth.

NLP is powerful, but more importantly, it is also accessible to developers everywhere. You don’t have to know a thing about Machine Learning (ML) or Artificial Intelligence (AI) to use it. All you need to how to do is make an AJAX call. Even I can do that!

Building An NLP Interface

So much of Machine Learning still remains inaccessible to developers. Even the best YouTube videos on the subject quickly become hard to follow with subjects like Neural Networks and Gradient Descents. We have, however, made significant progress in the field of Language Processing, to the point that it’s accessible to developers of nearly any skill level.

Natural Language Processing differs based on the service, but the overall idea is that the user has an intent, and that intent contains entities. That means exactly nothing to you at the moment, so let’s work up a hypothetical Home Automation bot and see how this works.

The Home Automation Example

In the field of Natural Language Processing, the canonical “Hello World” is usually a Home Automation demo. This is because it helps to clearly demonstrate the fundamental concepts of NLP without overloading your brain.

A Home Automation Bot is a service that can control hypothetical lights in a hypothetical house. For instance, we might want to say “Turn on the kitchen lights”. That is our intent. If we said “Hello”, we are clearly expressing a different intent. Inside of that intent, there are two pieces of information that we need to complete the action:

  1. The ‘Location’ of the light (kitchen)
  2. The desired state of the lights ‘Power’ (on/off)

These (Location, Power) are known as entities.

When we are finished designing our NLP interface, we are going to be able to call an HTTP endpoint and pass it our intent: “Turn on the kitchen lights.” That endpoint will return to us the intent (Control Lights) and two objects representing our entities: Location and Power. We can then pass those into a function which actually controls our lights…

function controlLights(location, power) {
  console.log(`Turning ${power} the ${location} lights`);
  
  // TODO: Call an imaginary endpoint which controls lights   
}

There are a lot of NLP services out there that are available today for developers. For this example, I’m going to show the LUIS project from Microsoft because it is free to use.

LUIS is a completely visual tool, so we won’t actually be writing any code at all. We’ve already talked about Intents and Entities, so you already know most of the terminology that you need to know to build this interface.

The first step is to create a “Control Lights” intent in LUIS.


Large preview

Before I do anything with that intent, I need to define my Location and Power entities. Entities can be different types — kind of like types in a programming language. You can have dates, lists and even entities that are related to other entities. In this case, Power is a list of values (on, off) and Location is a simple entity, which can be any value.

It will be up to LUIS to be smart enough to figure out exactly what the Location is.


Large preview

Large preview

Now we can begin to train this model to understand all of the different ways that we might ask it to control the lights in a different location. Let’s think of all the different ways that we could do that:

  • Turn off the kitchen lights;
  • Turn off the lights in the office;
  • The lights in the living room, turn them on;
  • Lights, kitchen, off;
  • Turn off the lights (no location).

As I feed these into the Control Lights intent as utterances, LUIS tries to determine where in the intent the entities are. You can see that because Power is a discreet list of values, it gets that right every time.


Large preview

But it has no idea what a Location even is. LUIS wants us to go through this list and tell it where the Location is. That’s done by clicking on a word or group of words and assigning to the right entity. As we are doing this, we are really creating a machine learning model that LUIS is going to use to statistically estimate what qualifies as a Location.


Large preview

When I’m done telling LUIS where in these utterances all the locations are, my dashboard looks like this…


Large preview

Now we train the model by clicking on the “Train” button at the top. Do you feel like a data scientist yet?

Now I can test it using the test panel. You can see that LUIS is already pretty smart. The Power is easy to pick out, but it can actually pick out Locations it has never seen before. It’s doing what your brain does — using the information that it has to make an educated guess. Machine Learning is equal parts impressive and scary.


Large preview

If we try hard enough, we can fool the AI. The more utterances we give it and label, the smarter it will get. I added 35 utterances to mine before I was done and it is close to bullet proof.

So now we get to the important part, which is how we actually use this NLP in an app. LUIS has a “Publish” menu option which allows us to publish our model to the internet where it’s exposed via a single HTTP endpoint. It will look something like this…

https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/c4396135-ee3f-40a9-8b83-4704cddabf7a?subscription-key=19d29a12d3fc4d9084146b466638e62a&verbose=true&timezoneOffset=0&q=

The very last part of that query string is a q= variable. This is where we would pass our intent.

https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/c4396135-ee3f-40a9-8b83-4704cddabf7a?subscription-key=19d29a12d3fc4d9084146b466638e62a&verbose=true&timezoneOffset=0&q=turn on the kitchen lights

The response that we get back looks is just a JSON object.

{
  "query": "turn on the kitchen lights",
  "topScoringIntent": {
    "intent": "Control Lights",
    "score": 0.999999046
  },
  "intents": [
    {
      "intent": "Control Lights",
      "score": 0.999999046
    },
    {
      "intent": "None",
      "score": 0.0532306843
    }
  ],
  "entities": [
    {
      "entity": "kitchen",
      "type": "Location",
      "startIndex": 12,
      "endIndex": 18,
      "score": 0.9516622
    },
    {
      "entity": "on",
      "type": "Power",
      "startIndex": 5,
      "endIndex": 6,
      "resolution": {
        "values": [
          "on"
        ]
      }
    }
  ]
}

Now this is something that we can work with as developers! This is how you add NLP to any project — with a single REST endpoint. Now you’re free to create a bot with some real brains!

Brian Holt used the browser speech API and a LUIS model to create a voice powered calculator that is running right inside of CodePen. Chrome is required for the speech API.

See the Pen Voice Calculator by Brian Holt (@btholt) on CodePen.

Bot Design Is Still Hard

Having a smart bot is only half the battle. We still need to account for any of the actions that our system might expose, and that can lead to a lot of different logical paths which makes for messy code.

Conversations also happen in stages, so the bot needs to be able to intelligently direct users down the right path without frustrating them or being unable to recover when something goes wrong. It needs to be able to recover when the conversation dies midstream and then starts again. That’s a whole other article and I’ve included some resources below to help.

When it comes to language understanding, the AI platforms are mature and ready to use today. While that won’t help you perfectly design your bot, it will be a key component to building a bot that people don’t hate.

Great UI Is Just Great UI

A final note: As we saw from the AT&T example, a truly smart interface combines great speech recognition, Natural Language Processing, different types of conversational UI (speech and text) and even a visual UI. In short, great UI is just that — great UI — and it is not a zero sum game. Great UIs will leverage all of the technology available to provide the best possible user experience.

Special thanks to Mat Velloso for his input on this article.

Further Resources:

Smashing Editorial(rb, ra, yk, il)


Source: Smashing Magazine

How To Streamline WordPress Multisite Migrations With MU-Migration

Migrating a standalone WordPress site to a site network (or “multisite”) environment is a tedious and tricky endeavor, the opposite is also true. The WordPress Importer works reasonably well for smaller, simpler sites, but leaves room for improvement. It exports content, but not site configuration data such as Widget and Customizer configurations, plugins, and site settings. The Importer also struggles to handle a large amount of content. In this article, you’ll learn how to streamline this type of migration by using MU-Migration, a WP-CLI plugin.
Source: Smashing Magazine

Replacing jQuery With Vue.js: No Build Step Necessary

It’s been impossible to ignore all of the hype surrounding JavaScript frameworks lately, but they might not be the right fit for your projects. Perhaps you don’t want to set up an entire build system for some small abstractions you could feasibly do without. Perhaps moving a project over to a build system and thus, different deployment method would mean a lot of extra time and effort that you might not be able to bill to a client.
Source: Smashing Magazine

A Comprehensive Guide To Mobile App Design

(This is a sponsored article.) More than ever, people are engaging with their phones in crucial moments. The average US user spends 5 hours per day on mobile. The vast majority of that time is spent in apps and on websites.
The difference between a good app and a bad app is usually the quality of its user experience (UX). A good UX is what separates successful apps from unsuccessful ones.
Source: Smashing Magazine

Using SSE Instead Of WebSockets For Unidirectional Data Flow Over HTTP/2

When building a web application, one must consider what kind of delivery mechanism they are going to use. Let’s say we have a cross-platform application that works with real-time data; a stock market application providing ability to buy or sell stock in real time. This application is composed of widgets that bring different value to the different users.
When it comes to data delivery from the server to the client, we are limited to two general approaches: client pull or server push.
Source: Smashing Magazine

Free Adobe XD Icon Sets Made By Legendary Designers

(This is a sponsored article.) Our friends at Adobe unveiled a very special goodie at the Awwwards Conference in Berlin today. A goodie which is too good to miss: They asked three renowned designers to create exclusive free icon sets to use in Adobe XD. And, well, we are very happy to feature them here on Smashing Magazine, too.
The icon kits were created by design legend Lance Wyman, award-winning design studio Anton & Irene, and the Swiss design group Büro Destruct.
Source: Smashing Magazine

What Is Gulp?

What is Gulp? One description is that Gulp is a task runner. Another would be that it’s a toolkit for automating time-consuming tasks.

Whatever you want to call it, there’s one characteristic that remains true: automation. Let’s dig a little deeper…

What Is Gulp?

 

What Is a Task Runner?

Basically, you use Gulp to automate stuff that you would normally have to do manually, such as manually compiling Sass, manually optimizing images, manually refreshing your page in the browser, and so on. 

Well, these three actions can be consolidated into independent tasks. Then you would take those tasks and have Gulp run them automatically. That’s why tools like Gulp and Grunt are called task runners.

Piping

A very big difference between Gulp and the other task runners out there is the way it handles file operations. Gulp will essentially pass a data stream from one plugin to the next without actually writing that stream in a temporary file between these tasks. That is called piping or streaming.

If you search the web for a definition for piping, you will probably get something very technical. So I am going to try to simplify it a little bit. A Gulp workflow works with several different plugins that perform various operations on certain files. 

To give you an example, the Sass plugin will take a Sass or SCSS file and compile it into a CSS file. The Uglify plugin will take a normal JavaScript file and minify it. 

So the thing with piping is that you can take a set of files and run them through a set of plugins or through one plugin. And you would get a different type of file in the end, exactly what I said with the Sass plugin. You start with an SCSS file, and you end up with a CSS file. 

Data Streams

Normally these types of task runners will write temporary files to the disk. Well, Gulp doesn’t do that—it uses data streams. 

So the contents of that file are actually preserved in a buffer—it’s a stream of data basically. And it’s just passed on from plugin to plugin until it reaches its final destination. And in between these plugins, that stream goes through some changes. 

So what you can do, for example, is start with the SCSS files and pass them down to the Sass plugin. Now, the Sass plugin accepts SCSS files and returns CSS files. So the data stream that you get after the Sass plugin is different from the one that entered the plugin. 

And then you can do more things with that. Maybe you run them through an autoprefixer, right? So Gulp will take that data stream, and it’s going to run it through the autoprefixer plugin, which accepts CSS a file. And it also returns that CSS file, but in between it adds all the necessary vendor prefixes. So it also changes that file’s contents. 

And finally, you can minify it, for example, or you can write it to a disk. So that’s essentially how piping works. You pass data at the beginning of the stream, and you get a different type of data at the end, and in the middle you have these points which perform certain operations on that data stream.

Watch the Full Course

So hopefully you now have a basic understanding of what Gulp is. To get a clearer picture, you could take the full course, The Web Designer’s Guide to Gulp, in which we go through how Gulp works in a whole lot more detail.

You can take this course straight away with a subscription to Envato Elements. For a single low monthly fee, you get access not only to this course, but also to our growing library of over 1,000 video courses and industry-leading eBooks on Envato Tuts+. 

Plus you now get unlimited downloads from the huge Envato Elements library of 440,000+ creative assets. Create with unique fonts, photos, graphics and templates, and deliver better projects faster.


Source: Webdesign Tuts+