<?xml version="1.0" encoding="utf-8"?>
<!-- generator="Stay Regular" -->
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">

  <channel>
    <title>Stay Regular Blog Feed</title>
    <link>http://stayregular.net/blog</link>
    <generator>Stay Regular</generator>
    <lastBuildDate>Mon, 30 Apr 2018 00:00:00 +0000</lastBuildDate>
    <atom:link href="http://stayregular.net" rel="self" type="application/rss+xml" />

        <description>The latest updates from the Stay Regular blog</description>
    
        <item>
      <title>Adding Images and Media to your GatsbyJS Blog</title>
      <link>http://stayregular.net/blog/adding-images-and-media-to-your-gatsbyjs-blog</link>
      <guid>blog/adding-images-and-media-to-your-gatsbyjs-blog</guid>
      <pubDate>Mon, 30 Apr 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>In <a href="http://stayregular.net/blog/deploy-a-static-react-blog-using-gatsbyjs-and-github">our last tutorial</a> we built a <strong>static React-powered blog</strong> using the GatsbyJS framework and static site generator. One of the major features we didn't cover was the handling of images and media we want to include in our Markdown content. In this tutorial, we'll cover how to add a cover image to your blog articles.</p>
<h2>What's the big deal with images?</h2>
<p>The way GatsbyJS works is by compiling our blog's assets into static content. The assets include things like the React components, CSS, and any images we directly include in the components or CSS. So when you run your build, your page component <code>/about.js</code> will become an HTML file in the static folder.</p>
<p>But when it comes to images queried by the GraphQL, Gatsby doesn't automatically copy these assets into our static build. If you try and link to a local file, you'll find it doesn't exist on your development or production server. </p>
<p>There's a whole page of the GatsbyJS docs <a href="https://www.gatsbyjs.org/docs/adding-images-fonts-files/">that talks about the implementation of this feature</a> -- but they seem forgotten, exchanged in favor for <a href="https://www.gatsbyjs.org/packages/gatsby-image/">a few plugins</a> that accomplish the task of copying media assets. The plugins work fantastically, and implement the functionality we need with an approachable API.</p>
<p>Lets get building.</p>
<p><em>If you haven't already, make sure to complete the <a href="http://stayregular.net/blog/deploy-a-static-react-blog-using-gatsbyjs-and-github">first part of this tutorial</a> or <a href="https://github.com/whoisryosuke/gatsby-blog-tutorial">download a starter from Github here</a>.</em></p>
<h2>The plugins</h2>
<p>We'll need to install 4 plugins:</p>
<ul>
<li><a href="https://www.npmjs.com/package/gatsby-plugin-sharp"><strong>gatsby-plugin-sharp</strong></a> - This plugin allows us to use the <a href="https://github.com/lovell/sharp">Sharp image processing library</a> to resize and compress our images.</li>
<li><a href="https://www.gatsbyjs.org/packages/gatsby-transformer-sharp/"><strong>gatsby-transformer-sharp</strong></a> - This plugin allows us to query the images on GraphQL through special <code>ImageSharp</code> nodes.</li>
<li><a href="https://www.npmjs.com/package/gatsby-remark-copy-linked-files"><strong>gatsby-remark-copy-linked-files</strong></a> - This plugin does the magic of grabbing any files we link in our Markdown, like images or even PDFs, and copies them to the <code>./public</code> folder.</li>
<li><a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-remark-images"><strong>gatsby-remark-images</strong></a> - This plugin makes all the images responsive, giving us access to a <code>&lt;Img /&gt;</code> component that automatically scales depending on the user's device size.</li>
</ul>
<p>Let's install them all:</p>
<pre><code class="language-bash">npm i --save gatsby-remark-images gatsby-plugin-sharp gatsby-remark-copy-linked-files gatsby-transformer-sharp</code></pre>
<p>Then add this to your <code>gatsby-config.js</code> file to let Gatsby know we have new plugins (and how to use some of them):</p>
<pre><code class="language-js">{
  plugins: [
    `gatsby-remark-copy-linked-files`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-remark-images`,
      options: {
        maxWidth: 1080,
      },
    },
  ],
}</code></pre>
<p>You can set the <code>maxWidth</code> of your images in the options to the size of your biggest image container.</p>
<h2>Add some images to Markdown</h2>
<p>We'll be adding a <code>cover_image</code> field to our Markdown files to show a big header image above posts, and to use as a thumbnail on archives. We'll add it to the <em>frontmatter</em> of the Markdown file to make it easy.</p>
<p>Open up one of the Markdown files in the <code>src/content/blog/</code> folder and add a <code>cover_image</code> field to the <em>frontmatter</em>:</p>
<pre><code class="language-markdown">---
title: "Using a Framework to Simplify Email Design"
date: "2017-08-10"
section: blog
cover_image: "./foundation-emails-guide@1x.jpg"
tags: design, development
---</code></pre>
<h2>Querying the images</h2>
<p>Let's open up the first page of the site and query up some images there. Head over to <code>src/pages/index.js</code> and scroll to the bottom where the GraphQL query is.</p>
<p>We're going to use the new <code>childImageSharp</code> node in GraphQL to grab responsive versions of the images. You can either scale by a certain size, or by resolution ratio. We'll be scaling by size.</p>
<p>Replace the entire <code>query</code> variable with this one:</p>
<pre><code class="language-js">
export const query = graphql`
  query IndexQuery {
    allMarkdownRemark(sort: {fields: [frontmatter___date], order: DESC}, limit: 3) {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            date(formatString: "DD MMMM, YYYY")
            cover_image {
              publicURL
              childImageSharp {
                sizes(maxWidth: 1240 ) {
                  srcSet
                }
              }
            }
            section
          }
          fields {
            slug
          }
          excerpt
        }
      }
    }
  }
