How to fork a theme

Fork github

Potentially outdated

This post is older than 365 days and may be outdated. Please use the site-search to search for updated information.

Hello Pagekiteers,

today I am going to show you, how to fork and customize a theme.

Why should I do that?

The Pagekit marketplace contains some really nice themes. But I'm sure that you would like to be something special. Adding custom colors, custom fonts and some JS can be done with spqr/assets, too, but if you would like to change a lot, you should consider to create your own theme.

Some of you may ask: "I am using theme-one and if I would like to change something, I simply edit the theme's css".

But: This is not the best idea! Let's assume the creator of the theme releases a security-related update. If you update your theme, all your changes might be lost. If you don't update your theme, your website could be successfully attacked.

So there's another possibility: Forking the theme.


Yes - forking. Forking is a term used in software development. It simply means that you are not only cloning the software - you are creating your own git repository for it. You can change whatever you want; in some cases forks are being merged with the original repositories (e.g. if you are forking something to add a bugfix or add new functionality) - in other cases you do not merge it (e.g. if you are changing something just for customization).

Let's go

In this tutorial we are using GitHub to create a fork of theme-one. You only need to visit .

Create a fork on GitHub

Now click the "Fork" button and choose your own user as the "fork-target". You may need an account - but don't worry: It's free.

Fork github fork target

Alright - GitHub is now forking the project - this can take some seconds.

Fork github forking

Once GitHub forked your repository, you can see an overview of all the files.

Fork github forked

Now you are able to change the files online - or, which I prefer, clone the repository and edit it with an IDE.

Cloning the repository

I am using PHPStorm as it's a great IDE for PHP projects, which uses a built-in git client.

Of course you can use every editor you want - you don't even have to use git (although I really advise to use git).

If you don't want to use git at all, you can simply download the files; in this case you don't have to create a fork, too.

Fork github download zip

If you decide to fork the theme and clone it, you need to know the URL of the repository. If you don't know it, you can just look it up using GitHub's web frontend.

Fork github git url

Just copy this URL and open your IDE.

In my case PHPStorm is able to create a new project from git.

Just click "Check out from version control" and click "GitHub" after that.

Fork phpstorm new project

Fork phpstorm clone from github

Now enter the git URL and decide, where you want your theme to be stored.

Fork phpstorm clone repository

Now open the project.

Fork phpstorm open project

Alright - you successfully forked the theme and cloned it on your local machine.

First steps

Once you opened your project, you can see all the files that have been cloned. And you are ready to edit them.

Fork phpstorm files

At first, we will have a look at composer.json.

Fork phpstorm composer json

