The Mijingo Blog

Latest news, updates, free tutorials, and more from Mijingo.

Manually Installing Craft 3

by Ryan Irelan

During the beta and RC period of Craft 3, the only supported installation option was using Composer. But not everyone wants to–or can–use Composer.

How do we install Craft without Composer?

Follow along in this video for step-by-step instructions (including some gotchas you should know about).

This was recorded from a live Twitch stream.

Want to learn even more with Craft (and save yourself a lot of time)? My Craft Essentials bundle covers Craft 2 & 3.

Installing and Configuring Laravel Valet for Craft

by Ryan Irelan

In this lesson, Ryan walks through how to install and use Laravel Valet and then uses it to run a local copy of Craft CMS 3.

Dry Run Before Adding to Git Repository

by Ryan Irelan

One focus in my Git classroom training is to give my students the knowledge and power to fix things when something goes wrong. I have an entire section on it (as well as in my video course series.

But it’s also important to test things before you do them so you can avoid things going wrong!

One way to do that in Git is to use the --dry-run flag with git-add.

Let’s say I have a bunch of changes and I just want to check what will happen when I run git-add to stage them for commit. Unstaging a staged change isn’t a big deal but I like to avoid problems (and fixing them!) if I can.


git add . --dry-run

Using this command I’m adding all changed files (the . means everything) but I’m only doing a simulation. When this happens I’ll get a list of files that will be included in the add and staged for the next commit.

A handy tip for the next time you want to see what happens before you do it.

The Slowest Git Commit in the World

by Ryan Irelan


In Git there’s the concept of “porcelain” commands and “plumbing” commands.

This obvious allusion to the toilet and its two types of interfaces. The simple, yet functional, porcelain. You interface with it and get the job done.

Behind the scenes is the plumbing. This does the dirty work of completing the job.

In Git, we have the same thing. The porcelain commands are the commands that you’ll typically use from the command line. git commit, etc.

The plumbing commands are the low level commands that make up the Git system. They are the commands that do the, uh, dirty work, and make your repository track and manage files and changes.

In this video, follow along as Ryan uses Git plumbing commands to manually hash, create and commit objects in Git.

We’ll start off by creating a new directory for our project and initializing a fresh repository.

And we’ll end up with the slowest Git commit in the world.

Git the Essentials

Learn everything you need to be proficient in Git. 40+ videos, 6 hours of learning, a better understanding of Git.

Get Git Essentials

Hashing Redirect Params in Craft

by Ryan Irelan

Back in version 2.6.2945 of Craft 2, Pixel & Tonic introduced the ability to require hashing of the redirect parameters that are set in forms (like when you sign in or sign up).

They introduced this enhancement to make Craft more secure. There is a potential Denial of Service (DoS) security issue with in-the-clear form data. In the example of a redirect parameter, this could allow someone to redirect the user to something other than what is specified in the hidden form element.

We need to protect our form data. Let’s learn how to do that, starting with Craft 2.

Protecting Return Parameters in Craft 2

The solution to protecting the redirect parameter in Craft 2 is two-fold:

  • In Craft 2.5.2750, the developers introduced the hash filter, which takes the input and hashes it using a HMAC (Hashed Message Authentication Code). On the back-end, while processing the request, the developer can validate the hash using a validateData method.
  • In Craft 2.6.2945. the developers introduced a configuration setting that forced each request with a redirect parameter to be hashed. This new config setting is called validateUnsafeRequestParams and it takes a boolean value. When set to true then the unsafe parameters (which is just the redirect parameter and perhaps some third party plugin parameters).

Together, these will protect your form redirect parameter from any security issues.

Let’s use the login form as an example:


<form method="post" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="users/login">
    <input type="hidden" name="redirect" value="{{ '/profile' | hash}}">
    <h3><label for="loginName">Username or email</label></h3>
    <input id="loginName" type="text" name="loginName"
        value="{{ craft.session.rememberedUsername }}">

    <h3><label for="password">Password</label></h3>
    <input id="password" type="password" name="password">

    <label>
        <input type="checkbox" name="rememberMe" value="1">
        Remember me
    </label>

    <input type="submit" value="Login">
</form>

We have our standard hidden field with the redirect name and the value is populated with a Twig output tag, a string for our redirect location. We use the hash filter on the string to hash it.

If we load this in the browser we should see that the string is hashed:


<input type="hidden" name="redirect" value="58c6ace5c2af26ac04772d20aea67659590b9441/profile">

Now, we need to require all redirect parameters to be hashed using the config option.

In our craft/config/general.php file we add the following item:


'validateUnsafeRequestParams' => true,

And now when we go to submit our form, it’ll validate the hash we pass as the redirect parameter and process the request.

If for some reason we have this enabled but we don’t hash our redirect parameter, Craft will return a error.

Protecting Redirect Parameters in Craft 3

Protect the redirect parameter in Craft 3 is a simpler process because Craft 3 requires hashing of all redirect parameters. The validateUnsafeRequestParams config setting we have in Craft 2 is gone. You can’t opt in (and you can’t opt out).

The only step we need to do in Craft 3 is to set our redirect hidden field in the form we’re using and pass it through the hash filter.


<input type="hidden" name="redirect" value="{{ '/profile' |  hash}}">

And what happens in Craft 3 if don’t hash the redirect parameter?

In the case of the login form, the login routine will proceed (successful if the username and password are correct) but the redirect will fail. The value of the redirect parameter will not be honored.

The Takeaway

Whether we are using Craft 2 or 3, we should be hashing the redirect parameters. It’s a good security practice in Craft 2 and by doing so you’ll be making your sites even more ready for a Craft 3 upgrade.

Global Sets in the Craft Element API

by Ryan Irelan

This article covers both Craft 2 and Craft 3. The Craft 3 changes are at the bottom of the article.

I’ve used the Element API in Craft CMS to share data with a Vue.js app, create a headless CMS for a blog, and to share common information among a group of related sites.

The Element API makes it easy to expose your Craft-powered website’s data via JSON so other applications can consume it and use it.

The third example is what we’ll work on in this article.

I have a network of related sites that all have the same footer containing a list of links (for a “network” of sites). I want to manage this set of links with the Craft CMS installation of the anchor site and share the links with the other sites in the network.

I’m storing this set of links and display information (like headers and new column indicators) in a Global Set called Network (with the handle network).

The Network Global Set has a single Matrix field called Sites (sites) with this setup:

  • Site (site)
    • Site Name (siteName), Plain Text
    • Site URl (siteUrl), Plain Text
  • Section Header (sectionHeader)
    • Section Title (sectionTitle), Plain Text
  • Column (column)
    • New Column (newColumn), Lightswitch

I’m organizing the Sites into sections (via a Section Header). I can control when a new column is created using g the New Column Lightswitch field. I want to ensure the same exact layout across all sites, so it made the most sense to include layout data in the Global Set.

In my video lesson on the Element API, I only worked with Entries. In this example we need to expose the data in a Global Set. The approach is similar but instead of using an Entries element type we use a GlobalSet element type.

Let’s code the Element API and see how it works.

Coding the Element API for Global Sets

If you’re not familiar with the basics of using Element API in Craft, please first review my video lesson on the topic.

We start with a basic Element API wrapper:


<?php
namespace Craft;

return [
    'endpoints' => [
    ]
];

We define our first endpoint. It can be whatever we want, but let’s call it api/network.json.


<?php
    namespace Craft;
    return [
        'endpoints' => [
            'api/network.json' =>
            [
                    
            ],
                
        ]
    ];

We need to decide what we want to return. Our network data is in a Global Set, so we need to set the elementType for this endpoint to ElementType::GlobalSet.

Then set the criteria for retrieving the Global Set by defining the handle of the set we want.

   
<?php
    namespace Craft;
    return [
        'endpoints' => [
          'api/network.json' =>
          [
            'elementType' => ElementType::GlobalSet 
            'criteria' => ['handle' => 'network'],
          ]
                
        ]
    ];

Now that we have our data, we need to transform it into a format that is acceptable as JSON. To do that we use a transformer. In the transformer, we create an anonymous function which passes in the GlobalSetModel so Craft knows the data model it should use.

   
<?php
    namespace Craft;
    return [
        'endpoints' => [
          'api/network.json' =>
          [
            'elementType' => ElementType::GlobalSet 
            'criteria' => ['handle' => 'network'],
            'transformer' => function(GlobalSetModel $globalSet) 
            {
                // our data here
            }
          ]
                
        ]
    ];

Inside of the transformer function we define our data as we want it to appear in the JSON output.

   
<?php
    namespace Craft;
    return [
        'endpoints' => [
          'api/network.json' =>
          [
            'elementType' => ElementType::GlobalSet 
            'criteria' => ['handle' => 'network'],
            'transformer' => function(GlobalSetModel $globalSet) 
            {
              $networkBlocks = [];
              foreach ($globalSet->sites as $block) {
                switch ($block->type->handle) {
                  case 'site':
                    $networkBlocks[] = [ 
                     array(
                       'siteName' => $block->siteName,
                       'siteUrl' => $block->siteUrl,
                     )
                    ];
                  break;
                  case 'sectionHeader':
                    $networkBlocks[] = [
                      'sectionTitle' => $block->sectionTitle,
                     ];
                  break;
                  case 'column':
                    $networkBlocks[] = [
                      'newColumn' => $block->newColumn,
                    ];
                }   
              }

            }
          ]
                
        ]
    ];

We define an empty array called $networkBlocks and then we fill up this array with our data.

At foreach ($globalSet->sites as $block) { we iterate over each site row in the Matrix field. For each one we are checking the block type using a switch statement.

If the block has more than one field, we assign its data to a nested array because we want those values to stick together. The keys we choose (e.g. siteName and siteUrl) will be used in the JSON.

We add the single field blocks to the main array with the keys set to the name we want to appear in the JSON.

To get our newly transformed data out, we need to return the array from the transformer function.

   
<?php
    namespace Craft;
    return [
        'endpoints' => [
          'api/network.json' =>
          [
            'elementType' => ElementType::GlobalSet 
            'criteria' => ['handle' => 'network'],
            'transformer' => function(GlobalSetModel $globalSet) 
            {
              $networkBlocks = [];
              foreach ($globalSet->sites as $block) {
                switch ($block->type->handle) {
                  case 'site':
                    $networkBlocks[] = [ 
                     array(
                       'siteName' => $block->siteName,
                       'siteUrl' => $block->siteUrl,
                     )
                    ];
                  break;
                  case 'sectionHeader':
                    $networkBlocks[] = [
                      'sectionTitle' => $block->sectionTitle,
                     ];
                  break;
                  case 'column':
                    $networkBlocks[] = [
                      'newColumn' => $block->newColumn,
                    ];
                }   
              }

              return ['network' => $networkBlocks];

            }
          ]
                
        ]
    ];

Let’s test the API and see what we get. If we coded it properly, we should see something like this at, for example, yoursite.com/api/network.json:



    {
      "data": [
        {
          "network": [
            {
              "sectionTitle": "Insight"
                },
                [
                    {
                        "siteName": "Personal Blog",
                        "siteUrl": "http://ryanirelan.com/"
                    }
                ],
                    {
                        "sectionTitle": "Training"
                    },
                [
                    {
                        "siteName": "Mijingo",
                        "siteUrl": "https://mijingo.com"
                    }
                ],
                [
                    {
                        "siteName": "Up and Running with SVG",
                        "siteUrl": "http://svgtutorial.com"
                    }
                ],
                [
                    {
                        "siteName": "Craft CMS Essentials",
                        "siteUrl": "http://craftcmsessentials.com"
                    }
                ],
                {
                    "newColumn": "1"
                },
                {
                    "sectionTitle": "Running"
                },
                [
                    {
                        "siteName": "Ryan Runs",
                        "siteUrl": "http://www.ryanruns.com"
                    }
                ],
            ]
        }
      ],
      "meta": {
    "pagination": {
      "total": 1,
      "count": 1,
      "per_page": 100,
      "current_page": 1,
      "total_pages": 1,
      "links": []
    }
      }
    }

With our Global Set data exposed as JSON via the Element API, we’re now ready to pull it into our target sites.

Making it Work in Craft 3

To get this same approach to work in Craft 3 (in RC1 as a I write this), we need to make a couple adjustments.

First, the file name inside of the config directory should be element-api.php instead of the elementapi.php name in Craft 2.

Second, at the top of the file we no longer need to specify the Craft namespace but instead specify the element type (or types) class name we plan to access. In our case we only need to access a Global Set, so the top of our file looks like this:


<?php
  use craft\elements\GlobalSet;

If we also want to fetch and return entries we’d would need to specify the Entry class name, too.

Next, we need to change where we refer to the Element Type and replace that with the Element Type class name we just added.


<?php
    use craft\elements\GlobalSet;
    return [
            'endpoints' => [
                'api/network.json' =>
                [
                    'elementType' => GlobalSet::Class
                    'criteria' => ['handle' => 'network'],
                    'transformer' => function(GlobalSet $globalSet) 
                    {

We also change the transformer to use GlobalSet instead of GlobalSetModel.

Everything else should work as-is!

If you need some assistance with Craft 3’s implementation of the Element API, you can refer to the official documentation.

How to Install Craft 3

by Ryan Irelan

Now that Craft 3 is available (as of this writing it is still in public beta), it’s time to learn how to install it.

There is one pre-requisite to installing Craft 3:

  • Install and configure Composer

What’s Composer? It’s a dependency management tool for PHP that helps manage software needed for individual projects (as opposed to traditional package managers that let you install software on your computer or server globally.)

Don’t have it installed yet? Watch my video install Composer.

After that you’re ready to install Craft 3. Here’s how:

 



What is the Element API in Craft CMS?

by Ryan Irelan

The Element API is a first-party plugin by Pixel & Tonic that allows you to create an API for sharing your data from Craft CMS. The responses are formatted as JSON (what is JSON?).

Using the plugin you can create an API that exposes Craft Elements via a JSON-formatted responses. The API only is read-only. You cannot write to Craft using this API and there’s no authentication built in. Be careful what you share!

The Element API is made up of the following pieces:

  • The plugin package itself
  • The elementapi.php file you have to create
  • The code in the file that defines the endpoints and the exposed data

To use the Element API plugin you need to meet these requirements:

  • Craft CMS installed and populated with data you want to expose via the API
  • PHP 5.4 or later (different than the current requirement for Craft CMS)

Installing the Element API plugin is like installing any other Craft plugin: drag the plugin file to the plugins directory and then install the plugin via the Craft Control Panel.

Watch the Free Lesson

How to Create an API with Craft CMS

by Ryan Irelan

In a recent lesson, I walked through how to use the Element API Plugin from Pixel & Tonic to create a JSON API that shares your website’s data (only that data which you choose, of course) for consumption by another website or service.

The free lesson is a fundamental approach to building a read-only API using the default ElementTypes (entry, category, asset, etc) in Craft. As long as you follow my steps, you can get an API up and running quickly.

Toward the end of the lesson, we also learn how to expose your Craft Commerce order data via an API so you can have an outside tool (like a Goole Spreadsheet or reporting tool) ingest it and use it create some sort of report.

Watch the Lesson

Using git-cherry-pick

by Ryan Irelan

Recently I ran into a problem on a project where I was working on the wrong branch and committed changes. Those commits were supposed to go elsewhere and I now I need to get them into the correct branch!

There are a few options to solve this:

  • Merge the incorrect branch into the correct branch. But I don’t want to that because there are items in the incorrect branch that I don’t want. So, that’s out.

  • Recreate those changes in my working branch and just go on with my day. But that’s a waste of my time and I’m adamantly against redoing work!

  • Create a patch and then apply that patch to the new branch.

All solid options but there’s still something better:


$ git cherry-pick

Let’s review where we’re at and then how to solve the problem using git-cherry-pick.

The State of Things

I created a new commit in my repository, in the branch called some_other_feature. But that’s the wrong branch!


$ git branch
    develop
    master
    my_new_feature
*   some_other_feature
    stage

The new commit should be on the my_new_feature branch. I could merge the branches but the some_other_feature branch contains commits and changes that I don’t want in the other branch (they are not ready for merging into any upstream branches, like develop or master.

Here’s the commit I need to get into my_new_feature:


commit ec485b624e85b2cad930cf8b7c383a134748b057
Author: Ryan Irelan 
Date:   Fri Aug 19 10:44:47 2016 -0500

    new contact page

Using git-cherry-pick

The syntax of git-cherry-pick is this:


$ git cherry-pick [commit hash]

The first step is fetch the commit hash for the commits we want to cherry-pick. We can do that using git-log and then copying the hash (in full or just the last 7 characters will work) to our clipboard.

Next, we need to be on the branch where we want the changes to be (our destination branch).


$ git checkout my_new_feature

Now we can run the git-cherry-pick command and apply the commit to our destination branch.


$ git cherry-pick ec485b624e85b2cad930cf8b7c383a134748b057

This will return something like this:


[my_new_feature 1bf8955] new contact page
Date: Fri Aug 19 10:44:47 2016 -0500
1 file changed, 1 insertion(+)
create mode 100644 contact.html

If we look at our log for this branch, we now see our commit:


$ git log
commit 1bf8955d5e6ca71633cc57971379e86b9de41916
Author: Ryan Irelan 
Date:   Fri Aug 19 10:44:47 2016 -0500

    new contact page

What’s happening when we run git-cherry-pick?

  • Git is fetching the changes in the specified commit and replaying them in the current branch. The commits are not removed from the source branch; they remain intact.
  • Because this commit is being applied to a new branch and therefore has different contents it will get a different hash than the source commit.

With the problem solved, we are ready to move on with our development work!

Learning More About Git

To learn more about Git check out our Git courses, lessons and tutorials.

Learn more about Git

New Lesson: Using Git in Sublime Text

by Ryan Irelan

A new lesson is available now on how to use Git version control right inside of Sublime Text 3. The goal for this lesson is to learn one way to work a bit more efficiently while coding. There are a few packages available for connecting Git and Sublime Text. In the past I’ve used one called Sublime Text Git and it’s a popular choice. Recently I’ve started using Git Savvy and I really like it so I wanted to share it.

This lesson walks you through installing an using Git Savvy in Sublime Text 3.

Watch the Lesson

Installing Sublime Text Package Control

by Ryan Irelan

Installing packages (add-on functionality that isn't core to the Sublime Text application) in Sublime Text is faster using the Package Control tool.

Package Control isn't part of Sublime Text but an independent project that makes adding additional functionality to Sublime Text easier. If you like Package Control and find yourself depending on it for your work, consider saying thanks to the developer with a small donation to help cover server costs.

To install Package Control on Sublime Text 3, you need input a series of commands into the Sublime Text console. This is actually a Python console but for our needs we just need to paste in a series of commands and Sublime Text will take care of the rest.

Get the Python Code

From the Package Control installation instructions, we grab the Python code to install Package Control. Get the latest version from the site (I could past it here but the code changes with each release and I want to make sure you have the latest code).

Run the Code

To kick of the installation, we run the code in the Sublime Text console.

  1. Type `control-`` to open the console in the bottom portion of the Sublime Text application window.
  2. Paste in the code and press enter.
  3. Once complete and successful, restart Sublime Text.

Type shift-command-p to open the command palate and type:

package control

If you see options for Package Control (like Package Control: Install Package) then Package is properly installed.

Sometimes the tool doesn't install properly. If this happens to you, use the manual installation instructions instead.

Export Files from a Git Repository

by Ryan Irelan

In this free lesson video, Ryan walks through how to use the git-archive command to export the files from a Git repository into a ZIP file.

Watch the lesson on archiving files from Git

Ready to learn more about Git?

We have more courses, articles, and tutorials on Git. Start learning immediately!

See the courses

Brief Overview of Craft Routing to Templates

by Ryan Irelan

How does Craft know which template to render when? It all starts and ends with Craft’s request routing.

The Craft documentation for Routing starts us off perfectly:

When a request comes in, Craft goes through several checks when determining where to route the request.

Craft does a routing check sequence that every request goes through so it ends up at the right place, delivering the right page or asset.

Pull up the routing documentation page and let’s talk through it.

The first three checks in the routing sequence:

  • “Should Craft handle this request in the first place?”
  • “Is it a resource request?”
  • “Is it an action request?”

cover whether Craft should take the request at all (sometimes it’s not necessary), if it’s a request for a Craft-managed resource, or if it’s an action request (like submitting a form or other actions from third-party plugins).

The fourth check is if the request is for an entry or category page. If there is a URI match then Craft will load the proper template (the one you specified when setting up the category or section).

The fifth check is if the request matches any Dynamic Routes you set up in the Craft control panel. Dynamic routes are hugely powerful in allowing you to create custom URIs that don’t necessarily match the template path. This saves you from having to conceive an unusual template directory and file naming scheme just to get the URLs to be how you want. If there is a match then Craft will render the template specified in the matching Dynamic Route.

The second-to-last check in the sequence to see if the request URI matches a template. If the URI is a valid template path (directory + template), then Craft will render that template.

This is a literal routing of the URI to the template.

If you have a request for mysite.com/offices/austin template offices/austin.html and Craft goes through its checks and doesn’t find a match before it gets to the template check then it will render the offices/austin.html template. If you had an entry with that URI then it would render the entry instead (using whichever section entry template you specified).

At the end of the check sequence, if there are no matches, Craft will return a 404 error. If you don’t have a custom 404 template, Craft will render the default view. To create a custom 404 template, add a 404.html template file in the root of your craft/templates directory and Craft will use it.

Ready to learn more about the Craft CMS?

My Craft Starter Pack is 4 ½ hours of premium learning that will get you started building sites with Craft for yourself, your company, or your clients.

Get Immediate Access

Sublime Text Tips and Plugins

by Ryan Irelan

Magnus Gyllenswärd of Thoughtbot did a short overview of some of the features and plugins he uses and likes in Sublime Text as part of his Thoughtbot Lunchtime Lightning presentation.


Here are some of the things he covers:

  • Fetch - fetch remote files from anywhere
  • Gist from condemil, create and edit Gists.
  • Less Tabs from Web Artisan. Remove tabs that you haven’t used in a while.
  • Emmet - Official plugin for Sublime Text for writing markup faster.
  • Multiple cursors - a flagship feature of Sublime Text. Memorize this if you don’t know it already.
  • Sublime Text Projects - a feature I don’t really use but probably should!
  • Can I Use plugin, that lets you highlight a property and see its support on caniuse.com.

By the way, if your company doesn’t do lunch time talks where you share information and techniques internally, I strongly encourage it. Whether you call them Lunchtime Lightning talks, Lunch ‘n’ Learns—as they were at my previous company—or no name at all, these gatherings are a way to rapidly transfer knowledge among team members. Very valuable!

(Link via Gabe at Macdrifter)

How to install Gulp.js

by Ryan Irelan

Just like its JavaScript Task Runner neighbor Grunt, Gulp also makes it simple (and fast!) to automate those really annoying web development tasks, like concatenating files, processing Sass, minifying JavaScript files, or optimizing batches of images.

In this tutorial, we’ll learn how to install Gulp.js.

Just like with Grunt, our first dependency is Node.js, so the video will start there. I’ll continue on after the video with some more steps to get set up.


Once inside the project where you want to run Gulp (you can get project shown in the video as part of the JavaScript Task Runners course I put together), we need to create a package.json file that we’ll use to define the decencies for the project, including Gulp.

We’ll do that on the command line using:

npm init

which will walk us through the process by asking some questions about our project. Once we’re done with the questions, npm will generate the package.json file for us, saving it at the root of our project.

We want to save Gulp as a dependency for our project, so in the project root we run:

npm install gulp --save-dev

We use --save-dev so the module is saved in package.json as a dependancy. When someone else wants to work on the project on their computer, they can run nom install and all of the dependencies listed in package.json will be installed automatically.

After the installation of Gulp is done, you should see some output and then a new command prompt.

We look at the package.json file and we see that gulp was added as a dependency for this project.

To ensure that Gulp is available for us on the command line, we need to install it globally:

npm install gulp -g

Running Gulp will now work for us, inside the project:

gulp

That should output:

[08:29:38] No gulpfile found

because we don’t yet have a Gulpfile.js file defining our Gulp tasks.

Creating a Gulpfile.js File

Either create a new file in your favorite code editor (right in the root of the project, alongside the package.json file), or do it in the command line:

touch Gulpfile.js

Now when we run Gulp:

gulp

We should get a bit more output, like this:


[08:33:46] Using gulpfile ~/projects/test-project/Gulpfile.js
[08:33:47] Task 'default' is not in your gulpfile
[08:33:47] Please check the documentation for proper gulpfile formatting

Gulp now sees our Gulpfile.js file but there’s nothing in it. At the very least, Gulp needs a default task to run when we use the plain gulp command. Let’s add one, shall we?

Open up the Gulpfile.js file and add the following to it:


var gulp = require('gulp');

gulp.task('default', function() {
    // Code for the default task
});

We have to first require gulp at the top of the file, so we can use Gulp to run our tasks. After that, we define our default Gulp task. The task is empty (containing only a code comment) but it will be enough to check that Gulp is running properly.

Save the file changes and the pop back onto the command line and re-run gulp:

gulp

You should now see more output from Gulp, this time showing that it ran the default task:


[08:43:04] Using gulpfile ~/projects/test-project/Gulpfile.js
[08:43:04] Starting 'default'...
[08:43:04] Finished 'default' after 79 μs

Now you’re ready to start defining your own Gulp tasks and automate those pesky development chores!

Learn More About Grunt & Gulp

My video course will get you up and running on both task runners in just 90 minutes.

Get the Grunt & Gulp video course

How to Install Grunt

by Ryan Irelan

Installing Grunt is the first step to automating your web development workflow with a JavaScript Task Runner and it takes just a few steps.

Here’s a video of the steps (pulled right from the course). The written steps are also below.


To install Grunt we need to use the command line.

  • Install Node.js. Using the big green button on the NodeJS site, download the installer package for your operating system. This includes NPM or Node Package Manager, which we also need to manage our Grunt plugins.
  • We do want to make sure we are up to date with npm. So, first, run:
npm update -g npm
  • Now we can install the Grunt command line tool using npm:
sudo npm install -g grunt-cli

This will install the grunt command line tool in your system path and allow it to be run from anywhere on your system. It doesn’t install Grunt, just allows us to run the local project version of Grunt from the command line.

Learn More About Grunt & Gulp

My video course will get you up and running on both task runners in just 90 minutes.

Get the Grunt & Gulp video course

Git Aliases in .bash_profile

by Ryan Irelan

Learn how to add system-wide Git aliases to your .bash_profile that allow you to:

  • create a shortcut to quickly push changes to the develop branch of your project
  • quickly push to the master branch using a bash alias
  • stage a boatload of files (added and deleted) with one five-letter command. This is perfect to large updates to CMSes, frameworks, and web apps.

This 7 minute video is an excerpt from the OS X Shell Tricks course.

Three Twig Tag Types in Craft CMS Explained

by Ryan Irelan

Templating in Craft using Twig can, at first, be a little confusing. If you, like me, come from other systems that have a proprietary template tag system, then it might take a little time to wrap your head around how Craft and Twig work.

But once we learn about the different types of tags things will be clearer and you’ll discover the power of using Twig in Craft. This tutorial will give you the direction and guidance you need to get started.

Let’s jump right in.

There are three tag types in Twig and Craft:

  • Statement/Logic Tags
  • Output Tags
  • Comment Tags

You will always use the first two in your Craft templates. The third, comment tags, are optional but a handy way of documenting anything that isn’t obvious by reading the code.

Statement/Logic Tags

Statement or logic tags use the curly brace plus percent sign delimiter. In Twig and Craft they can come in multiple forms.

Some are just a single tag, like this Craft-specific Twig tag:

{% requireLogin %}

which you would put at the top of a template in Craft to require a logged-in state. If a visitor is not logged in than Craft will automatically redirect them to the log-in page.

Other logic tags take parameters, like the redirect tag in Craft:

{% redirect "about/tos" %}

The redirect tag takes one parameter, which is the URL or path to where you want to redirect the visitor. This is a tag specific to Craft but there are some Twig tags you should know, too.

Another type of tag is one that has an opening and closing tag, like the for tag in Craft.


{% for %}
{% endfor %}

The tag pairs have an opening tag and a closing tag. The closing tag will typically have an “end” prefix, like endfor, endpaginate, and endblock.

Even the set tag we use to set a variable can be used as a tag pair. The simple version looks like this:

{% set author = "Ryan Irelan" %}

But using a tag pair for set, you can assign a block of text to a variable. Here we’re setting the variable socialLinks to an unordered list of social network links:


{% set socialLinks %}
<ul class="social">
    <li class="twitter"><a href="">Twitter</a></li>
    <li class="facebook"><a href="">Facebook</a></li>
    <li class="googleplus"><a href="">Google+</a></li>
</ul>
{% endset %}

Another example of a tag pair–and by far your most used tag while writing Twig template code for Craft–is the for-loop. It’s how you will loop through and display section entries in your templates and output other lists, like categories.

This is a for-loop to display content from an array of blog posts:


{% for entry in craft.entries.section('blog') %}
    {{ entry.body }}
{% endfor %}

It uses the curly brace plus percent sign delimiter for both the opening and closing tags of the for-loop. This delimiter tells Twig that what’s between needs to be executed as a statement (in this case a for-loop).

Output Tags

The code with the double curly braces are output tags. They print variable contents to the screen (i.e. output content in your template).

{{ author }}

The author variable would output my name (because we set it in the previous example).

If you want to use an output tag to pass in data to another tag, like when we set a variable in Twig, then you don’t need to use the double curly braces.

{% set name = author %}

If we printed out the value of the name variable we just set than it would render:

Ryan Irelan

But output tags can generate the output on the fly and then print it to the screen. How about a little math?

{{ 4 * 4 }}

This output tag will do the multiplication of 4 and 4 and print out the product. I’m unsure how practical it is to do math like this in the template but there you have it.

The Twig documentation calls out that the curly braces are not part of the variable itself but instead an indicator that the value of the variable contained within should printed to the screen.

Comment Tags

This tag type is straight-forward but perfect for adding comments to your templates but not have those comments render in the page source like HTML comments would.

{# Begin logic for sidebar #}

Using a single opening curly brace paired with a pound sign, we can create the un-rendered comments. They’ll always be available in your template file but never rendered by Twig.

Any code that is inside the comment tag will not be executed by Twig.


{# removing this for now to debug
    {% for entry in entries %}
        {{ entry.body }}
    {% endfor %}
#}

There’s a lot more to templating with Twig in Craft but this introduction to three different tags will get you set off in the right direction.

Don’t miss my new course on Craft + Twig

Coming soon is a brand new video course on Twig & Craft that will help you grasp what Twig is, how Craft and Twig work together, and some templating best practices. Sign up below to get notified when the course is ready!

Ready to learn more about Craft?

If you want to learn more right now about Craft, I have a popular 2 ½ hour video course that will get you started on the right path.

Get the Craft video course

Important SVG Elements

by Ryan Irelan

There are a lot of elements–and attributes–to consider when writing SVG. But to get started, we don’t have to learn them all. Let’s review the most important ones you’ll encounter while working with generated SVG or SVG you coded yourself.

svg Element

You’re probably already very familiar with this. It’s the main element of SVG and inside of which you nest any shapes, paths, lines, etc. that you want to draw.

The SVG element defines the viewport or canvas for SVG content.

Here are some of the specific attributes for svg:

  • height - the height of the viewport
  • preserveAspectRatio - forces the aspect ratio so your image isn’t stretched when using the viewBox element to define a new coordinate system.
  • viewBox- Allows you to set a new coordinate system by defining where x,y coordinates where the system starts as well as the width and height.
  • width - The width of the viewport for this SVG element.

g Element

This element is used to create groups of SVG objects. For example, if you had a series of related rectangles (rect), you can group them together inside of a g element. The nice thing about this is that any transformations you apply to g apply to everything inside of the group.

The g element accepts all global attributes (like stroke, fill, etc).

circle Element

This element does exactly what it says in the name: it creates circles.

circle accepts three element-specific attributes:

  • cx - This attribute defines the x coordinate of the center of the shape.
  • cy - This attribute defines the y coordinate of the center of the shape.
  • r - Defines the radius of the circle.

rect Element

This is the elements we used in all our examples up to this point. It creates rectangles.

The rect elements takes the following attributes:

  • height - Defines the height the shape.
  • width - Defines the width of the shape.
  • x - The x coordinate where the shape should start drawing.
  • y - The y coordinate where the shape should start drawing.

line Element

The line element allows you to draw lines in SVG. Each line connects two points by setting x and y coordinates.

Here are the attributes available in line:

  • x1 - the start of the line on the x axis
  • y1 - the start of the line on the y axis
  • x2 - the end of the line on the x axis
  • y2 - the end of the line on the y axis

path Element

You’ll see the path element if you take an existing artwork and convert it to SVG (in Adobe Illustrator, for example). Illustrator converts the artwork to SVG by tracing the shapes in the image and converting them to SVG path elements.

Any shape can be created with the path element. It takes the following specific attributes:

  • d - this is the definition attribute, which defines the path to follow to create the shape. The path is defined using “path descriptions:” Moveto, Lineto, Curveto, Arcto, ClosePath.
  • pathLength - Use this attribute to define the total length of the path.

polygon Element

The polygon elements allows you to create any shape with many sides. A typical example would be an octagon. You plot the sides of the polygon using points (the only specific attribute for this element).

text Element

Use the text element to set text in your SVG. text takes the global style attribute, which you can use to apply styles (size, font, stroke, etc) to the text.

  • dx -
  • dy -
  • lengthAdjust -
  • text-anchor -
  • textLength - An exact value of the length of the text. This used for very specific layouts.
  • rotate - A list of numbers that will determine the rotation of the text.
  • x - the coordinate where the text begins
  • y - the coordinate where the text begins

textPath Element

The textPath element allows you to put text along a path element and have the text follow the shape. This is a classic SVG demo element because it can make text on a curve.

Did you like this review of SVG elements?

Invest a small amount of time to improve how you use SVG with our hands-on video course, Up and Running with SVG.

Get the video course

Next Page

What are our customers saying?


"Just purchased your Flexible Twig course. Love it!"
Tyler Morrison
"Been enjoying @mijingo 's Learning Craft video tutorials. Feeling like I've got a good basic understanding of #craftcms Very impressive"
Laura Montgomery
"I bought your Craft Starter Pack a year and a half ago. Worth every dollar. In fact, I would've paid twice as much for it, because you saved me so much time."
Timothy Ingram
"Ben's knowledge of Craft combined with his relaxed and informal teaching style makes for a great learning experience."
Steve Abraham
"Ben puts a lot of thought into his teaching approach and has the ability to explain complex concepts in a way that just make sense"
Gareth Redfern
"Ben is great at taking a complex subject and breaking it down in a way that you can wrap your mind around. I thought that plugin development was something I would never understand, and happily Ben proved me wrong!"
Jonathan Melville
"I really appreciate all the videos and writing you have done. Your work has given me a jump start on my front end development business."
Shan Ricciardi

Perfect for Small Teams & Companies


Mijingo's courses are perfect as the training curriculum for both small teams and entire companies.

Our courses are offered in Team Packs (up to 5 people) and Company Packs (up to 25 people), so you can make one simple, fast purchase to train your entire staff.

Prices are listed with each course. Need more than 25 or something custom?

Send Your Requirements
Team Pack2-5 People
Company Pack6-25 People
Custom Pack25+ People