Showing posts with label wordpress. Show all posts
Showing posts with label wordpress. Show all posts

Tuesday, January 05, 2016

Using Gulp for WordPress Automation

Using Gulp for WordPress Automation

If you are not using Gulp or any task runner, believe me when I say that you are missing out on all the front-end fun stuff. Today, I intend to share my advanced Gulp based automatted workflow for building WordPress themes, with the community.

I remember the time when I had to minify CSS and JS files, compress the images and the fuss of testing my designs across different browsers let alone devices — oh my. If my recollection of lost isn't misleading me then I used to spend like 30% of my productive hours on this stuff.

Thankfully, someone wrote a piece about DRY (Don't Repeat Yourself) and it got me thinking about the flaws in my workflow. I believe a tweet from Chris Coyer led me to start using Grunt in 2012 or a little later. I used it for over a year and boy it was a fun ride.

Why Gulp?

While Grunt took care of optimizing images, compressing scripts, and compiling Sass, I never really enjoyed writing Grunt files. Then in Dec 2013, I heard about this new task runner called Gulp. On a Sunday morning, I thought to create a dummy project and try Gulp, to say that I was hooked would be an understatement.

Why Do I Like Gulp?

At that time, there was hardly any documentation available for using Gulp with WordPress, but thanks to the awesome helping community at Stack Exchange, I was able to make it work. I found Gulp to be a lot better than Grunt. Here is why:

  • Gulp is easier to understand and more efficient
  • Gulp has a JavaScript syntax unlike JSON syntax of Grunt
  • Gulp is faster than Grunt (One of my theme's compile time went from 12secs to 300ms)
  • Gulp is intuitive and gets 20K-25k downloads a day, which is equal to or great than Grunt downloads
  • Gulp's code-over-configuration makes it not only easy to write tasks for, but also much easier to read and maintain

That said, let's leave the story for now and see what it is like to be using Gulp with WordPress.

Do I Need to Use Gulp?

Are you a web developer? Do you program in HTML/CSS sometimes?

— Yes!

Did you ever use a task-runner? Feel like you belong to the stone age while all the crazy kids in town are using awesome advanced workflows?

— Yes! :(.

OK! let's get you started then.

Since this article is about an advanced Gulp based workflow, explaining how to do basic Gulp related stuff is out of the scope. But instead of leaving you (beginners) in the middle of nowhere, I'd like to suggest a few articles to help you get started.


If having a basic Gulp workflow is nothing new for you, then maybe you'll enjoy reading my advanced gulp workflow.

Advanced Gulp WordPress Workflow

While building premium themes for WordPress, I end up with a lot of grunt work which includes:

  • Minifying & optimizing CSS with stylesheets and Sass
  • Custom JavaScripts and 3rd Party Scripts via Bower
  • Synced cross-browser design testing on different devices
  • Tunneling my localhost dev branch to a random public URL for public access
  • Building an installable zip theme file without any node modules, cache files or .Dot files data in it

Let's explore how I get all this stuff done with Gulp.

I have set up a Github repository called Advanced Gulp WordPress. You can check out the structure of files inside it for better understanding.

Using Gulp for WordPress Automation

A Look at gulpfile.js

Now let's take a look at gulpfile.js which is present in the root folder of our theme. I will explain each task one by one to make it easier for you to understand. You'll find completed gulpfile.js at the end of this post.

Since I assume you already know how Gulp works, I will not be explaining how to put all the plugins/packages in package.json file and other basic setup related steps.

Step #1: Setting Up the Variables

First of all I am going to set up certain variables so that I don't have to change everything for every other theme I create. Let's review the code:

/**
 *
 * Gulpfile setup
 *
 * @since 1.0.0
 * @authors Ahmad Awais, @digisavvy, @desaiuditd, @jb510, @dmassiani and @Maxlopez
 * @package neat
 * @forks _s & some-like-it-neat
 */


// Project configuration
var project   = 'neat', // Project name, used for build zip.
 url   = 'neat.dev', // Local Development URL for BrowserSync. Change as-needed.
 bower   = './assets/bower_components/'; // Not truly using this yet, more or less playing right now. TO-DO Place in Dev branch
 build   = './buildtheme/', // Files that you want to package into a zip go here
 buildInclude  = [
    // include common file types
    '**/*.php',
    '**/*.html',
    '**/*.css',
    '**/*.js',
    '**/*.svg',
    '**/*.ttf',
    '**/*.otf',
    '**/*.eot',
    '**/*.woff',
    '**/*.woff2',

    // include specific files and folders
    'screenshot.png',

    // exclude files and folders
    '!node_modules/**/*',
    '!assets/bower_components/**/*',
    '!style.css.map',
    '!assets/js/custom/*',
    '!assets/css/patrials/*'

   ];

I've set up variables for:

  • L#12: Project name
  • L#13: Project URL at localhost
  • L#14: Path to folder of Bower Components
  • L#15: Name of the folder which will be created for building an installable theme zip file
  • L#16: Variable buildInclude contains the paths to files or folders which are to be included and excluded in while building a clean theme inside buildTheme folder for creating a zip file

Step #2: Loading Gulp Plugins

I am using quite a few gulp plugins to help manage everything we discussed above.

// Load plugins
 var  gulp         = require('gulp'),
  browserSync  = require('browser-sync'), // Asynchronous browser loading on .scss file changes
  reload       = browserSync.reload,
  autoprefixer = require('gulp-autoprefixer'), // Autoprefixing magic
  minifycss    = require('gulp-uglifycss'),
  filter       = require('gulp-filter'),
  uglify       = require('gulp-uglify'),
  imagemin     = require('gulp-imagemin'),
  newer        = require('gulp-newer'),
  rename       = require('gulp-rename'),
  concat       = require('gulp-concat'),
  notify       = require('gulp-notify'),
  cmq          = require('gulp-combine-media-queries'),
  runSequence  = require('gulp-run-sequence'),
  sass         = require('gulp-sass'),
  plugins      = require('gulp-load-plugins')({ camelize: true }),
  ignore       = require('gulp-ignore'), // Helps with ignoring files and directories in our run tasks
  rimraf       = require('gulp-rimraf'), // Helps with removing files and directories in our run tasks
  zip          = require('gulp-zip'), // Using to zip up our packaged theme into a tasty zip file that can be installed in WordPress!
  plumber      = require('gulp-plumber'), // Helps prevent stream crashing on errors
  cache        = require('gulp-cache'),
  sourcemaps   = require('gulp-sourcemaps');

The plugins I am using to are as follows:

  • Gulp — Pretty much self-explanatory
  • BrowserSyn — Amazing Time-saving synchronized browser testing
  • AutoPrefixer — Auto prefix CSS for legacy browsers
  • UglifyCSS — For CSS Minification
  • Filter — Enables you to work on a subset of the original files by filtering them using globbing.
  • UglifyJS — Minifies JS files
  • ImageMin — Minifies PNG, JPEG, GIF and SVG images
  • Newer — For passing through only those source files that are newer than corresponding destination files.
  • Rename — To easily rename files
  • Concat — To concatenate JS files
  • Notify — To send notification to OS based on node notifier module
  • Combine Media Queries — To combine repetitive media queries after Sass or Less
  • Run Sequence — Run a series of dependent gulp tasks in order
  • Gulp Sass — Gulp plugin for Sass which is based on libSass
  • Load Plugins — To automatically load in gulp plugins
  • Ignore — To ignore files in the stream based on file characteristics
  • Zip — To zip or compress files
  • Plumber — Fix node pipes, prevent them from breaking due to an error
  • Cache — A cache proxy task for Gulp
  • Source Maps — Source map support for CSS partial files

Phew! That was a lot. Well, at the end of the day, it's all worth the effort.

Step #3: Task to Setup Browser Sync

Let's dive a little deeper and create some awesome tasks to automate our workflow. Browsersync is one of my favorite plugins.

/**
 * Browser Sync
 *
 * Asynchronous browser syncing of assets across multiple devices!! Watches for changes to js, image and php files
 * Although, I think this is redundant, since we have a watch task that does this already.
*/
gulp.task('browser-sync', function() {
 var files = [
   '**/*.php',
   '**/*.{png,jpg,gif}'
      ];
 browserSync.init(files, {

  // Read here http://www.browsersync.io/docs/options/
  proxy: url,

  // port: 8080,

  // Tunnel the Browsersync server through a random Public URL
  // tunnel: true,

  // Attempt to use the URL "http://my-private-site.localtunnel.me"
  // tunnel: "ppress",

  // Inject CSS changes
  injectChanges: true

 });
});

I used to have LiveReload in my workflow, which would reload the web page whenever a file gets edited and saved. But when Browsersync was introduced, it helped me cut down half of the shitty things I had to do in order to automate syncing between different browsers. Browsersync helps me with the following stuff;

  • Injecting CSS changes without any web page getting reloaded
  • Change the port and set up a tunnel through a random public URL, which means my teammates can access the dev branch live at my localhost in a matter of minutes
  • Synced testing across different browsers, where I open the given URL at my Desktop, Laptop, Tab, and mobile to test same features in a single go with synced scroll, clicks, form inputs, etc. Watch the video at Browsersync.

Step #4: Gulp Style Task

Let's take a look at the styles task I built. In this task, there is a lot going on. We are compiling Sass, creating minified CSS and optimizing media queries.

/**
 * Styles
 *
 * Looking at src/sass and compiling the files into Expanded format, Autoprefixing and sending the files to the build folder
 *
 * Sass output styles: https://web-design-weekly.com/2014/06/15/different-sass-output-styles/
*/
gulp.task('styles', function () {
 return      gulp.src('./assets/css/*.scss')
   .pipe(plumber())
   .pipe(sourcemaps.init())
   .pipe(sass({
    errLogToConsole: true,
 
    //outputStyle: 'compressed',
    outputStyle: 'compact',
    // outputStyle: 'nested',
    // outputStyle: 'expanded',
    precision: 10
   }))
   .pipe(sourcemaps.write({includeContent: false}))
   .pipe(sourcemaps.init({loadMaps: true}))
   .pipe(autoprefixer('last 2 version', '> 1%', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
   .pipe(sourcemaps.write('.'))
   .pipe(plumber.stop())
   .pipe(gulp.dest('./'))
   .pipe(filter('**/*.css')) // Filtering stream to only css files
   .pipe(cmq()) // Combines Media Queries
   .pipe(reload({stream:true})) // Inject Styles when style file is created
   .pipe(rename({ suffix: '.min' }))
   .pipe(minifycss({
    maxLineLen: 80
   }))
   .pipe(gulp.dest('./'))
   .pipe(reload({stream:true})) // Inject Styles when min style file is created
   .pipe(notify({ message: 'Styles task complete', onLast: true }))
});

Let me explain line by line, what's going on in there:

  • L#1 – L#8: I created the styles task
  • L#9: Here I provided the source of Sass file, which is a style.scss file present at ./assets/css/style.scss
  • L#10: Initiated plumber to avoid pipe breaking due to minor CSS errors when I save a file
  • L#11: Sourcemaps got initiated. A source map provides a way of mapping code within a compressed file back to its original position in a source file. This means that – with the help of a bit of software – you can easily debug your applications even after your assets have been optimized. The Chrome and Firefox developer tools both ship with built-in support for source maps.
  • L#12 – L#20: Sass is being compiled in compact format, you can read about Sass formats here
  • L#23: I am prefixing CSS with autoprefixer. The legacy browsers which should be supported are mentioned inside the arguments array
  • L#26: Here I have saved the final compiled CSS file for our WordPress theme in the root directory. Since style.scss was being compiled, the output will be style.css file. Now all you need to do is make sure you use a "!" in the comments at the top of the style.scss file so that, even when the compiling/compressing happens, the comment remains: i.e. /*! Theme Name: Your Theme etc... */
  • L#27: I filtered all the .css files in the root directory, which at the moment is one style.css file
  • L#28: Combined the media queries inside selected files
  • L#30: Renamed the file to style.min.css
  • L#31 – L#33: Minified the style.min.css file
  • L#34: Output was saved as a style.min.css file in the root of WP theme folder

Step #5: Scripts Minification and Concatenation

Now to deal with custom JavaScript files and 3rd Party JS files, I have created two tasks called vendorsJs and scriptsJs. They both are pretty much similar. Let's review the code.

/**
 * Scripts: Vendors
 *
 * Look at src/js and concatenate those files, send them to assets/js where we then minimize the concatenated file.
*/
gulp.task('vendorsJs', function() {
 return      gulp.src(['./assets/js/vendor/*.js', bower+'**/*.js'])
   .pipe(concat('vendors.js'))
   .pipe(gulp.dest('./assets/js'))
   .pipe(rename( {
    basename: "vendors",
    suffix: '.min'
   }))
   .pipe(uglify())
   .pipe(gulp.dest('./assets/js/'))
   .pipe(notify({ message: 'Vendor scripts task complete', onLast: true }));
});


/**
 * Scripts: Custom
 *
 * Look at src/js and concatenate those files, send them to assets/js where we then minimize the concatenated file.
*/

gulp.task('scriptsJs', function() {
 return      gulp.src('./assets/js/custom/*.js')
   .pipe(concat('custom.js'))
   .pipe(gulp.dest('./assets/js'))
   .pipe(rename( {
    basename: "custom",
    suffix: '.min'
   }))
   .pipe(uglify())
   .pipe(gulp.dest('./assets/js/'))
   .pipe(notify({ message: 'Custom scripts task complete', onLast: true }));
});

Here is what's happening in there:

  • I selected the vendor JS files paths with bower path at L#7 and the custom JS files paths at L#27
  • Concatenated the files to two single files called vendors.js and custom.js
  • Saved the output in ./assets/js/ folder
  • Renamed the files to with .min suffix
  • Minified/uglified the files
  • And saved two more files called vendors.min.js and custom.js

Step #6: Image Optimization Task

There nothing new in the image optimization task. Look at the code below.

/**
 * Images
 *
 * Look at src/images, optimize the images and send them to the appropriate place
*/
gulp.task('images', function() {

// Add the newer pipe to pass through newer images only
 return  gulp.src(['./assets/img/raw/**/*.{png,jpg,gif}'])
    .pipe(newer('./assets/img/'))
    .pipe(rimraf({ force: true }))
    .pipe(imagemin({ optimizationLevel: 7, progressive: true, interlaced: true }))
    .pipe(gulp.dest('./assets/img/'))
    .pipe( notify( { message: 'Images task complete', onLast: true } ) );
});

  • I selected the ./assets/img/raw/**/*.{png,jpg,gif} path as a source
  • Optimized the images and placed them in ./assets/img/ folder

Step #7: Building a Clean Installable Theme Zip File

This is a group of tasks which are responsible for creating a clean copy of installable theme zip file. Take a quick look at the code. There is nothing much to it, it is all basic copy pasting and deleting or ignoring of files/folders.

/**
 * Clean gulp cache
 */
 gulp.task('clear', function () {
   cache.clearAll();
 });


 /**
  * Clean tasks for zip
  *
  * Being a little overzealous, but we're cleaning out the build folder, codekit-cache directory and annoying DS_Store files and Also
  * clearing out unoptimized image files in zip as those will have been moved and optimized
 */

 gulp.task('cleanup', function() {
  return  gulp.src(['./assets/bower_components', '**/.sass-cache','**/.DS_Store'], { read: false }) // much faster
   .pipe(ignore('node_modules/**')) //Example of a directory to ignore
   .pipe(rimraf({ force: true }))
   // .pipe(notify({ message: 'Clean task complete', onLast: true }));
 });
 gulp.task('cleanupFinal', function() {
  return  gulp.src(['./assets/bower_components','**/.sass-cache','**/.DS_Store'], { read: false }) // much faster
   .pipe(ignore('node_modules/**')) //Example of a directory to ignore
   .pipe(rimraf({ force: true }))
   // .pipe(notify({ message: 'Clean task complete', onLast: true }));
 });

 /**
  * Build task that moves essential theme files for production-ready sites
  *
  * buildFiles copies all the files in buildInclude to build folder - check variable values at the top
  * buildImages copies all the images from img folder in assets while ignoring images inside raw folder if any
  */

  gulp.task('buildFiles', function() {
   return  gulp.src(buildInclude)
    .pipe(gulp.dest(build))
    .pipe(notify({ message: 'Copy from buildFiles complete', onLast: true }));
  });


/**
* Images
*
* Look at src/images, optimize the images and send them to the appropriate place
*/
gulp.task('buildImages', function() {
 return  gulp.src(['assets/img/**/*', '!assets/images/raw/**'])
   .pipe(gulp.dest(build+'assets/img/'))
   .pipe(plugins.notify({ message: 'Images copied to buildTheme folder', onLast: true }));
});

 /**
  * Zipping build directory for distribution
  *
  * Taking the build folder, which has been cleaned, containing optimized files and zipping it up to send out as an installable theme
 */
 gulp.task('buildZip', function () {
  // return  gulp.src([build+'/**/', './.jshintrc','./.bowerrc','./.gitignore' ])
  return  gulp.src(build+'/**/')
   .pipe(zip(project+'.zip'))
   .pipe(gulp.dest('./'))
   .pipe(notify({ message: 'Zip task complete', onLast: true }));
 });


 // ==== TASKS ==== //
 /**
  * Gulp Default Task
  *
  * Compiles styles, fires-up browser sync, watches js and php files. Note browser sync task watches php files
  *
 */

 // Package Distributable Theme
 gulp.task('build', function(cb) {
  runSequence('styles', 'cleanup', 'vendorsJs', 'scriptsJs',  'buildFiles', 'buildImages', 'buildZip','cleanupFinal', cb);
 });

This task will run only when I will use gulp build command. Let's review what happens when this command is run:

  • clear: Task to clear the gulp cache
  • cleanup: Task to remove sass-cache, bower_components and .DS_Store files in the stream. It also ignores the node_modules folder
  • cleanupFinal: Another cleanup task to be run at the end of build sequence. It may or may not have any difference from cleanup task
  • buildFiles: Build task that moves essential theme files to the buildTheme folder
  • buildImages: Task to build and copy the final set of images to the buildTheme folder
  • buildZip: Task to create an installable Zip file of the buildTheme folder
  • build: Main task which runs styles task to compile CSS then cleans up everything with a cleanup task. After that, it runs all the scripts related and build related tasks and a final cleanup task at the end to produce a theme zip file via buildTheme folder.

Step #8: Watch Task

Finally, there is a watch task which helps in automatically running the styles, scripts, images and browser-sync related tasks in case of any change that occurs in the below-mentioned folder.

// Watch Task
 gulp.task('default', ['styles', 'vendorsJs', 'scriptsJs', 'images', 'browser-sync'], function () {
  gulp.watch('./assets/img/raw/**/*', ['images']); 
  gulp.watch('./assets/css/**/*.scss', ['styles']);
  gulp.watch('./assets/js/**/*.js', ['scriptsJs', browserSync.reload]);

 });

Final gulpfile.js

/**
 *
 * Gulpfile setup
 *
 * @since 1.0.0
 * @authors Ahmad Awais, @digisavvy, @desaiuditd, @jb510, @dmassiani and @Maxlopez
 * @package neat
 * @forks _s & some-like-it-neat
 */


// Project configuration
var project   = 'neat', // Project name, used for build zip.
 url    = 'neat.dev', // Local Development URL for BrowserSync. Change as-needed.
 bower    = './assets/bower_components/'; // Not truly using this yet, more or less playing right now. TO-DO Place in Dev branch
 build    = './buildtheme/', // Files that you want to package into a zip go here
 buildInclude  = [
      // include common file types
      '**/*.php',
      '**/*.html',
      '**/*.css',
      '**/*.js',
      '**/*.svg',
      '**/*.ttf',
      '**/*.otf',
      '**/*.eot',
      '**/*.woff',
      '**/*.woff2',

      // include specific files and folders
      'screenshot.png',

      // exclude files and folders
      '!node_modules/**/*',
      '!assets/bower_components/**/*',
      '!style.css.map',
      '!assets/js/custom/*',
      '!assets/css/patrials/*'

     ];

// Load plugins
 var gulp     = require('gulp'),
  browserSync  = require('browser-sync'), // Asynchronous browser loading on .scss file changes
  reload       = browserSync.reload,
  autoprefixer = require('gulp-autoprefixer'), // Autoprefixing magic
  minifycss    = require('gulp-uglifycss'),
  filter       = require('gulp-filter'),
  uglify       = require('gulp-uglify'),
  imagemin     = require('gulp-imagemin'),
  newer        = require('gulp-newer'),
  rename       = require('gulp-rename'),
  concat       = require('gulp-concat'),
  notify       = require('gulp-notify'),
  cmq          = require('gulp-combine-media-queries'),
  runSequence  = require('gulp-run-sequence'),
  sass         = require('gulp-sass'),
  plugins      = require('gulp-load-plugins')({ camelize: true }),
  ignore       = require('gulp-ignore'), // Helps with ignoring files and directories in our run tasks
  rimraf       = require('gulp-rimraf'), // Helps with removing files and directories in our run tasks
  zip          = require('gulp-zip'), // Using to zip up our packaged theme into a tasty zip file that can be installed in WordPress!
  plumber      = require('gulp-plumber'), // Helps prevent stream crashing on errors
  cache        = require('gulp-cache'),
  sourcemaps   = require('gulp-sourcemaps');


/**
 * Browser Sync
 *
 * Asynchronous browser syncing of assets across multiple devices!! Watches for changes to js, image and php files
 * Although, I think this is redundant, since we have a watch task that does this already.
*/
gulp.task('browser-sync', function() {
 var files = [
     '**/*.php',
     '**/*.{png,jpg,gif}'
    ];
 browserSync.init(files, {

  // Read here http://www.browsersync.io/docs/options/
  proxy: url,

  // port: 8080,

  // Tunnel the Browsersync server through a random Public URL
  // tunnel: true,

  // Attempt to use the URL "http://my-private-site.localtunnel.me"
  // tunnel: "ppress",

  // Inject CSS changes
  injectChanges: true

 });
});



/**
 * Styles
 *
 * Looking at src/sass and compiling the files into Expanded format, Autoprefixing and sending the files to the build folder
 *
 * Sass output styles: https://web-design-weekly.com/2014/06/15/different-sass-output-styles/
*/
gulp.task('styles', function () {
  gulp.src('./assets/css/*.scss')
  .pipe(plumber())
  .pipe(sourcemaps.init())
  .pipe(sass({
   errLogToConsole: true,
 
   //outputStyle: 'compressed',
   outputStyle: 'compact',
   // outputStyle: 'nested',
   // outputStyle: 'expanded',
   precision: 10
  }))
  .pipe(sourcemaps.write({includeContent: false}))
  .pipe(sourcemaps.init({loadMaps: true}))
  .pipe(autoprefixer('last 2 version', '> 1%', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
  .pipe(sourcemaps.write('.'))
  .pipe(plumber.stop())
  .pipe(gulp.dest('./'))
  .pipe(filter('**/*.css')) // Filtering stream to only css files
  .pipe(cmq()) // Combines Media Queries
  .pipe(reload({stream:true})) // Inject Styles when style file is created
  .pipe(rename({ suffix: '.min' }))
  .pipe(minifycss({
   maxLineLen: 80
  }))
  .pipe(gulp.dest('./'))
  .pipe(reload({stream:true})) // Inject Styles when min style file is created
  .pipe(notify({ message: 'Styles task complete', onLast: true }))
});


/**
 * Scripts: Vendors
 *
 * Look at src/js and concatenate those files, send them to assets/js where we then minimize the concatenated file.
*/
gulp.task('vendorsJs', function() {
 return  gulp.src(['./assets/js/vendor/*.js', bower+'**/*.js'])
    .pipe(concat('vendors.js'))
    .pipe(gulp.dest('./assets/js'))
    .pipe(rename( {
     basename: "vendors",
     suffix: '.min'
    }))
    .pipe(uglify())
    .pipe(gulp.dest('./assets/js/'))
    .pipe(notify({ message: 'Vendor scripts task complete', onLast: true }));
});


/**
 * Scripts: Custom
 *
 * Look at src/js and concatenate those files, send them to assets/js where we then minimize the concatenated file.
*/

gulp.task('scriptsJs', function() {
 return  gulp.src('./assets/js/custom/*.js')
    .pipe(concat('custom.js'))
    .pipe(gulp.dest('./assets/js'))
    .pipe(rename( {
     basename: "custom",
     suffix: '.min'
    }))
    .pipe(uglify())
    .pipe(gulp.dest('./assets/js/'))
    .pipe(notify({ message: 'Custom scripts task complete', onLast: true }));
});


/**
 * Images
 *
 * Look at src/images, optimize the images and send them to the appropriate place
*/
gulp.task('images', function() {

// Add the newer pipe to pass through newer images only
 return  gulp.src(['./assets/img/raw/**/*.{png,jpg,gif}'])
    .pipe(newer('./assets/img/'))
    .pipe(rimraf({ force: true }))
    .pipe(imagemin({ optimizationLevel: 7, progressive: true, interlaced: true }))
    .pipe(gulp.dest('./assets/img/'))
    .pipe( notify( { message: 'Images task complete', onLast: true } ) );
});


/**
 * Clean gulp cache
 */
 gulp.task('clear', function () {
   cache.clearAll();
 });


 /**
  * Clean tasks for zip
  *
  * Being a little overzealous, but we're cleaning out the build folder, codekit-cache directory and annoying DS_Store files and Also
  * clearing out unoptimized image files in zip as those will have been moved and optimized
 */

 gulp.task('cleanup', function() {
  return  gulp.src(['./assets/bower_components', '**/.sass-cache','**/.DS_Store'], { read: false }) // much faster
     .pipe(ignore('node_modules/**')) //Example of a directory to ignore
     .pipe(rimraf({ force: true }))
     // .pipe(notify({ message: 'Clean task complete', onLast: true }));
 });
 gulp.task('cleanupFinal', function() {
  return  gulp.src(['./assets/bower_components','**/.sass-cache','**/.DS_Store'], { read: false }) // much faster
     .pipe(ignore('node_modules/**')) //Example of a directory to ignore
     .pipe(rimraf({ force: true }))
     // .pipe(notify({ message: 'Clean task complete', onLast: true }));
 });

 /**
  * Build task that moves essential theme files for production-ready sites
  *
  * buildFiles copies all the files in buildInclude to build folder - check variable values at the top
  * buildImages copies all the images from img folder in assets while ignoring images inside raw folder if any
  */

  gulp.task('buildFiles', function() {
   return  gulp.src(buildInclude)
      .pipe(gulp.dest(build))
      .pipe(notify({ message: 'Copy from buildFiles complete', onLast: true }));
  });


/**
* Images
*
* Look at src/images, optimize the images and send them to the appropriate place
*/
gulp.task('buildImages', function() {
 return  gulp.src(['assets/img/**/*', '!assets/images/raw/**'])
     .pipe(gulp.dest(build+'assets/img/'))
     .pipe(plugins.notify({ message: 'Images copied to buildTheme folder', onLast: true }));
});

 /**
  * Zipping build directory for distribution
  *
  * Taking the build folder, which has been cleaned, containing optimized files and zipping it up to send out as an installable theme
 */
 gulp.task('buildZip', function () {
  // return  gulp.src([build+'/**/', './.jshintrc','./.bowerrc','./.gitignore' ])
  return  gulp.src(build+'/**/')
     .pipe(zip(project+'.zip'))
     .pipe(gulp.dest('./'))
     .pipe(notify({ message: 'Zip task complete', onLast: true }));
 });


 // ==== TASKS ==== //
 /**
  * Gulp Default Task
  *
  * Compiles styles, fires-up browser sync, watches js and php files. Note browser sync task watches php files
  *
 */

 // Package Distributable Theme
 gulp.task('build', function(cb) {
  runSequence('styles', 'cleanup', 'vendorsJs', 'scriptsJs',  'buildFiles', 'buildImages', 'buildZip','cleanupFinal', cb);
 });


 // Watch Task
 gulp.task('default', ['styles', 'vendorsJs', 'scriptsJs', 'images', 'browser-sync'], function () {
  gulp.watch('./assets/img/raw/**/*', ['images']); 
  gulp.watch('./assets/css/**/*.scss', ['styles']);
  gulp.watch('./assets/js/**/*.js', ['scriptsJs', browserSync.reload]);

 });

Saturday, June 06, 2015

Beginner’s Guide to PHP for WordPress – Part 1 of 3

Beginner’s Guide to PHP for WordPress

WordPress allows us to do so much in terms of building websites without knowing any code. With themes and plugins and a powerful admin area there is a lot we can do without typing any HTML, CSS, JS or PHP. However, at a certain point you need to get into the code to really customize things and get a site to look or behave exactly how you want.

Friday, February 27, 2015

How to Make Your WordPress Site Blazing Fast

WordPress Site

Today's web users have the need for speed. With internet and cellular connections getting faster and faster, users expect sites to feel snappy. As developers, we must make sure we're doing our best to serve those pages quickly. This article will focus on what you should be doing to make sure your WordPress sites are as fast as possible.

Make your Wordpress site blazing fast

There are essentially two main categories that performance can be broken down into: front-end and back-end. Back-end is anything related to the server and how data is populated on a page (PHP code in your theme is the "back-end"). The front-end consists of all your assets (CSS, JavaScript, images, etc.) and markup. Everything a web browser reads and interprets is the "front-end". This distinction is important because it's good to know what you're optimizing and, even more importantly, where you need to optimize the most.

To actually test site speed, use a combination of WebPagetest and Google PageSpeed Insights. WebPagetest gives you a good idea of the actual time (in seconds) that a site takes to load, explaining where bottlenecks may be. PageSpeed Insights is best for looking at how your front-end is site is rendered by the browser.

Front-end performance

The golden rule of performance, according to Fastly's Steve Souders is that 80-90% of a page's total load time consists of the front-end. The back-end's 10-20% is crucially important, but even if you're using the fastest host around, your site still won't live up to its full potential without optimizing the front-end and users perceive it to load quickly. Perception is an important part of front-end optimization. A user doesn't care how many seconds a site takes to load. A user cares about how quickly they can interact with a site without a delay. Not that you shouldn't be worried about the actual load time (you should), but by following these techniques, you can make sure that your site is in a usable state fast, before loading the rest of the page assets.

WordPress Site

CSS

Before delivering CSS to the browser, it’s important to compress it and remove unused selectors.

Once your stylesheet is ready to go, the easiest (and standard) way to load it is to reference it in the head. The browser will load and parse it before the rest of the DOM is loaded. However, there's a new technique where "critical" styles are inlined in the head and then the full stylesheet is loaded asynchronously using JavaScript. This technique can be used when trying to get a site to load (or perceive to load) in under a second, but it's a great tool to keep in your arsenal. Check out this great extensive article on using this technique.

WordPress Site

JavaScript

The golden rule(s) of optimizing JavaScript are simple: serve as few JavaScript files as possible and minify and concatenate. Third-party WordPress plugins can bloat your document with unminified blocking JavaScript files, so it's important to be mindful when choosing plugins. Ideally, you'd concatenate ALL JavaScript files into one and then minify it. When that's not possible, HTML attributes called async and defer can be used to load JavaScript files asynchronously or once the rest of the page is loaded.

The most common place to reference JavaScript is at the bottom, right before the closing tag. However, there are more advanced techniques to load JavaScript. The Filament Group has several tools you can use for this. The best approach is to load scripts dynamically by inlining a small function in the head that appends script tags without blocking the rest of the page. For more information, check out the loadJS script.

Images

Images are often the biggest files on a page, responsible for the largest load time delay. The good thing about images is that, unlike CSS and JavaScript, most browsers load them asynchronously. That helps with the perceived performance of a page. But it's still important that A) you're serving as few images as possible and B) those images are compressed as much as possible.

Compression tools are necessary for squeezing out as much excess as possible on images. ImageOptim is a great free Mac compression app, along with OptiPNG and jpegtran for use with task runners like Grunt.

WordPress Site

Fonts

Web fonts are super common these days. Google Web Fonts make sites pop. It's easy to not realize the performance hit you take by just referencing them in the head. The performance hit is small, but every little bit counts! For best performance using web fonts, check out the the Web Font Loader, co-developed by Google and Typekit. It's an open source script that both manages the loading of your fonts from third parties like Google Web Fonts and allows them to load asynchronously (getting tired of that word yet?).

As to be expected, there's some configuration needed to get Web Font Loader integrated into your project, so check out the project on GitHub for setup info.

WordPress Site

Back-end performance

The front-end has all kinds of tricks for speed, but we're not so fortunate on the back-end. A server is either fast or it's not. It's critical that your site gets to the browser as quickly as possible, which can be accomplished by getting on a quality host. Managed hosts like Flywheel are the most realistic way to see true performance gains for WordPress sites.

Dedicated Wordpress Hosts

There are are a host of managed WordPress hosts (pun intended). What managed hosts typically provide is a dedicated VPS (virtual private server), a caching layer and other infrastructural bonuses that set them apart from your typical shared hosting. These all matter when it comes to loading your site fast, so the best and first step to a super fast WordPress site should be the host.

For example, let's take a look at Flywheel. Flywheel is a managed host, and their infrastructure is designed so your sites never touch another customer's. Compared to a host that crams as many sites as possible on the same server, having your site on a server by itself works magic for speed. It means that server's resources are just working for you, not for everyone else.

WordPress Site

Theme Logic

There are many things you can do while developing to make your back-end as performant as possible. Nasty loops that do tons of comparisons and use lots of memory slow down a site down. There are lots of articles on performant PHP, but just take care when writing theme logic!

Another important time saver during database queries is the Transients API. WordPress transients store cached data in the database temporarily, which means your logic only has to run once (whenever the first visitor loads the page). The results are then stored in the database. The Codex has good documentation on the usage of transients.

Caching

Caching assets is one of the best ways to improve performance. Once a user loads your site the first time, you can take advantage of browser capabilities to cache the contents of that site locally, so on the next visit the user already has them loaded. The most common WordPress caching tool is W3 Total Cache plugin. This plugin (or one similar) is needed on most shared hosts. However, WordPress specific hosts like Flywheel handle caching for you behind the scenes. With hosts like Flywheel, all of the caching is done on the server outside of WordPress, which means your sites are already tuned for max performance.

WordPress Site

GZIP

Gzip is a file format that's used to compress other files together, similar to just zipping files. Gzipping allows files to be sent over the web at a compressed size. Once a browser receives gzipped data, it unzips it to get the source data. Gzipping is super important for speed, as it sends your data over the wire in much smaller packages (50 - 70% smaller, in fact). Smaller file size equals faster load times!

You should always check to see if your host supports Gzipping. Managed WordPress hosts like Flywheel enable Gzip compression by default, so it's one less to to worry about!

WordPress Site

CDN

A content delivery network (or CDN) is a network of servers that serves up your website and its assets from different locations based on the user's location. For example, let's say you're not using a CDN and your site is hosted in San Francisco. When someone from, say, Spain visits your site, they have to retrieve all your assets from your server in San Francisco. The long distance between the two locations clearly takes longer than if someone from San Francisco loads your site that's hosted in San Francisco. A CDN serves your assets from the closest geographical data center. Users will hit the server closest to them, speeding up the physical time and distance required to load the page.

Some of the most popular CDNs include Amazon Web Services, CloudFlare and MaxCDN. If you want a super easy setup, check out Flywheel's MaxCDN add-on.

WordPress Site

Conclusion

Tuning a web site to maximum capacity can be challenging. There are a lot of moving parts. By working through both the front end and the back end, a site can be designed or overhauled for maximum speed. On the front end, saving as much time and space as possible means the con-tent you’re serving gets to the content faster. But if even if your front end is brilliantly designed, none of that will matter the servers you host the site on aren’t running at their peak performance. Managed WordPress hosts tune sites to peak performance and take out the frustrations behind web hosting. Hosts like Flywheel will not only make your site fly, but make your hosting experience worry-free.


Friday, January 17, 2014

How to Make WordPress Sites Load 72.7% Faster

How to Make WordPress Sites Load 72.7% Faster

You want to know the secret to a faster WordPress website?

You and everyone else.

Thursday, January 09, 2014

WordPress Tutorial: What’s New in WordPress 3.8

What’s New in WordPress 3.8

WordPress 3.8 is here and there are a lot of exciting changes. Get up to date with the new features and start enhancing your blog or website today. In this video, lynda.com author Morten Rand-Hendriksen reveals the redesigned dashboard, which is high contrast, clean and more customizable than ever and the new Twenty Fourteen theme, which provides a (highly requested) featured content area on your front page. The new dashboard is also fully responsive, so you can now visit the dashboard from your mobile device. This is great for making changes on the go!



Magazine Theme

The magazine theme is a page layout for WordPress (a "theme") that mimics the layout of a newspaper or magazine, with multiple boxes and spaces for photographs, allowing for certain posts to be called out.

Look and feel

In software design, look and feel is a term used in respect of a graphical user interface and comprises aspects of its design, including elements such as colors, shapes, layout and typefaces (the "look"), as well as the behavior of dynamic elements such as buttons, boxes and menus (the "feel"). The term can also refer to aspects of an API, mostly to parts of an API that are not related to its functional properties. The term is used in reference to both software and websites.

Look and feel applies to other products. In documentation, for example, it refers to the graphical layout (document size, color, font, etc.) and the writing style. In the context of equipment, it refers to consistency in controls and displays across a product line.

Look and feel in operating system user interfaces serves two general purposes. First, it provides branding, helping to identify a set of products from one company. Second, it increases ease of use, since users will become familiar with how one product functions (looks, reads, etc.) and can translate their experience to other products with the same look and feel.

Some Popular WordPress Magazine Themes From ThemeForest


Wednesday, October 10, 2012

Wordpress: redirect to post if search results return one post

Wordpress: redirect to post if search results return one post

WordPress has a built in search functionality which allows your visitor to easily search for posts on the blog. It can search for keywords in the post title and in the post content.

When a search is performed WordPress will use the Archives.php file to display you the results. You can customise this page to display the entire list of posts returned from the WordPress database.

The problem is that if WordPress returns only one post in the search results it will still take you to the Archives.php file and display a list of posts, well the one post.