Posted on

Improved Grunt Tasks for the Vagrant WordPress Dev Box

Grunt WordPress Dev Kit

Last week I found myself having to rebuild my WordPress plugin development box after a “laptop fiasco”.   While it was a lot of work it feels as though I am in a better position to not only recover my environment quickly but also distribute it to other developers that are interested in assisting with plugin development.

If you are interested you can read more about it in the related WordPress Workflow and related WordPress Development Kit articles.

This morning I realized that having a new almost-fully-configured Vagrant box for my WordPress Development Kit allows me to make assumptions in my Grunt tasks.    While it would be more flexible to create options-based tasks where users can set their own configuration for things like MySQL usernames and passwords, the WP Dev Kit Vagrant box assumption allows me to bypass that for now and come back to it when time allows.  Fast turnaround and fewer interruptions in my already-busy work flow is paramount this week.

Today’s WordPress Dev Kit Updates

The official tag I’ve assigned to the newest WordPress Dev Kit is version 0.5.0.  Here is what has been added.

WordPress Database Reset

One of the tasks I do fairly often is to “clear the data cruft” from my development box WordPress tables.  I  accomplish this by dropping the WordPress database and recreating it.

The Vagrant box makes this far easier as I know that when I spin up the WP Dev Kit Vagrant box it already has the WordPress MySQL tables setup.  I also know the username and password.  As such I can execute a simple drop/create table as the privileges are already in place in the meta data for MySQL and will carry over.   Thus I only need to execute a single mysql-cli command to get the data reset.

To get this working in Grunt I added the grunt-ssh module and created a ‘resetdb’ target.

I can now reset my WordPress table with a simple grunt command:


$ grunt shell:resetdb

Online Documentation

The other change I made today will help me remember how the heck all this stuff works.  Now that the dev kit has grown to a couple of commands I know I will soon be forgetting the nuances to certain build and workflow processes.   I started creating my own Markdown files I realized that Bitbucket has a system for using .md files on the repository wiki.    The easy solution was to add the Bitbucket wiki as a submodule to the WP Dev Kit repository and edit the file there.    Doing so means that any doc update will also be published immediately when pushed back to the repo at the WP Dev Kit Bitbucket Wiki.

Now back to getting the Store Locator Plus and Enhanced Results first-pass testing run and prerelease copies published for my Premier Members.

Posted on

WordPress Development Fresh Start with Vagrant and Grunt

Banner Vagrant Cloud WP Dev Kit Box

HP finally did it.  They came out to replace a system board in my laptop and half of my files on my drive are corrupted.  Restoring the 70GB of corrupt files from the local USB3 backup will take some time and I am not 100% confident in the reliability of this system.   With 48 hours of downtime I decided it would be best to push forward with my Vagrant and Grunt setup for the WordPress Development Kit I’ve been working on.

Employing Vagrant

I am using VirutalBox and Vagrant to build a series of base boxes on which to layer my development environment.  Unlike most base boxes that are plain vanilla OS installs that then use provisioners to install all the software layers on top of the OS, my custom base boxes are going to be installed with all the base tools I need to develop WordPress plugins using my WordPress Development Kit tools.

Why?

Because it is far faster to download a compressed virtual machine image with most of my stuff installed  than to download a very similar image with no tools then have Vagrant go and download  a few dozen install kits.   Sure, the standard method is more flexible and ensures everything is up-to-date, but that is not what I am trying to accomplish here.    I am building a “fast start” box that has most of what you need pre-installed in a known environment.

I also want to have a method to deploy new virtual boxes with everything in place on my OS/X system, a different laptop, or even a cloud-based server the next time my HP laptop is smoked.  Which will probably be tomorrow.      As I’ve found, restoring a large image even from a local USB3 drive is not a quick process and it is not foolproof.   Especially when going from a Windows 8.1 based backup and restoring on an OS/X system that has not been patched or updated in 8 months.

How…

Since I already have Vagrant installed and have a published base box I am able to get started quickly.   Once Vagrant is installed I only need to set my Vagrantfile, a script that tells Vagrant what to do, to pull down the base box from the URL I have published on Vagrant Cloud:

  • Create a folder on my host system named “C65 WP Devkit  Box Setup”.
  • Create the Vagrantfile, in that directory with the config.vm.box pointing to charlestonsw/centos6.5-wordpress-dev-kit-base-box.
  • Open the command line for Windows and go to that C65 WP Devkit Box Setup directory.
  • Run the vagrant up command.
My new Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don’t touch unless you know what you’re doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "charlestonsw/centos6.5-wordpress-dev-kit-base-box"
config.vm.provider "virtualbox" do |vb|
vb.gui = true
end
end

What…

When you boot the WordPress Dev Kit Base Box with Vagrant you will find that the full CentOS GUI is active. You can login to the GUI using the standard vagrant username with a password of vagrant.

WordPress 3.9

You will find a Firefox icon on the menu bar. Opening Firefox will open the http://localhost/ URL which brings up the local copy of WordPress 3.9 that has been installed.

MySQL for WordPress

The MySQL database has been configured for WordPress.

Database name: wordpress
MySQL User: vagrant
MySQL Password: vagrant

NetBeans 8.0

NetBeans 8.0 has been installed with the PHP and HTML 5 support packages.   NetBeans is a great no-cost IDE that I have found to be very useful for editing structured WordPress PHP code.   Write your code using an object oriented design and add a good amount of phpDoc commenting and NetBeans becomes a coding power tool for WordPress plugin coding.

Firefox

Firefox is installed along with several add-on packs that I use for every day code management and development.  It includes Firebug to look at JavaScript, CSS, and HTML construction.   Selenium IDE is included which allows me to download and execute my web-interface based test scripts for Store Locator Plus.   LastPass is installed to provide unique long-string passwords to all of my web services.

WordPress Development Kit

My command line WordPress Development Kit is installed on the system under the vagrant user home directory in ~/wp-dev-kit. This comes with the basic Grunt build tasks I use to manage my plugins. While you can edit the ~/wp-dev-kit/grunt/plugins.json file and configure this for your site it is recommended that you create a fork of my WordPress Development Kit on the Bitbucket site and work from your forked repository. I would remove the wp-dev-kit directory with rm -rf and clone your forked copy into the same location.

The easiest method for cloning a public repository is to use git clone with the https repository path. If you have a private repository you may want to create a SSH key pair by going to ~/.ssh and running ssh-keygen. The key will need to be added as an authorized SSH key in your Bitbucket account access management list.  Since I will be pushing and pulling content from my various Bitbucket git repositories I will use this method when setting up my clone of the WP Dev Kit Basic Box.

Bitbucket HTTPS Path
Bitbucket HTTPS Path

Similar methods can be employed with Github repositories.

