Magic project builds on WordPress with package managers and a file

Today I want to share with the audience of Habra my approach to the organization of the automated project build on WordPress, which saves time when creating new sites.

Precondition

So, you make websites on WordPress, and with each new project  you have to go to wordpress.org to download from there, in fact, WordPress itself + set of plug-ins that you use constantly. Or install the plugins you do right from the admin panel, or worse — copying them from the directory of the previous site. I always hated it, something is not elegant or does not satisfy the aesthetic needs. Besides, it takes a little bit, but all the time. So I wondered how to improve this process. Download everything I need, folded neatly in file and executed a “git init” and “git push”. Well, now I have a repository on Bitbucket, where is my build of WP with everything I need. From this point on in the beginning of the development process, you can run “git clone” and get something ready. Method pleased me not long – revealed “shortcomings”. Namely:

  • excessive use of the repository (contains all the source code of the plugins and CMS);
  • always keep old version of all (of course ,you can periodically update, but too lazy);
  • I want to store in the same repository the source code to SCSS/SASS/LESS, not a minified JS code and other important components, which in theory should not interfere with the production version of the project;

Then I and my laziness consulted and came to the conclusion that at the beginning of work on a new website we are willing to expend energy for no more than the input one (max two) console commands for organizing of everything and go directly to the development process. Then laziness apart from me thought and continued: “and that in Git stored all at once, and that did not have a new version to roll (originally the new should be), and that it was possible on the server to pull correctly perform (you then is to serve all) and that to do all work itself, and do it quickly, while I rest.”

Satisfied laziness wishlist

Initially, I formalized the problem in a short list:

  1. automate the installation of WordPress core, and current versions of plug-ins wandering from project to project;
  2. to realize the dependence of the settings of the project from server environment;
  3. separate the source code of the client part of the project;
  4. automate builds of client-side;
  5. create not redundant storage in Git-repository.

And I started to implement. First, I went to read the WP documentation and found there a beautiful thing that allows you to separate the CMS core from what changes the developer. Sketched on that occasion the following project structure:

content/
wp/
index.php
wp-config.php

In the directory “wp” keep the core files of WordPress, “content” folder for themes, plugins, language versions, etc. “wp-config.php” — a standard file of settings of WP, and in “index.php” guided by the documentation I put the following:

define('WP_USE_THEMES', true);

require( dirname( __FILE__ ) . '/wp/wp-blog-header.php' );

Launched on the server, checked, OK, it works. Now we need to do so that would be downloading the latest version of WP. For this I used Composer (how to install it, you can read here). All the files that I created earlier, I put in the folder “app”, in order to make all service files level up from the executable “index.php”. In the future my site will be run from this directory (remember to modify the host configuration for your server). And the folder “wp” was cleaned of all content. In project root I have placed the file “composer.json” with the following content:

{

"require": {

"php": ">=5.4",

"johnpbloch/wordpress": "*",

},

"extra": {

"wordpress-install-dir": "app/wp",

}

}

“johnpbloch/wordpress” – fork WP, suitable for installation via Composer, and “wordpress-install-dir” specifies the directory of the core installation of the CMS. Writing in the console:

composer install

I made sure that everything works. Fresh WordPress download in the “app/wp”. What about the plugins? With them everything is fine, thanks to the project wpackagist.org they also can pull through Composer. To do this, just modify the “composer.json”:


{
  "repositories":[
    {
      "type":"composer",
      "url":"https://wpackagist.org"
    }
  ],
  "require": {
    "php": ">=5.4",
    "johnpbloch/wordpress": "*",
    "wpackagist-plugin/rus-to-lat-advanced": "*",
    "wpackagist-plugin/advanced-custom-fields": "*",
    "wpackagist-plugin/all-in-one-seo-pack": "*",
    "wpackagist-plugin/google-sitemap-generator": "*",
    "wpackagist-plugin/contact-form-7": "*",
    "wpackagist-plugin/woocommerce": "*",
    "wpackagist-plugin/saphali-woocommerce-lite": "*"
  },
  "extra": {
    "wordpress-install-dir": "app/wp",
    "installer-paths": {
      "app/content/plugins/{$name}/": ["vendor:wpackagist-plugin"],
      "app/content/themes/{$name}/": ["vendor:wpackagist-theme"]
    }
  }
}