`;</code></pre>
<p>Let's break the query down a bit. We call <code>allMarkdownRemark</code>, which accesses all Markdown files on our server. We also <code>sort</code> by the date and order it DESC. Then inside, we ask for fields we want to show on the page. In our case, we want to see things like the title and date, nested inside the frontmatter field.</p>
<blockquote>
<p>If <a href="http://graphql.org/learn">the syntax of GraphQL</a> throws you for a loop, and you don't understand why you have <code>edges</code> and <code>nodes</code>, <strong>don't get stressed.</strong> I was a little confused at the start too since my background is in SQL. </p>
</blockquote>
<p>I'd recommend taking a look at the GraphQLi query builder, usually at <a href="http://localhost:8000/___graphql"><a href="http://localhost:8000/___graphql">http://localhost:8000/___graphql</a></a>, or just add <code>___graphql</code> to the end of your development server. This pulls up a live query builder during development that helps ensure you build a properly formatted query. If you click inside, start a new line, and press any letter on your keyboard -- you'll see a tooltip popup with all the possible options for fields. </p>
<p>This helps immensely when making new queries from scratch, or just trying to seeing what fields are available at certain depths.</p>
<h2>The Responsive <Img /> Component</h2>
<p>Now that we've queried the images, let's actually see them! </p>
<p>Here we'll be using the <code>&lt;Img /&gt;</code> component (not to be confused with <code>&lt;img src...&gt;</code>) from the <code>gatsby-image</code> package. You can read the plugin page for details, but it basically creates a responsive image nested inside a couple divs. If the user loads mobile, it loads a smaller image, and stretches it accordingly to fit the size. It also does stuff like the blurred placeholder loading image (ala Facebook or Medium).</p>
<p>To use the <code>&lt;Img /&gt;</code> component, import the <code>gatsby-image</code> package:</p>
<pre><code class="language-js">import Img from "gatsby-image";</code></pre>
<p>And then add the <code>&lt;Img /&gt;</code> tag anywhere in your code:</p>
<pre><code class="language-js">&lt;Img sizes={featured.frontmatter.cover_image.childImageSharp.sizes} /&gt;</code></pre>
<p>We reach into the frontmatter to grab the cover_image, which now has a <code>ImageSharp</code> node (because we added the plugin above). Though we use <code>childImageSharp</code>, probably because it's not a direct image node, but a image attached to a field. The <code>ImageSharp</code> node provides us with a <code>sizes</code> array containing various images at different viewport sizes. This all gets fed into the <code>&lt;Img /&gt;</code> component, which does the heavy lifting of swapping between the set of images depending on the user's device.</p>
<h2>That's it!</h2>
<p>Once you figure it out and find the right plugins, it's a fairly simple process. And being able to generate queries using the help of the GraphiQL browser, combined with dumping data into the console, makes deciphering the data structure fairly simple.</p>
<p>You can see this code more fleshed out with CSS and whatnot in my personal blog's repo: <a href="https://github.com/whoisryosuke/ryosuke-gatsby-blog/"><a href="https://github.com/whoisryosuke/ryosuke-gatsby-blog/">https://github.com/whoisryosuke/ryosuke-gatsby-blog/</a></a></p>
<h2>Next time: Paginated Archives</h2>
<p>In the next part of <a href="http://stayregular.net/blog/tag:gatsbyjs">this tutorial series</a> we'll be adding a paginated archive for our blog. Each blog post has it's own page, but we need an archive for users -- and SEO spiders, to browse and find our older posts. Keep an eye on the <a href="http://stayregular.net/blog/tag:gatsbyjs">#GatsbyJS</a> tag to see our next post!</p>
<p>If you have any questions or issues: feel free to comment down below, <a href="http://twitter.com/stayregular420">send us a tweet</a>, or <a href="http://stayregular.net/contact">contact us through our site's form</a>.</p>
<p>Stay regular,<br />
Oscar</p>
<hr />
<p><strong>Keep Reading:</strong></p>
<ul>
<li><a href="http://gatsbyjs.org">GatsbyJS</a></li>
<li><a href="http://gatsbyjs.org/docs/">GatsbyJS Docs</a></li>
<li><a href="http://graphql.org/learn/">GraphQL Docs</a></li>
<li><a href="https://www.npmjs.com/package/gatsby-plugin-sharp">gatsby-plugin-sharp</a></li>
<li><a href="https://www.gatsbyjs.org/packages/gatsby-transformer-sharp/">gatsby-transformer-sharp</a></li>
<li><a href="https://www.npmjs.com/package/gatsby-remark-copy-linked-files">gatsby-remark-copy-linked-files</a></li>
<li><a href="https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-remark-images">gatsby-remark-images</a></li>
<li><a href="https://github.com/lovell/sharp">Sharp image processing library</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>How to Deploy a Laravel OAuth2 API on Heroku (for free!)</title>
      <link>http://stayregular.net/blog/deploy-laravel-on-heroku-to-create-oauth2-0-api</link>
      <guid>blog/deploy-laravel-on-heroku-to-create-oauth2-0-api</guid>
      <pubDate>Mon, 23 Apr 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>Are you developing a quick frontend application and need a <strong>backend API for user authentication?</strong> You could put together a Node/Express API from scratch and deploy it on <a href="http://heroku.com">Heroku</a>, but unless you've got a great boilerplate, you'll be spending <em>valuable time</em> integrating dependencies like <a href="http://www.passportjs.org/">PassportJS</a> for <a href="https://jwt.io/introduction/">JWT authentication</a>. Or maybe you don't know too much server-side JS, and you're more comfortable with PHP. That's where <strong>Laravel</strong> comes in. </p>
<p><strong><a href="http://laravel.com">Laravel</a></strong> is a PHP framework that gives you essential features like JWT user authentication and routing right out of the box <em>(with an official plugin)</em>. And it's surprisingly easy to deploy on Heroku if you know a couple of tips and tricks for proper configuration.</p>
<h2>A (Free) API for User Authentication</h2>
<p>Today we'll be creating a basic Laravel application with user signup/login and JWT authentication API for apps. And it'll be deployed on the free tier of Heroku, a cloud-based hosting service. </p>
<p>You can then use this cloud-hosted API to integrate a user authentication system to a frontend application made in React, Vue, Angular, etc. Although you will need a secondary &quot;gateway&quot; API to connect to this Laravel API, or use a service that offers environment variables (like <a href="http://netlify.com">Netlify</a>), since frontend apps leave API credentials vulnerable.</p>
<p><em>This article presumes you have <a href="https://getcomposer.org/download/">Composer installed globally</a>. You don't have to know the <a href="http://laravel.com/">Laravel framework</a>, but it'll help you understand the structure of the application. And it'd probably help to run through <a href="https://devcenter.heroku.com/articles/getting-started-with-php#introduction">the Heroku guide</a> at least once to get your footing there.</em></p>
<h2>Setup Laravel</h2>
<p>The first step is getting Laravel setup. We'll install it using Composer, create a SQLite database, and then configure the <code>.env</code> file.</p>
<ol>
<li>Install Laravel using Composer:</li>
</ol>
<pre><code class="language-sh">composer create-project --prefer-dist laravel/laravel laravel-api-heroku</code></pre>
<ol start="2">
<li>
<p>Open up the project folder (laravel-api-heroku) and go to the <code>database</code> folder and create a new file called <code>database.sqlite</code>. It should be an empty file -- so just create it, save, and close.</p>
</li>
<li>
<p>Go back to the root of the project and copy the <code>.env.example</code> file and name the new file<code>.env</code>.</p>
</li>
<li>Open up the new <code>.env</code> file. Change the <code>DB_CONNECTION</code> variable to equal <code>sqlite</code>, and delete the other <code>DB_...</code> variables in the section. The section should look like this:</li>
</ol>
<pre><code class="language-env">LOG_CHANNEL=stack

DB_CONNECTION=sqlite

BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=sync</code></pre>
<p>Now we can start to bootstrap Laravel with some basic features like user registration/authentication.</p>
<h2>Setting up an Authentication API</h2>
<p>Laravel makes it incredibly simple to create a website where users can create an account or login, but it takes the simplicity a step further with the Passport package. Not only do we get user login, registration, password reset, etc all out of the box -- we also get an OAuth2.0 package with Passport that allows you to create a kind of &quot;social login&quot; for your own website (think the Twitter API when you access private user data). </p>
<p>We'll basically be following the same instructions in the Laravel docs, <a href="https://laravel.com/docs/5.6/passport">so check those out if you get lost.</a></p>
<p>Install the authentication package by running:</p>
<pre><code class="language-sh">php artisan make:auth</code></pre>
<p>Now we can get the Passport package installed. </p>
<pre><code class="language-sh">composer require laravel/passport</code></pre>
<p>Then we migrate the new database tables, like the users tables, or API keys.</p>
<pre><code class="language-sh">php artisan migrate</code></pre>
<p>Now we can install Passport using Artisan:</p>
<pre><code class="language-sh">php artisan passport:install</code></pre>
<p>We add a new trait to our User model (<code>app/User.php</code>):</p>
<pre><code class="language-php">&lt;?php

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}</code></pre>
<p>Then <code>Passport::routes</code> method within the <code>boot</code> method of your  <code>app/Providers/AuthServiceProvider.php</code>:</p>
<pre><code class="language-php">&lt;?php

namespace App\Providers;

use Laravel\Passport\Passport;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        'App\Model' =&gt; 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this-&gt;registerPolicies();

        Passport::routes();
    }
}</code></pre>
<p>Finally, in <code>config/auth.php</code>, you should set the driver option of the  api authentication guard to passport to authenticate incoming requests with <code>TokenGuard</code>:</p>
<pre><code class="language-php">'guards' =&gt; [
    'web' =&gt; [
        'driver' =&gt; 'session',
        'provider' =&gt; 'users',
    ],

    'api' =&gt; [
        'driver' =&gt; 'passport',
        'provider' =&gt; 'users',
    ],
],</code></pre>
<blockquote>
<p>Protip: If you have a previous Laravel installation and you're changing the configuration, make sure to wipe out the config cache by running <code>php artisan config:cache</code> in the console.</p>
</blockquote>
<p>Now we have a Laravel application pre-built with user authentication and OAuth2.0. You can test out the user auth by running <code>php artisan serve</code> and going to <a href="http://localhost:8000">the local development server</a>.There you should see the default Laravel landing page, and login and register buttons in the top right of the screen.</p>
<h2>Deploying to Heroku</h2>
<p>Heroku is a great host with an excellent free hosting package if you're looking quick and easy deployment for most styles of apps (NodeJS, PHP, Ruby, etc). We'll also be leveraging the free tier of their Postres database hosting, which gives you 10k database records to play with.</p>
<blockquote>
<p>Check out the guide <a href="https://devcenter.heroku.com/articles/getting-started-with-laravel">on Heroku's website for deploying Laravel</a>.</p>
</blockquote>
<p>First we have to let the Heroku server know our app is actually in the <code>public/</code> folder. Let's create a new file in the project root called <code>Procfile</code> and add the following:</p>
<pre><code>web: vendor/bin/heroku-php-apache2 public/</code></pre>
<p>Then create a new Heroku application <a href="https://devcenter.heroku.com/articles/heroku-cli">using the CLI</a>:</p>
<pre><code class="language-sh">heroku create</code></pre>
<p>Now add your application key for the production site:</p>
<pre><code class="language-sh">heroku config:set APP_KEY=$(php artisan --no-ansi key:generate --show)</code></pre>
<p>Commit any changes and push the master branch to the Heroku remote repo:</p>
<pre><code>git push heroku master</code></pre>
<p>Now we can add the database. Add a SQLite database to your Heroku app by going to the <a href="https://elements.heroku.com/addons/heroku-postgresql">Heroku PostgresSQL</a> page and clicking the install button. Then pick your app from the dropdown and click continue. You'll be prompted to pick a pricing plan, I went with the free Hobby plan.</p>
<p>Now you can <a href="https://devcenter.heroku.com/articles/heroku-postgresql#connecting-in-php">connect your application to Heroku's Postgres database</a> by updating your <code>config/database.php</code> file:</p>
<pre><code class="language-php">$DATABASE_URL = parse_url(getenv("DATABASE_URL"));
$DB_CONNECTION = parse_url(getenv("DB_CONNECTION"));

return [

    'default' =&gt; env('DB_CONNECTION', $DB_CONNECTION),
    // …

    'connections' =&gt; [

        // …

        'pgsql' =&gt; [
            'driver' =&gt; 'pgsql',
            'host' =&gt; $DATABASE_URL["host"],
            'port' =&gt; $DATABASE_URL["port"],
            'database' =&gt; ltrim($DATABASE_URL["path"], "/"),
            'username' =&gt; $DATABASE_URL["user"],
            'password' =&gt; $DATABASE_URL["pass"],
            'charset' =&gt; 'utf8',
            'prefix' =&gt; '',
            'schema' =&gt; 'public',
            'sslmode' =&gt; 'require',
        ],

        // …

    ],

    // …

];</code></pre>
<p>We also need to edit the environment variables to let Laravel know to use the <code>pgsql</code> database driver when we use Heroku in production. Head over to your project on Heroku, go to the Settings page, and click Show Config Vars. Make a new entry with they key <code>DB_CONNECTION</code> and <code>pgsql</code> as the value.</p>
<p>Now remove the OAuth keys that were generated locally from the <code>.gitignore</code> file by deleting this line:<code>/storage/*.key</code>. Ideally we'd generate these in production, but I had issues with Heroku generating them, so we just import the local ones instead!</p>
<p>Commit your changes to make the database connection real:</p>
<pre><code class="language-sh">git add .
git commit -m "Added Heroku database configuration"
git push heroku master</code></pre>
<p>Now that your database has been connected, make sure to run your database migrations in production to structure your fresh DB. You'll be running it through the Heroku CLI:</p>
<pre><code class="language-sh">heroku run php artisan migrate</code></pre>
<p>Your Laravel website should be live! You can register new users and login with the credentials you create. </p>
<h2>Connecting to your new API</h2>
<p>If you'd like to make an authenticated request to the API through a certain user, you'll either need to go through the OAuth2.0 verification process, or provide a personal access token (or JWT). Laravel Passport allows you to create a new client with a simple command line script:</p>
<pre><code class="language-sh">heroku run php artisan passport:client --personal</code></pre>
<p>When prompted for an app name, name it anything, and click Enter. You'll be provided a Client ID and Secret which you'll use to access the API remotely.</p>
<p>If you're not familiar with the OAuth2.0 protocol, here's a quick breakdown. OAuth2.0 protects your API by creating a 3-step verification system before offering a secure token to access the Laravel API endpoints secured with middleware authentication. </p>
<ol>
<li>
<p>You first redirect the user to the Laravel API's OAuth Authorize page (<code>http://yourlaravelapp.com/oauth/authorize</code>) and attach your Client ID and a callback URL to the request. </p>
</li>
<li>The user is either presented a login screen - or if they're already logged in - they see an authorization form to allow your frontend app to access their data (similar to Twitter's authorization when you use social login). Then the API then redirects the user back to the callback URL you provided, and it sends over a secret token. </li>
</ol>
<figure class="border"><img src="http://stayregular.net/content/2-blog/20180423-deploy-laravel-on-heroku-to-create-oauth2-0-api/laravel-passport-default-authorization-request.png" alt=""><figcaption>Laravel's default API permission authorization screen</figcaption></figure>
<ol start="3">
<li>You take that secret token and send it back to the API with your Client ID, secret, and callback URL. The API responds back with another secret token, this time a personal access token for the specific user that authorized by logging in. This personal access token is <a href="https://jwt.io/">a <strong>JWT</strong></a> or <strong>JSON Web Token</strong>, which is an industry standard method for authorizing between APIs.</li>
</ol>
<p>Any time we'd like to access any part of the API that requires authentication, like private user data, we send our request to the API with a Authorization Bearer token in the header. That token in the JWT we generated in step 3.</p>
<p>Here's a snippet of this kind of setup in Laravel using <code>session()</code> to store the access token. <em>Remember, this is a separate &quot;gateway&quot; application that obfuscates your API credentials for a frontend app</em>:</p>
<pre><code class="language-php">
Route::get('/', function () {
    $query = http_build_query([
        'client_id' =&gt; '420',
        'redirect_uri' =&gt; 'http://127.0.0.1:8001/callback',
        'response_type' =&gt; 'code',
        'scope' =&gt; 'access-patient-status'
    ]);

    return redirect('http://127.0.0.1/oauth/authorize?'.$query);
});

Route::get('/callback', function (Request $request) {
    $response = (new GuzzleHttp\Client)-&gt;post('http://127.0.0.1/oauth/token', [
        'form_params' =&gt; [
            'grant_type' =&gt; 'authorization_code',
            'client_id' =&gt; '420',
            'client_secret' =&gt; 'EXKWFSwGHrbGdC3M4F5kkzmtCZIXyE3fbA8agtw2',
            'redirect_uri' =&gt; 'http://127.0.0.1:8001/callback',
            'code' =&gt; $request-&gt;code,
        ]
    ]);

    session()-&gt;put('token', json_decode((string) $response-&gt;getBody(), true));

    return redirect('/user');
});

Route::get('/user', function () {
    if ( ! session()-&gt;has('token')) {
        return redirect('/');
    }

    $response = (new GuzzleHttp\Client)-&gt;get('http://127.0.0.1/api/user', [
        'headers' =&gt; [
            'Authorization' =&gt; 'Bearer '.Session::get('token.access_token')
        ]
    ]);

    return json_decode((string) $response-&gt;getBody(), true);
});</code></pre>
<p>You could also accomplish this in a React app using <code>react-router</code> to create the callback route, and a service like Netlify to securely <a href="https://www.netlify.com/docs/continuous-deployment/#build-environment-variables">access API key variables in your build environment.</a> (rather than exposing them directly in your production code).</p>
<h2>Let the hackathons begin</h2>
<p>I hope this inspires you to tackle your projects in a new way. We're living in the transition away from the monolith towards a microservices based architecture, and this type of setup will help you migrate your projects into this new infrastructure. The <a href="http://jamstack.org">JAMstack revolution</a> is upon is, and developers are engineering more frontend applications that utilize these modular, cloud-distributed API solutions. </p>
<p>You can take your app's source code and host it on a CDN for the most efficient distribution. And rather than pound the same server you're using to host the frontend to run requests to the backend to login or register users, we break that service out into a separate API that lives on it's own server. If the authentication API server crashes, it never takes down the website CDN (besides the functionality the API provides). <strong>It's the future!</strong></p>
<blockquote>
<p>Consider leveraging the power of Laravel's <a href="https://laravel.com/docs/5.6/socialite">Socialite package</a> to integrate social login into your API, and allow users to create accounts with social media profiles from Twitter, Facebook, etc.</p>
</blockquote>
<p>Looking for the source code? 💻 ⚙️  Find this completed project source code <a href="https://github.com/whoisryosuke/laravel-api-heroku">on Github here</a>.</p>
<p>Stay regular,<br />
Oscar</p>
<hr />
<p><strong>Keep Reading:</strong></p>
<ul>
<li><a href="https://devcenter.heroku.com/articles/getting-started-with-php#introduction">Heroku - Getting Started</a></li>
<li><a href="https://devcenter.heroku.com/articles/getting-started-with-laravel">Heroku - Deploying Laravel</a></li>
<li><a href="https://elements.heroku.com/addons/heroku-postgresql">Heroku - PostgresSQL DB Hosting</a></li>
<li><a href="https://laravel.com">Laravel framework</a></li>
<li><a href="https://laravel.com/docs/5.6/passport">Laravel - Passport package</a></li>
<li><a href="https://jwt.io/">JSON Web Tokens / JWT</a></li>
<li><a href="https://mikateach.com/setting-up-laravel-5-6-on-heroku/">Mikateach - Setting up Laravel 5.6 on Heroku</a></li>
<li><a href="https://blog.pusher.com/build-rest-api-laravel-api-resources/">Pusher - Build REST API using Laravel</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>Deploy a Static React Blog using GatsbyJS and Github</title>
      <link>http://stayregular.net/blog/deploy-a-static-react-blog-using-gatsbyjs-and-github</link>
      <guid>blog/deploy-a-static-react-blog-using-gatsbyjs-and-github</guid>
      <pubDate>Mon, 16 Apr 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>We'll be creating a blog using <a href="https://www.gatsbyjs.org">GatsbyJS</a>, a static site generator for <a href="https://reactjs.org/">React</a>. GatsbyJS takes your content, either static files or external data from an API, and generates pages that are hardcoded with the data. Rather than calling the API for your latest blog posts for each request, all your posts are pre-cached into separate HTML files. This allows you to serve your entire website over a CDN. And without any external API calls or even server-side rendering, the website loads lightning fast -- and is offline-friendly.</p>
<p>Today we'll be developing a static blog generated by GatsbyJS, written in Markdown, and we'll deploy on Github Pages to host the blog. </p>
<h2>But first, what is GatsbyJS?</h2>
<p><strong>GatsbyJS</strong> is a generator that allows you to code React apps that get compiled into static assets (HTML + JS). Each <strong>page</strong> is a technically React <strong>component</strong> that gets converted into an HTML and JS file when it's time to build the production site. If you've ever worked with a generator like <a href="https://jekyllrb.com/">Jekyll</a>, which converts code like <em>Liquid</em> and <em>Markdown</em> into HTML, you'll be familiar with this kind of concept.</p>
<p>What makes GatsbyJS special is it's implementation of <strong><a href="https://graphql.org/">GraphQL</a></strong>. All of your content is served through a GraphQL server on the development side. When it comes time to compile the static assets, GatsbyJS queries the GraphQL server for the data and inserts it into your HTML files. </p>
<h2>And what the heck is a JAMstack?</h2>
<p>Static websites are growing in popularity with the <a href="jamstack.org">JAMstack revolution</a>. JAM stands for Javascript, API, and Markup. What it basically means is your site is only comprised of:</p>
<ul>
<li><strong>Javascript</strong> (usually a framework like React)</li>
<li><strong>API</strong> (like an RSS feed, or JSON API endpoint) <em>optional</em> </li>
<li><strong>Markup</strong> (HTML, CSS, any media like images)</li>
</ul>
<p>The goal is to create a website is comprised of only client-side HTML + CSS + JS. No need to install <strong>Node</strong>, <strong>Ruby</strong>, <strong>PHP</strong>, or any other server-side language. This means we could even deploy this directly on a CDN like <strong>S3</strong> on <em>AWS</em> or <a href="http://netlify.com"><strong>Netlify</strong></a>.</p>
<blockquote>
<p>When a website is made this simple, you can deploy it nearly anywhere, since most servers support HTML, CSS, and JS. </p>
</blockquote>
<p>There are plenty of benefits to making your website static, from <strong>lighting fast load times</strong> to <strong>decreased server load</strong>, and Gatsby makes it <em>fairly</em> easy to pump out your own. You can find a great <a href="https://www.gatsbyjs.org/tutorial/"><em>'Getting Started'</em> guide</a> on the official GatsbyJS site, as well as many of the concepts we convey in this tutorial. If you get lost, I'd poke around there and see if it helps paint a clearer picture.</p>
<p>Let's build and deploy a static blog!</p>
<h2>Installing Gatsby</h2>
<h3>Using the CLI</h3>
<p>You can either install Gatsby using their CLI, which is recommended:</p>
<p><code>npm install --global gatsby-cli</code></p>
<p>Then run this command in the folder where you want the project:</p>
<p><code>gatsby new gatsby-blog</code></p>
<h3>Classic Git Way</h3>
<p>Or you can <a href="https://github.com/gatsbyjs/gatsby">clone the repo from Github</a> and run an NPM install:</p>
<p><code>git clone https://github.com/gatsbyjs/gatsby.git gatsby-blog &amp;&amp; cd gatsby-blog &amp;&amp; npm install</code></p>
<p><em>Note if you opt against installing the CLI, you'll have to run NPM scripts instead of <code>gatsby</code> commands when building for development or production.</em></p>
<h2>Spin up the server</h2>
<p>Run the following command to start up your GatsbyJS blog locally:</p>
<p><code>gatsby develop</code></p>
<p>This command runs the build process, compiling the code into static assets, and gives you access to your GatsbyJS site at <a href="http://localhost:8000/"><a href="http://localhost:8000/">http://localhost:8000/</a></a>. And to make development easier, when you update your code while this is running, it'll re-compile -- allowing you to refresh and see changes instantly.</p>
<h2>Creating the content</h2>
<p>Our blog will use Markdown files to contain and display our posts. We'll be using the standard Markdown format with a top header. Make a new file in <code>src/blog/first-blog-post.md</code>:</p>
<pre><code class="language-markdown">---
title: My first blog post
date: "2018-04-20"
---

Do you enjoy Gabe the Dog? He is the immortal lead singer of Bork, a European band that does covers of popular pop songs from the 80s, 90s, and today.

&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/c--etqIJcow?ecver=1" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
</code></pre>
<p>Now that we have some content, let's display it on the website.</p>
<h2>Grabbing our Markdown files</h2>
<p>GatsbyJS uses components to create pages, so we could literally just create new JS files for each blog post. But that's messy and inefficient. So what do we do instead? Gatsby offers the ability to create <em>source</em> plugins that pull data from certain endpoints, like RSS, Medium, or Github. We're going to make Markdown in the same folder as the Gatsby project, so we'll be using the Filesystem source plugin to grab files locally.</p>
<p>We'll also install a <em>transformer</em> plugin, which takes GraphQL data and processes it. In our particular case, we want to take our data and process the Markdown into HTML. Run the following command to install that plugin:</p>
<p><code>npm install --save gatsby-source-filesystem gatsby-transformer-remark</code></p>
<p>And add the following JSON to your config to enable both plugins. If you look close at the <code>path</code> property of the filesystem plugin, we load our blog articles from the blog folder:</p>
<pre><code class="language-json">plugins: [
    // react-helmet is included by default with gatsby
    `gatsby-plugin-react-helmet`,
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src/blog/`,
      },
    },
  ],</code></pre>