This file contains all the information about our package. You might mention that this file contains all the information the original package provided. It got the same name, the same author information etc. Let's change this to:

    "name": "spqr/theme-two",
    "type": "pagekit-theme",
    "version": "0.0.1",
    "title": "Two",
    "description": "SPQR's default theme fork.",
    "license": "MIT",
    "authors": [
            "name": "Roman Lossin-Be├čler",
            "email": "[javascript protected email address]",
            "homepage": ""
    "extra": {
        "image": "image.jpg"
    "archive": {
        "exclude": ["node_modules", "!/app", "!/css", "/app/assets", "gulpfile.js", "bower.js", "package.js"]

Fork phpstorm composer json edited

As you can see, we named the theme theme-two and changed the vendor prefix from pagekit to spqr. If you are creating your own fork, you would not use spqr - of course you would use your own vendor prefix (e.g. thomasb or frankenstein).

Now save the file and switch over to the file called bower.json.

Change the content to:

  "name": "theme-two",
  "dependencies": {
    "uikit": "#master"
  "private": true

Did you already save the file? Fine - now open package.json and change the content to:

  "name": "pagekit-theme-two",
  "scripts": {
    "install": "bower install && gulp",
    "archive": "gulp && webpack -p && composer archive --format=zip"
  "devDependencies": {
    "babel-core": "^6.1.2",
    "babel-loader": "^6.1.0",
    "babel-plugin-transform-runtime": "^6.1.2",
    "babel-preset-es2015": "^6.1.2",
    "babel-runtime": "^5.8.0",
    "bower": "^1.7.6",
    "json-loader": "^0.5.2",
    "gulp": "^3.8.10",
    "gulp-header": "^1.2.2",
    "gulp-less": "^3.0.0",
    "gulp-rename": "^1.2.0",
    "gulp-util": "^3.0.4",
    "merge-stream": "^0.1.7",
    "vue-html-loader": "^1.0.0",
    "vue-loader": "^8.2.0",
    "webpack": "^1.12.9"

We are almost ready for takeoff - but we need to edit gulpfile.js before.

Change it to:

 * Popular Tasks
 * -------------
 * compile: compiles the .less files of the specified packages
 * lint: runs jshint on all .js files

var gulp       = require('gulp'),
    header     = require('gulp-header'),
    less       = require('gulp-less'),
    rename     = require('gulp-rename');

// banner for the css files
var banner = "/*! <%= data.title %> <%= data.version %> | (c) 2014 Pagekit | MIT License */\n";

gulp.task('default', ['compile']);

 * Compile all less files
gulp.task('compile', function () {

    return gulp.src('src/less/theme.less', {base: __dirname})
        .pipe(less({compress: true}))
        .pipe(header(banner, { data: require('./package.json') }))
        .pipe(rename(function (file) {
            // the compiled less file should be stored in the css/ folder instead of the less/ folder
            file.dirname = file.dirname.replace('less', 'css');

 * Watch for changes in files
gulp.task('watch', function () {'less/*.less', ['compile']);

Please take care of the path name. I changed it from

return gulp.src('less/theme.less', {base: __dirname})


return gulp.src('src/less/theme.less', {base: __dirname})

The last step is to open index.php and change the content to:


return [

    'name' => 'theme-two',

     * Menu positions
    'menus' => [

        'main' => 'Main',
        'offcanvas' => 'Offcanvas'


     * Widget positions
    'positions' => [

        'navbar' => 'Navbar',
        'hero' => 'Hero',
        'top' => 'Top',
        'sidebar' => 'Sidebar',
        'bottom' => 'Bottom',
        'footer' => 'Footer',
        'offcanvas' => 'Offcanvas'


     * Node defaults
    'node' => [

        'title_hide' => false,
        'title_large' => false,
        'alignment' => '',
        'html_class' => '',
        'sidebar_first' => false,
        'hero_image' => '',
        'hero_viewport' => '',
        'hero_contrast' => '',
        'hero_parallax' => '',
        'navbar_transparent' => '',
        'top_style' => 'uk-block-muted',
        'main_style' => 'uk-block-default',
        'bottom_style' => 'uk-block-muted'


     * Widget defaults
    'widget' => [

        'title_hide' => false,
        'title_size' => 'uk-panel-title',
        'alignment' => '',
        'html_class' => '',
        'panel' => ''


     * Settings url
    'settings' => '@site/settings#site-theme',

     * Configuration defaults
    'config' => [

        'logo_contrast' => '',
        'logo_offcanvas' => ''


     * Events
    'events' => [

        'view.system/site/admin/settings' => function ($event, $view) use ($app) {
            $view->script('site-theme', 'theme:app/bundle/site-theme.js', 'site-settings');
            $view->data('$theme', $this);

        'view.system/site/admin/edit' => function ($event, $view) {
            $view->script('node-theme', 'theme:app/bundle/node-theme.js', 'site-edit');

        'view.system/widget/edit' => function ($event, $view) {
            $view->script('widget-theme', 'theme:app/bundle/widget-theme.js', 'widget-edit');

         * Custom markup calculations based on theme settings
        'view.layout' => function ($event, $view) use ($app) {

            if ($app->isAdmin()) {

            $params = $view->params;

            $classes = [
                'navbar' => 'tm-navbar',
                'hero' => '',
                'parallax' => ''

            $sticky = [
                'media' => 767,
                'showup' => true,
                'animation' => 'uk-animation-slide-top'

            if ($params['hero_viewport']) {
                $classes['hero'] = 'tm-hero-height';

            // Sticky overlay navbar if hero position exists
            if ($params['navbar_transparent'] && $view->position()->exists('hero') && $params['hero_image']) {

                $sticky['top'] = '.uk-sticky-placeholder + *';
                $classes['navbar'] .= ' tm-navbar-overlay tm-navbar-transparent';

                if ($params['hero_viewport']) {
                    $classes['hero'] = 'uk-height-viewport';
                } else {
                    $classes['hero'] = 'tm-hero-padding';

                if ($params['hero_contrast']) {

                    $sticky['clsinactive'] = 'tm-navbar-transparent tm-navbar-contrast';
                    $classes['navbar'] .= ' tm-navbar-contrast';

                } else {
                    $sticky['clsinactive'] = 'tm-navbar-transparent';


            if ($params['hero_parallax'] && $view->position()->exists('hero') && $params['hero_image']) {
                $classes['parallax'] = 'data-uk-parallax="{bg: \'-400\'}"';

            if ($params['hero_contrast'] && $params['hero_image']) {
                $classes['hero'] .= ' uk-contrast';

            $classes['sticky'] = 'data-uk-sticky=\''.json_encode($sticky).'\'';

            $params['classes'] = $classes;

        'view.system/site/widget-menu' => function ($event, $view) {

            if ($event['widget']->position == 'navbar') {




Let's do something magic

Now we need to "compile" all the LESS, SASS and JavaScript: We are using webpack, gulp and bower to get this job done. Please install NodeJS on your computer, switch over to the theme's directory and run npm install.

This installs all the packages the theme needs to be "compiled" - these packages are defined in package.json.

Fork phpstorm npm install Fork phpstorm npm install Fork phpstorm npm install Fork phpstorm npm install

Once this is done, just enter bower install. This fetches the latest UIKit LESS-files and should not take that much time.

Fork phpstorm bower install

Now simply run gulp.

Fork phpstorm gulp 1 Fork phpstorm gulp 2

We are almost done - the last step is to run webpack.

Fork phpstorm webpack 1 Fork phpstorm webpack 1


Now you are good to go. You can now build a zip to upload the files.

Please exclude the following files and folders from zip:

  • .git
  • .idea (if you are using PHPStorm)
  • node_modules
  • app/components
  • app/assets/uikit/src
  • less

You can build your easily using PHPStorm - or do it manually. If you are using PHPStorm, just choose Tools > Deployment > Configuration and create a local deployment path.

Have a look at my configuration:

Fork phpstorm deployment 1 Fork phpstorm deployment 2 Fork phpstorm deployment 3 Fork phpstorm deployment 4

Now you are good to go to create your zip.

Fork phpstorm deploy files 1 Fork phpstorm deploy files 2 Fork create zip 1 Fork create zip 2 Fork create zip 3 Fork create zip 4

Upload the theme

Now enter the admin backend and enter System > Themes and choose "Upload".

Fork upload theme 1 Fork upload theme 2 Fork upload theme 3 Fork install theme 1 Fork install theme 2

Customize theme

Of course you are able to edit the settings of your new theme:

Fork customize theme 1 Fork customize theme 2

Uff - that's it

Took a while - but now we're ready.

Now you can adapt the theme over and over again. Always do the following:

  • Change the LESS-sources
  • Run gulp
  • Deploy & build archive
  • Upload zip
{{ message }}

{{ 'Comments are closed.' | trans }}

Wait a second!

Did you know that there's are great support channels for Pagekit? Visit us today and sign up for free using email or your GitHub-, Twitter-, Google- or Facebook-Account.

Latest blog posts

Latest comments

  • How to fork a theme

  • spqr/toc updated

  • spqr/toc updated

Like my work?

If you would like to support my work, you are invited to do so.