In the section “repositories” specified the address “wpackagist”, in the section “installer-paths” specified the path where to install plugins and themes, and in the section “require” added the names of WP-plugins as “wpackagist-plugin/{{plugin_name}}”. In “wpackagist” available almost all plugins with wordpress.org, the availability of plugins you can look in the search on the site wpackagist.org.

Completed:

composer update 

saw in the directory “app/content/plugins” had all the required plugins. Now we have to deal with the settings, let me remind you that the goal is to make the settings of the database and debug dependent on development environment, one on the local server and at the working others. To do this, squeeze them into a separate file “local-config.php”:


define( 'DB_NAME', '%%DB_NAME%%' );
define( 'DB_USER', '%%DB_USER%%' );
define( 'DB_PASSWORD', '%%DB_PASSWORD%%' );
define( 'DB_HOST', '%%DB_HOST%%' ); // Probably 'localhost'

ini_set( 'display_errors', true );
define( 'WP_DEBUG_DISPLAY', true );

define( 'AUTH_KEY',         'put your unique phrase here' );
define( 'SECURE_AUTH_KEY',  'put your unique phrase here' );
define( 'LOGGED_IN_KEY',    'put your unique phrase here' );
define( 'NONCE_KEY',        'put your unique phrase here' );
define( 'AUTH_SALT',        'put your unique phrase here' );
define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
define( 'LOGGED_IN_SALT',   'put your unique phrase here' );
define( 'NONCE_SALT',       'put your unique phrase here' );

and change “wp-config.php” in the following way:


if ( file_exists( dirname( __FILE__ ) . '/local-config.php' ) ) {
	define( 'WP_LOCAL_DEV', true );
	include( dirname( __FILE__ ) . '/local-config.php' );
} else {
	define( 'WP_LOCAL_DEV', false );
	define( 'DB_NAME', '%%DB_NAME%%' );
	define( 'DB_USER', '%%DB_USER%%' );
	define( 'DB_PASSWORD', '%%DB_PASSWORD%%' );
	define( 'DB_HOST', '%%DB_HOST%%' ); // Probably 'localhost'

	ini_set( 'display_errors', 0 );
	define( 'WP_DEBUG_DISPLAY', false );

	define( 'AUTH_KEY',         'put your unique phrase here' );
	define( 'SECURE_AUTH_KEY',  'put your unique phrase here' );
	define( 'LOGGED_IN_KEY',    'put your unique phrase here' );
	define( 'NONCE_KEY',        'put your unique phrase here' );
	define( 'AUTH_SALT',        'put your unique phrase here' );
	define( 'SECURE_AUTH_SALT', 'put your unique phrase here' );
	define( 'LOGGED_IN_SALT',   'put your unique phrase here' );
	define( 'NONCE_SALT',       'put your unique phrase here' );
}

Now, if there is a file “local-config.php” settings will be picked up from it. This file needs to add in “.gitignor” (why do we need passwords from the database in the repository?). It’s time to enter data to access database “local-config.php” to launch the installation procedure of WordPress and visit the admin area.

In the admin area you need to visit “Settings -> General” and there to fix the address, as follows:

wordpress

WordPress address with “/wp” at the end, website address without the “/wp”.
Great, you can use the site. The next step I dedicated custom styles and scripts (and somehow not logical, on the server everything is going, and all sorts of jquery to manually download?). In preparation I edited the project structure:


app/
       content/
             theme/
                  mytheme/
                        build/
                        index.php
                        style.css
       wp/
       index.php
       local-config.php
       wp-config.php
src/
      fonts/
      js/
            main.js
      scss/
            style.ccss 
composer.json

The original font files, scripts and styles are stored in the folder “src/”. Next they’re going with gulp, minified and put in the folder “app/content/theme/mytheme/build”. As the preprocessor for CSS I use SCSS (how to install, I think we all know, but if not, here are instructions), to build JS — browserify. I considered logical that based on client side you need to pull up with nmp. The file “package.json” I get this:


{
  "devDependencies": {
    "bourbon": "*",
    "bourbon-neat": "*",
    "browserify": "*",
    "fullpage.js": "*",
    "gulp": "*",
    "gulp-clean-css": "*",
    "gulp-concat": "*",
    "gulp-sass": "*",
    "gulp-sourcemaps": "*",
    "gulp-uglify": "*",
    "jquery": "*",
    "normalize-scss": "*",
    "vinyl-source-stream": "*"
  }
}

Section except “devDependencies”, did not fill, because to publish it in npm I obviously do not plan to. I write in the console:


npm install

I wait few minutes and see that all these dependencies carefully appeared in “node_modules”. The icing on the cake was the file “gulpfile.js” with this content:


'use strict';

var browserify = require('browserify'),
    source = require('vinyl-source-stream'),
    gulp = require('gulp'),
    sass = require('gulp-sass'),
    uglify = require('gulp-uglify'),
    cleanCSS = require('gulp-clean-css'),
    sourcemaps = require('gulp-sourcemaps'),
    sourcePath = './src/',
    buildPath = './app/content/themes/mytheme/build/';

//scss
gulp.task('scss', function () {
    return gulp.src('./src/scss/style.scss')
        .pipe(sass().on('error', sass.logError))
        .pipe(gulp.dest(buildPath + 'css'));
});

gulp.task('scss:watch', function () {
    return gulp.watch(sourcePath + 'scss/**/*.scss', ['scss']);
});

//js
gulp.task('browserify', function() {
    return browserify(sourcePath + 'js/main.js')
        .bundle()
        .pipe(source('main.js'))
        .pipe(gulp.dest(buildPath + 'js'));
});

gulp.task('browserify:watch', function () {
    return gulp.watch(sourcePath + 'js/**/*.js', ['browserify']);
});

//fonts
gulp.task('copy:fonts', function () {
    gulp.src(sourcePath + 'fonts/**/*', {base: sourcePath + 'fonts'})
        .pipe(gulp.dest(buildPath + 'fonts'));
});

//minify
gulp.task('minify:js', ['browserify'], function(){
    return gulp.src(buildPath + 'js/*.js')
        .pipe(sourcemaps.init())
        .pipe(uglify())
        .pipe(sourcemaps.write())
        .pipe(gulp.dest(buildPath + 'js'))
});

gulp.task('minify:css', ['scss'], function(){
    return gulp.src(buildPath + 'css/*.css')
        .pipe(cleanCSS({compatibility: 'ie9'}))
        .pipe(gulp.dest(buildPath + 'css'));
});


//task groups
gulp.task('default', ['copy:fonts', 'scss', 'browserify']);
gulp.task('watch', ['copy:fonts', 'scss:watch', 'browserify:watch']);
gulp.task('production', ['copy:fonts', 'scss', 'browserify', 'minify:js', 'minify:css']);

The command “gulp” will copy the fonts, compile SCSS, JS glued and folded it all neatly in a folder build. “gulp watch” does the same, but at each change of file. “gulp production” additionally clean the file from comments and minified it.

What is the result?

In the end, you don’t need to repeat the above. I conveniently have uploaded all on GitHub: https://github.com/IvanZhuck/kosher_wp_seeder.

You must clone the repository and run the following commands (after adjusting the list of plugins and dependencies, if necessary):

composer install npm install

Me and my laziness satisfied, the projects are to start faster and work better.

 

This text is a translation of the article “Волшебная сборка проекта на WordPress при помощи пакетных менеджеров и напильника”  published by @ivan_zhuck on habrahabr.ru.

About the CleanTalk service

CleanTalk is a cloud service to protect websites from spam bots. CleanTalk uses protection methods that are invisible to the visitors of the website. This allows you to abandon the methods of protection that require the user to prove that he is a human (captcha, question-answer etc.).

Leave a Reply

Your email address will not be published. Required fields are marked *