Preparing For Development

These are elements that will eventually go into a provisioner setup for the Vagrant box, assuming that at least one of the Vagrant provisioning services can hand user prompts and communication with third party services.

Create Your SSH Key

This will make it easier to push & pull content from your repositories.

cd ~/.ssh
ssh-keygen
xclip -sel clip < ~/.ssh/id_rsa.pub
Setting A Vagrant SSH Key
Setting A Vagrant SSH Key

Login to your Bitbucket account, go to my account / access management, add the copied SSH key.

Bitbucket Add Vagrant Key
Bitbucket Add Vagrant Key

 Configure Your Git ID

git config –global user.name “Lance Cleveland”
git config –global user.email lance@thisdomain.com

Add SmartGit

I like the GUI interface that SmartGit provides over the git command line and gitk branch rendering.  I find SmartGit to be twice as efficient for my method of work flow over the built-in IDE and command line, so I always install this next and clone my base projects like the WP Dev Kit and my Selenium IDE scripts.   Today I am using the SmartGit 6 beta release as I find the project grouping and new interface design to be a big help in managing my projects.

SmartGit UI
SmartGit UI

I immediately setup SmartGit and clone my Selenium IDE repository so I can complete the next step with a script.

SmartGit Bitbucket Setup
SmartGit Bitbucket Setup

Complete The WordPress Install

Open Firefox and go to http://localhost/

Enter the WordPress local site information for your test site.  I use my Selenium IDE new site install script to handle this for me.

Selenium IDE setting up a  new WordPress install.
Selenium IDE setting up a new WordPress install.

Ready To Go

Now my system is ready to go.   I can start cloning my plugin code repositories into the ./wp-content/plugins directory, edit code with NetBeans, commit changes with SmartGit, and publish to my server or the WordPress plugin directory using my Grunt scripts.

With the current configuration it takes me 15 minutes to pull down a new clone and get the box booted then 5 minutes to install and configure SmartGit, clone my repository, run the WordPress install script, and fetch my first plugin repo.   20 minutes from “nothingness” to writing code.    With a local .box file on my system that time is cut down to about 8 minutes by avoiding the 1.5GB download of the box.

Not bad.

Now on to the code…

Posted on

WordPress Development Kit Plugin Released

Grunt WordPress Dev Kit

The WordPress Development Kit plugin works hand-in-hand with the WordPress Development Kit system to assist in publishing public and private WordPress plugins.   I am using this system of Grunt tasks to manage the free plugins listed in the WordPress Plugin Directory as well as the premium add-on packs.

The WordPress plugin that goes along with this system communicates with the Grunt metadata files to present the latest plugin information on the website.   The plugin is now in charge of keeping the version page updated with the latest production release information.   In the version 0.4.0 release, that was published to the WordPress Plugin Directory today, a file list-and-download user interface is also available.

The 0.4.0 release now has the following base features:

  • List all the WP Dev Kit managed plugins in a formatted HTML output.
  • Filter the plugins listed to show only the prerelease or production listing.
  • Create a formatted list of downloadable files with version information with alt and title hover for file size and slug.
  • Create a detailed listing, including the changelog for plugins managed by the WP Dev Kit that have been published with readme data.

You can see the plugin in use on the Premier Subscription downloads page, the version info page, and some plugin details pages.  This update will help bring clarity to the prerelease and production versions that are available for download for all Premier Members.   Premier Members can select the Products/Download menu item on the top of this page to see the latest list of plugins that are available.

The plugin and the WP Dev Kit Grunt-based system are both available via the my Bitbucket repository as public open-source projects.

 

Screenshots

WordPress Dev Kit 0.4.0 Download List
WordPress Dev Kit 0.4.0 Download List
Posted on

WordPress Dev Kit : Grunt 0.3.0 and Plugin 0.0.2

Grunt WordPress Dev Kit

More refinements have been made this week to my WordPress Workflow and related WordPress Development Kit.  With new products going into production shortly and some older products coming out with new releases, I realized I needed a more efficient way to publish prerelease copies.  As part of the Premier membership program I am trying to get stable prerelease products in the hands of those Premier members that want them.   Some members like to test new releases or try out new features on their test systems before they come out.    It allows them to plan for future updates and provides an opportunity for feedback and updates before the new version is released.  A win-win for the Premier member and for Charleston Software Associates.

In order to support a formal prerelease and production configuration I realized I needed to be able to track two different versions and release dates separately.   Following the general format presented in other Grunt examples, this meant setting up new sub-sections within the plugins.json pluginMeta structure.   The new format looks something like this:

"wordpress-dev-kit-plugin": {
"production": {
"new_version": "0.0.02",
"last_updated": "2014-04-03"
},
"prerelease": {
"new_version": "0.0.03",
"last_updated": "2014-04-04"
},
"publishto" : "myserver"
}

Changing the structure meant updating both the Gruntfile.js for the development kit as well as the parser that is in the WordPress Development Kit plugin. The changes were relatively minor to address this particular issue, but I did learn some other things along the way.

Tasks and Targets

In my own Grunt tasks I had been calling one of my parameters in my build sequence the “type”, as in the “build type”. However the configuration file examples online often talk about a “target”. A target would be something like “production” or “prerelease” that shows up in a configuration block like this one:

// sftp
//
sftp: {
options: {
host: ‘<%= myServer.host %>’,
username: ‘<%= myServer.username %>’,
privateKey: ‘<%= myServer.privateKey %>’,
passphrase: ‘<%= myServer.passphrase %>’,
path: ‘<%= myServer.path %><%= grunt.task.current.target %>/’,
srcBasePath: "../public/<%= grunt.task.current.target %>/",
showProgress: true
},
production: { expand: true, cwd: "../public/<%= grunt.task.current.target %>/", src: ["<%= currentPlugin.zipbase %>.zip","plugins.json"] },
prerelease: { expand: true, cwd: "../public/<%= grunt.task.current.target %>/", src: ["<%= currentPlugin.zipbase %>.zip","plugins.json"] }
},

I have updated my scripts and documentation terminology to refer to this parameter as the “target” to follow convention.

Simplify Congiguration With grunt.task.current.target

I learned a new trick that helps condense my task configuration options. In one of my interim builds of the WordPress Dev Kit I had something that looked more like this:

// sftp
//
sftp: {
options: {
host: ‘<%= myServer.host %>’,
username: ‘<%= myServer.username %>’,
privateKey: ‘<%= myServer.privateKey %>’,
passphrase: ‘<%= myServer.passphrase %>’,
showProgress: true
},
production: {
expand: true,
cwd: "../public/<%= grunt.task.current.target %>/",
src: ["<%= currentPlugin.zipbase %>.zip","plugins.json"]
path: ‘<%= myServer.path %>production/’,
srcBasePath: "../public/production/",
},
prerelease: {
expand: true,
cwd: "../public/<%= grunt.task.current.target %>/",
src: ["<%= currentPlugin.zipbase %>.zip","plugins.json"]
path: ‘<%= myServer.path %>prerelease/’,
srcBasePath: "../public/prerelease/",
},
},

