A WordPress 5-ready development environment and build toolkit to accelerate and optimize every stage of the WordPress development process. For custom theme (or plugin) developers, especially those with complex CMS-type requirements. Its main features are:
- Instant setup of project-specific fast local development server (using Docker)
- Tools for coding leaner, cleaner themes (using Twig, PostCSS, MVC and BEM)
- Build script to preprocess, lint and optimize assets, including WP 5 / Gutenberg Blocks
- Live browser testing, synchronized across devices (using Browsersync)
- Version control for custom fields (using ACF-JSON)
- Instant deployment (using Wordmove)
2.1
- New Webpack/Babel build pipeline to compile theme-based WP 5/Gutenberg blocks (default filename
assets/js/blocks.js
) - New Gutenberg-ready common / front / editor boilerplate structure for CSS
- Automatic timestamp-based fingerprinting on production assets, for cache-busting where needed
- Use sanitize.css in boilerplate theme theme (switched from normalize.css)
- New
fdk deploy
task recompiles and runs Wordmove, so you can deploy in a new tab without having to stop the build process - General spring-cleaning, upgrading and tweaking (NB. no longer including Lost Grid in favour of CSS Grid; no longer including jQuery by default.)
2.0
- Fabrica Dev Kit is now installed globally via
npm
, rather than cloned for each project, and accessible asfdk
shell command β see below for instructions. Also includes options for plugin development and easier Wordmove configuration. Ruby is no longer a dependency.
- Using Docker, creates an independent development environment for your project running the Nginx web server with PHP-FPM. Docker's efficient architecture means that each Fabrica Dev Kit project runs and is stored separately (unlike MAMP, where all projects share space and servers), while avoiding the bloat of a Vagrant-like solution (where each project has a capacious virtual machine to itself).
- Automatically installs all the software required to develop, including the latest version of WordPress and your plugins of choice (you just list them in the initial setup file), as well as build, optimization and deployment tools.
- Setup of a new project takes a matter of seconds (after the one-time installation of initial dependencies and base images).
- ... with templates written in Twig rather than directly in PHP. Installs the revolutionary Timber to bring MVC-like separation of concerns to WordPress development, separating data processing and analytical logic from presentation, allowing you to write more elegant, legible and maintainable templates, eradicating
<?php
?>
tag-itis forever. A genuine 'never go back' improvement. See the MVC section in code examples below for more. - ... with BEM syntax. Uses the PostHTML-bem plugin for PostHTML which allows you to write much less repetitive BEM markup (see code examples below), and which in turn reflects your (Post)CSS structure more closely.
- ... with PostCSS for variables, mixins and other CSS preprocessing enhancements (it can compile your SASS or LESS code no problem).
- ... making use of the fantastic Advanced Custom Fields plugin, which is deeply supported by Timber (see above). Fabrica Dev Kit can automatically install ACF Pro if you supply your licence key at setup.
- Keeps the development source folder outside the virtual machine for easy editing and version control. (No need to log into a virtual machine to build / develop: it just acts as a fast server.)
- Includes a super-minimal object-orientated boilerplate theme (see below), specially constructed for bespoke theme development.
- Live-compiles and optimizes straight to the active theme folder inside the virtual machine as you develop, via a pre-configured Gulp watch, which:
- Preprocesses, Autoprefixes, lints and minifies (with source maps) your stylesheets.
- Minifies (with sourcemaps) and lints your Javascript.
- Optimizes / losslessly compresses image assets.
- Pipes all changes (to CSS or templates) directly to the browser, without requiring a page refresh, using Browsersync, so you can finally give your clapped-out
F5
key a break (OK,Cmd
+R
β¦ no Windows version yet).
- Allows simultaneous testing on multiple devices (with synchronized scrolling and keystrokes!), also via Browsersync.
- Combines NPM support with Webpack allowing super-fast installation and inclusion of front-end modules such as jQuery plugins / other JS libraries. (We include jQuery and sanitize.css by default.)
- Includes PHP Composer support in the starter theme for super-fast installation and automatic inclusion of back-end extensions.
- Allows one-command deployment (ie. with a single terminal command) to staging or production servers using Wordmove.
- Automatically activates ACF-JSON for βdatabaseβ version-control (tracks and synchronizes field settings for the Advanced Custom Fields plugin across multiple environments).
Fabrica Dev Kit is compatible with recent versions of Mac OS X. It has a few dependencies:
- Docker β download and run the installer by following the link for Mac OS X from the Docker downloads page (Stable channel is fine).
- Node.js β download and run the installer by following the link to the Recommended Version from the Node.js homepage.
- Gulp command line tools β once Node.js is installed, run
npm install gulpjs/gulp-cli -g
from the command line. (Version 1.2.2 or higher required.) - Composer β follow the Global installation instructions in the Composer installation guide.
Optional but strongly recommended:
- Wordmove (for fast command-line deployment) which can be installed with
gem install wordmove
. Note: if you want to use FTP for deployment (rather than SSH), you'll also need lftp (installation instructions).
First make sure you have all the required dependencies (see above). Then run npm install fabrica-dev-kit -g
to install Fabrica Dev Kit onto your system ready to use globally via the fdk
shell command.
- Create a folder for your project. In this folder run
fdk init
. This will create a templatesetup.yml
file for your basic project settings. - Edit
setup.yml
to configure basic parameters for your project. Plugins you want to be installed automatically can be listed here. - Run
fdk setup
from the same folder. This will set up your virtual machine and install everything required: Nginx, PHP-FPM, WordPress, your chosen plugins and our suite of build tools.
- To work on the project, run a Gulp watch with
gulp
from the project folder. This will compile / preprocess / optimize your source files and actively watch for changes. - Following its initial build, Gulp will tell you which dynamic port the site front-end and admin are accessible at, as well as the Browsersync proxy you can use for live-editing of markup and styles without needing to refresh:
Fabrica Dev Kit Project (fabricaproject) access URLs:
-------------------------------------------
π WordPress: http://localhost:32773/
π§ Admin: http://localhost:32773/wp-admin/
π Database: localhost:32769
-------------------------------------------
[BS] Proxying: http://localhost:32773
[BS] Access URLs:
---------------------------------
Local: http://localhost:3000
External: http://172.17.3.50:3000
- Theme development takes place in the
src/
folder (see below for information about what goes where). - You can escape Gulp with Ctrl + c. While Gulp is not running, changes to source files will not be reflected in the active theme.
- You can also run
gulp build
to compile the current source code into the active theme folder without starting a watch (eg. if you've made a tiny change and want to deploy it without needing to check on development site).
- To aid with plugin development across multiple installations, FDK can import plugin files from any location on your local file system. Edit the
config/imports.yml
to specify paths, and the files will be copied whenever you rungulp
(which will also watch for changes and update modified files, so you can develop and debug actively).
- Once you have a staging or production environment set up, edit the
config/wordmove.yml
file with the corresponding FTP or SSH details. - To deploy your theme, make sure the latest source code is compiled (if a watch isn't running, do a
gulp build
), then typewordmove push --themes
. Wordmove will push the new / modified files to the server. - If you are using ACF (whether normal or Pro), ACF-JSON will take care of synching your fields automatically, but it's a good idea to synchronize the fields on the remote site once you have deployed changes, so that the new fields are saved (from the files in the
acf-json
folder) into the production database.
To begin version control on your project run git init
in the project folder. This will track not only your source code but also the corresponding build script and names of the modules needed to compile it into an active theme.
For direct MySQL access to the development database, we recommend using Sequel Pro to access it while the development machine is up. The database server is accessible at 127.0.0.1
, and with the dynamic port which you'll be told when you run gulp
(see example output above). The username, password and database name are are wordpress
.
If you have finished working on a project and want to free up the space used by its development environment, run fdk remove
from the project folder. This will remove the Docker containers and images used for the project (so your development database will be deleted). You can delete the www/
folder too, but this removes all files from the WP installation, so make sure to save any files in www/wp-content/
you might need (such as secondary themes, plugins or uploads).
Theme source files live in the src/
folder β while Gulp is running your changes will be live-compiled from here into the virtual machine's active theme folder (in www/wp-content/themes/
). The build/
folder is a shortcut symlink to the active theme folder: no editing should be done here, but it may occasionally be useful for checking compiled code in case of problems.
File paths in this section refer to the src/
.
- If you want to make use of Timber (and you would be insane not to), the PHP files live in
templates/controllers/
and the corresponding Twig views intemplates/views/
. See the Timber documentation and the MVC section of code examples below for more information. - If you don't or can't use Timber, just create your vanilla WordPress templates in
templates/controllers/
as you usually would and they'll work fine.
- CSS goes in
assets/css/main.pcss
(automatically included in the front-end). If you prefer to split it into several files, you can include the additional files with@import
at the top. Vanilla CSS works fine but any PostCSS is processed automatically (see below). - Javascript / jQuery code goes in
assets/js/main.js
(automatically included in the front-end), or additional JS files can be enqueued in the standard WordPress way by hookingwp_enqueue_scripts
according to where you want the assets to load (most likely inincludes/front.php
β see next section). - Images can go in
assets/img/
and any local fonts inassets/fonts/
. These can be referenced from the stylesheet via../img/
or../fonts/
.
Fabrica Dev Kit's super-minimal boilerplate makes no assumptions about your data or design, but it's organized to make it easy for you to hook WordPress actions and filters and add your own functions.
There are several predefined files (all in the includes/
folder) to help keep your custom code well-organized. We recommend keeping all project code within the object-oriented namespaced structure provided by these files, but any other .php
file you create in the includes/
folder will be automatically included and run in the active theme: there is no need to manually require()
or include()
it.
project.php
for hooks that should affect both front-end and admin requests, and for any other functions which you might need to make available to your theme (as methods of the singletonProject
class).front.php
for hooks that should only affect front-end requests.admin.php
for hooks that should only affect admin requests (the constructor includes these conditions).ajax.php
for handling AJAX requests (the front-end calls can be added inassets/main.js
).models.php
is where to extend Post / Term / User objects by assigning extra properties to them when instantiated: see MVC section in code examples below.
- Additional build tools (eg. PostCSS plugins): use
npm install
in the project folder, and modify thegulpfile.js
accordingly to sequence them. - Front-end JS libraries: use
npm install
in thesrc/
folder and then either included (thanks to Webpack) viarequire
statements inassets/js/main.js
, - Front-end CSS libraries: use
npm install
in thesrc/
folder and included via@import
statements inassets/css/main.pcss
. The PostCSS Import plugin automatically searchesnode_modules
so a statement like@import 'library.css'
doesn't require an explicit path. - PHP modules: you can install / require Composer modules from within the
includes/
folder.
All of the techniques below are optional in Fabrica Dev Kit and vanilla HTML / CSS / PHP / WordPress API functions will all work fine β but we highly recommend making full use of these time- and sanity-saving enhancements.
Achieving a Model-View-Controller (MVC) paradigm with Timber + ACF
The magic combination of Timber and Advanced Custom Fields means we can render even complex data in our templates without carrying out any data retrieval or decision logic at all. Take for example this Repeater field setup:
With Twig (via Timber) we can display this data in a template as follows, without having to write any PHP.
{% if post.measurements %}
{% for measurement in post.get_field('measurements') %}
<div>
{{ measurement.title.label }}:
{{ measurement.value }}{{ measurement.unit }}
</div>
{% endfor %}
{% endif %}
But we can go further. Say we need to derive additional data about each object (in this case, the Post containing measurements) at runtime, in order to display that data in our template. For example, let's say we also want to show our metric (cm or m) measurements in imperial for US users.
One way of doing this would be to prepare the additional data in the template (eg. post.php
) just before it renders post.twig
. But we can go one step further and implement a full MVC paradigm, so that this information is available right from the moment the Post object is instantiated (and therefore available for all similar Post objects across the site, whenever required).
To achieve this we add the following child class in models.php
:
class PostWithMeasurements extends \Timber\Post {
var $_allMeasurements; // Used to cache the values for each instance
function allMeasurements() {
if (!$_allMeasurements) {
$ms = $this->get_field('measurements');
if (!$ms) {
return ($_allMeasurements = false); // No measurements saved
}
foreach ($ms as &$m) {
if ($m['unit'] == 'cm') { // Centimetres
$m['imperialUnit'] = 'in';
$m['imperialValue'] = $m['value'] / 2.54;
}
if ($m['unit'] == 'm') { // Metres
$m['imperialUnit'] = 'ft';
$m['imperialValue'] = $m['value'] * 3.28084;
}
}
$_allMeasurements = $ms;
}
return $_allMeasurements;
}
}
The additional information will be automatically available to the template, as long as we make sure to instantiate the enhanced post object with $post = new PostWithMeasurements();
in our post.php
. Then we only have to add one more short piece of Twig code to have this information displayed in our template:
{% if post.measurements %}
{% for measurement in post.allMeasurements %}
<div>
{{ measurement.title.label }}:
{{ measurement.value }}{{ measurement.unit }}
{% if measurement.imperialValue %}
({{ measurement.imperialValue }}{{ measurement.imperialUnit }})
{% endif %}
</div>
{% endfor %}
{% endif %}
Note how here we access post.allMeasurements
directly, without needing the call to post.get_field()
in Twig (which is normally essential to receive full ACF Repeater data), since we have already made that call when mapping the new property in models.php
.
The BEM methodology provides a conceptual framework which makes it easy to build blocks (groups of design and content elements) to be reused across a site without having to worry about either duplicated or conflicting rules. The methodology is simple but promotes logical, disciplined thinking and efficient, modular code. You can read more about the principles of BEM online, for example on CSS Wizardry.
The inclusion of PostHTML, PostCSS, and specific plugins for these, in Fabrica Dev Kit make the process of actually writing BEM markup and styles quicker, easier and less error-prone.
As an example, let's take some vanilla BEM markup and styles. We're using __
notation for elements and --
notation for modifiers. (If you prefer an alternative notation, you can configure it in gulpfile.js
by modifying the posthtmlBem
property of the options
hash.)
First, the HTML:
<div class="measurements">
<div class="measurement__entry measurement__entry--highlight">
<span class="measurements__label">Width</span>:
<span class="measurements__number">55</span>
<span class="measurements__unit">cm</span>
</div>
<div class="measurement__entry">
<span class="measurements__label">Length</span>:
<span class="measurements__number">10</span>
<span class="measurements__unit">m</span>
</div>
</div>
Second, some corresponding CSS (fairly basic, but targets several of the member elements):
.measurements {
font-family: monospace;
}
.measurements__entry--highlight {
color: #f00;
}
.measurements__label {
color: #777;
}
.measurements__number {
font-weight: bold;
}
.measurements__unit {
color: #aaa;
}
With PostHTML-bem + PostCSS we can avoid repetition in both places, which makes the code easier to write, easier to read, and less prone to typos. Here are the equivalent versions:
First, the markup: note how we use the attributes block
, elem
and mod
instead of classes, but these are automatically rendered as classes, so that the following compiles identically to the HTML above.
<div block="measurements">
<div elem="entry" mods="highlight">
<span elem="label">Width</span>:
<span elem="number">55</span>
<span elem="unit">cm</span>
</div>
<div elem="entry">
<span elem="label">Length</span>:
<span elem="number">10</span>
<span elem="unit">m</span>
</div>
</div>
Second, the PostCSS, where we can make use of the &
token both to nest elements within their containing block, and without repeating the block name, so that the following compiles to the CSS above.
.measurements {
font-family: monospace;
&__entry { /* Element */
&--highlight { /* Modifier of the element */
color: #f00;
}
}
&__label {
color: #777;
}
&__number {
font-weight: bold;
}
&__unit {
color: #aaa;
}
}