<p>Restart your development server to commit the changes (hit CTRL + C to terminate the server and then run <code>gatsby develop</code> again). Now run this GraphQL query on your local <a href="http://localhost:8000/___graphql">GraphiQL development panel</a>:</p>
<pre><code class="language-graphql">{
 allFile {
  edges {
    node {
      name
      extension
    }
  }
 }
}</code></pre>
<p>Enter the query and hit CMD + Enter. You should see a JSON object on the right side with the blog post we just made.</p>
<h2>Making pages dynamically</h2>
<p>We could easily start querying this data on our pages and displaying our posts. If you paste this into <code>src/pages/index.js</code> you'll see all your files printed out in your console:</p>
<pre><code class="language-javascript">
import React from "react"

export default ({ data }) =&gt; {
  // displays an object of the query data in console
  // simply access what you need using a map function
  // data.allFile.edges.map()
  console.log(data)
  return &lt;div&gt;Hello world&lt;/div&gt;
}

export const query = graphql`
  query MyFilesQuery {
    allFile {
      edges {
        node {
          relativePath
          prettySize
          extension
          birthTime(fromNow: true)
        }
      }
    }
  }
`
</code></pre>
<p>Which makes for a great frontpage with a list of all of our posts, but we end up at the same dilemma as before. If we want separate pages for each blog post, we have to make new components to query each page individually. That's where the GatsbyJS API comes into play.</p>
<p>GatsbyJS is capable of taking a GraphQL query and creating pages for every object based off a template. For every Markdown file we create, when we build our GatsbyJS website, it'll get run through a template to create a page. We end up with HTML files for each page with the Markdown parsed into readable text.</p>
<p>Paste this into your <code>gatsby-node.js</code> file.</p>
<pre><code class="language-javascript">const path = require(`path`);
const { createFilePath } = require(`gatsby-source-filesystem`);

exports.onCreateNode = ({ node, getNode, boundActionCreators }) =&gt; {
    const { createNodeField } = boundActionCreators
    if (node.internal.type === `MarkdownRemark`) {
        const slug = createFilePath({ node, getNode, basePath: `pages` })
        createNodeField({
            node,
            name: `slug`,
            value: slug,
        })
    }
};

exports.createPages = ({ graphql, boundActionCreators }) =&gt; {
    const { createPage } = boundActionCreators
    return new Promise((resolve, reject) =&gt; {
        graphql(`
      {
        allMarkdownRemark {
          edges {
            node {
              fields {
                slug
              }
            }
          }
        }
      }
    `).then(result =&gt; {
                result.data.allMarkdownRemark.edges.forEach(({ node }) =&gt; {
                    createPage({
                        path: node.fields.slug,
                        component: path.resolve(`./src/templates/blog-post.js`),
                        context: {
                            // Data passed to context is available in page queries as GraphQL variables.
                            slug: node.fields.slug,
                        },
                    })
                })
                resolve()
            })
    })
};
</code></pre>
<p>First, we'll create slugs based off our Markdown file names, and add them to the GraphQL query results. Then we'll use the <code>createPages</code> API to make new pages based off a GraphQL query for the Markdown posts. Then we'll use the <code>createPage</code> function to actually generate the page based off the new file path and component that'll act as the template.</p>
<p>When Gatsby runs the build process, it'll run this script as well, which will trigger the creation of pages.</p>
<p>There's not much to explain here since this is just very API specific code. It's simple enough to be self-explanatory, and anything that's unclear is probably opinionated decisions from the API.</p>
<h2>The Blog Template</h2>
<p>Now that our blog posts are ready to get converted into static pages, let's actually create the template we referenced above <code>./src/templates/blog-post.js</code>. Make a new file there and paste this into it:</p>
<pre><code class="language-javascript">import React from "react";

export default ({ data }) =&gt; {
    const post = data.markdownRemark;
    return (
        &lt;div&gt;
            &lt;h1&gt;{post.frontmatter.title}&lt;/h1&gt;
            &lt;div dangerouslySetInnerHTML={{ __html: post.html }} /&gt;
        &lt;/div&gt;
    );
};

export const query = graphql`
  query BlogPostQuery($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
      }
    }
  }
`;
</code></pre>
<h2>Show me the posts!</h2>
<p>We've got our blog posts as Markdown ready to get converted, we have the React template, the only thing left is linking to the posts.</p>
<p>Head over to your <code>index.js</code> file and paste the following:</p>
<pre><code class="language-javascript">import React from "react";
import Link from "gatsby-link";