A bit repetitive, right? I found you can use the variable grunt.task.current.target to drop the current task name as a string into a configuration directive:

// sftp
//
sftp: {
options: {
host: ‘<%= myServer.host %>’,
username: ‘<%= myServer.username %>’,
privateKey: ‘<%= myServer.privateKey %>’,
passphrase: ‘<%= myServer.passphrase %>’,
showProgress: true
},
production: {
expand: true,
cwd: "../public/<%= grunt.task.current.target %>/",
src: ["<%= currentPlugin.zipbase %>.zip","plugins.json"]
path: ‘<%= myServer.path %><%= grunk.task.current.target %>/’,
srcBasePath: "../public/<%= grunk.task.current.target %>/",
},
prerelease: {
expand: true,
cwd: "../public/<%= grunt.task.current.target %>/",
src: ["<%= currentPlugin.zipbase %>.zip","plugins.json"]
path: ‘<%= myServer.path %><%= grunk.task.current.target %>/’,
srcBasePath: "../public/<%= grunk.task.current.target %>/",
},
},

Now that the prerelease and production path and scrBasePath variables are identical they can be moved into the top options section.

Now if I can just figure out how to have shared FILE configurations which define the current working directory (cwd), source (src), and destination (dest) file sets I could eliminate ALL of the settings in the production and prerelease configuration blocks and leave them with a simple “use the defaults setup like this:

// sftp
//
sftp: {
options: {
host: ‘<%= myServer.host %>’,
username: ‘<%= myServer.username %>’,
privateKey: ‘<%= myServer.privateKey %>’,
passphrase: ‘<%= myServer.passphrase %>’,
path: ‘<%= myServer.path %><%= grunk.task.current.target %>/’,
srcBasePath: "../public/<%= grunk.task.current.target %>/",
showProgress: true
},
production: { },
prerelease: { },
},

Maybe someday.

Simplify Congiguration With Shared Variables

Another trick I learned is that common configuration strings can be put at the top of the configuration block and re-used. This is alluded to on the Grunt tasks configuration page but they never expound on how to use the common configuration variables. Here is how it works, define the variable at the top of the configuration block then reference that variable inside a string like ‘<%= my_var %>’. Here is my example with some “fluff” missing from the middle:

// Project configuration.
grunt.initConfig({

// Metadata.
currentPlugin: currentPlugin,
myServer: myServer,
pkg: grunt.file.readJSON(‘package.json’),
my_plugin_dir: ‘/var/www/wpslp/wp-content/plugins/<%= currentPlugin.slug %>’,
my_src_files: [
‘**’,
‘!**.neon’,
‘!**.md’,
‘!assets/**’,
‘!nbproject/**’
],
// compress
//
compress: {
options: {
mode: ‘zip’,
archive: ‘../public/<%= grunt.task.current.target %>/<%= currentPlugin.zipbase %>.zip’,
},
prerelease: { expand: true, cwd: ‘<%= my_plugin_dir %>’, src: ‘<%= my_src_files %>’ },
production: { expand: true, cwd: ‘<%= my_plugin_dir %>’, src: ‘<%= my_src_files %>’ },
},

In this example you can see how I’m using the my_plugin_dir variable to set my path to the plugins I am working on on my dev box and my_src_files to list the files I want to add (or ignore) when pushing my development plugin directories to a zip file or the WordPress svn repo for publication.

This has simplified a lot of task configuration entries in my custom grunt tasks script.

That combined with smarter configuration blocks in areas like the SFTP node module has simplified my Grunt configuration which will make it less prone to errors and easier to maintain going forward.

Back to coding…

Posted on

WordPress Dev Kit Plugin : 0.0.1

Grunt WordPress Dev Kit

For those of you that have been following along with my exploration of Grunt and automating my plugin workflow automation… I’m sorry.   Quite boring I’m sure but remember this blog is my personal notebook as much as fodder for the 3 people that may be interested in this stuff.

Last night I extended my journey toward less manual updates, each new step adding an option for human error, by creating the first WordPress Development Kit Plugin.  Yup, a plugin for plugin development.  Sort of.  What the new plugin is going to help me with is keeping my Plugin Version Info page updated.   Today it is very rudimentary with a basic list of plugin slugs, the version info, and release dates.  You can see it in action on my Plugin Version Info page. Ultimately the new Plugin companion to the WordPress Development Kit will be extended to get more information from the Grunt process into the public website via the automated toolkit.

My goal is to have ONE PLACE where plugin information is updated, preferably in the readme files.    For now the JSON file that drive Grunt will suffice with future plans to scrape the readme data into the plugins.

What WordPress Dev Kit Plugin Does

The WordPress Dev Kit plugin is very simplistic in its current form.  It reads the plugins.json file from the WP Dev Kit and renders information via a shortcode to a plugin or  post.

Version 0.0.3 of the plugin has the following shortcodes available:
* Actions (default: list)
* o [wpdevkit action='list'] list details about all plugins
*
* Styles (default: formatted)
* o [wpdevkit action='list' style='formatted'] list the details in an HTML formatted layout
* o [wpdevkit action='list' style='raw'] list the details in a print_r raw format
*
* Types (default: basic)
* o [wpdevkit action='list' type='basic'] list basic details = version, updated, directory, wp versions
* o [wpdevkit action='list' type='detailed'] list all details = version, updated, directory, wp versions, description
*
* Slug (default: none = list ALL)
* o [wpdevkit action='list' slug='wordpress-dev-kit-plugin'] list details about a specific plugin

This will list the entire plugin metadata structure in a pre tag as a standard PHP dump format.

WP Dev Kit Plugin Setup

It expects that you have the WordPress Development Kit plugins.json file pushed to a production files directory on your server.   You can set the location of the file to any web-server-readable directory.    The location is specified in the Settings / WP Dev Kit menu in the admin panel.

If you are using the WP Dev Kit Grunt tasks the build:<slug>:production process will move the plugins.json file over to your server along with your production.zip files.

My Process And How This Helps

In case you’re wondering why I would go through the trouble of building a full-fledged plugin like this, here is my typical workflow:

  1. Edit code.
  2. Edit readme to update version, features, etc.
  3. Edit main plugin to update version, etc.
  4. Create zip file.
  5. FTP zip file to server.
  6. If a WordPress Plugin Directory plugin, fetch SVN repo, update trunk, commit, add branch, commit, push.
  7. Login to my website.
  8. Update version info page on website.
  9. Create blog post about new plugin update with features and screen shots if warranted.
  10. If a Store Locator Plus plugin update the HTML that is pushed through the in-product signage app.

Until today nearly every step of that process was manual.  Now with the WP Dev Kit running on my system and the WP Dev Kit Plugin on my public site the process is now:

  1. Edit code.
  2. Edit readme to update version, features, etc.
  3. Edit main plugin to update version, etc.
  4. Edit the WP Dev Kit JSON file.
  5. grunt build:<slug>:production  which automatically
    1. checks that the version in the readme.txt and plugin file match (new quality control test)
    2. creates the zip file
    3. uses SFTP to put the file on my server
    4. updates the WordPress Plugin Directory Listings (fetch, update trunk, commit, add branch, commit, push)
    5. pushes plugin.json which talks to the WP Dev Kit Plugin and keeps the version info page upated
  6. Login to my website.
  7. Create blog post about new plugin update with features and screen shots if warranted.
  8. If a Store Locator Plus plugin update the HTML that is pushed through the in-product signage app.

The magic happens in steps 4 and 5.   It automates many of the steps in the process.  As I refine the WordPress Dev Kit I will be able to eliminate more steps along the way.

Not a bad start.   As each new plugin update happens I will be refining and improving the automation files and plugin to create a better presentation and improve quality control at each step.

Learn about this process via the WordPress Development Kit articles.

Posted on

WordPress Dev Kit : Grunt Helpers 0.2.0

Grunt WordPress Dev Kit

I am continuing on my quest to use Grunt to further automate my plugin development process. I hope to be generating better quality plugins through more automated testing and sanity checks during the production process. I also hope to take out a few of the steps required to get the plugins into the hands of my customer base. TheWordPress Development Kit articles describe the process as it evolves, both to possibly help others that are considering automating with Grunt and to help people that are starting to work on plugins related to those I’ve created understand my process.

My Environment For Grunt Helpers 0.2.0

I’ve made some changes to my plugin production environment since the original “Legacy Publisher” and even my “Grunt Helpers 0.1.0” article.   Some of the changes are based on things I’ve seen elsewhere as I learn about Grunt and other changes are to have a better defined environment.   Here is a summary of how things are working with the Grunt automation in the latest iteration.

I have two types of production, ready for public consumption, plugins:

WordPress Plugin Directory Listings

The WordPress Plugin Directory Listings (WordPress Hosted) are managed via the standard subversion (svn) repository update process.   They also are packages and put on my server for customers to download from my site.

Premium Plugins Served From My Site

The Premium Plugins (Premium) are only hosted on my server and made available to customers that have purchased the premium add-on packs.

For both types of plugins, whether WordPress Hosted or Premium, I now have two versions available; the production release (production) which is the official ready-for-deployment version and pre-release (prerelease) which is provided to select customers for testing an upcoming release before it has been fully tested.   Pre-release versions are beta releases that may not be fully tested.

Regardless of whether a plugin is a WordPress Hosted product or a Premium product, the pre-release is ONLY available from my server and only to select customers.    I use the Groups plugin combined with the WooCommerce add-on pack for Groups as well as the File Away plugin to manage access to the pre-release versions.

The Grunt Tasks

To support the various iterations of the plugins that are being produced I have created several grunt tasks that are managed by my WordPress Development Kit scripts.

grunt build:<slug>:production

This task will publish the production-ready copy of my plugin.   It goes through my development copy of the plugin directory, cleans out the “development cruft” and builds a .zip file that is ready for distribution.    It will then read the plugins.json file and determine the ultimate home for the production copy.  If the “publishto” property for the given slug is “wordpress” (maybe I should change it to “WordPress”) the product ends up on the WordPress Plugin Directory.    If the publishto property is “myserver” the product ends up on my web server in the production files directory.

grunt build:<slug>:prerelease

This tasks also cleans out the “development cruft” of the plugin directory and creates a zip file.   However in this mode the plugin zip file only ends up on my server regardless of the publishto property set in the plugins.json file.   The prerelease files are stored in a separate directory on my server from the production files.

My Grunt Configuration Files

There are now several files that are used to configure my development kit.

package.json

This now follows a standard Grunt package.json format.   It contains my author info, the grunt default project name, version, description, license, and a list of grunt dependencies.   Grunt dependencies are node.js modules that are used by this project.  Currently the list includes:

Those with the asterisk (*) are not currently used, but I know I will be making use of them in the future so I’ve left those recommended default modules in place.

plugins.json

This is now the home for all of the metadata about my WordPress plugins that are being managed by the WordPress Development Kit.  This includes variables that are later used by modules such as wp-deploy as well as my plugin specific information such as the slug and other information.   The format is typical JSON with the following nodes defined:

    • pluginMeta = an array of plugin slugs
      • <slug>
        • version = current production version of the plugin (most likely will be deprecated and auto-read from readme.txt)
        • name = the plugin name (most likely will be deprecated and auto-read from readme.txt)
        • description = the plugin description (most likely will be deprecated and auto-read from readme.txt)
        • publishto = where production files get published, either “wordpress” (WordPress Hosted) or “myserver” (Premium)
        • zipbase = the base name of the zip file, used if I want to create myplugin-test.zip instead of myplugin.zip
        • reposlug = the WordPress Hosted repository slug if not the same as <slug>
    • wp-plugin-dir = where on this server, my development server, do the in-development plugins live
    • wp-username = my WordPress Plugin Directory username

myserver.json

This file contains the details about my server that help with the SFTP push to my server.  It includes things like my local path to the SSH key files and where I want to put stuff on the remote server.

    • host = my fully qualified host name (no http, etc. just a pure host name)
    • username = the username to use for sftp login
    • privateKeyFile = the path on my development system where my private key file lives
    • privateKeyPassFile = the path on my development system where the private key password is stored (will become a command line option, this is a security risk, though my dev system is fairly well locked down and isolated)
    • path = the path on the production server that is the root directory under which my production and pre-release files will go.

Process Details

Here is what happens when I execute the two most-used commands in my new build kit.

WordPress Hosted Production

command: grunt build:<slug>:production

This process gathers all the files in my plugin directory and copies the “cleaned” version of the files into ./assets/build under the plugin directory itself.  I store it here because assets is one of the directories that is ignored (cleaned) during production and it allows me to see exactly what got moved into production.    These files are then published to the WordPress svn repository using the wp-deploy module.   The same files are sent through compress with a .zip file created and stored in the wp-dev-kit/public directory (yes this seems redundant and can probably be simplified).  Finally the zip file from that public directory is sent over to my live server with SFTP and put into the production folder on the live server.

[box type=”alert”]I did have to create a patch for wp-deploy to properly manage subdirectories. I have submitted the patch to the author. Hopefully it makes it into his production release soon.[/box]

Premium Production

command: grunt build:<slug>:production

This process is identical to the WordPress Hosted Production process with one exception.  It skips the wp-deploy call and does nothing with svn.  I creates the ./assets/build files, zips them, puts them in the WP Dev Kit public folder, and copies them over to the production folder on my server.

WordPress Hosted and Premium Prerelease

command: grunt build:<slug>:production

This process works much like the Premium Production process.  The only difference in the process is that the files are copied over to my server into a different directory that holds pre-release plugin files only.

Further Refinements

There are a number of refinements to be made to the process.  First on my agenda is reading the readme.txt file and extracting the version information so it can be appended to the zip file names for pre-release copies of the products.    I will then work on things like running the third party modules to do gettext sanity tests, JavaScript minification, and other “would be nice” features for production plugins.   I will also likely change this process a dozen times as I continue to iterate over both Premium and WordPress Hosted plugin builds over the next few months.

In the end I hope to have a handful of simple Grunt commands that manage the process efficiently and reduces the human error that my current process can introduce at several steps.

If you have suggestions or feedback on how to improve my process, please let me know!

Related Topics

Posted on

WordPress Dev Kit : Grunt Helpers 0.1.0

Grunt WordPress Dev Kit

Now that I have a very basic understanding of Grunt it is time to start incorporating it into my WordPress Development Kit.  My hope is not to simply replace the current Legacy Publisher elements of my WP-Dev-Kit scripts, but to speed up the production process and improve the quality of the plugins.

I can now start writing JavaScript to parse and process the myriad of files that are updated with each release.  I can mix in system commands and replace the Bash script processing to update repositories, upload files to my servers, and hopefully even start an automated web content production script.

WordPress-Centric Grunt Scripts

In addition there are at least a handful of pre-existing Grunt scripts that will improve the quality of my plugins doing things like creating the POT files and also checking my text domains (an ongoing problem for me) to assist in language translations.    There are also scripts to check the WP versions in my readme and base plugin match (bitten by that one more than once) and even generate a readme.md for Github or Bitbucket repos.    I’m sure I’ll discover more soon, here are the few I know about today:

checktextdomain by Stephen Harris
Checks the correct text domain is passed when using the WordPress translation functions.

checkwpversion by Stephen Harris
Make sure your plugin version numbers are all in sync in the plugin header, readme.txt and the Grunt package.json files.

pot by Stephen Harris
Generates a .POT file that can be used for translations.

wp-readme-to-markdown by Stephen Harris
Converts readme.txt file to readme.md for use in Github repo.

Setting Up The WP Dev Kit

You can follow along by cloning the git repository:

cd ~
git clone git@bitbucket.org:lance_cleveland/wp-dev-kit.git ./wp-dev-kit
cd ./wp-dev-kit/grunt
npm install

[box type=”alert” style=”rounded”]The WP Dev Kit Legacy Publisher scripts store published plugins in your ~/myplugins directory. With the newer Grunt scripts they are stored under the ./wp-dev-kit/public directories. If you mix-and-match legacy and Grunt scripts you will have inconsistent published zip files unless you symlink the directories.[/box]

After cloning the repository you will want to edit the plugins.json file in the ./grunt subdirectory to replace the plugin files with your own list of plugins that you are developing and/or managing.

[box type=”alert” style=”rounded”]Make sure you edit the ./grunt/plugins.json file to match the list of plugins you are developing.[/box]

If you are feeling adventurous you can even use git to clone my public Store Locator Plus plugin code into your WordPress plugins directory.

My WP Dev Kit Grunt Tasks

The following tasks are part of my my WP-Dev-Kit Grunt file.

build:<slug>[:<type>]

Builds the distribution file, a .zip file, for the specified plugin and put it in the wp-dev-kit public folder.   Ready for distribution.  As the Grunt toolkit expands this will also do some cleanup and maintenance like running version check and textdomain checks, minifying CSS and JavaScript and other nice things like that!

The type parameter can extend the build and make it do other things like:

makezip
The default mode.  Just build the zip file and put it in the public folder of the WP dev kit.

publish
Reads the package.json parameters and decides whether to SFTP the zip file to a private server or unpack it into a new tag in the svn repo and push it to the public WordPress Plugin Directory.   This will also push the zip file and plugins.json file to the server specified in myserver to allow for integration with some new WordPress plugins that are coming to publish plugin version lists and other “nice things” on a WordPress plugin store website like StoreLocatorPlus.com.

Set the package.json pluginMeta slug property ‘publish-to’ to either ‘wordpress’ or ‘myserver’ for each plugin being managed.

list

This will list the slugs for the plugins you are managing with the Grunt portion of the wp-dev-kit.

details

This will list the plugin names, slugs, and current version of the WordPress plugins being managed by the dev kit.

Configuring The Grunt Tasks

There are two files that need to be edited in the latest version of my WP Dev Kit.  The plugin details file, plugins.json, and the public plugin server details myserver.json file.

plugins.json

The plugins details file contains the settings for the WordPress plugins that you will manage with the WP Dev Kit.  The settings are as follows:

wp-plugin-dir – where is your WordPress plugin directory on this server?

pluginMeta – an array of plugin slugs with sub-keys that specify details about the plugin such as:

version – the current production version in major.minor.patch format.

zipbase – the name of the zip file to be created, usually the same as the slug .

publishto – where to send the production files when done, which can be one of the following:

wordpress = put it in the WordPress Plugin Directory via the svn repository

myserver = put it on the server specified in the myserver.json file using SFTP

name – the name of the plugin, usually as it appears in the readme.txt for the plugin

description – the description for the plugin, usually as it appears in the readme.txt

{
  "pluginMeta": {
    "slp-enhanced-results": {
      "version": "4.1.03",
      "zipbase": "slp4-er",
      "publishto" : "myserver",
      "name": "Store Locator Plus : Enhanced Results",
      "description": "A premium add-on pack for Store Locator Plus that adds enhanced search results to the plugin."
    },
    "store-locator-le": {
      "version": "4.1.10",
      "zipbase": "slp4",
      "publishto" : "wordpress",
      "name": "Store Locator Plus",
      "description": "Manage multiple locations with ease. Map stores or other points of interest with ease via Google Maps.  This is a highly customizable, easily expandable, enterprise-class location management system."
    }
  },
  "wp-plugin-dir": "/var/www/wpslp/wp-content/plugins/"
}

myserver.json

The connection details for the SFTP server used in the for myserver zip file publication as noted in the plugins.json description.   Settings include:

host – the fully qualified host name for the server

username – which user to login as

privateKeyFile – the path to the private key file, usually in your home/.ssh directory named id_rsa.

privateKeyPassFile – the path to a secured text file, that should NOT be part of any public repository , that has your private key file passphrase.

path – the path on the server where the files should be stored, relative to the username login directory.

{
    "host": "www.charlestonsw.com",
    "username": "serveradmin",
    "privateKeyFile": "/home/myuser/.ssh/id_rsa",
    "privateKeyPassFile": "/home/myuser/private/.pkpass",
    "path": "/var/www/wpslp/production/premium/"
}

That’s enough for this round of Grunt automated WordPress plugin publishing. I can see how this is going to help improve my process in the future even though it is adding an extra step today. I will continue to update this development kit for my production environment. As I do I will add more posts like this one and describe how I manage my free Store Locator Plus plugin and premium add-on packs.

Posted on

What I Learned About Grunt Compress

Grunt Configuring Tasks Banner

I learned a few interesting things while setting up my WordPress Development Kit project with some new Grunt tasks.   These are my findings while getting some custom build tasks working with the Grunt compress plugin (grunt-contrib-compress).

You can setup the default compress mode to be zip by using the main.options attribute in the JSON config parameters.

You can tell Compress where to put the final zip file and what to name it using dynamic elements, such as the plugin slug as the base file name by using an anonymous function in the archive property.

Use the files property to set an array of files to be created.   In each element of the array you specify attributes such as what files are to go INTO the zip file, where they are stored in the zip file, whether or not to use relative paths and more.    This is where things were a bit confusing for me so I’ll expand on that in a moment.

Here is my starting Grunt Compress settings that I am working with.  I will explain what this does below:

    compress: {
        main: {
            options: {
                mode: 'zip',
                archive: function() {
                    return slug + '.zip';
                }
            },
            files: [
                {
                    expand: true,
                    cwd: '/var/www/wpslp/wp-content/plugins/',
                    src: ['*'],
                    dest: 'public/',
                }
            ]
        },
    },

Here is a snippet of code that goes with the above configuration to do something.

  /**
   * makezip
   *
   * Build the zip file for the plugin, avoiding the assets directory, .git folders, and .neon files.
   */
  grunt.registerTask('makezip', 'Make a zip file for the plugin.', function(slug){
      grunt.log.writeln('Placeholder for makezip.  Slug name is ' + slug);
      global.slug = slug;
      grunt.task.run('compress');
  });

What Is In The Above Configuration

One of the first important things to note is that Grunt has a fairly robust built-in file manager. This file manager is available to all tasks and allows task files to use a default set of file rules such as the cwd, expand, src, and dest properties you see in the configuration section above. The Files section of the Grunt Configuring Tasks page will provide more insight beyond what I describe below.

archive

In the example above this is an anonymous function. The global variable “slug” is set in the makezip task and this is used to create the final zip file name. In my case it will be the WP Plugin Slug and .zip such as store-locator-le.zip for my Store Locator Plus plugin.

files.expand

The expand property tells the Grunt file processor to do dynamic source-and-destination processing.

files.cwd

Instructs the current processor, Compress in this case, to strip out the fully qualified path and make all file names in the processing loop relative to the parameter in the cwd command.  In my case it will make all files relative to my WordPress plugin root directory /var/www/wpslp/wp-content/plugins/.

file.src

This tells Compress which files are to be included in this round of processing.  For Compress it is the files that will be included in the .zip file distribution.   It uses the rules of something called minimatch as a file pattern matching system.  minimatch will grab as FEW files as possible so the ‘*’ rule here works different that typical operating-system wildcard file listings.   It will ONLY match the files in the exact directory specified.    In my case only the FILES (no directories or subdirectories) that are in my wp-content/plugins directory which in my case is only grabbing my legacy publisher scripts I put in the WP plugins directory on my dev box (blah, what a bad design).    I will explain how I fix this later.

file.dest

This one kind of threw me.   You can see I put public/ in as my destination.   I THOUGHT it would put the resulting .zip file in a folder named public under my current Grunt working directory with a <slug>.zip file in it.   WRONG.   What this does is tells compress where inside the resulting zip file you want the files it “gathers” with the file.src pattern noted above.

In the setup above it created a file in the ROOT grunt directory named store-locator-le.zip.   Inside that zip file is a folder named “public” in which all the contents of my WP Plugin directory (base files only) reside.  NOT what I wanted!

My Grunt Compress Mess
My Grunt Compress Mess

Fixing The Initial Grunt Problems

The first thing to fix is getting the .zip file to go to the ./wp-dev-kit/public folder where I will fetch it with other tasks for publication to the WordPress public plugin directory or to my server for private access for premium add-on packs.   There are two items to fix: files.dest and the archive path.

Removing the dest: property from my files section solved the first issue.   Now the files that match the src specification will go into the top-level of the .zip that is created.

Adding ../public/ to the start of my anonymous archive function will store the files in my public folder which resides next to the running Grunt tasks folder.

First two relatively minor issues are fixed, but there are deeper issues to resolve, specifically getting the files in the specified plugin directory and then adding some methods to ignore the files I don’t want part of the kit.

    compress: {
        main: {
            options: {
                mode: 'zip',
                archive: function() {
                    return '../public/' + slug + '.zip';
                }
            },
            files: [
                {
                    expand: true,
                    cwd: '/var/www/wpslp/wp-content/plugins/',
                    src: ['*'],
                }
            ]
        },
    },

Step 2 – Only Get The Specified Plugin

Getting the specified plugin directory wasn’t difficult, but it did involve a bit of Google and learning about named variable configuration in Grunt and how to get them into my “variable space” so I can use the <%= varname %> syntax in my Compress settings.    Luckily Chris Wren wrote a nice Grunt related article for newbs such as myself.

First step, add the variable declaration at the top of the Gruntfile, right above grunt.initConfig and inside the module.exports.

Grunt currentPlugin "global"
Grunt currentPlugin “global”

With that in place I can now tell the Compress plugin to make all file processing relative the plugin slug directory and use the same variable to set my zip file base name:

    compress: {
        main: {
            options: {
                mode: 'zip',
                archive: function() {
                    return '../public/' + currentPlugin.slug + '.zip';
                }
            },
            files: [
                {
                    expand: true,
                    cwd: '/var/www/wpslp/wp-content/plugins/<%= currentPlugin.slug %>',
                    src: ['**'],
                }
            ]
        },
    },

Inside my makezip tasks I now set the currentPlugin variable properties as opposed to a generic global variable, which is what I really wanted to do in the first place:

  /**
   * makezip
   *
   * Build the zip file for the plugin, avoiding the assets directory, .git folders, and .neon files.
   */
  grunt.registerTask('makezip', 'Make a zip file for the plugin.', function(slug){
      grunt.log.writeln('Placeholder for makezip.  Slug name is ' + slug);
      currentPlugin.slug = slug;
      grunt.task.run('compress');
  });

Now I am only getting the files for the specified plugin and not the WordPress plugin directory root files.   While I’m in there I also chanced the src parameter to ** versus *.   ** will grab all files in the current directory and any sub-directories that are part of my plugin.

Excluding Folders and Files

The last step will be to filter out those files I don’t want to include per my “no assets directory”, “no .git”, “no nbproject” and no “apigen.neon” files or folders.   If you follow my WordPress work flow posts you’ll know that this is my development environment and I prefer to work “inline” with the plugin directory and clear out the “cruft” of development files in the production cycle.

Thankfully the Grunt file processor makes excluding files a simple task.   I extend the src property with some “do not include” settings like so:

            files: [
                {
                    expand: true,
                    cwd: '/var/www/wpslp/wp-content/plugins/<%= currentPlugin.slug %>',
                    src: [
                        '**',
                        '!**.neon',
                        '!**.md',
                        '!assets/**',
                        '!nbproject/**'
                    ],
                }
            ]

That source specification will get all files in the main and sub-directories of my plugin EXCEPT for anything ending in .neon, .md or anything in the assets or nbproject sub-directories. By default the file filter will ignore any files starting with a dot, such as my .git, .gitignore, and .gitmodules folders and files.

Sweet!

I’m already liking Grunt WAY more than writing Bash files!

Follow along with other blog posts about the WordPress Workflow and WordPress Development Kit.

Posted on

Preparing A WordPress Plugin for Grunt Automation

Grunt Getting Started Banner

Thanks to my experience at WordCamp Atlanta (#wcatl), I’ve spent the past couple of days learning about Vagrant and how I can use it to build and distribute new VirtualBox systems to my developer-team-in-training.   I will refine that process to get new members of the development team setup with a CSA Standard environment to bring them up to speed with my process flow with less effort.

Today I am starting with another project inspired by my trip to Atlanta, using Grunt to automate my plugin building experience.   In this article I will go through my setup and initial project automation experience as I learn more about what Grunt can do for me,  getting it setup, and how I can use it to automate at least one of  the many steps involved in the final production phase of a WordPress plugin.

My Environment

My WordPress plugin development environment is fully contained within a virtual Linux workstation running on a laptop.   My current setup:

  • CentOS 6.5 with a full GUI desktop
  • Apache 2.x
  • PHP 5.4.23
  • MySQL 5.5.35
  • NetBeans 8.0 RC1
  • SmartGit 3.0.11 (on top of git 1.7.1)
  • WordPress 3.8.1 (soon to be update to latest nightly build for 3.9)
  • Firefox
  • Selenium IDE

My Process

The basic outline of a premium add-on pack production cycle follows a basic routine:

  • Code Cycle
    • Edit code in NetBeans writing directly to the local wp-content/plugins directory.
    • Commit changes via SmartGit to the current development branch.
    • Push changes with SmartGit to BitBucket when ready.
  • Test Cycle
    • sudo mysql < wpreset.sql to reset the WordPress database (blasts all tables)
    • start Firefox and open Selenium IDE
    • run the New WP Install Selenium IDE script
    • run some of the base Store Locator Plus data test scripts
    • for add-on packs run the add-on pack specific test scripts
    • Edit/Commit/Push/Repeat
  • Production Cycle
    • Validate the readme.txt file.
    • Publish a blog post about the update and new features.
    • Edit the CSA Server Update System with new version/date information.
    • Edit the CSA Version Information page.
    • Update the News and Info “signage”.
    • Package the plugin .zip file.
    • Publish the .zip file to the CSA servers.
    • If it is a WordPress Plugin Directory listing, update the svn repo to publish to WordPress.

As you can imagine, there are a lot of steps in the final production cycle that can be automated.    I will also be exploring phpUnit testing for my plugins to provide deeper testing of the plugins that can be automated to be a virtually hands-off test system, but that is a project for later.  For now, I need to learn Grunt and start replacing my useful but less-flexible bash scripts to simplify the final Production Cycle.

Installing Grunt

One of the first things I learned about Grunt is that it runs on node.js and I need the Node Package Manager (npm) to get it working.   On CentOS this is fairly easy.    I open a terminal, execute sudo, and install npm.    It brings the rest of the Node.JS stuff with it as dependencies.   When that is completed you can install grunt-cli and grunt-init via npm. Apparently I am going to want something called “grunt init templates” as part of the Grunt Scaffolding setup, so I will also use git to clone one of the official “bare bones” templates into my Linux user home directory.

NPM is part of the Extra Packages for Enterprise Linux (epel) repository.   You will need to install this before the install npm command will work.   If you are using a stock CentOS 6.5 release you can go to the following URL and click on the package link, open the download with package installer, and the epel yum repository will be installed and activated:

http://mirrors.severcentral.net/fedora/epel/6/i386/repoview/epel-release.html

$ sudo yum install npm
$ sudo npm install -g grunt-cli
$ sudo npm install -g grunt-init
$ git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile

With my initial install on CentOS 6.5 there were multiple “unmet dependency” errors followed by a “but will load” message. Running the command grunt seems to be pulling up the grunt CLI. For now I am going to assume those errors are not important for getting my first simplified Grunt tasks running.

Grunt CLI Install Warnings
Grunt CLI install warnings.

Adding Grunt To My Plugin Project

For years I’ve been using a series of Bash scripts to help manage my distribution.   One of the scripts that I use in every production cycle is a script named makezip.sh.    This script packages up the plugin subdirectory I specify skipping various files and directories (.git, the assets subdirectory and a few others) and creates a .zip file in a directory “far away from” the running WordPress install.  I can opt to send copies to the live server when they are ready for publication or keep them local for manual distribution and/or testing.   I bring this up because it impacts my first Grunt setup on my Enhanced Results premium add-on for Store Locator Plus.

I already use the assets sub-directory within the wp-content/<plugin> directory to store all of my development and production scripts and related assets.    As such I already have a place, the assets sub-directory within the plugin directory, where I should be able to store my Grunt configuration and script files without impacting the plugin distribution.

[box type=”note” style=”rounded”]My Dev Environment: The ./assets directory under the current plugin directory is NOT distributed during production.[/box]

To get started I go to my plugin sub-directory on my development system and create a grunt folder and the starting assets via the grunt-init template loaded with git clone as noted above.  After getting the template installed I run npm init to fetch the “helpers” for Grunt.  The helpers are node modules, aka Grunt plugins, that will be referenced by the Gruntfile.js execution.

cd ./wp-content/slp-enhanced-results
mkdir assets
cd assets
echo '<!--?php // Silence is golden.' --> index.php
mkdir grunt
cd grunt
echo '<!--?php // Silence is golden.' --> index.php
# get a basic package.json and Grunfile.js in place
grunt-init gruntfile
# set some defaults in package.json
npm init
# installs the modules specified in the package.json
npm install

[box type=”note” style=”rounded”]What are those echo commands? They create an index.php file to prevent browsing of the directories from a web interface. They are there as an extra safety measure in case the assets directory gets published.[/box]

With the gruntfile template I tell it that I am not using the DOM but will want to concatenate and minify files and that I will be using a package.json file at some point.

Grunt Gruntfile Template Setup
Grunt gruntfile template setup for my add-on pack.

Running this command puts the Gruntfile.js and package.json files in my ./assets/grunt folder and gives me access to the basic scripting tools necessary to start a grunt project.

I think I’m ready for some automation!

Gruntfile Defaults

Earlier I ran the the grunt-init gruntfile step to setup a default starter environment for Grunt.   Time to dig into the details of the two install files.   Some basic reading tells me that the package.json file tells Grunt which “helpers” are to available to this project by default including their version numbers:

Grunt “Helpers”

Helpers are officially termed “plugins” in the Grunt world.   I call them helpers at this stage to remind me that they help perform tasks within my project but I’ll still need to guide them as to what to do.

The default “helpers” in package.json:

{
  "engines": {
    "node": ">= 0.10.0"
  },
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-contrib-jshint": "~0.7.2",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-contrib-nodeunit": "~0.2.2",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-uglify": "~0.2.7"
  }
}

What are these helpers? The first couple of entries are obvious. The base JavaScript engine is node and the first “helper” is grunt. What are the rest?   They are all plugins from the grunt-contrib library which gives us some hints:

  • grunt-contrib-jshint

    Validate files with JSHint.   JSHint looks for issues in the syntax of JavaScript files.  With Grunt this happens BEFORE they are published if you keep this as a default task.

  • grunt-contrib-watch

    Run tasks whenever watched files change.  This watches files in your projects.  If a file changes, do something.

  • grunt-contrib-nodeunit

    Run Nodeunit unit tests. Allows node unit tests to be added to your project and run during a build cycle with Grunt.

  • grunt-contrib-concat

    Concatenate files.  Grab a list of files and concatenate them.

  • grunt-contrib-uglify

    Minify files with UglifyJS.  Create minimized JavaScript files from your source files.  Speeds up page load times by cutting out all of the non-executable parts of a JavaScript file including white space.

Grunt Commands and Execution

The other file that is created with the default template that I’ve used id the Gruntfile, stored as Gruntfile.js.   That is a pretty good hint that it is a JavaScript file.   Here is what it looks like:

/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
      '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
      ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
    // Task configuration.
    concat: {
      options: {
        banner: '<%= banner %>',
        stripBanners: true
      },
      dist: {
        src: ['lib/<%= pkg.name %>.js'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      dist: {
        src: '<%= concat.dist.dest %>',
        dest: 'dist/<%= pkg.name %>.min.js'
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        globals: {}
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      lib_test: {
        src: ['lib/**/*.js', 'test/**/*.js']
      }
    },
    nodeunit: {
      files: ['test/**/*_test.js']
    },
    watch: {
      gruntfile: {
        files: '<%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      lib_test: {
        files: '<%= jshint.lib_test.src %>',
        tasks: ['jshint:lib_test', 'nodeunit']
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-nodeunit');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // Default task.
  grunt.registerTask('default', ['jshint', 'nodeunit', 'concat', 'uglify']);

};

After sitting in on the Grunt session at WordCamp I know a couple of things about this file. The initConfig section sets the rules for the various “helpers” and way down near the bottom is a Default task. This is what does all of the work when I run Grunt in my project.

What is this going to do?

The default I have now is going to run jshint, which is going to look for any JavaScript files and scan them for syntax issues and other problems like unused variables (I can tell that by looking at the jshint section higher up in the code). It will then run any nodeunit tests by looking in test/**/ for any files ending in _test.js and execute them (I assume). It will concat any files that live in lib/ that end with .js and store them in dist/<pkg.name>.js.   Finally it will uglify… minify… any of the files that are stored in the destination directory defined by the concat section (dist/) and minify them.

Tweaking Gruntfile For Me

Looks like some decent defaults, but for my project I need to change some things.

I won’t run Node unit testing on this project.  In the Gruntfile I remove the nodeunit from the default tasks section and the config section above.   I also remove the package from the json file.

As noted above, the Grunt project directory on my setup is under the assets subdirectory for this plugin.   All of my main project files are up a couple of levels in the plugin parent directory.   Since I want to distribute both the original JS files AND the minified version, I need to change some paths.   I am going to concat and uglify the scripts in the main plugin distribution directories and output the minified versions there.   I need to change any paths in the upper “config part” of the Gruntfile.js:

Update the concat section:

    // Task configuration.
    concat: {
      options: {
        banner: '<%= banner %>',
        stripBanners: true
      },
      dist: {
        src: ['../../js/<%= pkg.name %>.js'],
        dest: '../../js/<%= pkg.name %>.concat.js'
      }
    },

And the JSHint section:

    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        globals: {}
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      lib_test: {
        src: ['../../js/*.js', '../../js/test/**/*.js']
      }
    },

That will ensure that all JavaScript stuff goes in my standard ./js subdirectory in my plugin. Yes, the users will get those files making for a larger zip file download and more disk space on their server. Disk space is cheap and download speeds are decent in most places. Not too mention zip is pretty darn good at compressing JavaScript files. When my plugin executes it will load the concatenated minified file which gives the full benefits of execution speed and reduced RAM footprints on the server and users browser. This keeps the original source available to my user base so they can read the code and hack functionality if they find the need without wading through obsfucated minified concatenated JavaScript.

I’ve also learned that I need to add more details to the package.json file in order to get the default rules and tools to work.  This includes adding the name, version, and author variables to package.json.   If you do not define all 3, INCLUDING AUTHOR, you will get the following error:

Running "concat:dist" (concat) task
Warning: An error occurred while processing a template (Cannot read property 'name' of undefined). Use --force to continue.

Adding the name, version, and author elements to the default package.json results in:

{
  "name": "slp-enhanced-results",
  "version": "4.1.01",
  "author": "csa",
  "engines": {
    "node": ">= 0.10.0"
  },
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-contrib-jshint": "~0.7.2",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-uglify": "~0.2.7"
  }
}

Now I an run the grunt command which will execute jshint, concat, and uglify on all my JavaScript files. Currently the Grunt configuration outputs some headers so I know it is thinking about doing something, but I don’t have anything interesting to process yet. But I will soon. That will be content for the next article about automating my WordPress workflow.

First Grunt Run - No Errors
First Grunt Run without errors.