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.

Craft 3 Remote Volumes with AWS S3

by Ryan Irelan

Watch as Ryan converts a Local Folder Assets Volume to Amazon S3. The video includes setting up an S3 bucket, creating a IAM policy, group, and user.

Splitting Up a Git Repository

by Ryan Irelan

Here’s the situation: you have a Git repository and you want to split it up into smaller repositories. Perhaps you have an application that has grown to large and you need to break out parts of into their own application (as services) or maybe as their libraries.

Whatever your reason is, the task is the same: how do I get this big Git repository broken out into two (or more)? And how do I do that while also maintaining the history of the changes in the directory I’m splitting out?

That is our most important requirement: we don’t want to lose the history of the files that we’re splitting up from the repository.

Let’s go through the steps.

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

Getting Started with Craft Plugin Development

by Ryan Irelan

I spent 90 minutes talking with Andrew Welch about Craft plugin development. This was live streamed, which is why the video is different than what you usually see from Mijingo.

We covered:

  • Why and when you want to create a plugin
  • Easiest way to start your first plugin
  • Moving from a project plugin to a public plugin
  • Craft modules
  • Andrew’s awesome PhpStorm tips



If you like videos from Mijingo, please subscribe to the YouTube channel.

When is Craft 3 Coming Out?

by Ryan Irelan

April 4, 2018

See the Craft 3 Launch FAQ for more.

I’ve already updated Craft Essentials for Craft 3 and there are more updates to come. It’s the best and easiest way to learn Craft CMS.

Live Stream: Craft Plugin Development

by Ryan Irelan

On Wednesday I’m putting myself in the hot seat.

I’m meeting up with Andrew Welch of nystudio107 (developer of SEOmatic and other Craft plugins) for a live stream where we’ll review one or two of my Craft plugins.

Andrew will be frank about my code and along the way we’ll:

  • discuss what I could do differently in my code,
  • how to take a plugin I developed for a project and get it ready for public distribution,
  • and ideas and tips for people new to Craft plugin development (and those new to plugin development in general).

During the live stream we’ll have a chat room going so you can ask questions in real time and we can answer them.

This live stream is meant for current plugin developers, struggling plugin developers, and those who think they aren’t good enough to create their own plugin.

It takes place on Wednesday February 28th at 12PM CST (check your timezone).

We’ve only 100 seats for this so hit the button below to register for the live stream. See you there!

Watch Ryan in the Hot Seat

Course Updates for Craft 3

by Ryan Irelan

Last week Pixel & Tonic released Craft 3 RC1, the first release candidate after the beta period. The final release of Craft 3 won’t be until April 2018.

The new version includes some improvements and minor changes to how we build sites with Craft but the general approach we all use (and the one I teach) will not change. There will be code changes here and there but it’s not a “rip it up and do it again” type of upgrade.

Where does this leave Mijingo’s Craft courses?

As of right now, the courses are still the best way to learn Craft. The general approach to building sites with Craft has not changed.

Here’s my plan to update them for Craft 3:

  • Updates to courses for Craft 3 will be free for all students who purchase the courses. The only exception is the Craft Plugin Development course.
  • I will redo Up and Running with Craft first because it is the one most impacted by the changes.
  • I will redo Fundamentals of Craft Commerce as soon as Pixel & Tonic releases the Commerce 2 beta and I can review what I need to update in the course.
  • I will evaluate the remaining courses for Craft 3’s impact on the material and amend or update accordingly.
  • I will keep you updated as I go.

Where does this leave you?

If you need to learn Craft now, then now is still the time to learn it. Grab a copy of Craft 2, a copy of Craft Essentials, and get to work.

After you complete the courses, then you can get acquainted with Craft 3 using my free lessons.

Major software releases are always a juggling act but as the official training partner for Craft we’re in a good spot going forward.

Happy learning!

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.

11 Things You Need to Know About Craft 3

by Ryan Irelan

There are dozens of changes to Craft in version 3 but below I’ve compiled the eleven things you need to know to have a smooth transition from Craft 2 to Craft 3.

Ready? Let's go.

1. Installable via Composer

If you installed Craft 3 during the beta period then you will know that Craft can now be installed with Composer. A nuisance to some but a big step up for others, Composer will make it easy to manage dependencies in Craft.

So how do you install Composer? This video walks through the process:


Note: The final release of Craft 3 will allow a non-Composer installation.

After you have Composer installed, you are ready to install Craft 3.

Follow the instructions in this video to get your first Craft 3 installation going:


Need help upgrading a Craft 2 site to Craft 3? Watch this video

2. Uses Twig 2