export default ({ data }) =&gt; {
  console.log(data);
  return (
    &lt;div&gt;
      &lt;h1 style={{ display: 'inline-block', borderBottom: '1px solid' }}&gt;
        Amazing Pandas Eating Things
      &lt;/h1&gt;
      &lt;h4&gt;{data.allMarkdownRemark.totalCount} Posts&lt;/h4&gt;
      {data.allMarkdownRemark.edges.map(({ node }) =&gt; (
        &lt;div key={node.id}&gt;
          &lt;Link
            to={node.fields.slug}
            css={{ textDecoration: `none`, color: `inherit` }}
          &gt;
            &lt;h3 style={{ marginBottom: '4px' }}&gt;
              {node.frontmatter.title}{" "}
              &lt;span style={{ color: "#BBB" }}&gt;— {node.frontmatter.date}&lt;/span&gt;
            &lt;/h3&gt;
          &lt;/Link&gt;
            &lt;p&gt;{node.excerpt}&lt;/p&gt;
        &lt;/div&gt;
          ))}
    &lt;/div&gt;
      );
      };

      export const query = graphql`
  query IndexQuery {
        allMarkdownRemark(sort: {fields: [frontmatter___date], order: DESC}) {
        totalCount
      edges {
        node {
      id
          frontmatter {
        title
            date(formatString: "DD MMMM, YYYY")
    }
          fields {
        slug
      }
      excerpt
    }
  }
}
}
`;
</code></pre>
<p>We query using the MarkdownRemark endpoint and grab the titles, slugs, and excerpts of our latest blog posts. Then we loop through the data to show the data, while using the <code>&lt;Link&gt;</code> component to link directly to the blog post (using the slug). </p>
<blockquote>
<p>Dont forget, you can always test out the query in the GraphiQL dev panel to make sure you have the right properties.</p>
</blockquote>
<p>If you restart your dev server at this point, you should see a list of the Markdown files you created. And if you click them, they'll take you to another page with the complete blog post. </p>
<p><strong>Congratulations!</strong> You've built your first static blog. You can stop here and just run <code>gatsby build</code> to make a production-ready version of your blog available in the <code>public</code> folder. Upload that directly to your FTP or web host and you're good to go. </p>
<figure><img src="http://stayregular.net/content/2-blog/20180416-deploy-a-static-react-blog-using-gatsbyjs-and-github/gatsby-first-blog-gabe-the-dog.png" alt=""></figure>
<p><strong>But why stop there?</strong> One of the principles of the JAMstack is using <strong>Git</strong> for version control. This allows you, or any dev on your team, to easily clone the website's repository and create an exact replica of the entire website. It also allows you to quickly push new changes to the server, rather than uploading files individually through an FTP. </p>
<h2>Let's git started</h2>
<p>If you haven't already installed Git on your computer, head over to the official website and download it. Then open up Terminal, <code>cd</code> to your project's root, and run the following command:</p>
<p><code>git init</code></p>
<p>This creates a new Git repository in your folder. Now let's commit all the changes we've made to the new repository:</p>
<p><code>git add -A &amp;&amp; git commit -m "Your Message"</code></p>
<p>This takes all the files in the folder and adds them to the Git repo. When you make changes, you'll be able to track the differences between previous versions before each commit (<code>git diff</code>). The message you leave usually hints at what kind of changes were made to the code. In this case, something like &quot;Initial commit&quot; or &quot;1.0&quot; is appropriate.</p>
<h2>Connect with Github</h2>
<p>Connecting with Github allows you to promote the highest accessibility for developers looking to access the website's source code, and to take advantage of Github's free hosting](<a href="https://pages.github.com/">https://pages.github.com/</a>). You'll sign up for a Github account if you don't already have one, create a public repo, and push (or upload) the project files to Github through Git commands.</p>
<h3>Sign up on Github</h3>
<ol>
<li>Create a new account on <a href="http://github.com">Github</a></li>
<li>Login to your account.</li>
<li>Click the plus sign in the top menu and click &quot;New repository&quot; from the dropdown.</li>
<li>Name your repo anything you'd like, then click the big green &quot;Create repository&quot; button.</li>
</ol>
<h3>Sync up your repo with Github</h3>
<p>To make syncing up to Github a single click we'll install <code>gh-pages</code>. This is a Github Pages package that pushes changes to Github and updates the page. Run the following command to install the package:</p>
<p><code>npm install gh-pages --save-dev</code></p>
<p>You'll also need to modify the <code>package.json</code> with a new script. This script runs the <code>gatsby build</code> process, then runs the <code>gh-pages</code> command to deploy to Github. Add the following line into the scripts section:</p>
<pre><code class="language-json">  {
        scripts: {
            // ...you'll see build, develop, format, etc above this....
            "deploy": "gatsby build --prefix-paths &amp;&amp; gh-pages -d public",
        }
    }
</code></pre>
<p>And since Github Pages hosts the blog in a subdirectory (e.g. <code>yourname.github.io/this-subdirectory/</code>), we have to add a path prefix to the configuration <code>gatsby-config.js</code> to let GatsbyJS know it's not in the root:</p>
<pre><code class="language-json">{
  siteMetadata: {
    title: `Your site Name`,
  },
  pathPrefix: "/your-repo-name",
}</code></pre>
<h3>Deploy!</h3>
<p>Go to your new repo on Github, click the Clone button, and copy the URL (ending in .git). Then run the following command to add a &quot;remote&quot; repo to your local git repo:</p>
<p><code>git remote add origin http://github.com/username/repo-name.git</code></p>
<p>Now we can build the site and push it to Github. Type in the following command, enter in your Github password when prompted, and profit!:</p>
<p><code>npm run deploy</code></p>
<p>The <code>public</code> folder of your blog will be uploaded to the <code>gh-pages</code> branch of your repo. If you click the dropdown labeled <strong>Branch: master</strong> you should see the gh-pages branch.</p>
<h3>Browse your blog</h3>
<p>Head back over to your repository on Github and see if you successfully pushed (or uploaded) your files. If it worked, head over to the project settings page. Here, you'll want to make sure Github Pages is enabled and that it's set to the <code>gh-pages</code> branch.</p>
<p>You should be able to access the blog by going to <a href="http://yourusername.github.io/repo-name/">http://yourusername.github.io/repo-name/</a>.</p>
<h2>Maybe not the Wordpress 5-minute install</h2>
<p>It might not be the most lightning fast blog creation out there, between the time it takes to install <code>npm</code> packages and the time you waste fussing with <code>git</code>. Though you have to admit that in a fairly short time span we were able to create a static blog ecosystem that deploys instantly. It's incredible to see the potential of GatsbyJS, and the different kind of experiences you can create compared to standard CMS platforms like Wordpress or Drupal.</p>
<p>If you've ever been thinking about taking the leap into a progressive web application (PWA), you want to try static, or you've just been interested in migrating off Wordpress -- I hope this guide helped you discover an alternative to the mainstream blogging experience.</p>
<h2>The potential is endless</h2>
<p>This is the first part in a series of articles we'll be writing featuring GatsbyJS. We've just dipped our toe in the water here, there's a wealth of plugins and potential we've yet to explore with this framework. We'll be looking into creating projects that explore or push the limitations of the JAMstack, from a portfolio site using the Behance API, to a static e-commerce store using Stripe, to building a true JAM app on a CDN with automatic and atomic builds.</p>
<p>Keep an eye on the <a href="http://stayregular.net/blog/tag:gatsbyjs">#GatsbyJS</a> tag to see our next post!</p>
<p>Find the <a href="https://whoisryosuke.github.io/gatsby-blog-tutorial/"><strong>example site here</strong></a>, and the <a href="https://github.com/whoisryosuke/gatsby-blog-tutorial"><strong>final example repo here</strong></a>.</p>
<p>Stay regular,<br />
Oscar</p>
<hr />
<p><strong>Keep Reading:</strong></p>
<ul>
<li><a href="http://kbroman.org/github_tutorial/pages/init.html">Git guide - Start a new git repository</a></li>
<li><a href="https://jamstack.org/best-practices/">JAMstack.org</a></li>
<li><a href="https://www.gatsbyjs.org">GatsbyJS</a></li>
<li><a href="https://www.gatsbyjs.org/tutorial/">GatsbyJS Tutorials</a></li>
<li><a href="https://www.gatsbyjs.org/packages/">GatsbyJS Plugins</a></li>
<li><a href="https://www.gatsbyjs.org/docs/how-gatsby-works-with-github-pages/">How GatsbyJS Works with Github Pages</a></li>
<li><a href="https://www.gatsbyjs.org/packages/gatsby-source-filesystem/?=filesy">gatsby-source-filesystem</a></li>
<li><a href="https://www.gatsbyjs.org/packages/gatsby-transformer-remark/?=remark">gatsby-transformer-remark</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>How to make Shopify Template Snippets</title>
      <link>http://stayregular.net/blog/how-to-make-shopify-template-snippets</link>
      <guid>blog/how-to-make-shopify-template-snippets</guid>
      <pubDate>Mon, 09 Apr 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>Customizable components are key to any modern platform. Users have an expectation to be able to adapt and change their websites using recyclable design components part of their theme's system. Users should be able to edit their sliders or page layouts on the fly, moving and editing things freely as they need, without development experience. </p>
<p>It's something that services like <strong><em>Squarespace</em></strong> and <strong><em>Wix</em></strong> embrace. Even <strong><em>Wordpress</em></strong> is trying to implement a version of it with their <em>Gutenberg</em> editor, and we've had it for years with the <em>WPBakery Page Builder</em> (formerly <em>Visual Composer</em>) plugin.</p>
<blockquote>
<p>Websites are a collection of components, there's no reason we can't abstract control away from the code and in the reach of a click.</p>
</blockquote>
<p><strong>Shopify</strong> offers a version of this with their '<strong>snippets</strong>'. A snippet is a reusable component that can be included in any template file. And on the frontpage of the website, you can use customizable snippets to compose a layout for the main landing page. </p>
<h2>How does it work?</h2>
<p>On the frontpage it's a very similar process to something like <em>Squarespace</em> or <em>Wix</em>. You have <strong><em>'content blocks'</em></strong>, each block is a <strong>snippet</strong>, and you arrange them in whatever order you'd like. If you click on a block, it reveals more options, like inserting text or images. </p>
<div class='images grid'><div class='image col-2'><img src=http://stayregular.net/content/2-blog/20180409-how-to-make-shopify-template-snippets/shopify-admin1.png /><p class='caption'>The widget</p></div><div class='image col-2'><img src=http://stayregular.net/content/2-blog/20180409-how-to-make-shopify-template-snippets/shopify-admin2.png /><p class='caption'>A block inside the widget</p></div></div>
<p>On any other page however, it still requires you to manually insert the include snippets into your Liquid page templates (<code>{% section 'your-snippet-here' %}</code>), and it doesn't offer the same level of customization. You can insert variables, but it's a different API than the block settings, so you'd have to account for that as well.</p>
<figure><img src="http://stayregular.net/content/2-blog/20180409-how-to-make-shopify-template-snippets/shopify-snippet.png" alt=""></figure>
<h2>Making the snippets</h2>
<p>Creating a snippet is a snap. Open up your Shopify theme folder, navigate to the snippets folder, and create a new Liquid file with any HTML you'd like. This is great for components that repeat across the website, like newsletter blocks or sidebar widgets. </p>
<p>Here's an example of a block that contains a text header and a flex grid of boxes with images as background:</p>
<pre><code class="language-html">&lt;div class="page-width"&gt;
  &lt;div class="section-block"&gt;
      &lt;div class="section-block__header section-block__header--padded text-center"&gt;
        &lt;h4 class="h1--mini section-block__title"&gt;Text columns with images&lt;/h4&gt;
      &lt;/div&gt;

    &lt;div class="flex column-flex"&gt;
        &lt;div class="flex__item column-overlay text-center"&gt;
            &lt;noscript&gt;
              &lt;div class="column-flex__image" style="background-image: url(http://images.google.com/imageurl.jpg); background-position: center center;"&gt;&lt;/div&gt;
            &lt;/noscript&gt;
            &lt;div class="column-flex__image lazyload"
              style="background-position: center center; background-image: url('http://images.google.com/imageurl.jpg);"&gt;
            &lt;/div&gt;
          &lt;div class="column-flex__content"&gt;
            &lt;p class="h5"&gt;Image Title&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h2>West Code Customs</h2>
<p>Customizing a snippet is where things get interesting. To make a snippet customizable, you have to add a <strong>schema</strong> to the bottom of the snippet. Copy and paste the following into the bottom of your current snippet:</p>
<pre><code class="language-json">{% schema %}
  {
    "name": "Text columns with images",
    "class": "index-section",
    "max_blocks": 24,
    "settings": [
      {
        "type": "checkbox",
        "id": "title_enable",
        "label": "Show header",
        "default": true
      },
      {
        "type": "text",
        "id": "title",
        "label": "Heading",
        "default": "Text columns with images"
      }
    ],
    "blocks": [
      {
        "type": "text_block",
        "name": "Text",
        "settings": [
          {
            "type": "text",
            "id": "title",
            "label": "Heading",
            "default": "Add a title or tagline"
          },
          {
            "type": "image_picker",
            "id": "image",
            "label": "Image"
          },
          {
            "type": "radio",
            "id": "image_align",
            "label": "Image alignment",
            "options": [
              { "value": "top center", "label": "Top center" },
              { "value": "center center", "label": "Center" },
              { "value": "bottom center", "label": "Bottom center" }
            ],
            "default": "top center"
          }
        ]
      }
    ],
    "presets": [
      {
        "name": "Overlay Columns",
        "category": "Text",
        "blocks": [
          {
            "type": "text_block"
          },
          {
            "type": "text_block"
          },
          {
            "type": "text_block"
          }
        ]
      }
    ]
  }
{% endschema %}</code></pre>
<p>Once you add this to your snippet, if you go to your frontpage and click &quot;Add Section&quot;, you should see the snippet title you defined in the list.</p>
<h2>What does the Schema mean?</h2>
<p>The first chunk of JSON is pretty self explanatory. The <strong>name</strong> is the title you'll see in Shopify's backend. The <strong>max_blocks</strong> limits the number of sub-components you can create (e.g.: a recent article snippet limited to 9 posts).</p>
<p>The <strong>settings array</strong> is where you put your top level configurations for the snippet. In this example, we give the user the type in their own header, and enable or disable the visibility of it.</p>
<p>The <strong>blocks array</strong> defines the extra <em>&quot;sub-blocks&quot;</em> you can create within your content blocks, or snippet. In this example, we create a block where the user can define header text, upload an image, and pick the image alignment. Depending on the <code>max_blocks</code> defined earlier, you can make that many <em>&quot;sub-blocks&quot;</em>.</p>
<p>The <strong>presets array</strong> creates a &quot;default&quot; setup for your snippet. If the widget is 3 column and works best with 3 blocks, you can create 3 sample blocks. When the user creates a new snippet, the 3 sample blocks will be automatically created for them (filled with the defaultvalues you define).</p>
<h2>Adding the variables to your snippet</h2>
<p>You can access top-level snippet configurations using <code>{{ section.settings.title | escape }}</code>, swapping title for the <strong>ID name</strong> of the desired setting. To get to block settings, you loop through the blocks and then access the for loop, like so:</p>
<pre><code class="language-html">{% for block in section.blocks %}
      {{ block.settings.title | escape }}
{% endfor %}</code></pre>
<h2>If block contains variable, do something</h2>
<p>When you combine the parameters you get from customization with Shopify's liquid templating system, you can achieve some fairly dynamic components with a minor tinkering. What happens if the user doesn't define any blocks? Or forgets to upload an image? We can handle all these conditional cases with Liquid's <code>{% if %}</code>.</p>
<p><strong>How do we handle the on/off toggles, like the header?</strong></p>
<p>Make a simple if statement checking for the variable. If it's switched to &quot;on&quot;, the variable will be true, so any code inside will be executed:</p>
<pre><code class="language-html">{% if section.settings.title_enable %}
      {{ section.settings.title | escape }}
{% endif %}</code></pre>
<p><strong>What if an image isn't defined?</strong></p>
<p>You can check for the variable and see if is equal (or in this case, not equal) to <code>blank</code>, a Shopify value that checks if the value is empty.</p>
<pre><code class="language-html">{% if block.settings.image != blank %}
      {{ block.settings.image | img_url: '600x600' }}
{% else %}
      &lt;img src="Placeholder.svg" /&gt;
{% endif %}</code></pre>
<p><strong>What if the user doesn't create blocks?</strong></p>
<p>The blocks variable contains a size attribute that lets you see how many blocks there are. You can check if it's equal to 0 in this case:</p>
<pre><code class="language-html">{% if section.blocks.size == 0 %}
      {% include 'no-blocks' %}
      {% comment %}
            We include a placeholder snippet that contains something like a statement saying "Sorry, no posts found".
      {% endcomment %}
{% endif %}</code></pre>
<p>This also comes in handy if you need to check for grid consistency (e.g.: if blocks == 3, then do 3-column class attributes).</p>
<h2>The final code</h2>
<p>When we string together a couple of simple if statements, and swap the hard-coded data with our Shopify snippet configuration variables, we have a fully customizable block:</p>
<pre><code class="language-html">&lt;div class="page-width"&gt;
  &lt;div class="section-block"&gt;
    {% if section.settings.title_enable %}
      &lt;div class="section-block__header section-block__header--padded text-center"&gt;
        &lt;h4 class="h1--mini section-block__title"&gt;{{ section.settings.title | escape }}&lt;/h4&gt;
      &lt;/div&gt;
    {% endif %}

    &lt;div class="flex column-flex"&gt;
      {% for block in section.blocks %}
        {% if block.settings.image != blank %}
          {% assign img_url = block.settings.image | img_url: '600x600' %}
        {% endif %}
        &lt;div class="flex__item column-overlay text-center" {{ block.shopify_attributes }}&gt;
          {% if block.settings.image != blank %}
            &lt;noscript&gt;
              &lt;div class="column-flex__image" style="background-image: url({{ block.settings.image | img_url: '600x600' }}); background-position: {{ block.settings.image_align }};"&gt;&lt;/div&gt;
            &lt;/noscript&gt;
            &lt;div class="column-flex__image lazyload"
              style="background-position: {{ block.settings.image_align }}; background-image: url('{{ block.settings.image | img_url: '300x300' }});"
              data-bgset="{% include 'bgset', image: block.settings.image %}"
              data-sizes="auto"
              data-parent-fit="cover"&gt;
            &lt;/div&gt;
          {% else %}
            &lt;div class="column-flex__image"&gt;
              &lt;div class="placeholder-background"&gt;
                {{ 'placeholder.svg' | asset_url }}
              &lt;/div&gt;
            &lt;/div&gt;
          {% endif %}
          &lt;div class="column-flex__content"&gt;
            &lt;p class="h5"&gt;{{ block.settings.title | escape }}&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      {% endfor %}
    &lt;/div&gt;

    {% if section.blocks.size == 0 %}
      {% include 'no-blocks' %}
    {% endif %}
  &lt;/div&gt;
&lt;/div&gt;

{% schema %}
  {
    "name": "Text columns with images",
    "class": "index-section",
    "max_blocks": 24,
    "settings": [
      {
        "type": "checkbox",
        "id": "title_enable",
        "label": "Show header",
        "default": true
      },
      {
        "type": "text",
        "id": "title",
        "label": "Heading",
        "default": "Text columns with images"
      }
    ],
    "blocks": [
      {
        "type": "text_block",
        "name": "Text",
        "settings": [
          {
            "type": "text",
            "id": "title",
            "label": "Heading",
            "default": "Add a title or tagline"
          },
          {
            "type": "image_picker",
            "id": "image",
            "label": "Image"
          },
          {
            "type": "radio",
            "id": "image_align",
            "label": "Image alignment",
            "options": [
              { "value": "top center", "label": "Top center" },
              { "value": "center center", "label": "Center" },
              { "value": "bottom center", "label": "Bottom center" }
            ],
            "default": "top center"
          }
        ]
      }
    ],
    "presets": [
      {
        "name": "Overlay Columns",
        "category": "Text",
        "blocks": [
          {
            "type": "text_block"
          },
          {
            "type": "text_block"
          },
          {
            "type": "text_block"
          }
        ]
      }
    ]
  }
{% endschema %}</code></pre>
<p>You should have something that looks like this:</p>
<figure><img src="http://stayregular.net/content/2-blog/20180409-how-to-make-shopify-template-snippets/speakers.png" alt=""></figure>
<h2>Easy as Schema</h2>
<p>I hope this helps you create some flexible components for your Shopify template. These customizable blocks empowers less tech-savvy editors with the ability to contribute on a new level effortlessly. </p>
<p>Is something not working correctly for you? Hit us up on <a href="http://twitter.com/stayregular420">Twitter</a> and ask for help. Or <a href="http://stayregular.net/contact">contact us today</a> if you need professional consultation and development for Shopify.</p>
<p>Stay regular,<br />
Oscar</p>
<hr />
<p>Keep Reading:</p>
<ul>
<li><a href="https://help.shopify.com/themes/liquid/tags/theme-tags#include">Shopify Docs on Snippets</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>How to use the Bulma CSS Framework (with SASS)</title>
      <link>http://stayregular.net/blog/how-to-use-the-bulma-css-framework-with-sass</link>
      <guid>blog/how-to-use-the-bulma-css-framework-with-sass</guid>
      <pubDate>Fri, 16 Mar 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>Bulma is described by it's site as a free and open source CSS framework based on Flexbox. Compared to packages like Bootstrap, it's <a href="https://codeburst.io/evaluating-css-frameworks-bulma-vs-foundation-vs-milligram-vs-pure-vs-semantic-vs-uikit-503883bd25a3#b3ae">more lightweight at 73kb</a> than other CSS systems like Bootstrap or Semantic. And it looks good, I like the aesthetic of the page and the <em>graphic</em> nature of it compared to a lot of other more reserved, almost <em>corporate</em> frameworks.</p>
<p>It's a simple as importing a single CSS if you're interested in using the default library. But if you want to easily change colors, typography, or any other settings across all the components -- it's much easier to use the SASS version. It was pretty easy, but it wasn't as well documented as I preferred, so I wrote this to help others through the process.</p>
<h2>Install Bulma-Start</h2>
<p>The kind folks at <strong>Bulma</strong> have put together a package to help developers compile <strong>SASS</strong> without any additional configuration to their existing project. Rather than installing <code>node-sass</code> yourself and setting up the <code>package.json</code>, you install the bulma-start package.</p>
<p>Run the following command in your project root:</p>
<p><code>npm install bulma-start</code></p>
<h2>How to use Bulma-Start</h2>
<p>The Github repo's readme wasn't very detailed on how to actually use the package. Luckily, <a href="https://github.com/jgthms/bulma-start/issues/1">someone had this issue already</a>, so the question's been roughly answered there.</p>
<p>In order to compile the SASS, you have to navigate terminal to the <code>node_modules/bulma-start</code> folder and run <code>npm</code> commands from there.</p>
<ol>
<li><code>cd node_modules/bulma-start/</code></li>
<li><code>npm run css-build</code></li>
</ol>
<h2>But what do I do with the files?</h2>
<p>You could include the CSS directly from the <code>node_modules</code> folder once it's compiled. But I personally put that folder under <code>.gitignore</code>, so it won't be committed to the repo.</p>
<p>I swapped this line in the <code>bulma-start/package.json</code>:</p>
<p><code>"css-build": "node-sass _sass/main.scss ../../assets/css/bulma.css",</code></p>
<p>This compiles the SASS file into a CSS file in your projects assets directory. And when you set NPM to watch, it'll keep updating the CSS file there as well. <em>Much easier.</em></p>
<h2>At the end of the day</h2>
<p>I wasn't a huge fan of Bulma. It's not organized well enough for my tastes. I had to convert it to a dark theme, which required me finding unique SASS variables for each components color (from background to link colors). It allows for greater customization between components, but makes mass-editing styles a nightmare. </p>
<p>They could really take a cue from Semantic UI and how they've designed their framework to be OOCSS. When I want a navbar to be blue, I don't have to dig through the Bulma SASS variables to find <code>$navbar-background-color</code>, I just include the CSS classes: <code>inverted blue</code>.</p>
<p>Stay regular,<br />
Oscar</p>
<hr />
<p><strong>Keep Reading:</strong></p>
<ul>
<li><a href="https://bulma.io/">Bulma</a></li>
<li><a href="https://bulma.io/bulma-start/">Bulma start (SASS Starter Kit)</a></li>
<li><a href="https://bulma.io/documentation/overview/start/">Bulma Docs</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>Make a NodeJS API with mySQL</title>
      <link>http://stayregular.net/blog/make-a-nodejs-api-with-mysql</link>
      <guid>blog/make-a-nodejs-api-with-mysql</guid>
      <pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>Today we'll be making an API to serve JSON data using NodeJS, Express, and MySQL. The example API we'll be building will serve cannabis strain data using <a href="https://github.com/kushyapp/cannabis-dataset">the open source Kushy dataset</a>. If you need example data, you can download it from the Github and import the SQL files to your DB.</p>
<p>I'll walk you through the process of installing dependencies, the structure of our app, and how to build it from scratch - step by step.</p>
<p><em>This guide assumes you have basic knowledge of mySQL (and ideally a database - either on your local server, <a href="https://www.apachefriends.org/index.html">LAMP</a>, remote URL, anywhere), and that you've at least <a href="https://nodejs.org/en/download/package-manager/">installed Node on your computer.</a> and used NPM before.</em></p>
<h2>Installing the dependencies</h2>
<p>In order to create the API, we need to use a few different libraries to make it happen. This is where things get opinionated. </p>
<p>We're going to use <strong><a href="http://expressjs.com">Express</a></strong> as our primary framework. If you're not jiving with this, you might want to try <a href="http://nodeframework.com/index.html#mvc">Koa or hapi</a> <em>(and another tutorial, cause we're jumping on the Express train).</em></p>
<h3>Production</h3>
<p><code>npm install express express-rate-limit cors helmet mysql --save</code></p>
<p>We'll be installing the following packages:</p>
<ul>
<li><strong>express</strong> - MVC for creating Node sites</li>
<li><strong>express-rate-limit</strong> - Allows for rate limiting of API</li>
<li><strong>cors</strong> - Cors will allow you to serve the API remotely</li>
<li><strong><a href="https://github.com/helmetjs/helmet">helmet</a></strong> - Secures your Express app with HTTP headers</li>
<li><strong><a href="https://github.com/mysqljs">mysql</a></strong> - Connects and interacts with MySQL through Node.</li>
</ul>
<h3>Development</h3>
<p><code>npm install --save-dev nodemon</code></p>
<p><a href="https://github.com/remy/nodemon">Nodemon</a> is used for hot reloading the server in development. Whenever we make a change in the code and save, if nodemon is running, it'll restart the Node server with the new code.</p>
<h2>App Structure</h2>
<p>Our app is structured as MVC, or Model View Controller. The <strong>model</strong> is the connection to the MySQL db. The <strong>view</strong> are the routes we connect to and display JSON data (like yoursite.com/api/users/). The <strong>controller</strong> are the functions that get data from the <strong>model</strong> and feed it to the <strong>view</strong>.</p>
<h2>Development Server</h2>
<p>Our 'development server' is Node. Isn't that convenient?</p>
<p>Let's setup your package.json. Under the scripts section, we'll set the start script to run our server.js file and set the port to 4200 (<code>PORT=4200 node server.js</code>). We'll also set the <strong>dev</strong> script to run nodemon, which will allow hot reloading in development. It should look like this:</p>
<script src="https://gist.github.com/stayregular/85f56a199d1080dc689a05d2ec5f46dc.js"></script>
<p>Now you can run the server using <code>npm start</code> in Terminal/Command Line. That'll spin up the Node server and run Express. Or you can enable hot reloading for development using Nodemon by running <code>npm run dev</code>.</p>
<h2>Hello World</h2>
<p>Lets set up the server to a working state. We'll create a file called server.js in your project root, include Express and it's router, and print out a 'Hello World' style statement to website. You can find <a href="https://expressjs.com/en/starter/hello-world.html">a version of this tutorial on the Express site</a>. My version is modified to use <strong>routes</strong>, instead of a direct printout:</p>
<script src="https://gist.github.com/stayregular/f4942b0bcf98252a65300c83a261c7b3.js"></script>
<h2>Model</h2>
<p>Now let's connect to our MySQL database and start pulling information to feed into Express. Create file in your models folder called <code>dbconnection.js</code>:</p>
<script src="https://gist.github.com/stayregular/4cde72889f1405ef1e1db1f16435b43a.js"></script>
<p>We define our variables that we want to query for, and execute the SQL statement using the <code>query</code> function. This returns a callback function, which has a object with results and another for any error reporting.</p>
<p>This MySQL package follows the same kind of principles you see from <a href="http://php.net/manual/en/ref.pdo-mysql.php">PDO in PHP</a>, you use prepared SQL statements. That's when you never directly insert your variables into a SQL statement, you use placeholders like <code>??</code> and <code>?</code> to represent spots you want escaped variables like <code>`table_name</code> <code>or</code>'value'`. <a href="https://github.com/mysqljs/mysql#preparing-queries">You can find more query examples here.</a></p>
<p>Now that we have a way to grab data, let's setup our routes to request it.</p>
<h2>Routes</h2>
<p>Routes tell the server what to show when you access certain parts of the site. For example, if you wanted to have an 'About' page located at <a href="http://yoursite.com/about/">http://yoursite.com/about/</a>, you'd have to setup a route for <code>/about/</code>. The route would tell the server, when someone requests <code>/about/</code>, we give them a response (like HTML).</p>
<p>We'll be creating a route file that shows the user welcome text when they come to the site (like the Hello World example). And we'll create another route for accessing strain data.</p>
<p>Let's do it!</p>
<h3>The Route</h3>
<p>Create a new file in your routes folder called <code>index.js</code> and add the following code:</p>
<script src="https://gist.github.com/stayregular/29450a6614134ea013704ff387735813.js"></script>
<p>We create a function that accepts the Express <code>app</code> variable. Inside the function, we import our controllers, which will actually display the data. Then we use <code>app</code> to assign the routes. </p>
<p>For the site index, we go with <code>app.use()</code>, which pumps out HTML. For the strains, we use <code>app.route</code> to send data to any GET POST request. </p>
<p>Now the server is programmed to use <code>getAllItems()</code> from the <code>strain</code> controller when we visit <a href="http://yoursite.com:4200/strains/">http://yoursite.com:4200/strains/</a>. If we visit there now, we'll get an error. So let's give it something to show.</p>
<h2>Controllers + GET Data</h2>
<p>We need a controller that pulls data from the model (MySQL DB), converts it to JSON, and returns it to the route. You could just create a single function that queries the DB. But we'll create a <code>Class</code>, that way we can have multiple functions (for different routes in the future). Type or copy paste the following:</p>
<script src="https://gist.github.com/stayregular/f72a153f4dbd67e4826b81656ddda66c.js"></script>
<p>The gist breaks down each step. We basically do a SQL query and we print results or error. We use <code>res.json()</code> to send the JSON to Express.</p>
<h2>POST/UPDATE/DELETE?</h2>
<p>We've handled the GET part of the POST request, but what about sending data or deleting? It's simple with the Express framework:</p>
<script src="https://gist.github.com/stayregular/7208540db6fdb3e0bffb67d5eb64df37.js"></script>
<p>We assign different functions to the <code>get</code>, <code>put</code>, and <code>delete</code> routes. In the put and delete functions, we use <code>req.params.rowId</code> to pull up the <code>:rowID</code>, and do a SQL statement to delete them. And ideally -- authenticate the request somehow (password, OAuth, <em>something</em>).</p>
<h2>Production</h2>
<p>You can run this server in production, <strong>but you'll notice one major flaw</strong>: once it crashes, it's down, and the API won't work until you manually restart the server command line-style. We solve this problem by using a <strong>process manager</strong>.</p>
<p>We can either use a server to deploy our app like <a href="heroku.com/">Heroku</a> (which is a cloud-based host with built-in process manager), or we install our own process manager on the production server. <em>We'll cover Heroku another time.</em></p>
<p>I use <a href="http://pm2.keymetrics.io/">PM2</a>, but there are <a href="https://expressjs.com/en/advanced/pm.html">other options</a>. I'll be covering PM2 here. There's <a href="http://pm2.keymetrics.io/docs/usage/quick-start/">a quick start guide on the PM2 site</a>, you'll find more details and useful commands there.</p>
<p><em>This requires SSH access to your production server. If you don't know what that is, I'd contact your host and see if it's available.</em></p>
<h3>Upload your project</h3>
<p>Upload the node project to your server. You can copy the node_modules folder, but it's recommended your run <code>npm install</code> in your project folder. The local node_modules folder will contain dev dependencies the production server might not need.</p>
<h3>Installing PM2</h3>
<p>You have to install PM2 globally, as we'll be using across the entire server.</p>
<p><code>npm install pm2 -g</code></p>
<h3>Quick Start</h3>
<p>We can quickly spin up our app right away using the following command in the project folder:</p>
<p><code>pm2 start app.js</code></p>
<p>But let's create a configuration file to pass variables to the app, like <code>PORT=4200</code> so our app knows it should run on that port. It's basically like the <code>package.json</code> script earlier, but PM2 uses a different structure.</p>
<h3>Create your ecosystem file</h3>
<p>Create a file called <code>ecosystem.json</code> in your project root (where <code>server.js</code> is):</p>
<script src="https://gist.github.com/stayregular/f70e26385f7baaf63ec9506750d7834c.js"></script>
<h3>Run the server!</h3>
<p>You're good to go! Run this script in your project folder:</p>
<p><code>pm2 start ecosystem.json --env production</code></p>
<h3>Check sever status!</h3>
<p>How do we know it's running? Did it crash? Where's my console.log?! -- No worries! PM2 stores it's data in logs, which we can access with the following shell scripts:</p>
<ul>
<li><code>pm2 show kushy-api</code> - Show server info and stats.</li>
<li><code>pm2 logs kushy-api --lines 50</code> - Show last 50 lines of server logs</li>
</ul>
<p>Change kushy-api to the app name you specified in your ecosystem file.</p>
<h2>Conclusion</h2>
<p>You can make any kind of API with this. As much as I have space in my heart for PHP, <strong>once you understand Node and Express, it's insanely easy to make an API</strong>. It feels more natural than using libraries like <a href="https://www.slimframework.com/">Slim</a> in PHP.</p>
<p>If you have any questions, feel free to <a href="http://twitter.com/stayregular420/">hit us up Twitter</a>.</p>
<p>Hope that helps,<br />
Oscar</p>
<hr />
<p><strong>Keep Reading</strong></p>
<ul>
<li><a href="http://expressjs.com">Express</a></li>
<li><a href="https://stackoverflow.com/questions/38133084/how-to-access-rowdatapacket-mysql-node-js">How to access RowDataPacket mysql-node.js</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>Using a Framework to Simplify Email Design</title>
      <link>http://stayregular.net/blog/using-a-framework-to-simplify-email-design</link>
      <guid>blog/using-a-framework-to-simplify-email-design</guid>
      <pubDate>Tue, 06 Mar 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>We switch from a standard HTML template stuffed with messy tabular components to clean human friendly code from Foundation for Emails.</p>
<h2>The Problem</h2>
<p><strong>Email design is hard.</strong> It's a bunch of nested tables and inline styles that create a deafening cacophony of inefficient code. </p>
<blockquote>
<p>If you've ever designed an email from scratch, or even altering a template, you've experienced the pain of parsing through the spaghetti. </p>
</blockquote>
<p>We were using a template that had enough components to make it flexible, but required us removing each component and it's inlined CSS every time. It was cumbersome to say the least, and we struggled to design emails that were short enough not to get clipped by standard ESPs like GMail.</p>
<h2>The Solution - Foundation for Emails</h2>
<p><a href="http://foundation.zurb.com/emails/getting-started.html"><strong>Foundation for Emails</strong></a> by ZURB is an email design framework that simplifies the development, testing, and building of emails. It comes pre-packaged with a SASS compiler, browser sync for fast development, production builds zipped by Gulp, and even sends test emails via AWS and Litmus.</p>
<h2>Inky</h2>
<p>One of the most attractive features was <strong>Inky</strong>, a templating language that simplifies the process of creating layouts with tables. With just a few lines of a code, you create a tabular layout that respects the complex email compatibility requirements.</p>
<p><strong>Inky:</strong></p>
<pre><code class="language-html">&lt;container&gt;
  &lt;row&gt;
    &lt;columns&gt;This is a column.&lt;/columns&gt;
  &lt;/row&gt;
&lt;/container&gt;</code></pre>
<p>And the <strong>final compiled HTML:</strong></p>
<pre><code class="language-html">&lt;table class="container"&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;table class="row"&gt;
          &lt;tbody&gt;
            &lt;tr&gt;
              &lt;th class="small-12 large-12 columns first last"&gt;
                &lt;table&gt;
                  &lt;tr&gt;
                    &lt;th&gt;This is a column.&lt;/th&gt;
                    &lt;th class="expander"&gt;&lt;/th&gt;
                  &lt;/tr&gt;
                &lt;/table&gt;
              &lt;/th&gt;
            &lt;/tr&gt;
          &lt;/tbody&gt;
        &lt;/table&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;</code></pre>
<p>This allowed us to cut out a significant amount of code from our emails, which made the template more <strong>elegant</strong> and <strong><em>legible</em></strong>. Things like spacing elements with nested tables and blank GIFs were made effortless using the <code>&lt;spacer&gt;</code> tag.</p>
<pre><code class="language-html">
&lt;container&gt;

  &lt;row class="header leaf"&gt;
    &lt;columns small="12" style="background:url(./assets/img/bg-leaf.jpg)"&gt;
        &lt;spacer size="25"&gt;&lt;/spacer&gt;
        &lt;center&gt;
            &lt;a href="http://stayregular.net/?utm_source=newsletter&amp;utm_campaign=redesign2018"&gt;
                &lt;img src="./assets/img/logo.png" alt="Stay Regular logo" /&gt;
            &lt;/a&gt;
        &lt;/center&gt;
        &lt;spacer size="100"&gt;&lt;/spacer&gt;
        &lt;img src="./assets/img/text-header-1.png" alt="We redesigned our portfolio site" /&gt;
        &lt;spacer size="45"&gt;&lt;/spacer&gt;
        &lt;a href="http://stayregular.net/?utm_source=newsletter&amp;utm_campaign=redesign2018"&gt;
            &lt;img src="./assets/img/btn-check-us-out.jpg" alt="Check us out" /&gt;
        &lt;/a&gt;
        &lt;spacer size="145"&gt;&lt;/spacer&gt;
    &lt;/columns&gt;
  &lt;/row&gt;

&lt;/container&gt;</code></pre>
<h2>The Flaws</h2>
<p>Even though the framework made designing emails incredibly simpler in a lot of ways, it still had a few kinks. </p>
<p>I had random conversion errors with <strong>MailChimp</strong> and sending the emails to <strong>GMail</strong> accounts. <em>Foundation for Emails</em> comes pre-built with a grid system, and it has media queries that make the email responsive at smaller widths (so it's not hard-set to a certain pixel width). The email code looked fine in MailChimp, but GMail compiled it differently, inlining the smallest media queries CSS. It broke the layout completely making the email fluid -- rather than a set width.</p>
<p>I also had issues testing emails with anything other than AWS. I wanted to use <a href="http://mailtrap.io"><strong>Mailtrap</strong></a>, since it's my go-to dev server for emails. Though I can't find any documentation on how to use Foundation with it.</p>
<p>At the end of the day you're still designing emails, so you're limited to what is compatible with common ESPs. No fancy CSS or JS effects, even with the SASS support. <em>But don't hate the player, hate the game.</em></p>
<h2>All in one solution?</h2>
<p>This framework is the easiest and best solution I've found for developing emails. No one comes close to this complete package. Despite a few kinks, the automated sync and build process are stellar additions to this framework. </p>
<blockquote>
<p>All my changes, from SASS to compressing images, gets compiled in <em>seconds</em> into production build that I can live edit or zip up for MailChimp. </p>
</blockquote>
<p>It even makes collaboration a bit easier by keeping all emails and styles under one repository. You git clone it off our Gitlab and <strong>you're good to go</strong> designing emails using our styled components.</p>
<h2>Quick Start Guide</h2>
<p>If I've piqued your interest with how successful our transition was, it's very easy to get started with Foundation for Emails. Just paste the following commands into terminal in your project's parent folder:</p>
<pre><code class="language-bash">git clone https://github.com/zurb/foundation-emails-template your_project_folder
cd your_project_folder
npm install</code></pre>
<p>Thanks again to <a href="http://zurb.com">ZURB</a> and <a href="https://github.com/zurb/foundation-emails/graphs/contributors">all the contributors</a> for putting together such an awesome seamless and simplified email development solution <em>(that's open source!).</em></p>
<p>Stay regular,<br />
Oscar</p>
<hr />
<p><strong>Keep Reading:</strong></p>
<ul>
<li><a href="https://github.com/zurb/foundation-emails">Foundation for Emails on Github</a></li>
<li><a href="https://foundation.zurb.com/emails/docs/">Foundation for Emails Docs</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>How to Get Certified for METRC</title>
      <link>http://stayregular.net/blog/how-to-get-certified-for-metrc</link>
      <guid>blog/how-to-get-certified-for-metrc</guid>
      <pubDate>Mon, 05 Mar 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>Are you looking to become compliant with your state's medical or recreational cannabis tracking system? Maybe you're a 3rd party looking to consult or create applications that interact with the state tracking API. Either way, you'll find yourself applying for METRC certification in your corresponding state. </p>
<p>We're here to help you demystify the process so you can gain access to METRC.</p>
<h2>What is METRC?</h2>
<p><strong>METRC</strong> is a 3rd party company that has been contracted by many states to handle their seed to sale tracking. METRC offers an online interface and API for growers, distributors, and retailers to update with their cannabis plant's progress (from planting seeds to sales receipt). Under the METRC system, each plant and 'package' is assigned a unique RFID tag distributed solely by METRC. This unique RFID tracks the plant through the system.</p>
<h2>Certification Process</h2>
<p>To gain access to METRC, you must first get certified to use the METRC system. This involves studying their terminology and workflow, and then taking 40 question multiple choice test.</p>
<p>Once you're certified, you can apply for access to certain API endpoints that your company requires access to. If you're developing a seed to sale application for example, you'll apply for access to the Plants, Plant Batches, Strains, Rooms, and Harvests endpoints. To apply for the access, you have to complete a competency examination for each endpoint (a GET, POST, UPDATE, and DELETE request usually).</p>
<h2>The Steps</h2>
<p>It's a fairly straightforward process to get certification. <a href="https://www.metrc.com/california">If you visit the METRC website for your state</a>, you'll find their checklist there. This is technically the bare minimum required to achieve certification and access to the API:</p>
<ul>
<li>Contact Metrc</li>
<li>Attend webinar</li>
<li>Get sandbox API keys</li>
<li>Take the sandbox test(s)</li>
<li>Get production API access</li>
</ul>
<h2>The Initial Steps</h2>
<p>The first few steps are easy, albeit time consuming. Contacting METRC is a snap and they respond back within a day with more details. Make sure to reserve your spot for the webinar when you make your initial contact, to cut back on the back and forth.</p>
<p>They only host the webinars every couple of weeks, and they do 2 sessions (a morning and afternoon). So if you don't catch it, you've got to wait a couple weeks until you can progress.</p>
<blockquote>
<p>The webinar sucks the life out of you. My experience with the webinar was absolutely terrible. </p>
</blockquote>
<p>They used GoToMeeting, requiring me to download that program. The webinar was full when I first clicked the invitation link and I didn't get in until 15 minutes later after about 20 attempts. After finally getting into the webinar, the audio was working fine, but the screen presenter's slides didn't work for the first half of the presentation. Luckily after complaining in the chat, they sent out a link to a PDF copy. The speaker was terrible, mumbling most of the time and incoherently stumbling through the subject matter. </p>
<figure class="border"><img src="http://stayregular.net/content/2-blog/20180305-how-to-get-certified-for-metrc/webinar-full.png" alt=""><figcaption>METRC overbooks webinars despite requiring you to reserve a spot</figcaption></figure>
<p>By the end of the presentation, I was handed a 200+ page METRC manual and essentially sent off to go do some homework.</p>
<h2>The Certification Test</h2>
<p>The test was one of the more difficult parts, primarily due to the spotty reference material I was sourcing. You're required to know how the METRC online interface works as well. The 200+ page manual has plenty of screenshots of the website to work off of, but it can get confusing.</p>
<p>Here's an example of one of the questions:</p>
<figure class="border"><img src="http://stayregular.net/content/2-blog/20180305-how-to-get-certified-for-metrc/metrc-exam.png" alt=""><figcaption>The METRC certification test</figcaption></figure>
<p>Some are fairly simple. Other can be pretty innocuous. While some questions aren't even in any documentation provided. One question asked: &quot;Which of the following attributes are required for the input of sales?&quot;. The manual cites: &quot;Please see your State Supplemental for entering sales into METRC&quot;. I had to track this <em>supplemental</em> down on Google. And questions repeat. It's a 40 question test, with about 3-4 questions that were exactly the same.</p>
<h2>Sandbox Tests</h2>
<p>Once you take the first test and get certified, you can request API access. METRC sends over the sandbox API information, as well as a Word document that contains your API examination.</p>
<p>The sandbox tests to acquire API access were by far one of the worst punishments I've received lately. Between the essentially <a href="https://api-ca.metrc.com/Documentation/#Plants.post_plants_v1_create_plantings">incomplete API documentation</a> and the useless manual, you're left to poke and prod about to properly use most of the API.</p>
<p>Here are some of the key issues I had with the sandbox test:</p>
<h3>Guesswork</h3>
<p>METRC simple doesn't provide you with enough data to complete the test, between their incomplete documentation to the cryptic paperwork you're occasionally forwarded. I had to poke around their API and experiment with what works. </p>
<p>The first question on the test asks you to perform a <code>POST</code> request to an endpoint, but doesn't give you the necessary parameters (license number) to complete it. So I had to go to their Facilities endpoint (<code>GET /facilities/v1/</code>), go through each one, and find a license number that works with the <code>POST</code> request. If it involved lab tests, I had to find a license associated with a testing lab.</p>
<p>After seeing the Facilities endpoint, I realized that Metrc had emailed me JSON files with the license numbers inside the filenames. It was never mentioned in the email or any docs, I apparently had to <em>intuitively</em> attain the information. And even after checking the JSON files, they still would require you to <code>GET</code> request multiple endpoints to figure out which facility was which.</p>
<h3>Half Ass Docs</h3>
<p>The plant batches API endpoint to <code>POST</code> plant growth changes requires 2 extra parameters that the documentation fails to outline -- but an error message will inform you of. Strain Name and Actual Date are necessary as well as the other 6 fields mentioned in the docs.</p>
<h3>Finding your POST results</h3>
<p>Once you figure out how to make a <code>POST</code> request with a valid license number, you'll get a 200 response code signifying success -- <strong><em>and nothing else.</em></strong> <code>POST</code> requests to Metrc don't provide any response, not even the IDs of the posts you just made.</p>
<p>To find your posts, use the same license number and request the <code>GET</code> endpoint for active posts. And depending on the endpoint, you have to specify the time range. If you <code>POST</code> a couple strains, you'll find them at <code>GET /strains/v1/active</code>.  </p>
<p>Often you'll need the ID of an item you just created, so you'll have to do a <code>GET</code> on the appropriate section's endpoint to find it. A bit cumbersome, particularly when you do a batch of requests.</p>
<h3>Don't Timeout</h3>
<p>Responses can and will take a long time. Make sure you don't set a timeout on the HTTP request. I set a 2 second timeout and couldn't POST to some endpoints because of how intensive error generation was (<strong>9993ms!</strong>). I only hope the production API is half as fast, since an average dispensary services about 1000 customers per hour (16 per minute, 0.2 per second), plus any other API requests (inventory changes, patient verification, etc).</p>
<h3>Downtime</h3>
<p>Speaking of slow servers, the API sandbox crashed during my testing period, and I couldn't test my application for 3 days before they were able to get it back online. If you're allotting yourself time for this in your schedule, keep this in mind.</p>
<figure class="border"><img src="http://stayregular.net/content/2-blog/20180305-how-to-get-certified-for-metrc/metrc-fail-website-down.png" alt=""><figcaption>The Sandbox API displaying an error message</figcaption></figure>
<h3>Track and Trace Flow</h3>
<p><strong>Know the flow</strong> for METRC, because the docs won't give you any hints. If you're <em>lucky</em> you'll get an error message pointing you in the right direction. </p>
<p>Every plant has to have a tag associated to it, plants belong to batches that associate a strain and plant type. Here's the order of operations for creating new items, from first to last:</p>
<blockquote>
<p>Strains &gt; Room &gt; Individual Plants &gt; Harvest &gt; Package</p>
</blockquote>
<p><strong>Strains</strong> are required to make plant. But things like <strong>plant batches</strong> can be created without first creating plants (think of it like a category that contains a certain type of plant). It's a bit confusing at first (and there are holes), but it's a little more manageable once you've gone through the flow a couple times.</p>
<h3>Plants Missing Tags?</h3>
<p>I had a major issue where I had to find plants to change their growth phase, however the facility I was using didn't have any plants with plant tags. The field was <code>null</code>, making it impossible to access through certain endpoints that require plant tags as a reference point. This was clearly a fault on METRC's side, either inputting incomplete sample data into the sandbox, or allowing for users to send incomplete POST requests that break the system's flow.</p>
<p>I contacted the METRC staff about the problem and never received any support. The only solution was to change the facility, find another plant with actual tags, and use that instead.</p>
<figure class="border"><img src="http://stayregular.net/content/2-blog/20180305-how-to-get-certified-for-metrc/metrc-fail-plant-tags.png" alt=""><figcaption>Plants require tags, but some plants don't have tags</figcaption></figure>
<p>You also can't create new plants using the API. Either the sandbox doesn't allow it, or METRC is expected to input every new plant when you purchase RFID tags from them. <em>I wouldn't know,</em> because after contacting METRC about it, I received no response.</p>
<h3>New Plant Tags</h3>
<p>If a <code>POST</code> request requires a new plant tag, you have to look inside the JSON file that's labeled with your facilities license number. If you can't find your license number in the files, you have to change to one of the provided options.</p>
<p>Sometimes plant tags may already be taken by other users in the sandbox environment. Just grab another from the sample data.</p>
<h2>That's it!</h2>
<p>Once you complete the examination, it's sent off to a 3rd party to check it, and you're give production level API keys.</p>
<p>It's a bit of a cumbersome process due to the METRC's incomplete and disorganized direction. What should be a straightforward process easily becomes a multi-week endeavor to navigate through their rat's nest of a system.</p>
<p>I wrote this article because I couldn't find anyone documenting any form of the process, despite METRC being used in 9 different states. If you have any information you'd like to share or clarify, please send us a copy and we'll update this post with your insights.</p>
<p>Stay regular!~<br />
Oscar</p>
<hr />
<p><strong>Keep Reading:</strong></p>
<ul>
<li><a href="https://www.metrc.com/">Official METRC website</a> </li>
<li><a href="https://api-ca.metrc.com/Documentation/">METRC API Documentation for California</a></li>
<li><a href="https://cannabis.ca.gov/track-and-trace-system/">California Cannabis Track and Trace System</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>Quick Tip: VSCode - Find and Replace with New Line</title>
      <link>http://stayregular.net/blog/quick-tip-vscode-find-and-replace-with-new-line</link>
      <guid>blog/quick-tip-vscode-find-and-replace-with-new-line</guid>
      <pubDate>Sat, 03 Mar 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>I made the switch to VSCode from Sublime Text a couple months ago, and there are quite a few subtle <em>(and not-so-subtle)</em> differences between the workflow. The first major difference I found was finding and replacing code that spanned across multiple lines. You simply can't do it feasibly in VSCode. </p>
<p>In Sublime (and Atom I believe), you can grab multiple lines of code and find and replace the entire code snippet with something else (like an entire other code snippet). It's totally possible in VSCode, don't get me wrong. But it requires you to manually RegEx the snippet each time. </p>
<p>It's a feature that's been requested <a href="https://github.com/Microsoft/vscode/issues/15727">since Nov 18, 2016</a>. And there are <a href="https://marketplace.visualstudio.com/items?itemName=axlan.multiline-find-and-replace">plugins available</a>, but they're not as elegant as just using the Find and Replace dialog.</p>
<h2>The &quot;Solution&quot;</h2>
<p>Switch your Find and Replace over to RegEx mode. Add <code>\n</code> or <code>\t</code> wherever you want a line break. It's a little tricky figuring out where it is sometimes, especially when applying it to snippets with tabbed indents.</p>
<p>You can also use <code>*.</code> continue the search across the line so it grabs everything.</p>
<h2>Example</h2>
<pre><code>'something
like this'</code></pre>
<pre><code>'something\n like this'
-with regex enabled</code></pre>
<h2>You get the idea</h2>
<p>It's really a shame that VSCode hasn't implemented this kind of feature. I don't mind flexing the RegEx muscles every now and then, but when it inhibits my workflow -- and I know a competitor easily accomplishes it -- it's unacceptable.</p>
<p>I hope this helps you with this simple problem I had switching over.</p>
<p>Stay regular,<br />
Oscar</p>
<hr />
<p><strong>Keep Reading:</strong></p>
<ul>
<li><a href="https://stackoverflow.com/questions/30351529/find-and-replace-with-a-newline-in-visual-studio-code">StackOverflow - Find and replace VSCode</a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=axlan.multiline-find-and-replace">Multiline Find and Replace plugin for VSCode</a></li>
</ul>        ]]>    
      </description>
    </item>
        <item>
      <title>The State of Payment Processing for Cannabis E-Commerce</title>
      <link>http://stayregular.net/blog/the-state-of-payment-processing-for-cannabis-e-commerce</link>
      <guid>blog/the-state-of-payment-processing-for-cannabis-e-commerce</guid>
      <pubDate>Fri, 02 Mar 2018 00:00:00 +0000</pubDate>
      <description>
        <![CDATA[
                
        
        
        
        <p>The cannabis industry is booming, and the online sector is no stranger to the success. Over the last few years we've watched a sea of new companies flood the digital market with cannabis based goods. But how do these companies sell products like CBD online and process credit cards? It's not magic -- <em>you just gotta know a guy.</em></p>
<h2>High Risk</h2>
<p>Payment processing for cannabis falls under the category of 'high risk'. It literally means just that for the banks and processors, they're dealing with a client that's a higher risk than others. Whether it's a higher risk of chargebacks or fraud -- or in the case of cannabis, selling a product that's borderline illegal.</p>
<p>Other companies that fall under the category of 'high risk' include:</p>
<ul>
<li>Adult orientated sites <em>(anything porn)</em></li>
<li>Auctions</li>
<li>Drug Paraphrenalia</li>
<li>Gambling</li>
<li>Get Rich Quick / Life Coaching</li>
</ul>
<h2>What does High Risk mean for business?</h2>
<p>You'll have to find a payment processor that specializes in high risk accounts, and they'll connect you to banks and credit institutions willing to work with you.</p>
<p>It also means you'll have to pay more. You'll pay more per transaction, as the fees tend to be around 6-12% -- instead of the 3.5% you see on a site like Paypal or Stripe. You also may have to pay a small fee per chargeback.</p>
<h2>The Rules</h2>
<p>Most online processors have a baseline of rules for dealing with cannabis companies. </p>
<ul>
<li>CBD or services. No actual cannabis with THC (unless you get a really good deal, and honestly, it's probably not a permanent solution)</li>
<li>21+ popup (most processors require it)</li>
<li>Terms of Service that reflect the age limitation</li>
<li>No sale or promotion of illegal drugs (As tempting as it may be, you can't associate your brand with magic mushrooms, cocaine, or any other illicit substance)</li>
</ul>
<p>In some cases, processors may ask for this (but if they do, I'd personally keep looking):</p>
<ul>
<li>Clean site of any cannabis references, apply, then re-apply canna-branding after confirmation.</li>
<li>Remove all social media posts referencing cannabis</li>
</ul>
<h2>The Slim List</h2>
<ul>
<li><a href="http://shopify.com">Shopify</a></li>
<li>Any other 3rd party <a href="http://Authorize.net">Authorize.net</a> reseller</li>
<li><a href="https://skyhighmoly.com/">SkyHighMoly</a></li>
<li>European Banks (<a href="https://www.emerchantpay.com/">EMerchantPay</a>, <a href="https://www.skrill.com/en-us/">Skrill</a>, etc)</li>
</ul>
<p>Here's where things get interesting. In my research of over 200 companies, I found that most (read: 99%) of American based companies would not offer any website associated with cannabis processing. And I'm talking <em>any</em> website, even if you're in lifestyle selling apparel -- if it's got a leaf it's a scarlet letter. </p>
<p>If you're working in the online space and you're looking for a quick option to sign up and get going -- there are few and far between. And the handful that are listed only work with non-cannabis selling entities, you'd basically have to be slinging only CBD.</p>
<h2>What should you pick?</h2>
<p><strong>Your easiest bet</strong> is to go with Shopify. I tried going directly to Authorize.net, Shopify's payment processor, and they denied any form of cannabis business. But they informed me that their resellers can offer payment services to cannabis companies at their own risk. Which Shopify does --<br />
albeit not openly, you can find plenty of <a href="http://smokecartel.com">paraphrenalia</a> and CBD shops on their platform.</p>
<p><strong>Your safest bet</strong> is to go overseas to Europe and poach on financial institutes in countries like the UK and Amsterdam -- where they already have a proliferation of quazi-legal cannabis-based businesses between coffeeshops and headshops. Find a bank/processor that allows for overseas banking and you should be set.</p>
<p>SkyHighMoly is a <strong>semi-safe</strong> option. They've been around for at least couple years now, and they were able to offer me personally some of the best rates around. And I've shopped everywhere else.</p>
<h2>My Advice?</h2>
<ul>
<li>
<p><strong>Never settle for check processing.</strong> It's a scam. In this day and age, there's no reason you can't be processing with credit or even debit. If the salesman offers you check processing and can't offer credit, walk away, they're a waste of time. Don't give any percent of your profits to people who can't even provide you a standardized experience.</p>
</li>
<li>
<p><strong>Go hard. Never hide anything.</strong> Show all your cards from the start and see what's allowed. The hidden cards will be played out on the table eventually. Most processors will work with you and advise you on what particular aspects failed their criteria. It's easier to go back and forth a few rounds in the preliminary process, than lose profits when your site is booming due to a random spot check.</p>
</li>
<li><strong>Have a backup plan.</strong> Make sure to have a minimum top 2, or top 3-5 options. With the flaky relationship of finance and cannabis due to federal limitations, a processor that seemed reliable for years may disappear in a day. It happened to dispensaries in <a href="http://www.miamiherald.com/news/local/community/miami-dade/article191287899.html">Florida recently when their banking solution closed all cannabis accounts</a>. The bank wanted to clean their slate due to a buyout from a federally regulated institution.</li>
</ul>
<p>Oh and don't fall for any of those phony <strong>&quot;potcoin&quot;</strong> fads. Cryptocurrency has proven to be an excellent way for businesses to facilitate sales. However, it comes at the cost of pouring money in a volatile micro-economy often controlled by a small subset that have been <a href="https://nypost.com/2018/01/08/ceo-of-porn-cryptocurrency-disappears-with-investor-money/">known to steal funds</a>. But if you're seriously interested in cryptocurrency, I'd recommend going with a mainstream coin like Bitcoin. And services like <a href="http://bitpay.com">Bitpay</a> can get your sales going.</p>
<h2>Still need help?</h2>
<p>If you've gotten this far <em>and</em> you've already expended all the options I've laid out -- welcome to the club! </p>
<p>Regardless of what choice you make, there is always an immense amount of risk involved in sustaining payment processing. And most businesses can and will lose their current processor in the next 1-2 years <em>(or tomorrow!)</em>. That's why you might want to look into a payment processing consultant who specializes in developing relationships with processors and even banks to offer you solutions. These experts find private banks on your behalf and create the relationship to facilitate sales. <strong>If you're selling cannabis</strong>, like a dispensary or distributor, <strong>this is your best option</strong>.</p>
<h2>It's not impossible!</h2>
<p>You can sell cannabis, and cannabis-related products, with a credit card. It is totally possible, and it's happening every single day with countless businesses. The most important thing is to not feel defeated, because the battle for payment processing will be an uphill struggle. That's why most people lean on simple solutions like Shopify, or run to consultants who solve everything for small percentages of everything.</p>
<p>Whichever you decide, I wish you the best of luck on your entrepreneurial journey!</p>
<p>Stay regular,<br />
Oscar</p>        ]]>    
      </description>
    </item>
    
  </channel>
</rss>