
Сегодня я хочу поделиться с достопочтенной аудиторией Хабра своим подходом к организации автоматической сборки проекта на WordPress, который значительно экономит время при создании новых сайтов.
Предпосылки
И так, вы делаете сайты на WordPress, и с каждым новым проектом вам приходится идти на wordpress.org, качать от туда, собственно, сам WordPress + набор плагинов, которые вы используете постоянно. Или же установкой плагинов вы занимаетесь прямо из админ-панели или того хуже — копируете их из директории предыдущего сайта. Мне это всегда не нравилось, как-то не элегантно что ли, не удовлетворяет эстетическим потребностям. К тому же занимает хоть немного, но все же время. Поэтому я задумался, как бы этот процесс улучшить. Скачал все что нужно, сложил аккуратненько в папочку и выполнил «git init» и «git push». Что ж, теперь у меня есть репозиторий на Bitbucket, где хранится моя сборка WP со всем необходимым. С этого момента в начале процесса разработки можно выполнить «git clone» и получить нечто готовое к работе. Способ радовал меня не долго — обнаружились «недостатки». А именно:
- избыточное использование репозитория (хранятся все иcходники плагинов и самой CMS);
- всегда хранится старая версия всего (можно конечно периодически обновлять, но лень);
- хочется хранить в том же репозитории исходники SCSS/SASS/LESS, не минифицированный JS-код и прочие важные компоненты, которые по идее не должны пересекаться с production-версией проекта;
Тут я и моя лень посовещались и пришли к выводу, что при начале работы над новым сайтом мы готовы тратить энергии не более чем на ввод одной (максимум двух) консольных команд для организации всего и вся и переходу непосредственно к процессу разработки. Потом лень отдельно от меня подумала и продолжила: «и что бы в Git все хранилось сразу, и что бы не надо было новые версии накатывать (изначально мол новые должны быть), и что бы можно было на сервере pull корректно выполнять (тебе ж потом это обслуживать все), и что бы вообще все само работало, и приступай побыстрее, а я пока отдохну».
Удовлетворяем хотелки лени
Первоначально я формализовал задачи в небольшой список:
- автоматизировать установку ядра WordPress и актуальных версий плагинов кочующих из проекта в проект;
- реализовать зависимость настроек проекта от серверного окружения;
- отделить исходники клиентской части от проекта;
- автоматизировать сборку клиентской части;
- организовать не избыточное хранение в Git-репозитории.
И приступил к реализации. Для начала я отправился читать документацию WP и нашел там прекрасную вещь, которая позволяет отделить ядро CMS от того, что изменяет разработчик. Набросал по этому случаю следующую структуру проекта:
content/ wp/ index.php wp-config.php
В директории «wp» хранятся файлы ядра WordPress, «content» — папка для тем, плагинов, языковых версий и т.д., «wp-config.php» — стандартный файл настроек WP, а в «index.php», руководствуясь документацией я поместил следующее:
define('WP_USE_THEMES', true); require( dirname( __FILE__ ) . '/wp/wp-blog-header.php' );
Запустил на сервере, проверил, ок, работает. Теперь нужно сделать так, что бы скачивалась самая последняя версия WP. Для этого я использовал Composer (как его установить, можно почитать тут). Все файлы, которые я создал ранее я поместил в папку «app», для того, что бы вынести все служебные файлы на уровень выше от исполняемого «index.php». В дальнейшем мой сайт будет запускаться из этой директории (не забудьте поправить настройки хоста для вашего сервера). А папка «wp» была вычищена от всего содержимого. В корень проекта я поместил файл «composer.json» со следующим содержимым:
{ "require": { "php": ">=5.4", "johnpbloch/wordpress": "*", }, "extra": { "wordpress-install-dir": "app/wp", } }
«johnpbloch/wordpress» — форк WP, пригодный для установки через Composer, а «wordpress-install-dir» указывает на директорию установки ядра CMS. Написав в консоли:
composer install
я убедился, что все работает. Свежий WordPress скачался в «app/wp». Что же с плагинами? С ними все хорошо, благодаря проекту wpackagist.org их так же можно подтягивать через Composer. Для этого нужно лишь немного модифицировать «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"] } } }
В секции «repositories» указывается адрес «wpackagist», в секции «installer-paths» указываются пути, куда будут устанавливаться плагины и темы, а в секции «require» добавляются названия WP-плагинов в виде «wpackagist-plugin/{{plugin_name}}». В «wpackagist» доступны почти все плагины с wordpress.org, доступность плагинов можно смотреть в поиске на сайте wpackagist.org.
Выполнив:
composer update
увидел, как в директории «app/content/plugins» появились все нужные плагины. Теперь нужно разобраться с настройками, напомню, что стоит задача сделать настройки БД и дебага зависимыми от среды разработки, на локальном сервере свои, на боевом свои. Для этого выдавим их в отдельный файл «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' );
и изменим «wp-config.php» следующим образом:
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' ); }
Теперь, если существует файл «local-config.php», настройки будут подхватываться из него. Этот файл нужно добавить в ".gitignor" (зачем нам пароли от БД в репозитории?). Самое время внести данные для доступа к базе данных в «local-config.php», запустить процедуру установки WordPress и посетить админку.
В админке нужно посетить раздел «Настройки -> Общие» и там поправить адреса, следующим образом:

Адрес WordPress c "/wp" на конце, адрес сайта без "/wp".
Здорово, сайтом можно пользоваться. Следующим этап я посвятил пользовательским стилям и скриптам (а то как-то не логично, на сервере все само собирается, а всякие jquery вручную качать?). В качестве подготовки я отредактировал структуру проекта:
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
В папке «src/» хранятся исходные файлы шрифтов, скриптов и стилей. Далее они собираются с помощью gulp, минифицируются и складываются в папку «app/content/theme/mytheme/build». В качестве препроцессора для CSS я использую SCSS (как установить, думаю всем известно, но если нет, то вот инструкция), для сборки JS — browserify. Посчитал логичным, что зависимости клиентской части нужно подтягивать при помощи nmp. Файл «package.json» у меня получился такой:
{ "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": "*" } }
Секции кроме «devDependencies», заполнять не стал, поскольку публиковать это в npm я явно не планирую. Пишу в консоли:
npm install
Жду пару минут и вижу, что все указанные зависимости аккуратно оказались в «node_modules». Вишенкой на торте послужил файл «gulpfile.js» с таким содержимым:
'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']);
Команда «gulp» скопирует шрифты, скомпилирует SCSS, склеит JS и сложит это все аккуратненько в папку билда. «gulp watch» делает тоже самое, но при каждом изменении файла. «gulp production» дополнительно почистит файлы от комментариев и минифицирует.
Что в итоге?
В итоге вышеописанное вам повторять совсем не обязательно. Я все удобненько залил на GitHub: https://github.com/IvanZhuck/kosher_wp_seeder.
Для запуска необходимо клонировать репозиторий и выполнить следующие команды (предварительно поправив список плагинов и зависимостей, если это требуется):
composer install npm install
Я и моя лень довольны, проекты стали стартовать быстрее, а работа приятнее. Ваши вопросы и предложения жду в комментариях.