Craft 3 uses Twig 2. This update to Twig is, for the most part, a clean-up release. Here are a few important things to know about Twig 2 with regards to Craft:

  • Twig 2 Requires PHP 7 (and so does Craft 3)
  • Your current templates should work as-is with Twig 2. There is some deprecated template code but that’s related to Craft services, not Twig.
  • Twig slightly changed how macros are handled. All macros defined in-template must be imported explicitly in each template in which you want to use them (including “included” templates). See the docs for more information on macros.

3. Access to Craft service APIs in your templates

As of Craft 3 you now have access to the Craft service APIs right inside of your templates. Previously, Craft made available some special template functions that made some of the service APIs available.

Many of those template functions are going away in Craft 3 in favor of using the new service API access.

These template functions were mostly just Twig variables that exposed the data via an existing function. So instead of doing that we just get direct access to the function itself.

There is no PHP allowed in Craft templates, so previously if you wanted to access something in the backend of Craft you had to use a plugin.

Using a plugin is still a good idea if you have a significant amount of features you need to achieve, but for simple one-off things, having access to the Services inside of your template is going to be a game changer.

Here’s a look at how you can use this new functionality in your templates:


4. Multi-site Support

Another new feature in Craft 3 is multi-site. This was a popular feature when it was first announced but there was some confusion about it so let’s clear things up.

The Craft 3 multi-site feature allows you to handle multiple sites of content right from the Craft control panel. This could be a multi-language site, where there’s a different version of the site for different languages, or multiple sites with similar content (like micro sites for product lines).

Note: this feature is an enhancement of and replaces Locales in Craft 2.

Here's a walk-thru of using the new multi-site feature:


5. Better Debugging

The Yii Debug Toolbar is a new feature in Craft 3 that allows you to have a constant toolbar at the bottom of your front-end and control panel pages.

This toolbar gives you access to important debugging information including items that aren’t specific to Craft.

Here’s how it works and how you enable it:


6. Command Line Interface

When you are done installing Craft with Composer, you'll notice a little message at the end, just before the new command prompt, encouraging you to use the Craft setup command.

Craft 3 offers a new way to set up the site, which replaces the normal set up you do via the web browser.

So, why is this important?

  • Keeps you right in the terminal after installing
  • Possible to script the setup process--maybe part of a bigger routine where you're installing and setting up a new installation.
  • It automates the populating of your .env file for the site's database connection.

The craft CLI offers several options, but we're only going to concern ourselves right now with setup command.

Here’s how it works:


7. Hash Redirect Parameters

Back in version 2.5, Pixel & Tonic introduced a hash filter and later in a 2.6 release 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 security issue with in -the-clear form data. In the example of the redirect parameter, this could allow someone to redirect the user to something other than what is specified in the hidden form element.

In Craft 3, however, the hashing of redirect parameters is required.

Here’s an overview of how that works:


8. Always use .all()

In Craft 2, we might do something like:

{% for entry in craft.entries.section('news') %}
       {{ entry
.title }}
    {
% endfor %

We iterate over the element query directly. Behind the scenes Craft knew we wanted that actual data so it calls find() for us automatically.

Based on a problem discovered with Twig’s loop variables and Craft, the Craft team decided to just force the usage of .all() and deprecate the usage of iterating over the element query without explicitly calling for the results.

What does this mean?

We need to now use all() on every element query in Craft 3. If you don’t it will still work but you’ll receive a deprecation error in your log (and it’ll break in Craft 4).

So the above code is now:

{% for entry in craft.entries.section('news').all() %}
       {{ entry
.title }}
    {
% endfor %

Here’s a hands-on review of this:


9. Use one() instead of first()

In Craft 3 the first() method to execute an Element Query is now deprecated in favor of one(). The new method will return the same thing as first() (the first matching element) and also return null if there are no matches.

So, this code:

{set entry craft.entries.section('news').first() %}
    {{ entry
.title }} 

Will now need to be written as:

{set entry craft.entries.section('news').one() %}
    {{ entry
.title }} 

10. Support for PostgreSQL

You hatin’ on MySQL or maybe your systems admininistrator thinks PostgreSQL is better? Now you can run Craft off a PostgreSQL database server.

11. Remote Assets are Now Plugins

Remote Assets Volumes (they’re called Volumes in Craft 3) now require a free, third-party plugin. The default installation of Craft only includes Local Volume support.

Until the Craft Plugin Store is available, you can download the Remote Volumes plugins from their Github repositories:

Is that it?

Well, that’s 11. But if you want even more here’s a big list of changes from Craft 2 to Craft 3.

What is a bare Git repository?

by Ryan Irelan

The standard way of initializing a new Git repository is to run git init. The directory in which you do this will be become the Working Tree for the repository.

As part of the initialization process, Git creates a .git directory (which his hidden by default because of the . in the name) that contains the repository itself. This is brains of the repository; it's where Git tracks your changes, stores commit objects, refs, etc. You probably only rarely interact with that hidden directory.

Okay, so all of this is to lay the groundwork for understanding a bare Git repository. What the heck is it?

A bare Git repository is a repository that is created without a Working Tree. Go ahead and create one to see.

git init --bare .

Run ls on that directory and you won't see a Working Tree but just the contents of what is typically in the .git directory.

Why this setup?

A bare Git repository is typically used as a Remote Repository that is sharing a repository among several different people. You don't do work right inside the remote repository so there's no Working Tree (the files in your project that you edit), just bare repository data.

And that's it.

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

What is a Git Remote Repository?

by Ryan Irelan

By default Git is completely local to your computer. You can optionally have remote copies of the repository (either on a central server or service—like Github—or on a co-workers computer).

To get your copy of the repository up to a remote server you use the command git-push. If you want to retrieve others’ changes to the repository you use git-pull.

A Remote Repository in Git is a special type of repository in that it doesn't have a Working Tree. This is different than your local repository, which has your project files and then a hidden .git directory.

You can host your own Git remote repository or use one the popular online services, like Github, Gitlab, or Bitbucket.

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

What is the Working Tree in Git?

by Ryan Irelan

Th Working Tree in Git is a directory (and its files and subdirectories) on your file system that is associated with a repository.

It's full of the files you edit, where you add new files, and from which you remove unneeded files. Any changes to the Working Tree are noted by the Index (see below), and show up as modified files.

When you open the files for a project that is being managed as a Git repository then you are access the Working Tree.

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

Using Git Hooks

by Ryan Irelan

Git hooks are similar to SVN hooks; you can execute a script at a point in the Git routine. Git hooks are both local and server-side. The local hooks pertain to local activities, like committing, merging, checking out, etc. The server-side hooks deal with receiving pushes from a local client.

The scripts that Git hooks execute are stored in the .git/hooks directory of your project. In every repository there are a collection of sample hooks that you can rename and use as inspiration for your own.

The scripts can be in any language that support executable scripts. The samples are mostly shell scripts, but you can use Perl, Ruby, Python, or something else that is familiar to you.

Here are all the hooks available in Git:

  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • applypatch-msg
  • pre-applypatch
  • post-applypath
  • pre-rebase
  • post-rewrite
  • post-checkout
  • post-merge
  • pre-push
  • pre-receive
  • update
  • post-receive

Local Git Hooks

Local Git hooks reside in the .git/hooks directory and are not treated as project files. They are not tracked in the Index and because of that they are not included when someone clones a repository.

Because of this there are some limitations to keep in mind while working with Git hooks. First and foremost: local hooks are not a reliable way to enforce policies, like a commit message structure. And, because you are unable to include the contents of the .git/hooks directory in version control, you will need to consider a way to share hooks that you’d like your team to use.

Here are the local hooks:

  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • applypatch-msg
  • pre-applypatch
  • post-applypath
  • pre-rebase
  • post-rewrite
  • post-checkout
  • post-merge
  • pre-push

Server-side Hooks

Server-side hooks are set up to kick off scripts when a typical remote repository actions takes place.

There are only three server-side hooks:

  • pre-receive
  • update
  • post-receive

They all operate around when the server receives a git-push from a client. These are reliable methods for enforcing some sort of repository or standard. You can run checks, kick of an integration script, testing, etc.

Implement a Git Hook

For our example we’re going to implement a local hook. We’d like to display a message after each commit, reminding us to push our commits to the remote repository.

The setup for this message will be to use the post-commit hook. This hook is triggered after each successful commit. For our implementation, we want the hook to trigger and display a message for us. 
There isn’t a sample file for post-commit already in place. That’s okay, we can create it.

Create a new file called post-commit in .git/hooks.

I’m going to use Ruby as the scripting language. Remember, Git Hooks can use any executable script. But I like Ruby so we’ll use that. This Ruby code is as simple as it comes, with just a single puts statement.

Add this code to the post-commit file:


#!/usr/local/bin
puts "======================="
puts "Please remember to push your commits!"
puts "======================="

With the code in place, we can then save the hook file and set it as executable.


$ chmod +x post-commit

Test it by making a change to our project and creating a commit. If you see the message, it worked!

If you didn’t, check your code, that the hook file is executable, and that you have it properly named.

In another article I’ll talk about triggering hooks on the server.

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

Git Merge Therapy

by Ryan Irelan

Have a seat on the sofa for a moment, please. I want share something important with you.

Ready?

Git merge conflicts are normal and okay.

They are supposed to happen and, most likely, will happen regularly. They don’t happen because you did something wrong. They happen because Git is trying to protect you from losing your hard work.

If you’re new to Git or haven’t done extensive work with it in a team environment then you probably haven’t had the experience of a lot of merge conflicts.

In a future article I will share how you can resolve conflicts but right now, let’s talk about prevention.

We can do some things to prevent conflicts; here’s a list of a few:

  • Ignore generated files
  • Ignore cache or other runtime directories and files
  • Have a good branching strategy
  • Avoid whitespace errors

I’ll go into each one in detail in future articles.

Until then: Git conflicts are okay!

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

The Big Picture of Git

by Ryan Irelan

When starting out with Git, it’s much easier to understand how to use it if we also understand the basics of what Git is.

By that I mean what Git is beyond the commands. Conceptually speaking.

What is a Version Control System (VCS)?

Git is a version control system. You’ll hear this referred to as a VCS sometimes. This is a general term to describe tools that track changes to files over a period of time. The reason we track the changes is so we can revert to previous versions, have a log of the work that was completed, as well as have an incremental backup of the project.

Version control systems aren’t just for code but that’s where they got their start and are most widely used.

You could–and I have–use version control for a book you’re writing.

You could use version control for designs you’re creating for a project.

You could use version control for a series of documents, like proposals, contracts, or agreements.

If it’s a file, it can be tracked by a version control system.

Okay, great. So why should use a version control system for your projects?

First and foremost is because it’s a reliable way to track changes to your files. You might’ve used a simple version control system in the past where you zipped up a project and put a date on it, thereby capturing that day’s work. A version control system also lets you snapshot changes to the project but in a more structured and reliable way.

Getting Git

There are lot of other version control systems out there and perhaps you’ve used one or two before. In the past I’ve used CVS, Subversion, and Mercurial, in addition to Git. I prefer Git because it is local, simple, and fast.

So let’s talk briefly and at a high level of how Git works.

Snapshots of Your Project

When you initialize a new Git repository, you are telling Git to track a set of files.

This set of files will be in a common directory (and subdirectories).

Git now cares about what happens to those files.

At first Git will just tell you that it sees a bunch of files but isn’t yet tracking them. It’ll be up to you to add those files so Git will care about them on an individual basis. After that, Git will notice every change to the file.

By initializing a Git repository, you tell Git: “Hey I want you to pay attention to this set of files. If you don’t know about a file yet, please tell me. If something changes in a file, please tell me. In return, I’ll commit those changes to your repository so you are aware.

Let me try an analogy and see if this works.

Imagine you’re a summer camp counselor. Your job is to take care of, educate, and otherwise entertain a specific group of kids. The kids are organized into groups.

You arrive at the camp on Day 1 and you know you’re responsible for a group of kids. You walk into the room and your supervisor says: “Okay, Ryan, this is your group.”

You look out at the group of kids and say “Okay, ya’ll are mine. I will take care of you.”

“First order of business. I see I have 15 kids here. But I don’t know your names. I need you to form a line and then give me your names so I can write them on this list. This is the list I will use to track your progress at camp so I can report back to your parents when they pick you up on Sunday.”

The kids form a line and, one by one, they give you their name and you write it down on the paper attached to your clipboard. You now have them tracked and know exactly who the kids are.

As summer camp goes on, you watch your campers and their actives. If Suzanne swims a 1km lap in the lake, you mark that change down next to her name on the list.

If Albert gets sick because he ate too many bowls of chocolate pudding after dinner, then you mark that down next to his name to track his health.

The bottom line is: you are watching these kids and tracking how they change during their time at camp.

This analogy may be a little thin but I hope you get the idea. Key takeaway: Think about Git as a system that watches a set of files you tell it to.

This is the git init command.

Once you tell it to watch a set of files, you then have to introduce it to each file.

This is the git add command.

(I go over the actual commands in my Git Essentials course bundle.)

Just like with the campers and and counselor, think about your Git repository as the set of files. Every time you make a change to a file and commit that change (record it as a change), Git snapshots the state of the entire collection of files at that moment.

This might sound like Git is just zipping up the files and such. It’s much more nuanced than that (and it’s something we cover in the Git: Under the Hood course).

Git only saves and records changes to the files that have changed. For the other files, the snapshot simply points to the previous snapshot. This allows Git to efficiently store files without becoming unnecessarily large over the lifecycle of a project.

So, what is Git doing?

It’s caring about your project files because you told it to. Every time you work with Git think of it in this way. Git cares a lot and sometimes you have to tell it no longer care (git ignore), too.

And, as you’ll learn in a different video on merging branches in Git, Git cares so much that it won’t let you lose changes or work. It really is looking out for you.

What this in video form

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

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:

 



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